OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/ash/event_rewriter.h" | 5 #include "chrome/browser/ui/ash/event_rewriter.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "ash/shell.h" | 9 #include "ash/shell.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "chrome/browser/prefs/pref_service.h" | 12 #include "chrome/browser/prefs/pref_service.h" |
13 #include "chrome/browser/profiles/profile_manager.h" | 13 #include "chrome/browser/profiles/profile_manager.h" |
14 #include "ui/aura/root_window.h" | 14 #include "ui/aura/root_window.h" |
15 #include "ui/base/events/event.h" | 15 #include "ui/base/events/event.h" |
16 #include "ui/base/keycodes/keyboard_code_conversion.h" | 16 #include "ui/base/keycodes/keyboard_code_conversion.h" |
17 | 17 |
18 #if defined(OS_CHROMEOS) | 18 #if defined(OS_CHROMEOS) |
19 #include <X11/extensions/XInput2.h> | 19 #include <X11/extensions/XInput2.h> |
20 #include <X11/keysym.h> | 20 #include <X11/keysym.h> |
21 #include <X11/XF86keysym.h> | 21 #include <X11/XF86keysym.h> |
22 #include <X11/Xlib.h> | 22 #include <X11/Xlib.h> |
23 | 23 |
24 // Get rid of a macro from Xlib.h that conflicts with OwnershipService class. | 24 // Get rid of a macro from Xlib.h that conflicts with OwnershipService class. |
25 #undef Status | 25 #undef Status |
26 | 26 |
27 #include "base/chromeos/chromeos_version.h" | 27 #include "base/chromeos/chromeos_version.h" |
28 #include "base/command_line.h" | |
28 #include "chrome/browser/chromeos/input_method/input_method_manager.h" | 29 #include "chrome/browser/chromeos/input_method/input_method_manager.h" |
29 #include "chrome/browser/chromeos/input_method/xkeyboard.h" | 30 #include "chrome/browser/chromeos/input_method/xkeyboard.h" |
30 #include "chrome/browser/chromeos/login/base_login_display_host.h" | 31 #include "chrome/browser/chromeos/login/base_login_display_host.h" |
31 #include "chrome/browser/chromeos/login/user_manager.h" | 32 #include "chrome/browser/chromeos/login/user_manager.h" |
32 #include "chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.h" | 33 #include "chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.h" |
34 #include "chrome/common/chrome_switches.h" | |
33 #include "chrome/common/pref_names.h" | 35 #include "chrome/common/pref_names.h" |
34 #include "ui/base/keycodes/keyboard_code_conversion_x.h" | 36 #include "ui/base/keycodes/keyboard_code_conversion_x.h" |
35 #include "ui/base/x/x11_util.h" | 37 #include "ui/base/x/x11_util.h" |
36 | 38 |
37 using chromeos::input_method::InputMethodManager; | 39 using chromeos::input_method::InputMethodManager; |
38 #endif | 40 #endif |
39 | 41 |
40 namespace { | 42 namespace { |
41 | 43 |
42 const int kBadDeviceId = -1; | 44 const int kBadDeviceId = -1; |
(...skipping 16 matching lines...) Expand all Loading... | |
59 { XK_Control_L, XK_Control_R, XK_Control_L, XK_Control_R }}, | 61 { XK_Control_L, XK_Control_R, XK_Control_L, XK_Control_R }}, |
60 { chromeos::input_method::kAltKey, ui::EF_ALT_DOWN, Mod1Mask, | 62 { chromeos::input_method::kAltKey, ui::EF_ALT_DOWN, Mod1Mask, |
61 ui::VKEY_MENU, { XK_Alt_L, XK_Alt_R, XK_Meta_L, XK_Meta_R }}, | 63 ui::VKEY_MENU, { XK_Alt_L, XK_Alt_R, XK_Meta_L, XK_Meta_R }}, |
62 { chromeos::input_method::kVoidKey, 0, 0U, ui::VKEY_UNKNOWN, | 64 { chromeos::input_method::kVoidKey, 0, 0U, ui::VKEY_UNKNOWN, |
63 { XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol }}, | 65 { XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol }}, |
64 { chromeos::input_method::kCapsLockKey, 0, 0U, ui::VKEY_CAPITAL, | 66 { chromeos::input_method::kCapsLockKey, 0, 0U, ui::VKEY_CAPITAL, |
65 { XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock }}, | 67 { XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock }}, |
66 }; | 68 }; |
67 | 69 |
68 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1]; | 70 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1]; |
71 const ModifierRemapping* kModifierRemappingCapsLock = &kModifierRemappings[4]; | |
69 | 72 |
70 // A structure for converting |native_modifier| to a pair of |flag| and | 73 // A structure for converting |native_modifier| to a pair of |flag| and |
71 // |pref_name|. | 74 // |pref_name|. |
72 const struct ModifierFlagToPrefName { | 75 const struct ModifierFlagToPrefName { |
73 unsigned int native_modifier; | 76 unsigned int native_modifier; |
74 int flag; | 77 int flag; |
75 const char* pref_name; | 78 const char* pref_name; |
76 } kModifierFlagToPrefName[] = { | 79 } kModifierFlagToPrefName[] = { |
77 // TODO(yusukes): When the device has a Chrome keyboard (i.e. the one without | 80 // TODO(yusukes): When the device has a Chrome keyboard (i.e. the one without |
78 // Caps Lock), we should not check kLanguageRemapCapsLockKeyTo. | 81 // Caps Lock), we should not check kLanguageRemapCapsLockKeyTo. |
(...skipping 26 matching lines...) Expand all Loading... | |
105 case XK_Meta_R: | 108 case XK_Meta_R: |
106 case XK_Shift_R: | 109 case XK_Shift_R: |
107 case XK_Super_R: | 110 case XK_Super_R: |
108 return true; | 111 return true; |
109 default: | 112 default: |
110 break; | 113 break; |
111 } | 114 } |
112 return false; | 115 return false; |
113 } | 116 } |
114 | 117 |
115 bool ShouldRemapCapsLock() { | 118 bool HasChromeOSKeyboard() { |
116 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask, it's | 119 return CommandLine::ForCurrentProcess()->HasSwitch( |
117 // not possible to make both features work. For now, we don't remap Mod3Mask | 120 switches::kHasChromeOSKeyboard); |
118 // when Neo2 is in use. | 121 } |
122 | |
123 bool IsMod3InUse() { | |
Daniel Erat
2012/11/01 19:13:06
nit: IsMod3UsedByCurrentInputMethod() may be a bit
Yusuke Sato
2012/11/01 19:25:27
Thanks, done.
| |
124 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask, | |
125 // it's not possible to make both features work. For now, we don't remap | |
126 // Mod3Mask when Neo2 is in use. | |
119 // TODO(yusukes): Remove the restriction. | 127 // TODO(yusukes): Remove the restriction. |
120 return InputMethodManager::GetInstance()->GetCurrentInputMethod().id() != | 128 return InputMethodManager::GetInstance()->GetCurrentInputMethod().id() == |
121 kNeo2LayoutId; | 129 kNeo2LayoutId; |
122 } | 130 } |
123 #endif | 131 #endif |
124 | 132 |
125 const PrefService* GetPrefService() { | 133 const PrefService* GetPrefService() { |
126 Profile* profile = ProfileManager::GetDefaultProfile(); | 134 Profile* profile = ProfileManager::GetDefaultProfile(); |
127 if (profile) | 135 if (profile) |
128 return profile->GetPrefs(); | 136 return profile->GetPrefs(); |
129 return NULL; | 137 return NULL; |
130 } | 138 } |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
387 if (chromeos::UserManager::Get()->IsLoggedInAsGuest() && | 395 if (chromeos::UserManager::Get()->IsLoggedInAsGuest() && |
388 chromeos::BaseLoginDisplayHost::default_host()) { | 396 chromeos::BaseLoginDisplayHost::default_host()) { |
389 return; | 397 return; |
390 } | 398 } |
391 | 399 |
392 const PrefService* pref_service = | 400 const PrefService* pref_service = |
393 pref_service_ ? pref_service_ : GetPrefService(); | 401 pref_service_ ? pref_service_ : GetPrefService(); |
394 if (!pref_service) | 402 if (!pref_service) |
395 return; | 403 return; |
396 | 404 |
397 const bool skip_mod3 = !ShouldRemapCapsLock(); | 405 // When a Chrome OS keyboard is available, the configuration UI for Caps Lock |
406 // is not shown. Therefore, ignore the kLanguageRemapCapsLockKeyTo syncable | |
407 // pref. If Mod3 is in use, don't check the pref either. | |
408 const bool skip_mod3 = HasChromeOSKeyboard() || IsMod3InUse(); | |
409 | |
398 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) { | 410 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) { |
399 if (skip_mod3 && | 411 if (skip_mod3 && |
400 (kModifierFlagToPrefName[i].native_modifier == Mod3Mask)) { | 412 (kModifierFlagToPrefName[i].native_modifier == Mod3Mask)) { |
401 continue; | 413 continue; |
402 } | 414 } |
403 if (original_native_modifiers & | 415 if (original_native_modifiers & |
404 kModifierFlagToPrefName[i].native_modifier) { | 416 kModifierFlagToPrefName[i].native_modifier) { |
405 const ModifierRemapping* remapped_key = | 417 const ModifierRemapping* remapped_key = |
406 GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service); | 418 GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service); |
407 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. | 419 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
455 DCHECK_EQ(chromeos::input_method::kControlKey, | 467 DCHECK_EQ(chromeos::input_method::kControlKey, |
456 kModifierRemappingCtrl->remap_to); | 468 kModifierRemappingCtrl->remap_to); |
457 | 469 |
458 XEvent* xev = event->native_event(); | 470 XEvent* xev = event->native_event(); |
459 XKeyEvent* xkey = &(xev->xkey); | 471 XKeyEvent* xkey = &(xev->xkey); |
460 KeySym keysym = XLookupKeysym(xkey, 0); | 472 KeySym keysym = XLookupKeysym(xkey, 0); |
461 | 473 |
462 ui::KeyboardCode remapped_keycode = event->key_code(); | 474 ui::KeyboardCode remapped_keycode = event->key_code(); |
463 KeyCode remapped_native_keycode = xkey->keycode; | 475 KeyCode remapped_native_keycode = xkey->keycode; |
464 | 476 |
465 const bool skip_mod3 = !ShouldRemapCapsLock(); | |
466 | |
467 // First, remap |keysym|. | 477 // First, remap |keysym|. |
468 const char* pref_name = NULL; | 478 const ModifierRemapping* remapped_key = NULL; |
469 switch (keysym) { | 479 switch (keysym) { |
470 // XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock is pressed. | 480 // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock |
481 // is pressed (with one exception: when IsMod3InUse() is true, the key | |
482 // generates XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7). | |
471 case XF86XK_Launch7: | 483 case XF86XK_Launch7: |
472 pref_name = skip_mod3 ? NULL : prefs::kLanguageRemapCapsLockKeyTo; | 484 // When a Chrome OS keyboard is available, the configuration UI for Caps |
485 // Lock is not shown. Therefore, ignore the kLanguageRemapCapsLockKeyTo | |
486 // syncable pref. | |
487 if (HasChromeOSKeyboard()) | |
488 remapped_key = kModifierRemappingCapsLock; | |
489 else | |
490 remapped_key = | |
491 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service); | |
473 break; | 492 break; |
474 case XK_Super_L: | 493 case XK_Super_L: |
475 case XK_Super_R: | 494 case XK_Super_R: |
476 pref_name = prefs::kLanguageRemapSearchKeyTo; | 495 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. |
496 if (IsAppleKeyboard()) | |
497 remapped_key = kModifierRemappingCtrl; | |
498 else | |
499 remapped_key = | |
500 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service); | |
477 break; | 501 break; |
478 case XK_Control_L: | 502 case XK_Control_L: |
479 case XK_Control_R: | 503 case XK_Control_R: |
480 pref_name = prefs::kLanguageRemapControlKeyTo; | 504 remapped_key = |
505 GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service); | |
481 break; | 506 break; |
482 case XK_Alt_L: | 507 case XK_Alt_L: |
483 case XK_Alt_R: | 508 case XK_Alt_R: |
484 case XK_Meta_L: | 509 case XK_Meta_L: |
485 case XK_Meta_R: | 510 case XK_Meta_R: |
486 pref_name = prefs::kLanguageRemapAltKeyTo; | 511 remapped_key = |
512 GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service); | |
487 break; | 513 break; |
488 default: | 514 default: |
489 break; | 515 break; |
490 } | 516 } |
491 if (pref_name) { | 517 |
492 const ModifierRemapping* remapped_key = | 518 if (remapped_key) { |
493 GetRemappedKey(pref_name, *pref_service); | 519 remapped_keycode = remapped_key->keycode; |
494 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. | 520 const size_t level = (event->IsShiftDown() ? (1 << 1) : 0) + |
495 if (IsAppleKeyboard() && (keysym == XK_Super_L || keysym == XK_Super_R)) | 521 (IsRight(keysym) ? (1 << 0) : 0); |
496 remapped_key = kModifierRemappingCtrl; | 522 const KeySym native_keysym = remapped_key->native_keysyms[level]; |
497 if (remapped_key) { | 523 remapped_native_keycode = NativeKeySymToNativeKeycode(native_keysym); |
498 remapped_keycode = remapped_key->keycode; | |
499 const size_t level = (event->IsShiftDown() ? (1 << 1) : 0) + | |
500 (IsRight(keysym) ? (1 << 0) : 0); | |
501 const KeySym native_keysym = remapped_key->native_keysyms[level]; | |
502 remapped_native_keycode = NativeKeySymToNativeKeycode(native_keysym); | |
503 } | |
504 } | 524 } |
505 | 525 |
506 // Next, remap modifier bits. | 526 // Next, remap modifier bits. |
507 int remapped_flags = 0; | 527 int remapped_flags = 0; |
508 unsigned int remapped_native_modifiers = 0U; | 528 unsigned int remapped_native_modifiers = 0U; |
509 GetRemappedModifierMasks(event->flags(), xkey->state, | 529 GetRemappedModifierMasks(event->flags(), xkey->state, |
510 &remapped_flags, &remapped_native_modifiers); | 530 &remapped_flags, &remapped_native_modifiers); |
511 | 531 |
512 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if | 532 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if |
513 // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external | 533 // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
727 const DeviceType type = EventRewriter::GetDeviceType(device_name); | 747 const DeviceType type = EventRewriter::GetDeviceType(device_name); |
728 if (type == kDeviceAppleKeyboard) { | 748 if (type == kDeviceAppleKeyboard) { |
729 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " | 749 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " |
730 << "id=" << device_id; | 750 << "id=" << device_id; |
731 } | 751 } |
732 // Always overwrite the existing device_id since the X server may reuse a | 752 // Always overwrite the existing device_id since the X server may reuse a |
733 // device id for an unattached device. | 753 // device id for an unattached device. |
734 device_id_to_type_[device_id] = type; | 754 device_id_to_type_[device_id] = type; |
735 return type; | 755 return type; |
736 } | 756 } |
OLD | NEW |