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

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: review 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_flag;
44 ui::KeyboardCode keycode;
45 unsigned int native_keysyms[4]; // left, right, shift+left, shift+right.
Daniel Erat 2012/05/23 16:37:32 nit: use KeySym instead?
Yusuke Sato 2012/05/24 08:24:42 Done.
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_flag| to a pair of |flag| and |key_name|.
61 const struct ModifierFlagToPrefName {
62 unsigned int native_flag;
Daniel Erat 2012/05/23 16:37:32 nit: native_modifiers?
Yusuke Sato 2012/05/24 08:24:42 Done.
63 int flag;
64 const char* key_name;
Daniel Erat 2012/05/23 16:37:32 nit: pref_name?
Yusuke Sato 2012/05/24 08:24:42 Done.
65 } kModifierFlagToPrefName[] = {
66 { Mod4Mask, 0, prefs::kLanguageXkbRemapSearchKeyTo },
67 { ControlMask, ui::EF_CONTROL_DOWN, prefs::kLanguageXkbRemapControlKeyTo },
68 { Mod1Mask, ui::EF_ALT_DOWN, prefs::kLanguageXkbRemapAltKeyTo },
69 };
70
71 // Gets a remapped key for |key_name| key. For example, to find out which
72 // key Search is currently remapped to, call the function with
73 // prefs::kLanguageXkbRemapSearchKeyTo.
74 const ModifierRemapping* GetRemappedKey(const std::string& key_name,
75 PrefService* pref_service) {
Daniel Erat 2012/05/23 16:37:32 nit: const PrefService&
Yusuke Sato 2012/05/24 08:24:42 Done.
76 if (!pref_service || !pref_service->FindPreference(key_name.c_str()))
77 return NULL; // The |key_name| hasn't been registered. On login screen?
78 const int value = pref_service->GetInteger(key_name.c_str());
79 for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
80 if (value == kModifierRemappings[i].remap_to)
81 return &kModifierRemappings[i];
82 }
83 return NULL;
84 }
85
86 bool IsRight(unsigned int native_keysym) {
Daniel Erat 2012/05/23 16:37:32 nit: KeySym
Yusuke Sato 2012/05/24 08:24:42 Done.
87 switch (native_keysym) {
88 case XK_Alt_R:
89 case XK_Control_R:
90 case XK_Hyper_R:
91 case XK_Meta_R:
92 case XK_Shift_R:
93 case XK_Super_R:
94 return true;
95 }
96 return false;
97 }
98 #endif
99
100 PrefService* GetPrefService() {
Daniel Erat 2012/05/23 16:37:32 nit: const PrefService* ?
Yusuke Sato 2012/05/24 08:24:42 Done.
101 Profile* profile = ProfileManager::GetDefaultProfile();
102 if (profile)
103 return profile->GetPrefs();
104 return NULL;
105 }
106
31 } // namespace 107 } // namespace
32 108
33 KeyRewriter::KeyRewriter() : last_device_id_(kBadDeviceId) { 109 KeyRewriter::KeyRewriter()
110 : last_device_id_(kBadDeviceId),
111 #if defined(OS_CHROMEOS)
112 xkeyboard_(NULL),
113 #endif
114 pref_service_(NULL) {
34 // The ash shell isn't instantiated for our unit tests. 115 // The ash shell isn't instantiated for our unit tests.
35 if (ash::Shell::HasInstance()) 116 if (ash::Shell::HasInstance())
36 ash::Shell::GetInstance()->GetRootWindow()->AddRootWindowObserver(this); 117 ash::Shell::GetInstance()->GetRootWindow()->AddRootWindowObserver(this);
37 #if defined(OS_CHROMEOS) 118 #if defined(OS_CHROMEOS)
38 if (base::chromeos::IsRunningOnChromeOS()) { 119 if (base::chromeos::IsRunningOnChromeOS()) {
39 chromeos::XInputHierarchyChangedEventListener::GetInstance() 120 chromeos::XInputHierarchyChangedEventListener::GetInstance()
40 ->AddObserver(this); 121 ->AddObserver(this);
41 } 122 }
42 RefreshKeycodes(); 123 RefreshKeycodes();
43 #endif 124 #endif
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 DeviceAdded(device_id); 229 DeviceAdded(device_id);
149 } 230 }
150 231
151 last_device_id_ = device_id; 232 last_device_id_ = device_id;
152 } 233 }
153 234
154 void KeyRewriter::RefreshKeycodes() { 235 void KeyRewriter::RefreshKeycodes() {
155 Display* display = ui::GetXDisplay(); 236 Display* display = ui::GetXDisplay();
156 control_l_xkeycode_ = XKeysymToKeycode(display, XK_Control_L); 237 control_l_xkeycode_ = XKeysymToKeycode(display, XK_Control_L);
157 control_r_xkeycode_ = XKeysymToKeycode(display, XK_Control_R); 238 control_r_xkeycode_ = XKeysymToKeycode(display, XK_Control_R);
239 alt_l_xkeycode_ = XKeysymToKeycode(display, XK_Alt_L);
240 alt_r_xkeycode_ = XKeysymToKeycode(display, XK_Alt_R);
241 meta_l_xkeycode_ = XKeysymToKeycode(display, XK_Meta_L);
242 meta_r_xkeycode_ = XKeysymToKeycode(display, XK_Meta_R);
243 windows_l_xkeycode_ = XKeysymToKeycode(display, XK_Super_L);
244 caps_lock_xkeycode_ = XKeysymToKeycode(display, XK_Caps_Lock);
245 void_symbol_xkeycode_ = XKeysymToKeycode(display, XK_VoidSymbol);
158 kp_0_xkeycode_ = XKeysymToKeycode(display, XK_KP_0); 246 kp_0_xkeycode_ = XKeysymToKeycode(display, XK_KP_0);
159 kp_1_xkeycode_ = XKeysymToKeycode(display, XK_KP_1); 247 kp_1_xkeycode_ = XKeysymToKeycode(display, XK_KP_1);
160 kp_2_xkeycode_ = XKeysymToKeycode(display, XK_KP_2); 248 kp_2_xkeycode_ = XKeysymToKeycode(display, XK_KP_2);
161 kp_3_xkeycode_ = XKeysymToKeycode(display, XK_KP_3); 249 kp_3_xkeycode_ = XKeysymToKeycode(display, XK_KP_3);
162 kp_4_xkeycode_ = XKeysymToKeycode(display, XK_KP_4); 250 kp_4_xkeycode_ = XKeysymToKeycode(display, XK_KP_4);
163 kp_5_xkeycode_ = XKeysymToKeycode(display, XK_KP_5); 251 kp_5_xkeycode_ = XKeysymToKeycode(display, XK_KP_5);
164 kp_6_xkeycode_ = XKeysymToKeycode(display, XK_KP_6); 252 kp_6_xkeycode_ = XKeysymToKeycode(display, XK_KP_6);
165 kp_7_xkeycode_ = XKeysymToKeycode(display, XK_KP_7); 253 kp_7_xkeycode_ = XKeysymToKeycode(display, XK_KP_7);
166 kp_8_xkeycode_ = XKeysymToKeycode(display, XK_KP_8); 254 kp_8_xkeycode_ = XKeysymToKeycode(display, XK_KP_8);
167 kp_9_xkeycode_ = XKeysymToKeycode(display, XK_KP_9); 255 kp_9_xkeycode_ = XKeysymToKeycode(display, XK_KP_9);
168 kp_decimal_xkeycode_ = XKeysymToKeycode(display, XK_KP_Decimal); 256 kp_decimal_xkeycode_ = XKeysymToKeycode(display, XK_KP_Decimal);
169 } 257 }
258
259 unsigned int KeyRewriter::NativeKeySymToNativeKeycode(int keysym) {
Daniel Erat 2012/05/23 16:37:32 nit: KeySym
Yusuke Sato 2012/05/24 08:24:42 Done.
260 switch (keysym) {
261 case XK_Control_L:
262 return control_l_xkeycode_;
263 case XK_Control_R:
264 return control_r_xkeycode_;
265 case XK_Alt_L:
266 return alt_l_xkeycode_;
267 case XK_Alt_R:
268 return alt_r_xkeycode_;
269 case XK_Meta_L:
270 return meta_l_xkeycode_;
271 case XK_Meta_R:
272 return meta_r_xkeycode_;
273 case XK_Super_L:
274 return windows_l_xkeycode_;
275 case XK_Caps_Lock:
276 return caps_lock_xkeycode_;
277 case XK_VoidSymbol:
278 return void_symbol_xkeycode_;
279 case XK_KP_0:
280 return kp_0_xkeycode_;
281 case XK_KP_1:
282 return kp_1_xkeycode_;
283 case XK_KP_2:
284 return kp_2_xkeycode_;
285 case XK_KP_3:
286 return kp_3_xkeycode_;
287 case XK_KP_4:
288 return kp_4_xkeycode_;
289 case XK_KP_5:
290 return kp_5_xkeycode_;
291 case XK_KP_6:
292 return kp_6_xkeycode_;
293 case XK_KP_7:
294 return kp_7_xkeycode_;
295 case XK_KP_8:
296 return kp_8_xkeycode_;
297 case XK_KP_9:
298 return kp_9_xkeycode_;
299 case XK_KP_Decimal:
300 return kp_decimal_xkeycode_;
301 }
302 return 0U;
303 }
170 #endif 304 #endif
171 305
172 void KeyRewriter::Rewrite(aura::KeyEvent* event) { 306 void KeyRewriter::Rewrite(aura::KeyEvent* event) {
173 RewriteCommandToControl(event); 307 RewriteCommandToControl(event);
308 RewriteModifiers(event);
174 RewriteNumPadKeys(event); 309 RewriteNumPadKeys(event);
175 // TODO(yusukes): Implement crbug.com/115112 (Search/Ctrl/Alt remapping) and 310 // TODO(yusukes): Implement crosbug.com/27167 (allow sending function keys).
176 // crosbug.com/27167 (allow sending function keys) here.
177 } 311 }
178 312
179 bool KeyRewriter::RewriteCommandToControl(aura::KeyEvent* event) { 313 bool KeyRewriter::RewriteCommandToControl(aura::KeyEvent* event) {
180 bool rewritten = false; 314 bool rewritten = false;
181 if (last_device_id_ == kBadDeviceId) 315 if (last_device_id_ == kBadDeviceId)
182 return rewritten; 316 return rewritten;
183 317
184 // Check which device generated |event|. 318 // Check which device generated |event|.
185 std::map<int, DeviceType>::const_iterator iter = 319 std::map<int, DeviceType>::const_iterator iter =
186 device_id_to_type_.find(last_device_id_); 320 device_id_to_type_.find(last_device_id_);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 } 359 }
226 360
227 DCHECK_NE(ui::VKEY_LWIN, ui::KeyboardCodeFromXKeyEvent(xev)); 361 DCHECK_NE(ui::VKEY_LWIN, ui::KeyboardCodeFromXKeyEvent(xev));
228 DCHECK_NE(ui::VKEY_RWIN, ui::KeyboardCodeFromXKeyEvent(xev)); 362 DCHECK_NE(ui::VKEY_RWIN, ui::KeyboardCodeFromXKeyEvent(xev));
229 #else 363 #else
230 // TODO(yusukes): Support Ash on other platforms if needed. 364 // TODO(yusukes): Support Ash on other platforms if needed.
231 #endif 365 #endif
232 return rewritten; 366 return rewritten;
233 } 367 }
234 368
369 bool KeyRewriter::RewriteModifiers(aura::KeyEvent* event) {
370 bool rewritten = false;
Daniel Erat 2012/05/23 16:37:32 nit: maybe remove this variable and just return fa
Yusuke Sato 2012/05/24 08:24:42 Sure, removed the variable.
371 PrefService* pref_service = pref_service_ ? pref_service_ : GetPrefService();
372 if (!pref_service)
373 return rewritten;
374
375 #if defined(OS_CHROMEOS)
376 XEvent* xev = event->native_event();
377 XKeyEvent* xkey = &(xev->xkey);
378 KeySym keysym = XLookupKeysym(xkey, 0);
379
380 ui::KeyboardCode remapped_keycode = event->key_code();
381 unsigned int remapped_native_keycode = xkey->keycode;
Daniel Erat 2012/05/23 16:37:32 nit: KeyCode
Yusuke Sato 2012/05/24 08:24:42 Done.
382 int remapped_flags = 0;
383 unsigned int remapped_native_flags = 0U;
384
385 // First, remap |keysym|.
386 const char* key_name = NULL;
387 switch (keysym) {
388 case XK_Super_L:
389 key_name = prefs::kLanguageXkbRemapSearchKeyTo;
390 break;
391 case XK_Control_L:
392 case XK_Control_R:
393 key_name = prefs::kLanguageXkbRemapControlKeyTo;
394 break;
395 case XK_Alt_L:
396 case XK_Alt_R:
397 case XK_Meta_L:
398 case XK_Meta_R:
399 key_name = prefs::kLanguageXkbRemapAltKeyTo;
400 break;
Daniel Erat 2012/05/23 16:37:32 nit: add a no-op default? think that some compile
Yusuke Sato 2012/05/24 08:24:42 Done.
401 }
402 if (key_name) {
403 const ModifierRemapping* remapped_key =
404 GetRemappedKey(key_name, pref_service);
405 if (remapped_key) {
406 remapped_keycode = remapped_key->keycode;
407 const size_t level = (event->IsShiftDown() ? (1 << 1) : 0) +
408 (IsRight(keysym) ? (1 << 0) : 0);
409 const KeySym native_keysym = remapped_key->native_keysyms[level];
410 remapped_native_keycode = NativeKeySymToNativeKeycode(native_keysym);
411 }
412 }
413
414 // Next, remap modifier bits.
415 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) {
416 if (xkey->state & kModifierFlagToPrefName[i].native_flag) {
417 const ModifierRemapping* remapped_key =
418 GetRemappedKey(kModifierFlagToPrefName[i].key_name, pref_service);
419 if (remapped_key) {
420 remapped_flags |= remapped_key->flag;
421 remapped_native_flags |= remapped_key->native_flag;
422 } else {
423 remapped_flags |= kModifierFlagToPrefName[i].flag;
424 remapped_native_flags |= kModifierFlagToPrefName[i].native_flag;
425 }
426 }
427 }
428 remapped_flags = (event->flags() & ~(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)) |
429 remapped_flags;
430 remapped_native_flags = (xkey->state & ~(Mod4Mask | ControlMask | Mod1Mask)) |
431 remapped_native_flags;
432
433 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if
434 // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external
435 // keyboard is pressed) since X can handle that case.
436 if ((event->type() == ui::ET_KEY_PRESSED) &&
437 (event->key_code() != ui::VKEY_CAPITAL) &&
438 (remapped_keycode == ui::VKEY_CAPITAL)) {
439 chromeos::input_method::XKeyboard* xkeyboard = xkeyboard_ ?
440 xkeyboard_ : InputMethodManager::GetInstance()->GetXKeyboard();
441 xkeyboard->SetCapsLockEnabled(!xkeyboard->CapsLockIsEnabled());
442 }
443
444 OverwriteEvent(event,
445 remapped_native_keycode, remapped_native_flags,
446 remapped_keycode, remapped_flags);
447 rewritten = true;
448 #else
449 // TODO(yusukes): Support Ash on other platforms if needed.
450 #endif
451 return rewritten;
452 }
453
235 bool KeyRewriter::RewriteNumPadKeys(aura::KeyEvent* event) { 454 bool KeyRewriter::RewriteNumPadKeys(aura::KeyEvent* event) {
236 bool rewritten = false; 455 bool rewritten = false;
237 #if defined(OS_CHROMEOS) 456 #if defined(OS_CHROMEOS)
238 XEvent* xev = event->native_event(); 457 XEvent* xev = event->native_event();
239 XKeyEvent* xkey = &(xev->xkey); 458 XKeyEvent* xkey = &(xev->xkey);
240 459
241 const KeySym keysym = XLookupKeysym(xkey, 0); 460 const KeySym keysym = XLookupKeysym(xkey, 0);
242 switch (keysym) { 461 switch (keysym) {
243 case XK_KP_Insert: 462 case XK_KP_Insert:
244 OverwriteEvent(event, kp_0_xkeycode_, xkey->state | Mod2Mask, 463 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); 558 const DeviceType type = KeyRewriter::GetDeviceType(device_name);
340 if (type == kDeviceAppleKeyboard) { 559 if (type == kDeviceAppleKeyboard) {
341 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " 560 VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
342 << "id=" << device_id; 561 << "id=" << device_id;
343 } 562 }
344 // Always overwrite the existing device_id since the X server may reuse a 563 // Always overwrite the existing device_id since the X server may reuse a
345 // device id for an unattached device. 564 // device id for an unattached device.
346 device_id_to_type_[device_id] = type; 565 device_id_to_type_[device_id] = type;
347 return type; 566 return type;
348 } 567 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698