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 |