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

Side by Side Diff: chrome/browser/ui/views/ash/key_rewriter.cc

Issue 10383301: Move modifier remapping code from X to Ash (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: reverted ui/base/keycodes/keyboard_code_conversion_x.cc (this was just for debugging) Created 8 years, 7 months 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/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"
11 #include "base/string_util.h" 11 #include "base/string_util.h"
12 #include "chrome/browser/prefs/pref_service.h"
13 #include "chrome/browser/profiles/profile_manager.h"
12 #include "ui/aura/event.h" 14 #include "ui/aura/event.h"
13 #include "ui/aura/root_window.h" 15 #include "ui/aura/root_window.h"
14 #include "ui/base/keycodes/keyboard_code_conversion.h" 16 #include "ui/base/keycodes/keyboard_code_conversion.h"
15 17
16 #if defined(OS_CHROMEOS) 18 #if defined(OS_CHROMEOS)
17 #include <X11/extensions/XInput2.h> 19 #include <X11/extensions/XInput2.h>
18 #include <X11/keysym.h> 20 #include <X11/keysym.h>
19 #include <X11/Xlib.h> 21 #include <X11/Xlib.h>
20 22
21 #include "base/chromeos/chromeos_version.h" 23 #include "base/chromeos/chromeos_version.h"
24 #include "chrome/browser/chromeos/input_method/input_method_manager.h"
25 #include "chrome/browser/chromeos/input_method/xkeyboard.h"
22 #include "chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.h" 26 #include "chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.h"
27 #include "chrome/common/pref_names.h"
23 #include "ui/base/keycodes/keyboard_code_conversion_x.h" 28 #include "ui/base/keycodes/keyboard_code_conversion_x.h"
24 #include "ui/base/x/x11_util.h" 29 #include "ui/base/x/x11_util.h"
30
31 using chromeos::input_method::InputMethodManager;
25 #endif 32 #endif
26 33
27 namespace { 34 namespace {
28 35
29 const int kBadDeviceId = -1; 36 const int kBadDeviceId = -1;
30 37
38 #if defined(OS_CHROMEOS)
39 // A key code and a flag we should use when a key is remapped to |remap_to|.
40 const struct ModifierRemapping {
41 int remap_to;
42 int flag;
43 unsigned int native_modifier;
44 ui::KeyboardCode keycode;
45 KeySym native_keysyms[4]; // left, right, shift+left, shift+right.
46 } kModifierRemappings[] = {
47 { chromeos::input_method::kSearchKey, 0, Mod4Mask, ui::VKEY_LWIN,
48 { XK_Super_L, XK_Super_L, XK_Super_L, XK_Super_L }},
49 { chromeos::input_method::kControlKey, ui::EF_CONTROL_DOWN, ControlMask,
50 ui::VKEY_CONTROL,
51 { XK_Control_L, XK_Control_R, XK_Control_L, XK_Control_R }},
52 { chromeos::input_method::kAltKey, ui::EF_ALT_DOWN, Mod1Mask,
53 ui::VKEY_MENU, { XK_Alt_L, XK_Alt_R, XK_Meta_L, XK_Meta_R }},
54 { chromeos::input_method::kVoidKey, 0, 0U, ui::VKEY_UNKNOWN,
55 { XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol }},
56 { chromeos::input_method::kCapsLockKey, 0, 0U, ui::VKEY_CAPITAL,
57 { XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock }},
58 };
59
60 // A structure for converting |native_modifier| to a pair of |flag| and
61 // |pref_name|.
62 const struct ModifierFlagToPrefName {
63 unsigned int native_modifier;
64 int flag;
65 const char* pref_name;
66 } kModifierFlagToPrefName[] = {
67 { Mod4Mask, 0, prefs::kLanguageXkbRemapSearchKeyTo },
68 { ControlMask, ui::EF_CONTROL_DOWN, prefs::kLanguageXkbRemapControlKeyTo },
69 { Mod1Mask, ui::EF_ALT_DOWN, prefs::kLanguageXkbRemapAltKeyTo },
70 };
71
72 // Gets a remapped key for |pref_name| key. For example, to find out which
73 // key Search is currently remapped to, call the function with
74 // prefs::kLanguageXkbRemapSearchKeyTo.
75 const ModifierRemapping* GetRemappedKey(const std::string& pref_name,
76 const PrefService& pref_service) {
77 if (!pref_service.FindPreference(pref_name.c_str()))
78 return NULL; // The |pref_name| hasn't been registered. On login screen?
79 const int value = pref_service.GetInteger(pref_name.c_str());
80 for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
81 if (value == kModifierRemappings[i].remap_to)
82 return &kModifierRemappings[i];
83 }
84 return NULL;
85 }
86
87 bool IsRight(KeySym native_keysym) {
88 switch (native_keysym) {
89 case XK_Alt_R:
90 case XK_Control_R:
91 case XK_Hyper_R:
92 case XK_Meta_R:
93 case XK_Shift_R:
94 case XK_Super_R:
95 return true;
96 default:
97 break;
98 }
99 return false;
100 }
101 #endif
102
103 const PrefService* GetPrefService() {
104 Profile* profile = ProfileManager::GetDefaultProfile();
105 if (profile)
106 return profile->GetPrefs();
107 return NULL;
108 }
109
31 } // namespace 110 } // namespace
32 111
33 KeyRewriter::KeyRewriter() : last_device_id_(kBadDeviceId) { 112 KeyRewriter::KeyRewriter()
113 : last_device_id_(kBadDeviceId),
114 #if defined(OS_CHROMEOS)
115 xkeyboard_(NULL),
116 #endif
117 pref_service_(NULL) {
34 // The ash shell isn't instantiated for our unit tests. 118 // The ash shell isn't instantiated for our unit tests.
35 if (ash::Shell::HasInstance()) 119 if (ash::Shell::HasInstance())
36 ash::Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this); 120 ash::Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this);
37 #if defined(OS_CHROMEOS) 121 #if defined(OS_CHROMEOS)
38 if (base::chromeos::IsRunningOnChromeOS()) { 122 if (base::chromeos::IsRunningOnChromeOS()) {
39 chromeos::XInputHierarchyChangedEventListener::GetInstance() 123 chromeos::XInputHierarchyChangedEventListener::GetInstance()
40 ->AddObserver(this); 124 ->AddObserver(this);
41 } 125 }
42 RefreshKeycodes(); 126 RefreshKeycodes();
43 #endif 127 #endif
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 DeviceAdded(device_id); 232 DeviceAdded(device_id);
149 } 233 }
150 234
151 last_device_id_ = device_id; 235 last_device_id_ = device_id;
152 } 236 }
153 237
154 void KeyRewriter::RefreshKeycodes() { 238 void KeyRewriter::RefreshKeycodes() {
155 Display* display = ui::GetXDisplay(); 239 Display* display = ui::GetXDisplay();
156 control_l_xkeycode_ = XKeysymToKeycode(display, XK_Control_L); 240 control_l_xkeycode_ = XKeysymToKeycode(display, XK_Control_L);
157 control_r_xkeycode_ = XKeysymToKeycode(display, XK_Control_R); 241 control_r_xkeycode_ = XKeysymToKeycode(display, XK_Control_R);
242 alt_l_xkeycode_ = XKeysymToKeycode(display, XK_Alt_L);
243 alt_r_xkeycode_ = XKeysymToKeycode(display, XK_Alt_R);
244 meta_l_xkeycode_ = XKeysymToKeycode(display, XK_Meta_L);
245 meta_r_xkeycode_ = XKeysymToKeycode(display, XK_Meta_R);
246 windows_l_xkeycode_ = XKeysymToKeycode(display, XK_Super_L);
247 caps_lock_xkeycode_ = XKeysymToKeycode(display, XK_Caps_Lock);
248 void_symbol_xkeycode_ = XKeysymToKeycode(display, XK_VoidSymbol);
158 kp_0_xkeycode_ = XKeysymToKeycode(display, XK_KP_0); 249 kp_0_xkeycode_ = XKeysymToKeycode(display, XK_KP_0);
159 kp_1_xkeycode_ = XKeysymToKeycode(display, XK_KP_1); 250 kp_1_xkeycode_ = XKeysymToKeycode(display, XK_KP_1);
160 kp_2_xkeycode_ = XKeysymToKeycode(display, XK_KP_2); 251 kp_2_xkeycode_ = XKeysymToKeycode(display, XK_KP_2);
161 kp_3_xkeycode_ = XKeysymToKeycode(display, XK_KP_3); 252 kp_3_xkeycode_ = XKeysymToKeycode(display, XK_KP_3);
162 kp_4_xkeycode_ = XKeysymToKeycode(display, XK_KP_4); 253 kp_4_xkeycode_ = XKeysymToKeycode(display, XK_KP_4);
163 kp_5_xkeycode_ = XKeysymToKeycode(display, XK_KP_5); 254 kp_5_xkeycode_ = XKeysymToKeycode(display, XK_KP_5);
164 kp_6_xkeycode_ = XKeysymToKeycode(display, XK_KP_6); 255 kp_6_xkeycode_ = XKeysymToKeycode(display, XK_KP_6);
165 kp_7_xkeycode_ = XKeysymToKeycode(display, XK_KP_7); 256 kp_7_xkeycode_ = XKeysymToKeycode(display, XK_KP_7);
166 kp_8_xkeycode_ = XKeysymToKeycode(display, XK_KP_8); 257 kp_8_xkeycode_ = XKeysymToKeycode(display, XK_KP_8);
167 kp_9_xkeycode_ = XKeysymToKeycode(display, XK_KP_9); 258 kp_9_xkeycode_ = XKeysymToKeycode(display, XK_KP_9);
168 kp_decimal_xkeycode_ = XKeysymToKeycode(display, XK_KP_Decimal); 259 kp_decimal_xkeycode_ = XKeysymToKeycode(display, XK_KP_Decimal);
169 } 260 }
261
262 KeyCode KeyRewriter::NativeKeySymToNativeKeycode(KeySym keysym) {
263 switch (keysym) {
264 case XK_Control_L:
265 return control_l_xkeycode_;
266 case XK_Control_R:
267 return control_r_xkeycode_;
268 case XK_Alt_L:
269 return alt_l_xkeycode_;
270 case XK_Alt_R:
271 return alt_r_xkeycode_;
272 case XK_Meta_L:
273 return meta_l_xkeycode_;
274 case XK_Meta_R:
275 return meta_r_xkeycode_;
276 case XK_Super_L:
277 return windows_l_xkeycode_;
278 case XK_Caps_Lock:
279 return caps_lock_xkeycode_;
280 case XK_VoidSymbol:
281 return void_symbol_xkeycode_;
282 case XK_KP_0:
283 return kp_0_xkeycode_;
284 case XK_KP_1:
285 return kp_1_xkeycode_;
286 case XK_KP_2:
287 return kp_2_xkeycode_;
288 case XK_KP_3:
289 return kp_3_xkeycode_;
290 case XK_KP_4:
291 return kp_4_xkeycode_;
292 case XK_KP_5:
293 return kp_5_xkeycode_;
294 case XK_KP_6:
295 return kp_6_xkeycode_;
296 case XK_KP_7:
297 return kp_7_xkeycode_;
298 case XK_KP_8:
299 return kp_8_xkeycode_;
300 case XK_KP_9:
301 return kp_9_xkeycode_;
302 case XK_KP_Decimal:
303 return kp_decimal_xkeycode_;
304 default:
305 break;
306 }
307 return 0U;
308 }
170 #endif 309 #endif
171 310
172 void KeyRewriter::Rewrite(aura::KeyEvent* event) { 311 void KeyRewriter::Rewrite(aura::KeyEvent* event) {
173 RewriteCommandToControl(event); 312 RewriteCommandToControl(event);
313 RewriteModifiers(event);
174 RewriteNumPadKeys(event); 314 RewriteNumPadKeys(event);
175 // TODO(yusukes): Implement crbug.com/115112 (Search/Ctrl/Alt remapping) and 315 // TODO(yusukes): Implement crosbug.com/27167 (allow sending function keys).
176 // crosbug.com/27167 (allow sending function keys) here.
177 } 316 }
178 317
179 bool KeyRewriter::RewriteCommandToControl(aura::KeyEvent* event) { 318 bool KeyRewriter::RewriteCommandToControl(aura::KeyEvent* event) {
180 bool rewritten = false; 319 bool rewritten = false;
181 if (last_device_id_ == kBadDeviceId) 320 if (last_device_id_ == kBadDeviceId)
182 return rewritten; 321 return rewritten;
183 322
184 // Check which device generated |event|. 323 // Check which device generated |event|.
185 std::map<int, DeviceType>::const_iterator iter = 324 std::map<int, DeviceType>::const_iterator iter =
186 device_id_to_type_.find(last_device_id_); 325 device_id_to_type_.find(last_device_id_);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 } 364 }
226 365
227 DCHECK_NE(ui::VKEY_LWIN, ui::KeyboardCodeFromXKeyEvent(xev)); 366 DCHECK_NE(ui::VKEY_LWIN, ui::KeyboardCodeFromXKeyEvent(xev));
228 DCHECK_NE(ui::VKEY_RWIN, ui::KeyboardCodeFromXKeyEvent(xev)); 367 DCHECK_NE(ui::VKEY_RWIN, ui::KeyboardCodeFromXKeyEvent(xev));
229 #else 368 #else
230 // TODO(yusukes): Support Ash on other platforms if needed. 369 // TODO(yusukes): Support Ash on other platforms if needed.
231 #endif 370 #endif
232 return rewritten; 371 return rewritten;
233 } 372 }
234 373
374 bool KeyRewriter::RewriteModifiers(aura::KeyEvent* event) {
375 const PrefService* pref_service =
376 pref_service_ ? pref_service_ : GetPrefService();
377 if (!pref_service)
378 return false;
379
380 #if defined(OS_CHROMEOS)
381 XEvent* xev = event->native_event();
382 XKeyEvent* xkey = &(xev->xkey);
383 KeySym keysym = XLookupKeysym(xkey, 0);
384
385 ui::KeyboardCode remapped_keycode = event->key_code();
386 KeyCode remapped_native_keycode = xkey->keycode;
387 int remapped_flags = 0;
388 unsigned int remapped_native_modifiers = 0U;
389
390 // First, remap |keysym|.
391 const char* pref_name = NULL;
392 switch (keysym) {
393 case XK_Super_L:
394 pref_name = prefs::kLanguageXkbRemapSearchKeyTo;
395 break;
396 case XK_Control_L:
397 case XK_Control_R:
398 pref_name = prefs::kLanguageXkbRemapControlKeyTo;
399 break;
400 case XK_Alt_L:
401 case XK_Alt_R:
402 case XK_Meta_L:
403 case XK_Meta_R:
404 pref_name = prefs::kLanguageXkbRemapAltKeyTo;
405 break;
406 default:
407 break;
408 }
409 if (pref_name) {
410 const ModifierRemapping* remapped_key =
411 GetRemappedKey(pref_name, *pref_service);
412 if (remapped_key) {
413 remapped_keycode = remapped_key->keycode;
414 const size_t level = (event->IsShiftDown() ? (1 << 1) : 0) +
415 (IsRight(keysym) ? (1 << 0) : 0);
416 const KeySym native_keysym = remapped_key->native_keysyms[level];
417 remapped_native_keycode = NativeKeySymToNativeKeycode(native_keysym);
418 }
419 }
420
421 // Next, remap modifier bits.
422 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) {
423 if (xkey->state & kModifierFlagToPrefName[i].native_modifier) {
424 const ModifierRemapping* remapped_key =
425 GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service);
426 if (remapped_key) {
427 remapped_flags |= remapped_key->flag;
428 remapped_native_modifiers |= remapped_key->native_modifier;
429 } else {
430 remapped_flags |= kModifierFlagToPrefName[i].flag;
431 remapped_native_modifiers |= kModifierFlagToPrefName[i].native_modifier;
432 }
433 }
434 }
435
436 remapped_flags = (event->flags() & ~(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)) |
437 remapped_flags;
438 remapped_native_modifiers =
439 (xkey->state & ~(Mod4Mask | ControlMask | Mod1Mask)) |
440 remapped_native_modifiers;
441
442 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if
443 // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external
444 // keyboard is pressed) since X can handle that case.
445 if ((event->type() == ui::ET_KEY_PRESSED) &&
446 (event->key_code() != ui::VKEY_CAPITAL) &&
447 (remapped_keycode == ui::VKEY_CAPITAL)) {
448 chromeos::input_method::XKeyboard* xkeyboard = xkeyboard_ ?
449 xkeyboard_ : InputMethodManager::GetInstance()->GetXKeyboard();
450 xkeyboard->SetCapsLockEnabled(!xkeyboard->CapsLockIsEnabled());
451 }
452
453 OverwriteEvent(event,
454 remapped_native_keycode, remapped_native_modifiers,
455 remapped_keycode, remapped_flags);
456 return true;
457 #else
458 // TODO(yusukes): Support Ash on other platforms if needed.
459 return false;
460 #endif
461 }
462
235 bool KeyRewriter::RewriteNumPadKeys(aura::KeyEvent* event) { 463 bool KeyRewriter::RewriteNumPadKeys(aura::KeyEvent* event) {
236 bool rewritten = false; 464 bool rewritten = false;
237 #if defined(OS_CHROMEOS) 465 #if defined(OS_CHROMEOS)
238 XEvent* xev = event->native_event(); 466 XEvent* xev = event->native_event();
239 XKeyEvent* xkey = &(xev->xkey); 467 XKeyEvent* xkey = &(xev->xkey);
240 468
241 const KeySym keysym = XLookupKeysym(xkey, 0); 469 const KeySym keysym = XLookupKeysym(xkey, 0);
242 switch (keysym) { 470 switch (keysym) {
243 case XK_KP_Insert: 471 case XK_KP_Insert:
244 OverwriteEvent(event, kp_0_xkeycode_, xkey->state | Mod2Mask, 472 OverwriteEvent(event, kp_0_xkeycode_, xkey->state | Mod2Mask,
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 const DeviceType type = KeyRewriter::GetDeviceType(device_name); 567 const DeviceType type = KeyRewriter::GetDeviceType(device_name);
340 if (type == kDeviceAppleKeyboard) { 568 if (type == kDeviceAppleKeyboard) {
341 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " 569 VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
342 << "id=" << device_id; 570 << "id=" << device_id;
343 } 571 }
344 // Always overwrite the existing device_id since the X server may reuse a 572 // Always overwrite the existing device_id since the X server may reuse a
345 // device id for an unattached device. 573 // device id for an unattached device.
346 device_id_to_type_[device_id] = type; 574 device_id_to_type_[device_id] = type;
347 return type; 575 return type;
348 } 576 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/ash/key_rewriter.h ('k') | chrome/browser/ui/views/ash/key_rewriter_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698