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 |