Chromium Code Reviews| 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/views/ash/key_rewriter.h" | 5 #include "chrome/browser/ui/views/ash/key_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" |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 const ash::KeyRewriterDelegate::Action kActionRewrite = | 182 const ash::KeyRewriterDelegate::Action kActionRewrite = |
| 183 ash::KeyRewriterDelegate::ACTION_REWRITE_EVENT; | 183 ash::KeyRewriterDelegate::ACTION_REWRITE_EVENT; |
| 184 if (!event->HasNativeEvent()) { | 184 if (!event->HasNativeEvent()) { |
| 185 // Do not handle a fabricated event generated by tests. | 185 // Do not handle a fabricated event generated by tests. |
| 186 return kActionRewrite; | 186 return kActionRewrite; |
| 187 } | 187 } |
| 188 Rewrite(event); | 188 Rewrite(event); |
| 189 return kActionRewrite; // Do not drop the event. | 189 return kActionRewrite; // Do not drop the event. |
| 190 } | 190 } |
| 191 | 191 |
| 192 ash::KeyRewriterDelegate::Action KeyRewriter::RewriteOrFilterLocatedEvent( | |
| 193 aura::LocatedEvent* event) { | |
| 194 const ash::KeyRewriterDelegate::Action kActionRewrite = | |
| 195 ash::KeyRewriterDelegate::ACTION_REWRITE_EVENT; | |
| 196 if (!event->HasNativeEvent()) { | |
| 197 // Do not handle a fabricated event generated by tests. | |
| 198 return kActionRewrite; | |
| 199 } | |
| 200 RewriteLocatedEvent(event); | |
| 201 return kActionRewrite; | |
|
Daniel Erat
2012/07/09 18:18:28
nit: just simplify this to three lines?
... KeyRe
Yusuke Sato
2012/07/09 20:36:50
Done.
| |
| 202 } | |
| 203 | |
| 192 void KeyRewriter::OnKeyboardMappingChanged(const aura::RootWindow* root) { | 204 void KeyRewriter::OnKeyboardMappingChanged(const aura::RootWindow* root) { |
| 193 #if defined(OS_CHROMEOS) | 205 #if defined(OS_CHROMEOS) |
| 194 RefreshKeycodes(); | 206 RefreshKeycodes(); |
| 195 #endif | 207 #endif |
| 196 } | 208 } |
| 197 | 209 |
| 198 #if defined(OS_CHROMEOS) | 210 #if defined(OS_CHROMEOS) |
| 199 void KeyRewriter::DeviceAdded(int device_id) { | 211 void KeyRewriter::DeviceAdded(int device_id) { |
| 200 DCHECK_NE(XIAllDevices, device_id); | 212 DCHECK_NE(XIAllDevices, device_id); |
| 201 DCHECK_NE(XIAllMasterDevices, device_id); | 213 DCHECK_NE(XIAllMasterDevices, device_id); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 346 device_id_to_type_.find(last_device_id_); | 358 device_id_to_type_.find(last_device_id_); |
| 347 if (iter == device_id_to_type_.end()) { | 359 if (iter == device_id_to_type_.end()) { |
| 348 LOG(ERROR) << "Device ID " << last_device_id_ << " is unknown."; | 360 LOG(ERROR) << "Device ID " << last_device_id_ << " is unknown."; |
| 349 return false; | 361 return false; |
| 350 } | 362 } |
| 351 | 363 |
| 352 const DeviceType type = iter->second; | 364 const DeviceType type = iter->second; |
| 353 return type == kDeviceAppleKeyboard; | 365 return type == kDeviceAppleKeyboard; |
| 354 } | 366 } |
| 355 | 367 |
| 368 void KeyRewriter::GetRemappedModifierMasks( | |
| 369 int original_flags, | |
| 370 unsigned int original_native_modifiers, | |
| 371 int* remapped_flags, | |
| 372 unsigned int* remapped_native_modifiers) const { | |
| 373 #if defined(OS_CHROMEOS) | |
| 374 // TODO(glotov): remove the following condition when we do not restart chrome | |
| 375 // when user logs in as guest. See Rewrite() for details. | |
| 376 if (chromeos::UserManager::Get()->IsLoggedInAsGuest() && | |
| 377 chromeos::BaseLoginDisplayHost::default_host()) { | |
| 378 return; | |
| 379 } | |
| 380 | |
| 381 const PrefService* pref_service = | |
| 382 pref_service_ ? pref_service_ : GetPrefService(); | |
| 383 if (!pref_service) | |
| 384 return; | |
| 385 | |
| 386 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) { | |
| 387 if (original_native_modifiers & | |
| 388 kModifierFlagToPrefName[i].native_modifier) { | |
| 389 const ModifierRemapping* remapped_key = | |
| 390 GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service); | |
| 391 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. | |
| 392 if (IsAppleKeyboard() && | |
| 393 (kModifierFlagToPrefName[i].native_modifier == Mod4Mask)) { | |
| 394 remapped_key = kModifierRemappingCtrl; | |
| 395 } | |
| 396 if (remapped_key) { | |
| 397 *remapped_flags |= remapped_key->flag; | |
| 398 *remapped_native_modifiers |= remapped_key->native_modifier; | |
| 399 } else { | |
| 400 *remapped_flags |= kModifierFlagToPrefName[i].flag; | |
| 401 *remapped_native_modifiers |= | |
| 402 kModifierFlagToPrefName[i].native_modifier; | |
| 403 } | |
| 404 } | |
| 405 } | |
| 406 | |
| 407 *remapped_flags = | |
| 408 (original_flags & ~(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)) | | |
| 409 *remapped_flags; | |
| 410 *remapped_native_modifiers = | |
| 411 (original_native_modifiers & ~(Mod4Mask | ControlMask | Mod1Mask)) | | |
| 412 *remapped_native_modifiers; | |
| 413 #endif | |
| 414 } | |
| 415 | |
| 356 bool KeyRewriter::RewriteModifiers(aura::KeyEvent* event) { | 416 bool KeyRewriter::RewriteModifiers(aura::KeyEvent* event) { |
| 357 // Do nothing if we have just logged in as guest but have not restarted chrome | 417 // Do nothing if we have just logged in as guest but have not restarted chrome |
| 358 // process yet (so we are still on the login screen). In this situations we | 418 // process yet (so we are still on the login screen). In this situations we |
| 359 // have no user profile so can not do anything useful. | 419 // have no user profile so can not do anything useful. |
| 360 // Note that currently, unlike other accounts, when user logs in as guest, we | 420 // Note that currently, unlike other accounts, when user logs in as guest, we |
| 361 // restart chrome process. In future this is to be changed. | 421 // restart chrome process. In future this is to be changed. |
| 362 // TODO(glotov): remove the following condition when we do not restart chrome | 422 // TODO(glotov): remove the following condition when we do not restart chrome |
| 363 // when user logs in as guest. | 423 // when user logs in as guest. |
| 364 #if defined(OS_CHROMEOS) | 424 #if defined(OS_CHROMEOS) |
| 365 if (chromeos::UserManager::Get()->IsLoggedInAsGuest() && | 425 if (chromeos::UserManager::Get()->IsLoggedInAsGuest() && |
| 366 chromeos::BaseLoginDisplayHost::default_host()) | 426 chromeos::BaseLoginDisplayHost::default_host()) |
| 367 return false; | 427 return false; |
| 368 #endif // defined(OS_CHROMEOS) | 428 #endif // defined(OS_CHROMEOS) |
| 369 const PrefService* pref_service = | 429 const PrefService* pref_service = |
| 370 pref_service_ ? pref_service_ : GetPrefService(); | 430 pref_service_ ? pref_service_ : GetPrefService(); |
| 371 if (!pref_service) | 431 if (!pref_service) |
| 372 return false; | 432 return false; |
| 373 | 433 |
| 374 #if defined(OS_CHROMEOS) | 434 #if defined(OS_CHROMEOS) |
| 375 DCHECK_EQ(chromeos::input_method::kControlKey, | 435 DCHECK_EQ(chromeos::input_method::kControlKey, |
| 376 kModifierRemappingCtrl->remap_to); | 436 kModifierRemappingCtrl->remap_to); |
| 377 | 437 |
| 378 XEvent* xev = event->native_event(); | 438 XEvent* xev = event->native_event(); |
| 379 XKeyEvent* xkey = &(xev->xkey); | 439 XKeyEvent* xkey = &(xev->xkey); |
| 380 KeySym keysym = XLookupKeysym(xkey, 0); | 440 KeySym keysym = XLookupKeysym(xkey, 0); |
| 381 | 441 |
| 382 ui::KeyboardCode remapped_keycode = event->key_code(); | 442 ui::KeyboardCode remapped_keycode = event->key_code(); |
| 383 KeyCode remapped_native_keycode = xkey->keycode; | 443 KeyCode remapped_native_keycode = xkey->keycode; |
| 384 int remapped_flags = 0; | |
| 385 unsigned int remapped_native_modifiers = 0U; | |
| 386 | 444 |
| 387 // First, remap |keysym|. | 445 // First, remap |keysym|. |
| 388 const char* pref_name = NULL; | 446 const char* pref_name = NULL; |
| 389 switch (keysym) { | 447 switch (keysym) { |
| 390 case XK_Super_L: | 448 case XK_Super_L: |
| 391 case XK_Super_R: | 449 case XK_Super_R: |
| 392 pref_name = prefs::kLanguageXkbRemapSearchKeyTo; | 450 pref_name = prefs::kLanguageXkbRemapSearchKeyTo; |
| 393 break; | 451 break; |
| 394 case XK_Control_L: | 452 case XK_Control_L: |
| 395 case XK_Control_R: | 453 case XK_Control_R: |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 413 if (remapped_key) { | 471 if (remapped_key) { |
| 414 remapped_keycode = remapped_key->keycode; | 472 remapped_keycode = remapped_key->keycode; |
| 415 const size_t level = (event->IsShiftDown() ? (1 << 1) : 0) + | 473 const size_t level = (event->IsShiftDown() ? (1 << 1) : 0) + |
| 416 (IsRight(keysym) ? (1 << 0) : 0); | 474 (IsRight(keysym) ? (1 << 0) : 0); |
| 417 const KeySym native_keysym = remapped_key->native_keysyms[level]; | 475 const KeySym native_keysym = remapped_key->native_keysyms[level]; |
| 418 remapped_native_keycode = NativeKeySymToNativeKeycode(native_keysym); | 476 remapped_native_keycode = NativeKeySymToNativeKeycode(native_keysym); |
| 419 } | 477 } |
| 420 } | 478 } |
| 421 | 479 |
| 422 // Next, remap modifier bits. | 480 // Next, remap modifier bits. |
| 423 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) { | 481 int remapped_flags = 0; |
| 424 if (xkey->state & kModifierFlagToPrefName[i].native_modifier) { | 482 unsigned int remapped_native_modifiers = 0U; |
| 425 const ModifierRemapping* remapped_key = | 483 GetRemappedModifierMasks(event->flags(), xkey->state, |
| 426 GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service); | 484 &remapped_flags, &remapped_native_modifiers); |
| 427 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. | |
| 428 if (IsAppleKeyboard() && | |
| 429 (kModifierFlagToPrefName[i].native_modifier == Mod4Mask)) { | |
| 430 remapped_key = kModifierRemappingCtrl; | |
| 431 } | |
| 432 if (remapped_key) { | |
| 433 remapped_flags |= remapped_key->flag; | |
| 434 remapped_native_modifiers |= remapped_key->native_modifier; | |
| 435 } else { | |
| 436 remapped_flags |= kModifierFlagToPrefName[i].flag; | |
| 437 remapped_native_modifiers |= kModifierFlagToPrefName[i].native_modifier; | |
| 438 } | |
| 439 } | |
| 440 } | |
| 441 | |
| 442 remapped_flags = (event->flags() & ~(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)) | | |
| 443 remapped_flags; | |
| 444 remapped_native_modifiers = | |
| 445 (xkey->state & ~(Mod4Mask | ControlMask | Mod1Mask)) | | |
| 446 remapped_native_modifiers; | |
| 447 | 485 |
| 448 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if | 486 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if |
| 449 // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external | 487 // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external |
| 450 // keyboard is pressed) since X can handle that case. | 488 // keyboard is pressed) since X can handle that case. |
| 451 if ((event->type() == ui::ET_KEY_PRESSED) && | 489 if ((event->type() == ui::ET_KEY_PRESSED) && |
| 452 (event->key_code() != ui::VKEY_CAPITAL) && | 490 (event->key_code() != ui::VKEY_CAPITAL) && |
| 453 (remapped_keycode == ui::VKEY_CAPITAL)) { | 491 (remapped_keycode == ui::VKEY_CAPITAL)) { |
| 454 chromeos::input_method::XKeyboard* xkeyboard = xkeyboard_ ? | 492 chromeos::input_method::XKeyboard* xkeyboard = xkeyboard_ ? |
| 455 xkeyboard_ : InputMethodManager::GetInstance()->GetXKeyboard(); | 493 xkeyboard_ : InputMethodManager::GetInstance()->GetXKeyboard(); |
| 456 xkeyboard->SetCapsLockEnabled(!xkeyboard->CapsLockIsEnabled()); | 494 xkeyboard->SetCapsLockEnabled(!xkeyboard->CapsLockIsEnabled()); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 588 OverwriteEvent(event, next_xkeycode_, xkey->state & ~Mod1Mask, | 626 OverwriteEvent(event, next_xkeycode_, xkey->state & ~Mod1Mask, |
| 589 ui::VKEY_NEXT, event->flags() & ~ui::EF_ALT_DOWN); | 627 ui::VKEY_NEXT, event->flags() & ~ui::EF_ALT_DOWN); |
| 590 rewritten = true; | 628 rewritten = true; |
| 591 } | 629 } |
| 592 #else | 630 #else |
| 593 // TODO(yusukes): Support Ash on other platforms if needed. | 631 // TODO(yusukes): Support Ash on other platforms if needed. |
| 594 #endif | 632 #endif |
| 595 return rewritten; | 633 return rewritten; |
| 596 } | 634 } |
| 597 | 635 |
| 636 void KeyRewriter::RewriteLocatedEvent(aura::LocatedEvent* event) { | |
| 637 #if defined(OS_CHROMEOS) | |
| 638 XEvent* xevent = event->native_event(); | |
| 639 if (!xevent || xevent->type != GenericEvent) | |
| 640 return; | |
| 641 | |
| 642 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data); | |
| 643 if (xievent->evtype != XI_ButtonPress && xievent->evtype != XI_ButtonRelease) | |
| 644 return; | |
| 645 | |
| 646 // First, remap modifier masks. | |
| 647 int remapped_flags = 0; | |
| 648 unsigned int remapped_native_modifiers = 0U; | |
| 649 GetRemappedModifierMasks(event->flags(), xievent->mods.effective, | |
| 650 &remapped_flags, &remapped_native_modifiers); | |
| 651 xievent->mods.effective = remapped_native_modifiers; | |
| 652 | |
| 653 // Then, remap Alt+Button1 to Button3. | |
| 654 if ((xievent->mods.effective & Mod1Mask) && xievent->detail == 1) { | |
| 655 xievent->mods.effective &= ~Mod1Mask; | |
| 656 xievent->detail = 3; | |
| 657 if (xievent->evtype == XI_ButtonRelease) { | |
| 658 // On the release clear the left button from the existing state and the | |
| 659 // mods, and set the right button. | |
| 660 XISetMask(xievent->buttons.mask, 3); | |
| 661 XIClearMask(xievent->buttons.mask, 1); | |
| 662 xievent->mods.effective &= ~Button1Mask; | |
| 663 } | |
| 664 } | |
| 665 | |
| 666 event->set_flags(ui::EventFlagsFromNative(xevent)); | |
| 667 #else | |
| 668 // TODO(yusukes): Support Ash on other platforms if needed. | |
| 669 #endif | |
| 670 } | |
| 671 | |
| 598 void KeyRewriter::OverwriteEvent(aura::KeyEvent* event, | 672 void KeyRewriter::OverwriteEvent(aura::KeyEvent* event, |
| 599 unsigned int new_native_keycode, | 673 unsigned int new_native_keycode, |
| 600 unsigned int new_native_state, | 674 unsigned int new_native_state, |
| 601 ui::KeyboardCode new_keycode, | 675 ui::KeyboardCode new_keycode, |
| 602 int new_flags) { | 676 int new_flags) { |
| 603 #if defined(OS_CHROMEOS) | 677 #if defined(OS_CHROMEOS) |
| 604 XEvent* xev = event->native_event(); | 678 XEvent* xev = event->native_event(); |
| 605 XKeyEvent* xkey = &(xev->xkey); | 679 XKeyEvent* xkey = &(xev->xkey); |
| 606 xkey->keycode = new_native_keycode; | 680 xkey->keycode = new_native_keycode; |
| 607 xkey->state = new_native_state; | 681 xkey->state = new_native_state; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 620 const DeviceType type = KeyRewriter::GetDeviceType(device_name); | 694 const DeviceType type = KeyRewriter::GetDeviceType(device_name); |
| 621 if (type == kDeviceAppleKeyboard) { | 695 if (type == kDeviceAppleKeyboard) { |
| 622 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " | 696 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " |
| 623 << "id=" << device_id; | 697 << "id=" << device_id; |
| 624 } | 698 } |
| 625 // Always overwrite the existing device_id since the X server may reuse a | 699 // Always overwrite the existing device_id since the X server may reuse a |
| 626 // device id for an unattached device. | 700 // device id for an unattached device. |
| 627 device_id_to_type_[device_id] = type; | 701 device_id_to_type_[device_id] = type; |
| 628 return type; | 702 return type; |
| 629 } | 703 } |
| OLD | NEW |