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 IsMod3UsedByCurrentInputMethod() { |
| 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 = |
| 409 HasChromeOSKeyboard() || IsMod3UsedByCurrentInputMethod(); |
| 410 |
398 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) { | 411 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) { |
399 if (skip_mod3 && | 412 if (skip_mod3 && |
400 (kModifierFlagToPrefName[i].native_modifier == Mod3Mask)) { | 413 (kModifierFlagToPrefName[i].native_modifier == Mod3Mask)) { |
401 continue; | 414 continue; |
402 } | 415 } |
403 if (original_native_modifiers & | 416 if (original_native_modifiers & |
404 kModifierFlagToPrefName[i].native_modifier) { | 417 kModifierFlagToPrefName[i].native_modifier) { |
405 const ModifierRemapping* remapped_key = | 418 const ModifierRemapping* remapped_key = |
406 GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service); | 419 GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service); |
407 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. | 420 // 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, | 468 DCHECK_EQ(chromeos::input_method::kControlKey, |
456 kModifierRemappingCtrl->remap_to); | 469 kModifierRemappingCtrl->remap_to); |
457 | 470 |
458 XEvent* xev = event->native_event(); | 471 XEvent* xev = event->native_event(); |
459 XKeyEvent* xkey = &(xev->xkey); | 472 XKeyEvent* xkey = &(xev->xkey); |
460 KeySym keysym = XLookupKeysym(xkey, 0); | 473 KeySym keysym = XLookupKeysym(xkey, 0); |
461 | 474 |
462 ui::KeyboardCode remapped_keycode = event->key_code(); | 475 ui::KeyboardCode remapped_keycode = event->key_code(); |
463 KeyCode remapped_native_keycode = xkey->keycode; | 476 KeyCode remapped_native_keycode = xkey->keycode; |
464 | 477 |
465 const bool skip_mod3 = !ShouldRemapCapsLock(); | |
466 | |
467 // First, remap |keysym|. | 478 // First, remap |keysym|. |
468 const char* pref_name = NULL; | 479 const ModifierRemapping* remapped_key = NULL; |
469 switch (keysym) { | 480 switch (keysym) { |
470 // XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock is pressed. | 481 // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock |
| 482 // is pressed (with one exception: when IsMod3UsedByCurrentInputMethod() is |
| 483 // true, the key generates XK_ISO_Level3_Shift with Mod3Mask, not |
| 484 // XF86XK_Launch7). |
471 case XF86XK_Launch7: | 485 case XF86XK_Launch7: |
472 pref_name = skip_mod3 ? NULL : prefs::kLanguageRemapCapsLockKeyTo; | 486 // When a Chrome OS keyboard is available, the configuration UI for Caps |
| 487 // Lock is not shown. Therefore, ignore the kLanguageRemapCapsLockKeyTo |
| 488 // syncable pref. |
| 489 if (HasChromeOSKeyboard()) |
| 490 remapped_key = kModifierRemappingCapsLock; |
| 491 else |
| 492 remapped_key = |
| 493 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service); |
473 break; | 494 break; |
474 case XK_Super_L: | 495 case XK_Super_L: |
475 case XK_Super_R: | 496 case XK_Super_R: |
476 pref_name = prefs::kLanguageRemapSearchKeyTo; | 497 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. |
| 498 if (IsAppleKeyboard()) |
| 499 remapped_key = kModifierRemappingCtrl; |
| 500 else |
| 501 remapped_key = |
| 502 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service); |
477 break; | 503 break; |
478 case XK_Control_L: | 504 case XK_Control_L: |
479 case XK_Control_R: | 505 case XK_Control_R: |
480 pref_name = prefs::kLanguageRemapControlKeyTo; | 506 remapped_key = |
| 507 GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service); |
481 break; | 508 break; |
482 case XK_Alt_L: | 509 case XK_Alt_L: |
483 case XK_Alt_R: | 510 case XK_Alt_R: |
484 case XK_Meta_L: | 511 case XK_Meta_L: |
485 case XK_Meta_R: | 512 case XK_Meta_R: |
486 pref_name = prefs::kLanguageRemapAltKeyTo; | 513 remapped_key = |
| 514 GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service); |
487 break; | 515 break; |
488 default: | 516 default: |
489 break; | 517 break; |
490 } | 518 } |
491 if (pref_name) { | 519 |
492 const ModifierRemapping* remapped_key = | 520 if (remapped_key) { |
493 GetRemappedKey(pref_name, *pref_service); | 521 remapped_keycode = remapped_key->keycode; |
494 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. | 522 const size_t level = (event->IsShiftDown() ? (1 << 1) : 0) + |
495 if (IsAppleKeyboard() && (keysym == XK_Super_L || keysym == XK_Super_R)) | 523 (IsRight(keysym) ? (1 << 0) : 0); |
496 remapped_key = kModifierRemappingCtrl; | 524 const KeySym native_keysym = remapped_key->native_keysyms[level]; |
497 if (remapped_key) { | 525 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 } | 526 } |
505 | 527 |
506 // Next, remap modifier bits. | 528 // Next, remap modifier bits. |
507 int remapped_flags = 0; | 529 int remapped_flags = 0; |
508 unsigned int remapped_native_modifiers = 0U; | 530 unsigned int remapped_native_modifiers = 0U; |
509 GetRemappedModifierMasks(event->flags(), xkey->state, | 531 GetRemappedModifierMasks(event->flags(), xkey->state, |
510 &remapped_flags, &remapped_native_modifiers); | 532 &remapped_flags, &remapped_native_modifiers); |
511 | 533 |
512 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if | 534 // 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 | 535 // 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); | 749 const DeviceType type = EventRewriter::GetDeviceType(device_name); |
728 if (type == kDeviceAppleKeyboard) { | 750 if (type == kDeviceAppleKeyboard) { |
729 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " | 751 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " |
730 << "id=" << device_id; | 752 << "id=" << device_id; |
731 } | 753 } |
732 // Always overwrite the existing device_id since the X server may reuse a | 754 // Always overwrite the existing device_id since the X server may reuse a |
733 // device id for an unattached device. | 755 // device id for an unattached device. |
734 device_id_to_type_[device_id] = type; | 756 device_id_to_type_[device_id] = type; |
735 return type; | 757 return type; |
736 } | 758 } |
OLD | NEW |