Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: chrome/browser/ui/ash/event_rewriter.cc

Issue 11314020: Allow Caps Lock to be remapped [part 1 of 2] (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/Xlib.h> 22 #include <X11/Xlib.h>
22 23
23 // 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.
24 #undef Status 25 #undef Status
25 26
26 #include "base/chromeos/chromeos_version.h" 27 #include "base/chromeos/chromeos_version.h"
27 #include "chrome/browser/chromeos/input_method/input_method_manager.h" 28 #include "chrome/browser/chromeos/input_method/input_method_manager.h"
28 #include "chrome/browser/chromeos/input_method/xkeyboard.h" 29 #include "chrome/browser/chromeos/input_method/xkeyboard.h"
29 #include "chrome/browser/chromeos/login/base_login_display_host.h" 30 #include "chrome/browser/chromeos/login/base_login_display_host.h"
30 #include "chrome/browser/chromeos/login/user_manager.h" 31 #include "chrome/browser/chromeos/login/user_manager.h"
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 67
67 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1]; 68 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1];
68 69
69 // A structure for converting |native_modifier| to a pair of |flag| and 70 // A structure for converting |native_modifier| to a pair of |flag| and
70 // |pref_name|. 71 // |pref_name|.
71 const struct ModifierFlagToPrefName { 72 const struct ModifierFlagToPrefName {
72 unsigned int native_modifier; 73 unsigned int native_modifier;
73 int flag; 74 int flag;
74 const char* pref_name; 75 const char* pref_name;
75 } kModifierFlagToPrefName[] = { 76 } kModifierFlagToPrefName[] = {
77 // TODO(yusukes): When the device has a Chrome keyboard (i.e. the one without
78 // Caps Lock), we should not check kLanguageRemapCapsLockKeyTo.
79 { Mod3Mask, 0, prefs::kLanguageRemapCapsLockKeyTo },
76 { Mod4Mask, 0, prefs::kLanguageRemapSearchKeyTo }, 80 { Mod4Mask, 0, prefs::kLanguageRemapSearchKeyTo },
77 { ControlMask, ui::EF_CONTROL_DOWN, prefs::kLanguageRemapControlKeyTo }, 81 { ControlMask, ui::EF_CONTROL_DOWN, prefs::kLanguageRemapControlKeyTo },
78 { Mod1Mask, ui::EF_ALT_DOWN, prefs::kLanguageRemapAltKeyTo }, 82 { Mod1Mask, ui::EF_ALT_DOWN, prefs::kLanguageRemapAltKeyTo },
79 }; 83 };
80 84
81 // Gets a remapped key for |pref_name| key. For example, to find out which 85 // Gets a remapped key for |pref_name| key. For example, to find out which
82 // key Search is currently remapped to, call the function with 86 // key Search is currently remapped to, call the function with
83 // prefs::kLanguageRemapSearchKeyTo. 87 // prefs::kLanguageRemapSearchKeyTo.
84 const ModifierRemapping* GetRemappedKey(const std::string& pref_name, 88 const ModifierRemapping* GetRemappedKey(const std::string& pref_name,
85 const PrefService& pref_service) { 89 const PrefService& pref_service) {
(...skipping 14 matching lines...) Expand all
100 case XK_Hyper_R: 104 case XK_Hyper_R:
101 case XK_Meta_R: 105 case XK_Meta_R:
102 case XK_Shift_R: 106 case XK_Shift_R:
103 case XK_Super_R: 107 case XK_Super_R:
104 return true; 108 return true;
105 default: 109 default:
106 break; 110 break;
107 } 111 }
108 return false; 112 return false;
109 } 113 }
114
115 bool ShouldRemapCapsLock() {
116 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask, it's
117 // not possible to make both features work. For now, we don't remap Mod3Mask
118 // when Neo2 is in use.
119 // TODO(yusukes): Remove the restriction.
120 return InputMethodManager::GetInstance()->GetCurrentInputMethod().id() !=
121 kNeo2LayoutId;
122 }
110 #endif 123 #endif
111 124
112 const PrefService* GetPrefService() { 125 const PrefService* GetPrefService() {
113 Profile* profile = ProfileManager::GetDefaultProfile(); 126 Profile* profile = ProfileManager::GetDefaultProfile();
114 if (profile) 127 if (profile)
115 return profile->GetPrefs(); 128 return profile->GetPrefs();
116 return NULL; 129 return NULL;
117 } 130 }
118 131
119 } // namespace 132 } // namespace
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 #endif 348 #endif
336 349
337 void EventRewriter::Rewrite(ui::KeyEvent* event) { 350 void EventRewriter::Rewrite(ui::KeyEvent* event) {
338 #if defined(OS_CHROMEOS) 351 #if defined(OS_CHROMEOS)
339 // Do not rewrite an event sent by ui_controls::SendKeyPress(). See 352 // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
340 // crbug.com/136465. 353 // crbug.com/136465.
341 if (event->native_event()->xkey.send_event) 354 if (event->native_event()->xkey.send_event)
342 return; 355 return;
343 #endif 356 #endif
344 RewriteModifiers(event); 357 RewriteModifiers(event);
345 // This should be called after RewriteModifiers(). Otherwise, remapped
346 // Mod3Mask might be re-remapped.
347 RewriteFnKey(event);
348 RewriteNumPadKeys(event); 358 RewriteNumPadKeys(event);
349 RewriteBackspaceAndArrowKeys(event); 359 RewriteBackspaceAndArrowKeys(event);
350 // TODO(yusukes): Implement crosbug.com/27167 (allow sending function keys). 360 // TODO(yusukes): Implement crosbug.com/27167 (allow sending function keys).
351 } 361 }
352 362
353 bool EventRewriter::IsAppleKeyboard() const { 363 bool EventRewriter::IsAppleKeyboard() const {
354 if (last_device_id_ == kBadDeviceId) 364 if (last_device_id_ == kBadDeviceId)
355 return false; 365 return false;
356 366
357 // Check which device generated |event|. 367 // Check which device generated |event|.
(...skipping 19 matching lines...) Expand all
377 if (chromeos::UserManager::Get()->IsLoggedInAsGuest() && 387 if (chromeos::UserManager::Get()->IsLoggedInAsGuest() &&
378 chromeos::BaseLoginDisplayHost::default_host()) { 388 chromeos::BaseLoginDisplayHost::default_host()) {
379 return; 389 return;
380 } 390 }
381 391
382 const PrefService* pref_service = 392 const PrefService* pref_service =
383 pref_service_ ? pref_service_ : GetPrefService(); 393 pref_service_ ? pref_service_ : GetPrefService();
384 if (!pref_service) 394 if (!pref_service)
385 return; 395 return;
386 396
397 const bool skip_mod3 = !ShouldRemapCapsLock();
387 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) { 398 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) {
399 if (skip_mod3 &&
400 (kModifierFlagToPrefName[i].native_modifier == Mod3Mask)) {
401 continue;
402 }
388 if (original_native_modifiers & 403 if (original_native_modifiers &
389 kModifierFlagToPrefName[i].native_modifier) { 404 kModifierFlagToPrefName[i].native_modifier) {
390 const ModifierRemapping* remapped_key = 405 const ModifierRemapping* remapped_key =
391 GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service); 406 GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service);
392 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. 407 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R.
393 if (IsAppleKeyboard() && 408 if (IsAppleKeyboard() &&
394 (kModifierFlagToPrefName[i].native_modifier == Mod4Mask)) { 409 (kModifierFlagToPrefName[i].native_modifier == Mod4Mask)) {
395 remapped_key = kModifierRemappingCtrl; 410 remapped_key = kModifierRemappingCtrl;
396 } 411 }
397 if (remapped_key) { 412 if (remapped_key) {
398 *remapped_flags |= remapped_key->flag; 413 *remapped_flags |= remapped_key->flag;
399 *remapped_native_modifiers |= remapped_key->native_modifier; 414 *remapped_native_modifiers |= remapped_key->native_modifier;
400 } else { 415 } else {
401 *remapped_flags |= kModifierFlagToPrefName[i].flag; 416 *remapped_flags |= kModifierFlagToPrefName[i].flag;
402 *remapped_native_modifiers |= 417 *remapped_native_modifiers |=
403 kModifierFlagToPrefName[i].native_modifier; 418 kModifierFlagToPrefName[i].native_modifier;
404 } 419 }
405 } 420 }
406 } 421 }
407 422
408 *remapped_flags = 423 *remapped_flags =
409 (original_flags & ~(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)) | 424 (original_flags & ~(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)) |
410 *remapped_flags; 425 *remapped_flags;
426
427 unsigned int native_mask = Mod4Mask | ControlMask | Mod1Mask;
428 if (!skip_mod3)
429 native_mask |= Mod3Mask;
411 *remapped_native_modifiers = 430 *remapped_native_modifiers =
412 (original_native_modifiers & ~(Mod4Mask | ControlMask | Mod1Mask)) | 431 (original_native_modifiers & ~native_mask) |
413 *remapped_native_modifiers; 432 *remapped_native_modifiers;
414 #endif 433 #endif
415 } 434 }
416 435
417 bool EventRewriter::RewriteModifiers(ui::KeyEvent* event) { 436 bool EventRewriter::RewriteModifiers(ui::KeyEvent* event) {
418 // Do nothing if we have just logged in as guest but have not restarted chrome 437 // Do nothing if we have just logged in as guest but have not restarted chrome
419 // process yet (so we are still on the login screen). In this situations we 438 // process yet (so we are still on the login screen). In this situations we
420 // have no user profile so can not do anything useful. 439 // have no user profile so can not do anything useful.
421 // Note that currently, unlike other accounts, when user logs in as guest, we 440 // Note that currently, unlike other accounts, when user logs in as guest, we
422 // restart chrome process. In future this is to be changed. 441 // restart chrome process. In future this is to be changed.
(...skipping 13 matching lines...) Expand all
436 DCHECK_EQ(chromeos::input_method::kControlKey, 455 DCHECK_EQ(chromeos::input_method::kControlKey,
437 kModifierRemappingCtrl->remap_to); 456 kModifierRemappingCtrl->remap_to);
438 457
439 XEvent* xev = event->native_event(); 458 XEvent* xev = event->native_event();
440 XKeyEvent* xkey = &(xev->xkey); 459 XKeyEvent* xkey = &(xev->xkey);
441 KeySym keysym = XLookupKeysym(xkey, 0); 460 KeySym keysym = XLookupKeysym(xkey, 0);
442 461
443 ui::KeyboardCode remapped_keycode = event->key_code(); 462 ui::KeyboardCode remapped_keycode = event->key_code();
444 KeyCode remapped_native_keycode = xkey->keycode; 463 KeyCode remapped_native_keycode = xkey->keycode;
445 464
465 const bool skip_mod3 = !ShouldRemapCapsLock();
466
446 // First, remap |keysym|. 467 // First, remap |keysym|.
447 const char* pref_name = NULL; 468 const char* pref_name = NULL;
448 switch (keysym) { 469 switch (keysym) {
470 // XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock is pressed.
471 case XF86XK_Launch7:
472 pref_name = skip_mod3 ? NULL : prefs::kLanguageRemapCapsLockKeyTo;
473 break;
449 case XK_Super_L: 474 case XK_Super_L:
450 case XK_Super_R: 475 case XK_Super_R:
451 pref_name = prefs::kLanguageRemapSearchKeyTo; 476 pref_name = prefs::kLanguageRemapSearchKeyTo;
452 break; 477 break;
453 case XK_Control_L: 478 case XK_Control_L:
454 case XK_Control_R: 479 case XK_Control_R:
455 pref_name = prefs::kLanguageRemapControlKeyTo; 480 pref_name = prefs::kLanguageRemapControlKeyTo;
456 break; 481 break;
457 case XK_Alt_L: 482 case XK_Alt_L:
458 case XK_Alt_R: 483 case XK_Alt_R:
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 OverwriteEvent(event, 523 OverwriteEvent(event,
499 remapped_native_keycode, remapped_native_modifiers, 524 remapped_native_keycode, remapped_native_modifiers,
500 remapped_keycode, remapped_flags); 525 remapped_keycode, remapped_flags);
501 return true; 526 return true;
502 #else 527 #else
503 // TODO(yusukes): Support Ash on other platforms if needed. 528 // TODO(yusukes): Support Ash on other platforms if needed.
504 return false; 529 return false;
505 #endif 530 #endif
506 } 531 }
507 532
508 bool EventRewriter::RewriteFnKey(ui::KeyEvent* event) {
509 #if defined(OS_CHROMEOS)
510 // Since both German Neo2 XKB layout and F15 depend on Mod3Mask, it's not
511 // possible to make both features work. For now, we don't remap Mod3Mask to
512 // ControlMask when Neo2 is in use.
513 // TODO(yusukes): Remove the restriction.
514 if (InputMethodManager::GetInstance()->GetCurrentInputMethod().id() ==
515 kNeo2LayoutId) {
516 return false;
517 }
518
519 XEvent* xev = event->native_event();
520 XKeyEvent* xkey = &(xev->xkey);
521
522 int remapped_flags = event->flags();
523 unsigned int remapped_native_modifiers = xkey->state;
524
525 // TODO(yusukes): Add a pref entry for specifying how to remap Fn key, and
526 // check it here if not in guest mode.
527 if (xkey->state & Mod3Mask) {
528 remapped_flags |= ui::EF_CONTROL_DOWN;
529 remapped_native_modifiers =
530 (remapped_native_modifiers & ~Mod3Mask) | ControlMask;
531 }
532
533 OverwriteEvent(event,
534 xkey->keycode, remapped_native_modifiers,
535 event->key_code(), remapped_flags);
536 return true;
537 #else
538 // TODO(yusukes): Support Ash on other platforms if needed.
539 return false;
540 #endif
541 }
542
543 bool EventRewriter::RewriteNumPadKeys(ui::KeyEvent* event) { 533 bool EventRewriter::RewriteNumPadKeys(ui::KeyEvent* event) {
544 bool rewritten = false; 534 bool rewritten = false;
545 #if defined(OS_CHROMEOS) 535 #if defined(OS_CHROMEOS)
546 XEvent* xev = event->native_event(); 536 XEvent* xev = event->native_event();
547 XKeyEvent* xkey = &(xev->xkey); 537 XKeyEvent* xkey = &(xev->xkey);
548 538
549 const KeySym keysym = XLookupKeysym(xkey, 0); 539 const KeySym keysym = XLookupKeysym(xkey, 0);
550 switch (keysym) { 540 switch (keysym) {
551 case XK_KP_Insert: 541 case XK_KP_Insert:
552 OverwriteEvent(event, kp_0_xkeycode_, xkey->state | Mod2Mask, 542 OverwriteEvent(event, kp_0_xkeycode_, xkey->state | Mod2Mask,
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 const DeviceType type = EventRewriter::GetDeviceType(device_name); 727 const DeviceType type = EventRewriter::GetDeviceType(device_name);
738 if (type == kDeviceAppleKeyboard) { 728 if (type == kDeviceAppleKeyboard) {
739 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " 729 VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
740 << "id=" << device_id; 730 << "id=" << device_id;
741 } 731 }
742 // Always overwrite the existing device_id since the X server may reuse a 732 // Always overwrite the existing device_id since the X server may reuse a
743 // device id for an unattached device. 733 // device id for an unattached device.
744 device_id_to_type_[device_id] = type; 734 device_id_to_type_[device_id] = type;
745 return type; 735 return type;
746 } 736 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698