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