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

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

Issue 11421055: Add power-user keyboard mode for ChromeOS with Search key acting as a typical Fn key. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix unittest Created 8 years 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"
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 break; 114 break;
115 } 115 }
116 return false; 116 return false;
117 } 117 }
118 118
119 bool HasChromeOSKeyboard() { 119 bool HasChromeOSKeyboard() {
120 return CommandLine::ForCurrentProcess()->HasSwitch( 120 return CommandLine::ForCurrentProcess()->HasSwitch(
121 switches::kHasChromeOSKeyboard); 121 switches::kHasChromeOSKeyboard);
122 } 122 }
123 123
124 bool EventSourceIsChromebookKeyboard(ui::KeyEvent* /* event */) {
125 // TODO(danakj): Determine if the event came from a Chromebook internal
126 // keyboard.
127 return true;
128 }
129
124 bool IsMod3UsedByCurrentInputMethod() { 130 bool IsMod3UsedByCurrentInputMethod() {
125 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask, 131 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
126 // it's not possible to make both features work. For now, we don't remap 132 // it's not possible to make both features work. For now, we don't remap
127 // Mod3Mask when Neo2 is in use. 133 // Mod3Mask when Neo2 is in use.
128 // TODO(yusukes): Remove the restriction. 134 // TODO(yusukes): Remove the restriction.
129 return InputMethodManager::GetInstance()->GetCurrentInputMethod().id() == 135 return InputMethodManager::GetInstance()->GetCurrentInputMethod().id() ==
130 kNeo2LayoutId; 136 kNeo2LayoutId;
131 } 137 }
132 #endif 138 #endif
133 139
134 const PrefService* GetPrefService() { 140 const PrefService* GetPrefService() {
135 Profile* profile = ProfileManager::GetDefaultProfile(); 141 Profile* profile = ProfileManager::GetDefaultProfile();
136 if (profile) 142 if (profile)
137 return profile->GetPrefs(); 143 return profile->GetPrefs();
138 return NULL; 144 return NULL;
139 } 145 }
140 146
141 } // namespace 147 } // namespace
142 148
143 EventRewriter::EventRewriter() 149 EventRewriter::EventRewriter()
144 : last_device_id_(kBadDeviceId), 150 : last_device_id_(kBadDeviceId),
145 #if defined(OS_CHROMEOS) 151 #if defined(OS_CHROMEOS)
152 drop_search_key_release_(false),
146 xkeyboard_(NULL), 153 xkeyboard_(NULL),
147 #endif 154 #endif
148 pref_service_(NULL) { 155 pref_service_(NULL) {
149 // The ash shell isn't instantiated for our unit tests. 156 // The ash shell isn't instantiated for our unit tests.
150 if (ash::Shell::HasInstance()) 157 if (ash::Shell::HasInstance())
151 ash::Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this); 158 ash::Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this);
152 #if defined(OS_CHROMEOS) 159 #if defined(OS_CHROMEOS)
153 if (base::chromeos::IsRunningOnChromeOS()) { 160 if (base::chromeos::IsRunningOnChromeOS()) {
154 chromeos::XInputHierarchyChangedEventListener::GetInstance() 161 chromeos::XInputHierarchyChangedEventListener::GetInstance()
155 ->AddObserver(this); 162 ->AddObserver(this);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 return kDeviceUnknown; 204 return kDeviceUnknown;
198 } 205 }
199 206
200 void EventRewriter::RewriteForTesting(ui::KeyEvent* event) { 207 void EventRewriter::RewriteForTesting(ui::KeyEvent* event) {
201 Rewrite(event); 208 Rewrite(event);
202 } 209 }
203 210
204 ash::EventRewriterDelegate::Action EventRewriter::RewriteOrFilterKeyEvent( 211 ash::EventRewriterDelegate::Action EventRewriter::RewriteOrFilterKeyEvent(
205 ui::KeyEvent* event) { 212 ui::KeyEvent* event) {
206 if (event->HasNativeEvent()) 213 if (event->HasNativeEvent())
207 Rewrite(event); 214 return Rewrite(event);
208 return ash::EventRewriterDelegate::ACTION_REWRITE_EVENT; 215 return ash::EventRewriterDelegate::ACTION_REWRITE_EVENT;
209 } 216 }
210 217
211 ash::EventRewriterDelegate::Action EventRewriter::RewriteOrFilterLocatedEvent( 218 ash::EventRewriterDelegate::Action EventRewriter::RewriteOrFilterLocatedEvent(
212 ui::LocatedEvent* event) { 219 ui::LocatedEvent* event) {
213 if (event->HasNativeEvent()) 220 if (event->HasNativeEvent())
214 RewriteLocatedEvent(event); 221 RewriteLocatedEvent(event);
215 return ash::EventRewriterDelegate::ACTION_REWRITE_EVENT; 222 return ash::EventRewriterDelegate::ACTION_REWRITE_EVENT;
216 } 223 }
217 224
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 return kp_9_xkeycode_; 356 return kp_9_xkeycode_;
350 case XK_KP_Decimal: 357 case XK_KP_Decimal:
351 return kp_decimal_xkeycode_; 358 return kp_decimal_xkeycode_;
352 default: 359 default:
353 break; 360 break;
354 } 361 }
355 return 0U; 362 return 0U;
356 } 363 }
357 #endif 364 #endif
358 365
359 void EventRewriter::Rewrite(ui::KeyEvent* event) { 366 ash::EventRewriterDelegate::Action EventRewriter::Rewrite(ui::KeyEvent* event) {
360 #if defined(OS_CHROMEOS) 367 #if defined(OS_CHROMEOS)
361 // Do not rewrite an event sent by ui_controls::SendKeyPress(). See 368 // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
362 // crbug.com/136465. 369 // crbug.com/136465.
363 if (event->native_event()->xkey.send_event) 370 if (event->native_event()->xkey.send_event)
364 return; 371 return ash::EventRewriterDelegate::ACTION_REWRITE_EVENT;
372
373 if (DropSearchKey(event))
374 return ash::EventRewriterDelegate::ACTION_DROP_EVENT;
365 #endif 375 #endif
366 RewriteModifiers(event); 376 RewriteModifiers(event);
367 RewriteNumPadKeys(event); 377 RewriteNumPadKeys(event);
368 RewriteBackspaceAndArrowKeys(event); 378 RewriteBackspaceAndArrowKeys(event);
369 // TODO(yusukes): Implement crosbug.com/27167 (allow sending function keys). 379 return ash::EventRewriterDelegate::ACTION_REWRITE_EVENT;
370 } 380 }
371 381
372 bool EventRewriter::IsAppleKeyboard() const { 382 bool EventRewriter::IsAppleKeyboard() const {
373 if (last_device_id_ == kBadDeviceId) 383 if (last_device_id_ == kBadDeviceId)
374 return false; 384 return false;
375 385
376 // Check which device generated |event|. 386 // Check which device generated |event|.
377 std::map<int, DeviceType>::const_iterator iter = 387 std::map<int, DeviceType>::const_iterator iter =
378 device_id_to_type_.find(last_device_id_); 388 device_id_to_type_.find(last_device_id_);
379 if (iter == device_id_to_type_.end()) { 389 if (iter == device_id_to_type_.end()) {
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 } 641 }
632 #else 642 #else
633 // TODO(yusukes): Support Ash on other platforms if needed. 643 // TODO(yusukes): Support Ash on other platforms if needed.
634 #endif 644 #endif
635 return rewritten; 645 return rewritten;
636 } 646 }
637 647
638 bool EventRewriter::RewriteBackspaceAndArrowKeys(ui::KeyEvent* event) { 648 bool EventRewriter::RewriteBackspaceAndArrowKeys(ui::KeyEvent* event) {
639 bool rewritten = false; 649 bool rewritten = false;
640 #if defined(OS_CHROMEOS) 650 #if defined(OS_CHROMEOS)
651 // On a Chromebook keyboard, modifier keys can be used to access extended
652 // keyboard shortcuts. On other keyboards, keys such as delete and page up are
653 // already available, so we do not need to rewrite anything here.
654 if (!EventSourceIsChromebookKeyboard(event))
655 return rewritten;
656
657 const PrefService* pref_service =
658 pref_service_ ? pref_service_ : GetPrefService();
659 bool chromebook_function_key = CommandLine::ForCurrentProcess()->HasSwitch(
660 switches::kEnableChromebookFunctionKey);
661
662 bool search_as_function_key = chromebook_function_key && pref_service &&
663 pref_service->GetBoolean(prefs::kLanguageSearchKeyActsAsFunctionKey);
664
641 XEvent* xev = event->native_event(); 665 XEvent* xev = event->native_event();
642 XKeyEvent* xkey = &(xev->xkey); 666 XKeyEvent* xkey = &(xev->xkey);
667 const KeySym keysym = XLookupKeysym(xkey, 0);
643 668
644 const KeySym keysym = XLookupKeysym(xkey, 0); 669 if (!search_as_function_key &&
645 if (keysym == XK_BackSpace && (xkey->state & Mod1Mask)) { 670 keysym == XK_BackSpace && (xkey->state & Mod1Mask)) {
646 // Remap Alt+Backspace to Delete. 671 // Without Search as Function key: Remap Alt+Backspace to Delete.
647 OverwriteEvent(event, delete_xkeycode_, xkey->state & ~Mod1Mask, 672 OverwriteEvent(event, delete_xkeycode_, xkey->state & ~Mod1Mask,
648 ui::VKEY_DELETE, event->flags() & ~ui::EF_ALT_DOWN); 673 ui::VKEY_DELETE, event->flags() & ~ui::EF_ALT_DOWN);
649 rewritten = true; 674 rewritten = true;
650 } else if (keysym == XK_Up && 675 } else if (search_as_function_key &&
676 keysym == XK_BackSpace && (xkey->state & Mod4Mask)) {
677 // With Search as Function key: Remap Search+Backspace to Delete.
678 OverwriteEvent(event, delete_xkeycode_, xkey->state & ~Mod4Mask,
679 ui::VKEY_DELETE, event->flags());
680 rewritten = true;
681 } else if (!search_as_function_key && keysym == XK_Up &&
651 (xkey->state & ControlMask) && (xkey->state & Mod1Mask)) { 682 (xkey->state & ControlMask) && (xkey->state & Mod1Mask)) {
652 // Remap Ctrl+Alt+Up to Home. 683 // Without Search as Function key: Remap Ctrl+Alt+Up to Home.
653 OverwriteEvent(event, 684 OverwriteEvent(event,
654 home_xkeycode_, 685 home_xkeycode_,
655 xkey->state & ~(Mod1Mask | ControlMask), 686 xkey->state & ~(Mod1Mask | ControlMask),
656 ui::VKEY_HOME, 687 ui::VKEY_HOME,
657 event->flags() & ~(ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN)); 688 event->flags() & ~(ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN));
658 rewritten = true; 689 rewritten = true;
659 } else if (keysym == XK_Up && (xkey->state & Mod1Mask)) { 690 } else if (search_as_function_key &&
660 // Remap Alt+Up to Prior (aka PageUp). 691 keysym == XK_Left && (xkey->state & Mod4Mask)) {
692 // With Search as Function key: Remap Search+Left to Home.
693 OverwriteEvent(event, home_xkeycode_, xkey->state & ~Mod4Mask,
694 ui::VKEY_HOME, event->flags());
695 rewritten = true;
696 } else if (!search_as_function_key &&
697 keysym == XK_Up && (xkey->state & Mod1Mask)) {
698 // Without Search as Function key: Remap Alt+Up to Prior (aka PageUp).
661 OverwriteEvent(event, prior_xkeycode_, xkey->state & ~Mod1Mask, 699 OverwriteEvent(event, prior_xkeycode_, xkey->state & ~Mod1Mask,
662 ui::VKEY_PRIOR, event->flags() & ~ui::EF_ALT_DOWN); 700 ui::VKEY_PRIOR, event->flags() & ~ui::EF_ALT_DOWN);
663 rewritten = true; 701 rewritten = true;
664 } else if (keysym == XK_Down && 702 } else if (search_as_function_key &&
703 keysym == XK_Up && (xkey->state & Mod4Mask)) {
704 // With Search as Function key: Remap Search+Up to Prior (aka PageUp).
705 OverwriteEvent(event, prior_xkeycode_, xkey->state & ~Mod4Mask,
706 ui::VKEY_PRIOR, event->flags());
707 rewritten = true;
708 } else if (!search_as_function_key && keysym == XK_Down &&
665 (xkey->state & ControlMask) && (xkey->state & Mod1Mask)) { 709 (xkey->state & ControlMask) && (xkey->state & Mod1Mask)) {
666 // Remap Ctrl+Alt+Down to End. 710 // Without Search as Function key: Remap Ctrl+Alt+Down to End.
667 OverwriteEvent(event, 711 OverwriteEvent(event,
668 end_xkeycode_, 712 end_xkeycode_,
669 xkey->state & ~(Mod1Mask | ControlMask), 713 xkey->state & ~(Mod1Mask | ControlMask),
670 ui::VKEY_END, 714 ui::VKEY_END,
671 event->flags() & ~(ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN)); 715 event->flags() & ~(ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN));
672 rewritten = true; 716 rewritten = true;
673 } else if (keysym == XK_Down && (xkey->state & Mod1Mask)) { 717 } else if (search_as_function_key &&
674 // Remap Alt+Down to Next (aka PageDown). 718 keysym == XK_Right && (xkey->state & Mod4Mask)) {
719 // With Search as Function key: Remap Search+Right to End.
720 OverwriteEvent(event, end_xkeycode_, xkey->state & ~Mod4Mask,
721 ui::VKEY_END, event->flags());
722 rewritten = true;
723 } else if (!search_as_function_key &&
724 keysym == XK_Down && (xkey->state & Mod1Mask)) {
725 // Without Search as Function key: Remap Alt+Down to Next (aka PageDown).
675 OverwriteEvent(event, next_xkeycode_, xkey->state & ~Mod1Mask, 726 OverwriteEvent(event, next_xkeycode_, xkey->state & ~Mod1Mask,
676 ui::VKEY_NEXT, event->flags() & ~ui::EF_ALT_DOWN); 727 ui::VKEY_NEXT, event->flags() & ~ui::EF_ALT_DOWN);
677 rewritten = true; 728 rewritten = true;
729 } else if (search_as_function_key &&
730 keysym == XK_Down && (xkey->state & Mod4Mask)) {
731 // With Search as Function key: Remap Search+Down to Next (aka PageDown).
732 OverwriteEvent(event, next_xkeycode_, xkey->state & ~Mod4Mask,
733 ui::VKEY_NEXT, event->flags());
734 rewritten = true;
678 } 735 }
679 #else 736 #else
680 // TODO(yusukes): Support Ash on other platforms if needed. 737 // TODO(yusukes): Support Ash on other platforms if needed.
681 #endif 738 #endif
682 return rewritten; 739 return rewritten;
683 } 740 }
684 741
742 #if defined(OS_CHROMEOS)
743 bool EventRewriter::DropSearchKey(ui::KeyEvent* event) {
744 const PrefService* pref_service =
745 pref_service_ ? pref_service_ : GetPrefService();
746 bool chromebook_function_key = CommandLine::ForCurrentProcess()->HasSwitch(
747 switches::kEnableChromebookFunctionKey);
748 bool search_as_function_key = chromebook_function_key && pref_service &&
749 pref_service->GetBoolean(prefs::kLanguageSearchKeyActsAsFunctionKey);
750
751 if (!search_as_function_key)
752 return false;
753
754 XEvent* xev = event->native_event();
755 XKeyEvent* xkey = &(xev->xkey);
756
757 const KeySym keysym = XLookupKeysym(xkey, 0);
758
759 bool drop_key = false;
760 unsigned int nonsearch_modifiers = Mod1Mask | ControlMask | ShiftMask;
761
762 // If the Search key acts like a modifier for another key, then drop the
763 // release of the Search key when it happens.
764 if ((xkey->state & Mod4Mask) && keysym != XK_Super_L)
765 drop_search_key_release_ = true;
766
767 if (event->type() == ui::ET_KEY_PRESSED && keysym == XK_Super_L &&
768 // Only drop the Search key press if no other modifier was present.
769 !(xkey->state & nonsearch_modifiers)) {
770 // When Search key is acting as Function key, then drop Search key presses
771 // that don't include other modifiers.
772 drop_key = true;
Yusuke Sato 2012/11/26 21:15:05 I'm wondering if this is still necessary. If it is
danakj 2012/11/26 21:17:59 Actually, it was just to make sure future shortcut
Yusuke Sato 2012/11/26 21:26:34 I see. Then I'd prefer to add a test to accelerato
danakj 2012/11/26 21:47:50 Ah, okay. By solving this in accelerator_controlle
773 } else if (event->type() == ui::ET_KEY_RELEASED && keysym == XK_Super_L) {
774 if (drop_search_key_release_) {
775 // If we ate the Search key press, then also drop the release if another
776 // key used Search as a modifier.
777 drop_key = true;
778 }
779 drop_search_key_release_ = false;
Yusuke Sato 2012/11/26 21:15:05 As I wrote above, please do that kind of suppressi
danakj 2012/11/26 21:17:59 Ah, okay will do!
780 }
781
782 return drop_key;
783 }
784 #endif
785
685 void EventRewriter::RewriteLocatedEvent(ui::LocatedEvent* event) { 786 void EventRewriter::RewriteLocatedEvent(ui::LocatedEvent* event) {
686 #if defined(OS_CHROMEOS) 787 #if defined(OS_CHROMEOS)
687 if (event->flags() & ui::EF_IS_SYNTHESIZED) 788 if (event->flags() & ui::EF_IS_SYNTHESIZED)
688 return; 789 return;
689 790
690 XEvent* xevent = event->native_event(); 791 XEvent* xevent = event->native_event();
691 if (!xevent || xevent->type != GenericEvent) 792 if (!xevent || xevent->type != GenericEvent)
692 return; 793 return;
693 794
694 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data); 795 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 const DeviceType type = EventRewriter::GetDeviceType(device_name); 851 const DeviceType type = EventRewriter::GetDeviceType(device_name);
751 if (type == kDeviceAppleKeyboard) { 852 if (type == kDeviceAppleKeyboard) {
752 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " 853 VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
753 << "id=" << device_id; 854 << "id=" << device_id;
754 } 855 }
755 // Always overwrite the existing device_id since the X server may reuse a 856 // Always overwrite the existing device_id since the X server may reuse a
756 // device id for an unattached device. 857 // device id for an unattached device.
757 device_id_to_type_[device_id] = type; 858 device_id_to_type_[device_id] = type;
758 return type; 859 return type;
759 } 860 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/ash/event_rewriter.h ('k') | chrome/browser/ui/ash/event_rewriter_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698