• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/chromeos/events/event_rewriter.h"
6 
7 #include <vector>
8 
9 #include "ash/sticky_keys/sticky_keys_controller.h"
10 #include "ash/wm/window_state.h"
11 #include "ash/wm/window_util.h"
12 #include "base/command_line.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/strings/string_util.h"
17 #include "base/sys_info.h"
18 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
19 #include "chrome/browser/extensions/extension_commands_global_registry.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/common/pref_names.h"
22 #include "chromeos/chromeos_switches.h"
23 #include "chromeos/ime/ime_keyboard.h"
24 #include "chromeos/ime/input_method_manager.h"
25 #include "components/user_manager/user_manager.h"
26 #include "ui/events/event.h"
27 #include "ui/events/event_utils.h"
28 #include "ui/events/keycodes/keyboard_code_conversion.h"
29 #include "ui/wm/core/window_util.h"
30 
31 #if defined(USE_X11)
32 #include <X11/extensions/XInput2.h>
33 #include <X11/Xlib.h>
34 // Get rid of macros from Xlib.h that conflicts with other parts of the code.
35 #undef RootWindow
36 #undef Status
37 
38 #include "ui/base/x/x11_util.h"
39 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
40 #endif
41 
42 namespace chromeos {
43 
44 namespace {
45 
46 // Table of key properties of remappable keys and/or remapping targets.
47 // This is searched in two distinct ways:
48 //  - |remap_to| is an |input_method::ModifierKey|, which is the form
49 //    held in user preferences. |GetRemappedKey()| maps this to the
50 //    corresponding |key_code| and characterstic event |flag|.
51 //  - |flag| is a |ui::EventFlags|. |GetRemappedModifierMasks()| maps this
52 //    to the corresponding user preference |pref_name| for that flag's
53 //    key, so that it can then be remapped as above.
54 // In addition |kModifierRemappingCtrl| is a direct reference to the
55 // Control key entry in the table, used in handling Chromebook Diamond
56 // and Apple Command keys.
57 const struct ModifierRemapping {
58   int remap_to;
59   int flag;
60   ui::KeyboardCode key_code;
61   const char* pref_name;
62 } kModifierRemappings[] = {
63       {input_method::kSearchKey, ui::EF_COMMAND_DOWN, ui::VKEY_LWIN,
64        prefs::kLanguageRemapSearchKeyTo},
65       {input_method::kControlKey, ui::EF_CONTROL_DOWN, ui::VKEY_CONTROL,
66        prefs::kLanguageRemapControlKeyTo},
67       {input_method::kAltKey, ui::EF_ALT_DOWN, ui::VKEY_MENU,
68        prefs::kLanguageRemapAltKeyTo},
69       {input_method::kVoidKey, 0, ui::VKEY_UNKNOWN, NULL},
70       {input_method::kCapsLockKey, ui::EF_MOD3_DOWN, ui::VKEY_CAPITAL,
71        prefs::kLanguageRemapCapsLockKeyTo},
72       {input_method::kEscapeKey, 0, ui::VKEY_ESCAPE, NULL},
73       {0, 0, ui::VKEY_F15, prefs::kLanguageRemapDiamondKeyTo},
74 };
75 
76 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1];
77 
78 // Gets a remapped key for |pref_name| key. For example, to find out which
79 // key Search is currently remapped to, call the function with
80 // prefs::kLanguageRemapSearchKeyTo.
GetRemappedKey(const std::string & pref_name,const PrefService & pref_service)81 const ModifierRemapping* GetRemappedKey(const std::string& pref_name,
82                                         const PrefService& pref_service) {
83   if (!pref_service.FindPreference(pref_name.c_str()))
84     return NULL;  // The |pref_name| hasn't been registered. On login screen?
85   const int value = pref_service.GetInteger(pref_name.c_str());
86   for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
87     if (value == kModifierRemappings[i].remap_to)
88       return &kModifierRemappings[i];
89   }
90   return NULL;
91 }
92 
HasDiamondKey()93 bool HasDiamondKey() {
94   return CommandLine::ForCurrentProcess()->HasSwitch(
95       chromeos::switches::kHasChromeOSDiamondKey);
96 }
97 
IsISOLevel5ShiftUsedByCurrentInputMethod()98 bool IsISOLevel5ShiftUsedByCurrentInputMethod() {
99   // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
100   // it's not possible to make both features work. For now, we don't remap
101   // Mod3Mask when Neo2 is in use.
102   // TODO(yusukes): Remove the restriction.
103   input_method::InputMethodManager* manager =
104       input_method::InputMethodManager::Get();
105   return manager->IsISOLevel5ShiftUsedByCurrentInputMethod();
106 }
107 
IsExtensionCommandRegistered(const ui::KeyEvent & key_event)108 bool IsExtensionCommandRegistered(const ui::KeyEvent& key_event) {
109   // Some keyboard events for ChromeOS get rewritten, such as:
110   // Search+Shift+Left gets converted to Shift+Home (BeginDocument).
111   // This doesn't make sense if the user has assigned that shortcut
112   // to an extension. Because:
113   // 1) The extension would, upon seeing a request for Ctrl+Shift+Home have
114   //    to register for Shift+Home, instead.
115   // 2) The conversion is unnecessary, because Shift+Home (BeginDocument) isn't
116   //    going to be executed.
117   // Therefore, we skip converting the accelerator if an extension has
118   // registered for this shortcut.
119   Profile* profile = ProfileManager::GetActiveUserProfile();
120   if (!profile || !extensions::ExtensionCommandsGlobalRegistry::Get(profile))
121     return false;
122 
123   int modifiers = key_event.flags() & (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
124                                        ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
125   ui::Accelerator accelerator(key_event.key_code(), modifiers);
126   return extensions::ExtensionCommandsGlobalRegistry::Get(profile)
127       ->IsRegistered(accelerator);
128 }
129 
GetDeviceType(const std::string & device_name)130 EventRewriter::DeviceType GetDeviceType(const std::string& device_name) {
131   std::vector<std::string> tokens;
132   Tokenize(device_name, " .", &tokens);
133 
134   // If the |device_name| contains the two words, "apple" and "keyboard", treat
135   // it as an Apple keyboard.
136   bool found_apple = false;
137   bool found_keyboard = false;
138   for (size_t i = 0; i < tokens.size(); ++i) {
139     if (!found_apple && LowerCaseEqualsASCII(tokens[i], "apple"))
140       found_apple = true;
141     if (!found_keyboard && LowerCaseEqualsASCII(tokens[i], "keyboard"))
142       found_keyboard = true;
143     if (found_apple && found_keyboard)
144       return EventRewriter::kDeviceAppleKeyboard;
145   }
146 
147   return EventRewriter::kDeviceUnknown;
148 }
149 
150 }  // namespace
151 
EventRewriter(ash::StickyKeysController * sticky_keys_controller)152 EventRewriter::EventRewriter(ash::StickyKeysController* sticky_keys_controller)
153     : last_keyboard_device_id_(ui::ED_UNKNOWN_DEVICE),
154       ime_keyboard_for_testing_(NULL),
155       pref_service_for_testing_(NULL),
156       sticky_keys_controller_(sticky_keys_controller),
157       current_diamond_key_modifier_flags_(ui::EF_NONE) {
158 }
159 
~EventRewriter()160 EventRewriter::~EventRewriter() {
161 }
162 
KeyboardDeviceAddedForTesting(int device_id,const std::string & device_name)163 EventRewriter::DeviceType EventRewriter::KeyboardDeviceAddedForTesting(
164     int device_id,
165     const std::string& device_name) {
166   // Tests must avoid XI2 reserved device IDs.
167   DCHECK((device_id < 0) || (device_id > 1));
168   return KeyboardDeviceAddedInternal(device_id, device_name);
169 }
170 
RewriteMouseButtonEventForTesting(const ui::MouseEvent & event,scoped_ptr<ui::Event> * rewritten_event)171 void EventRewriter::RewriteMouseButtonEventForTesting(
172     const ui::MouseEvent& event,
173     scoped_ptr<ui::Event>* rewritten_event) {
174   RewriteMouseButtonEvent(event, rewritten_event);
175 }
176 
RewriteEvent(const ui::Event & event,scoped_ptr<ui::Event> * rewritten_event)177 ui::EventRewriteStatus EventRewriter::RewriteEvent(
178     const ui::Event& event,
179     scoped_ptr<ui::Event>* rewritten_event) {
180   if ((event.type() == ui::ET_KEY_PRESSED) ||
181       (event.type() == ui::ET_KEY_RELEASED)) {
182     return RewriteKeyEvent(static_cast<const ui::KeyEvent&>(event),
183                            rewritten_event);
184   }
185   if ((event.type() == ui::ET_MOUSE_PRESSED) ||
186       (event.type() == ui::ET_MOUSE_RELEASED)) {
187     return RewriteMouseButtonEvent(static_cast<const ui::MouseEvent&>(event),
188                                    rewritten_event);
189   }
190   if (event.type() == ui::ET_MOUSEWHEEL) {
191     return RewriteMouseWheelEvent(
192         static_cast<const ui::MouseWheelEvent&>(event), rewritten_event);
193   }
194   if ((event.type() == ui::ET_TOUCH_PRESSED) ||
195       (event.type() == ui::ET_TOUCH_RELEASED)) {
196     return RewriteTouchEvent(static_cast<const ui::TouchEvent&>(event),
197                              rewritten_event);
198   }
199   if (event.IsScrollEvent()) {
200     return RewriteScrollEvent(static_cast<const ui::ScrollEvent&>(event),
201                               rewritten_event);
202   }
203   return ui::EVENT_REWRITE_CONTINUE;
204 }
205 
NextDispatchEvent(const ui::Event & last_event,scoped_ptr<ui::Event> * new_event)206 ui::EventRewriteStatus EventRewriter::NextDispatchEvent(
207     const ui::Event& last_event,
208     scoped_ptr<ui::Event>* new_event) {
209   if (sticky_keys_controller_) {
210     // In the case of sticky keys, we know what the events obtained here are:
211     // modifier key releases that match the ones previously discarded. So, we
212     // know that they don't have to be passed through the post-sticky key
213     // rewriting phases, |RewriteExtendedKeys()| and |RewriteFunctionKeys()|,
214     // because those phases do nothing with modifier key releases.
215     return sticky_keys_controller_->NextDispatchEvent(new_event);
216   }
217   NOTREACHED();
218   return ui::EVENT_REWRITE_CONTINUE;
219 }
220 
BuildRewrittenKeyEvent(const ui::KeyEvent & key_event,ui::KeyboardCode key_code,int flags,scoped_ptr<ui::Event> * rewritten_event)221 void EventRewriter::BuildRewrittenKeyEvent(
222     const ui::KeyEvent& key_event,
223     ui::KeyboardCode key_code,
224     int flags,
225     scoped_ptr<ui::Event>* rewritten_event) {
226   ui::KeyEvent* rewritten_key_event = NULL;
227 #if defined(USE_X11)
228   XEvent* xev = key_event.native_event();
229   if (xev) {
230     XEvent xkeyevent;
231     // Convert all XI2-based key events into X11 core-based key events,
232     // until consumers no longer depend on receiving X11 core events.
233     if (xev->type == GenericEvent)
234       ui::InitXKeyEventFromXIDeviceEvent(*xev, &xkeyevent);
235     else
236       xkeyevent.xkey = xev->xkey;
237 
238     unsigned int original_x11_keycode = xkeyevent.xkey.keycode;
239     // Update native event to match rewritten |ui::Event|.
240     // The X11 keycode represents a physical key position, so it shouldn't
241     // change unless we have actually changed keys, not just modifiers.
242     // This is one guard against problems like crbug.com/390263.
243     if (key_event.key_code() != key_code) {
244       xkeyevent.xkey.keycode =
245           XKeyCodeForWindowsKeyCode(key_code, flags, gfx::GetXDisplay());
246     }
247     ui::KeyEvent x11_key_event(&xkeyevent);
248     rewritten_key_event = new ui::KeyEvent(x11_key_event);
249 
250     // For numpad keys, the key char should always NOT be changed because
251     // XKeyCodeForWindowsKeyCode method cannot handle non-US keyboard layout.
252     // The correct key char can be got from original X11 keycode but not for the
253     // rewritten X11 keycode.
254     // For Shift+NumpadKey cases, use the rewritten X11 keycode (US layout).
255     // Please see crbug.com/335644.
256     if (key_code >= ui::VKEY_NUMPAD0 && key_code <= ui::VKEY_DIVIDE) {
257       XEvent numpad_xevent;
258       numpad_xevent.xkey = xkeyevent.xkey;
259       // Remove the shift state before getting key char.
260       // Because X11/XKB sometimes returns unexpected key char for
261       // Shift+NumpadKey. e.g. Shift+Numpad_4 returns 'D', etc.
262       numpad_xevent.xkey.state &= ~ShiftMask;
263       numpad_xevent.xkey.state |= Mod2Mask;  // Always set NumLock mask.
264       if (!(flags & ui::EF_SHIFT_DOWN))
265         numpad_xevent.xkey.keycode = original_x11_keycode;
266       rewritten_key_event->set_character(
267           ui::GetCharacterFromXEvent(&numpad_xevent));
268     }
269   }
270 #endif
271   if (!rewritten_key_event)
272     rewritten_key_event = new ui::KeyEvent(key_event);
273   rewritten_key_event->set_flags(flags);
274   rewritten_key_event->set_key_code(key_code);
275 #if defined(USE_X11)
276   ui::UpdateX11EventForFlags(rewritten_key_event);
277   rewritten_key_event->NormalizeFlags();
278 #endif
279   rewritten_event->reset(rewritten_key_event);
280 }
281 
DeviceKeyPressedOrReleased(int device_id)282 void EventRewriter::DeviceKeyPressedOrReleased(int device_id) {
283   if (!device_id_to_type_.count(device_id))
284     KeyboardDeviceAdded(device_id);
285   last_keyboard_device_id_ = device_id;
286 }
287 
GetPrefService() const288 const PrefService* EventRewriter::GetPrefService() const {
289   if (pref_service_for_testing_)
290     return pref_service_for_testing_;
291   Profile* profile = ProfileManager::GetActiveUserProfile();
292   return profile ? profile->GetPrefs() : NULL;
293 }
294 
IsAppleKeyboard() const295 bool EventRewriter::IsAppleKeyboard() const {
296   if (last_keyboard_device_id_ == ui::ED_UNKNOWN_DEVICE)
297     return false;
298 
299   // Check which device generated |event|.
300   std::map<int, DeviceType>::const_iterator iter =
301       device_id_to_type_.find(last_keyboard_device_id_);
302   if (iter == device_id_to_type_.end()) {
303     LOG(ERROR) << "Device ID " << last_keyboard_device_id_ << " is unknown.";
304     return false;
305   }
306 
307   const DeviceType type = iter->second;
308   return type == kDeviceAppleKeyboard;
309 }
310 
TopRowKeysAreFunctionKeys(const ui::KeyEvent & event) const311 bool EventRewriter::TopRowKeysAreFunctionKeys(const ui::KeyEvent& event) const {
312   const PrefService* prefs = GetPrefService();
313   if (prefs && prefs->FindPreference(prefs::kLanguageSendFunctionKeys) &&
314       prefs->GetBoolean(prefs::kLanguageSendFunctionKeys))
315     return true;
316 
317   ash::wm::WindowState* state = ash::wm::GetActiveWindowState();
318   return state ? state->top_row_keys_are_function_keys() : false;
319 }
320 
GetRemappedModifierMasks(const PrefService & pref_service,const ui::Event & event,int original_flags) const321 int EventRewriter::GetRemappedModifierMasks(const PrefService& pref_service,
322                                             const ui::Event& event,
323                                             int original_flags) const {
324   int unmodified_flags = original_flags;
325   int rewritten_flags = current_diamond_key_modifier_flags_;
326   for (size_t i = 0; unmodified_flags && (i < arraysize(kModifierRemappings));
327        ++i) {
328     const ModifierRemapping* remapped_key = NULL;
329     if (!(unmodified_flags & kModifierRemappings[i].flag))
330       continue;
331     switch (kModifierRemappings[i].flag) {
332       case ui::EF_COMMAND_DOWN:
333         // Rewrite Command key presses on an Apple keyboard to Control.
334         if (IsAppleKeyboard()) {
335           DCHECK_EQ(ui::EF_CONTROL_DOWN, kModifierRemappingCtrl->flag);
336           remapped_key = kModifierRemappingCtrl;
337         }
338         break;
339       case ui::EF_MOD3_DOWN:
340         // If EF_MOD3_DOWN is used by the current input method, leave it alone;
341         // it is not remappable.
342         if (IsISOLevel5ShiftUsedByCurrentInputMethod())
343           continue;
344         // Otherwise, Mod3Mask is set on X events when the Caps Lock key
345         // is down, but, if Caps Lock is remapped, CapsLock is NOT set,
346         // because pressing the key does not invoke caps lock. So, the
347         // kModifierRemappings[] table uses EF_MOD3_DOWN for the Caps
348         // Lock remapping.
349         break;
350       default:
351         break;
352     }
353     if (!remapped_key && kModifierRemappings[i].pref_name) {
354       remapped_key =
355           GetRemappedKey(kModifierRemappings[i].pref_name, pref_service);
356     }
357     if (remapped_key) {
358       unmodified_flags &= ~kModifierRemappings[i].flag;
359       rewritten_flags |= remapped_key->flag;
360     }
361   }
362   return rewritten_flags | unmodified_flags;
363 }
364 
RewriteWithKeyboardRemappingsByKeyCode(const KeyboardRemapping * remappings,size_t num_remappings,const MutableKeyState & input,MutableKeyState * remapped_state)365 bool EventRewriter::RewriteWithKeyboardRemappingsByKeyCode(
366     const KeyboardRemapping* remappings,
367     size_t num_remappings,
368     const MutableKeyState& input,
369     MutableKeyState* remapped_state) {
370   for (size_t i = 0; i < num_remappings; ++i) {
371     const KeyboardRemapping& map = remappings[i];
372     if (input.key_code != map.input_key_code)
373       continue;
374     if ((input.flags & map.input_flags) != map.input_flags)
375       continue;
376     remapped_state->key_code = map.output_key_code;
377     remapped_state->flags = (input.flags & ~map.input_flags) | map.output_flags;
378     return true;
379   }
380   return false;
381 }
382 
RewriteKeyEvent(const ui::KeyEvent & key_event,scoped_ptr<ui::Event> * rewritten_event)383 ui::EventRewriteStatus EventRewriter::RewriteKeyEvent(
384     const ui::KeyEvent& key_event,
385     scoped_ptr<ui::Event>* rewritten_event) {
386   if (IsExtensionCommandRegistered(key_event))
387     return ui::EVENT_REWRITE_CONTINUE;
388   if (key_event.source_device_id() != ui::ED_UNKNOWN_DEVICE)
389     DeviceKeyPressedOrReleased(key_event.source_device_id());
390   MutableKeyState state = {key_event.flags(), key_event.key_code()};
391   // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
392   // crbug.com/136465.
393   if (!(key_event.flags() & ui::EF_FINAL)) {
394     RewriteModifierKeys(key_event, &state);
395     RewriteNumPadKeys(key_event, &state);
396   }
397   ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
398   if (sticky_keys_controller_) {
399     status = sticky_keys_controller_->RewriteKeyEvent(
400         key_event, state.key_code, &state.flags);
401     if (status == ui::EVENT_REWRITE_DISCARD)
402       return ui::EVENT_REWRITE_DISCARD;
403   }
404   if (!(key_event.flags() & ui::EF_FINAL)) {
405     RewriteExtendedKeys(key_event, &state);
406     RewriteFunctionKeys(key_event, &state);
407   }
408   if ((key_event.flags() == state.flags) &&
409       (key_event.key_code() == state.key_code) &&
410 #if defined(USE_X11)
411       // TODO(kpschoedel): This test is present because several consumers of
412       // key events depend on having a native core X11 event, so we rewrite
413       // all XI2 key events (GenericEvent) into corresponding core X11 key
414       // events. Remove this when event consumers no longer care about
415       // native X11 event details (crbug.com/380349).
416       (!key_event.HasNativeEvent() ||
417        (key_event.native_event()->type != GenericEvent)) &&
418 #endif
419       (status == ui::EVENT_REWRITE_CONTINUE)) {
420     return ui::EVENT_REWRITE_CONTINUE;
421   }
422   // Sticky keys may have returned a result other than |EVENT_REWRITE_CONTINUE|,
423   // in which case we need to preserve that return status. Alternatively, we
424   // might be here because key_event changed, in which case we need to
425   // return |EVENT_REWRITE_REWRITTEN|.
426   if (status == ui::EVENT_REWRITE_CONTINUE)
427     status = ui::EVENT_REWRITE_REWRITTEN;
428   BuildRewrittenKeyEvent(
429       key_event, state.key_code, state.flags, rewritten_event);
430   return status;
431 }
432 
RewriteMouseButtonEvent(const ui::MouseEvent & mouse_event,scoped_ptr<ui::Event> * rewritten_event)433 ui::EventRewriteStatus EventRewriter::RewriteMouseButtonEvent(
434     const ui::MouseEvent& mouse_event,
435     scoped_ptr<ui::Event>* rewritten_event) {
436   int flags = mouse_event.flags();
437   RewriteLocatedEvent(mouse_event, &flags);
438   ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
439   if (sticky_keys_controller_)
440     status = sticky_keys_controller_->RewriteMouseEvent(mouse_event, &flags);
441   int changed_button = ui::EF_NONE;
442   if ((mouse_event.type() == ui::ET_MOUSE_PRESSED) ||
443       (mouse_event.type() == ui::ET_MOUSE_RELEASED)) {
444     changed_button = RewriteModifierClick(mouse_event, &flags);
445   }
446   if ((mouse_event.flags() == flags) &&
447       (status == ui::EVENT_REWRITE_CONTINUE)) {
448     return ui::EVENT_REWRITE_CONTINUE;
449   }
450   if (status == ui::EVENT_REWRITE_CONTINUE)
451     status = ui::EVENT_REWRITE_REWRITTEN;
452   ui::MouseEvent* rewritten_mouse_event = new ui::MouseEvent(mouse_event);
453   rewritten_event->reset(rewritten_mouse_event);
454   rewritten_mouse_event->set_flags(flags);
455 #if defined(USE_X11)
456   ui::UpdateX11EventForFlags(rewritten_mouse_event);
457 #endif
458   if (changed_button != ui::EF_NONE) {
459     rewritten_mouse_event->set_changed_button_flags(changed_button);
460 #if defined(USE_X11)
461     ui::UpdateX11EventForChangedButtonFlags(rewritten_mouse_event);
462 #endif
463   }
464   return status;
465 }
466 
RewriteMouseWheelEvent(const ui::MouseWheelEvent & wheel_event,scoped_ptr<ui::Event> * rewritten_event)467 ui::EventRewriteStatus EventRewriter::RewriteMouseWheelEvent(
468     const ui::MouseWheelEvent& wheel_event,
469     scoped_ptr<ui::Event>* rewritten_event) {
470   if (!sticky_keys_controller_)
471     return ui::EVENT_REWRITE_CONTINUE;
472   int flags = wheel_event.flags();
473   ui::EventRewriteStatus status =
474       sticky_keys_controller_->RewriteMouseEvent(wheel_event, &flags);
475   if ((wheel_event.flags() == flags) &&
476       (status == ui::EVENT_REWRITE_CONTINUE)) {
477     return ui::EVENT_REWRITE_CONTINUE;
478   }
479   if (status == ui::EVENT_REWRITE_CONTINUE)
480     status = ui::EVENT_REWRITE_REWRITTEN;
481   ui::MouseWheelEvent* rewritten_wheel_event =
482       new ui::MouseWheelEvent(wheel_event);
483   rewritten_event->reset(rewritten_wheel_event);
484   rewritten_wheel_event->set_flags(flags);
485 #if defined(USE_X11)
486   ui::UpdateX11EventForFlags(rewritten_wheel_event);
487 #endif
488   return status;
489 }
490 
RewriteTouchEvent(const ui::TouchEvent & touch_event,scoped_ptr<ui::Event> * rewritten_event)491 ui::EventRewriteStatus EventRewriter::RewriteTouchEvent(
492     const ui::TouchEvent& touch_event,
493     scoped_ptr<ui::Event>* rewritten_event) {
494   int flags = touch_event.flags();
495   RewriteLocatedEvent(touch_event, &flags);
496   if (touch_event.flags() == flags)
497     return ui::EVENT_REWRITE_CONTINUE;
498   ui::TouchEvent* rewritten_touch_event = new ui::TouchEvent(touch_event);
499   rewritten_event->reset(rewritten_touch_event);
500   rewritten_touch_event->set_flags(flags);
501 #if defined(USE_X11)
502   ui::UpdateX11EventForFlags(rewritten_touch_event);
503 #endif
504   return ui::EVENT_REWRITE_REWRITTEN;
505 }
506 
RewriteScrollEvent(const ui::ScrollEvent & scroll_event,scoped_ptr<ui::Event> * rewritten_event)507 ui::EventRewriteStatus EventRewriter::RewriteScrollEvent(
508     const ui::ScrollEvent& scroll_event,
509     scoped_ptr<ui::Event>* rewritten_event) {
510   int flags = scroll_event.flags();
511   ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
512   if (sticky_keys_controller_)
513     status = sticky_keys_controller_->RewriteScrollEvent(scroll_event, &flags);
514   if (status == ui::EVENT_REWRITE_CONTINUE)
515     return status;
516   ui::ScrollEvent* rewritten_scroll_event = new ui::ScrollEvent(scroll_event);
517   rewritten_event->reset(rewritten_scroll_event);
518   rewritten_scroll_event->set_flags(flags);
519 #if defined(USE_X11)
520   ui::UpdateX11EventForFlags(rewritten_scroll_event);
521 #endif
522   return status;
523 }
524 
RewriteModifierKeys(const ui::KeyEvent & key_event,MutableKeyState * state)525 void EventRewriter::RewriteModifierKeys(const ui::KeyEvent& key_event,
526                                         MutableKeyState* state) {
527   DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
528          key_event.type() == ui::ET_KEY_RELEASED);
529 
530   // Do nothing if we have just logged in as guest but have not restarted chrome
531   // process yet (so we are still on the login screen). In this situations we
532   // have no user profile so can not do anything useful.
533   // Note that currently, unlike other accounts, when user logs in as guest, we
534   // restart chrome process. In future this is to be changed.
535   // TODO(glotov): remove the following condition when we do not restart chrome
536   // when user logs in as guest.
537   // TODO(kpschoedel): check whether this is still necessary.
538   if (user_manager::UserManager::Get()->IsLoggedInAsGuest() &&
539       LoginDisplayHostImpl::default_host())
540     return;
541 
542   const PrefService* pref_service = GetPrefService();
543   if (!pref_service)
544     return;
545 
546   MutableKeyState incoming = *state;
547   state->flags = ui::EF_NONE;
548   int characteristic_flag = ui::EF_NONE;
549 
550   // First, remap the key code.
551   const ModifierRemapping* remapped_key = NULL;
552   switch (incoming.key_code) {
553     // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent
554     // when Diamond key is pressed.
555     case ui::VKEY_F15:
556       // When diamond key is not available, the configuration UI for Diamond
557       // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo
558       // syncable pref.
559       if (HasDiamondKey())
560         remapped_key =
561             GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service);
562       // Default behavior of F15 is Control, even if --has-chromeos-diamond-key
563       // is absent, according to unit test comments.
564       if (!remapped_key) {
565         DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code);
566         remapped_key = kModifierRemappingCtrl;
567       }
568       // F15 is not a modifier key, so we need to track its state directly.
569       if (key_event.type() == ui::ET_KEY_PRESSED) {
570         int remapped_flag = remapped_key->flag;
571         if (remapped_key->remap_to == input_method::kCapsLockKey)
572           remapped_flag |= ui::EF_CAPS_LOCK_DOWN;
573         current_diamond_key_modifier_flags_ = remapped_flag;
574       } else {
575         current_diamond_key_modifier_flags_ = ui::EF_NONE;
576       }
577       break;
578     // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock
579     // is pressed (with one exception: when
580     // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates
581     // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7).
582     case ui::VKEY_F16:
583       characteristic_flag = ui::EF_CAPS_LOCK_DOWN;
584       remapped_key =
585           GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service);
586       break;
587     case ui::VKEY_LWIN:
588     case ui::VKEY_RWIN:
589       characteristic_flag = ui::EF_COMMAND_DOWN;
590       // Rewrite Command-L/R key presses on an Apple keyboard to Control.
591       if (IsAppleKeyboard()) {
592         DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code);
593         remapped_key = kModifierRemappingCtrl;
594       } else {
595         remapped_key =
596             GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service);
597       }
598       // Default behavior is Super key, hence don't remap the event if the pref
599       // is unavailable.
600       break;
601     case ui::VKEY_CONTROL:
602       characteristic_flag = ui::EF_CONTROL_DOWN;
603       remapped_key =
604           GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service);
605       break;
606     case ui::VKEY_MENU:
607       // ALT key
608       characteristic_flag = ui::EF_ALT_DOWN;
609       remapped_key =
610           GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service);
611       break;
612     default:
613       break;
614   }
615 
616   if (remapped_key) {
617     state->key_code = remapped_key->key_code;
618     incoming.flags |= characteristic_flag;
619     characteristic_flag = remapped_key->flag;
620   }
621 
622   // Next, remap modifier bits.
623   state->flags |=
624       GetRemappedModifierMasks(*pref_service, key_event, incoming.flags);
625   if (key_event.type() == ui::ET_KEY_PRESSED)
626     state->flags |= characteristic_flag;
627   else
628     state->flags &= ~characteristic_flag;
629 
630   // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if
631   // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external
632   // keyboard is pressed) since X can handle that case.
633   if (key_event.type() == ui::ET_KEY_PRESSED &&
634       incoming.key_code != ui::VKEY_CAPITAL &&
635       state->key_code == ui::VKEY_CAPITAL) {
636     chromeos::input_method::ImeKeyboard* ime_keyboard =
637         ime_keyboard_for_testing_
638             ? ime_keyboard_for_testing_
639             : chromeos::input_method::InputMethodManager::Get()
640                   ->GetImeKeyboard();
641     ime_keyboard->SetCapsLockEnabled(!ime_keyboard->CapsLockIsEnabled());
642   }
643 }
644 
RewriteNumPadKeys(const ui::KeyEvent & key_event,MutableKeyState * state)645 void EventRewriter::RewriteNumPadKeys(const ui::KeyEvent& key_event,
646                                       MutableKeyState* state) {
647   DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
648          key_event.type() == ui::ET_KEY_RELEASED);
649   if (!(state->flags & ui::EF_NUMPAD_KEY))
650     return;
651   MutableKeyState incoming = *state;
652 
653   static const KeyboardRemapping kNumPadRemappings[] = {
654       {ui::VKEY_INSERT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD0, ui::EF_NUMPAD_KEY},
655       {ui::VKEY_DELETE, ui::EF_NUMPAD_KEY, ui::VKEY_DECIMAL, ui::EF_NUMPAD_KEY},
656       {ui::VKEY_END, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD1, ui::EF_NUMPAD_KEY},
657       {ui::VKEY_DOWN, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD2, ui::EF_NUMPAD_KEY},
658       {ui::VKEY_NEXT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD3, ui::EF_NUMPAD_KEY},
659       {ui::VKEY_LEFT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD4, ui::EF_NUMPAD_KEY},
660       {ui::VKEY_CLEAR, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD5, ui::EF_NUMPAD_KEY},
661       {ui::VKEY_RIGHT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD6, ui::EF_NUMPAD_KEY},
662       {ui::VKEY_HOME, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD7, ui::EF_NUMPAD_KEY},
663       {ui::VKEY_UP, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD8, ui::EF_NUMPAD_KEY},
664       {ui::VKEY_PRIOR, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD9, ui::EF_NUMPAD_KEY},
665   };
666 
667   RewriteWithKeyboardRemappingsByKeyCode(
668       kNumPadRemappings, arraysize(kNumPadRemappings), incoming, state);
669 }
670 
RewriteExtendedKeys(const ui::KeyEvent & key_event,MutableKeyState * state)671 void EventRewriter::RewriteExtendedKeys(const ui::KeyEvent& key_event,
672                                         MutableKeyState* state) {
673   DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
674          key_event.type() == ui::ET_KEY_RELEASED);
675 
676   MutableKeyState incoming = *state;
677   bool rewritten = false;
678 
679   if ((incoming.flags & (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) ==
680       (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) {
681     // Allow Search to avoid rewriting extended keys.
682     static const KeyboardRemapping kAvoidRemappings[] = {
683         {  // Alt+Backspace
684          ui::VKEY_BACK, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, ui::VKEY_BACK,
685          ui::EF_ALT_DOWN,
686         },
687         {  // Control+Alt+Up
688          ui::VKEY_UP,
689          ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN,
690          ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
691         },
692         {  // Alt+Up
693          ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, ui::VKEY_UP,
694          ui::EF_ALT_DOWN,
695         },
696         {  // Control+Alt+Down
697          ui::VKEY_DOWN,
698          ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN,
699          ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
700         },
701         {  // Alt+Down
702          ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, ui::VKEY_DOWN,
703          ui::EF_ALT_DOWN,
704         }};
705 
706     rewritten = RewriteWithKeyboardRemappingsByKeyCode(
707         kAvoidRemappings, arraysize(kAvoidRemappings), incoming, state);
708   }
709 
710   if (!rewritten && (incoming.flags & ui::EF_COMMAND_DOWN)) {
711     static const KeyboardRemapping kSearchRemappings[] = {
712         {  // Search+BackSpace -> Delete
713          ui::VKEY_BACK, ui::EF_COMMAND_DOWN, ui::VKEY_DELETE, 0},
714         {  // Search+Left -> Home
715          ui::VKEY_LEFT, ui::EF_COMMAND_DOWN, ui::VKEY_HOME, 0},
716         {  // Search+Up -> Prior (aka PageUp)
717          ui::VKEY_UP, ui::EF_COMMAND_DOWN, ui::VKEY_PRIOR, 0},
718         {  // Search+Right -> End
719          ui::VKEY_RIGHT, ui::EF_COMMAND_DOWN, ui::VKEY_END, 0},
720         {  // Search+Down -> Next (aka PageDown)
721          ui::VKEY_DOWN, ui::EF_COMMAND_DOWN, ui::VKEY_NEXT, 0},
722         {  // Search+Period -> Insert
723          ui::VKEY_OEM_PERIOD, ui::EF_COMMAND_DOWN, ui::VKEY_INSERT, 0}};
724 
725     rewritten = RewriteWithKeyboardRemappingsByKeyCode(
726         kSearchRemappings, arraysize(kSearchRemappings), incoming, state);
727   }
728 
729   if (!rewritten && (incoming.flags & ui::EF_ALT_DOWN)) {
730     static const KeyboardRemapping kNonSearchRemappings[] = {
731         {  // Alt+BackSpace -> Delete
732          ui::VKEY_BACK, ui::EF_ALT_DOWN, ui::VKEY_DELETE, 0},
733         {  // Control+Alt+Up -> Home
734          ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, ui::VKEY_HOME, 0},
735         {  // Alt+Up -> Prior (aka PageUp)
736          ui::VKEY_UP, ui::EF_ALT_DOWN, ui::VKEY_PRIOR, 0},
737         {  // Control+Alt+Down -> End
738          ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, ui::VKEY_END, 0},
739         {  // Alt+Down -> Next (aka PageDown)
740          ui::VKEY_DOWN, ui::EF_ALT_DOWN, ui::VKEY_NEXT, 0}};
741 
742     rewritten = RewriteWithKeyboardRemappingsByKeyCode(
743         kNonSearchRemappings, arraysize(kNonSearchRemappings), incoming, state);
744   }
745 }
746 
RewriteFunctionKeys(const ui::KeyEvent & key_event,MutableKeyState * state)747 void EventRewriter::RewriteFunctionKeys(const ui::KeyEvent& key_event,
748                                         MutableKeyState* state) {
749   CHECK(key_event.type() == ui::ET_KEY_PRESSED ||
750         key_event.type() == ui::ET_KEY_RELEASED);
751   MutableKeyState incoming = *state;
752   bool rewritten = false;
753 
754   if ((incoming.key_code >= ui::VKEY_F1) &&
755       (incoming.key_code <= ui::VKEY_F24)) {
756     // By default the top row (F1-F12) keys are system keys for back, forward,
757     // brightness, volume, etc. However, windows for v2 apps can optionally
758     // request raw function keys for these keys.
759     bool top_row_keys_are_function_keys = TopRowKeysAreFunctionKeys(key_event);
760     bool search_is_pressed = (incoming.flags & ui::EF_COMMAND_DOWN) != 0;
761 
762     //  Search? Top Row   Result
763     //  ------- --------  ------
764     //  No      Fn        Unchanged
765     //  No      System    Fn -> System
766     //  Yes     Fn        Fn -> System
767     //  Yes     System    Search+Fn -> Fn
768     if (top_row_keys_are_function_keys == search_is_pressed) {
769       // Rewrite the F1-F12 keys on a Chromebook keyboard to system keys.
770       static const KeyboardRemapping kFkeysToSystemKeys[] = {
771           {ui::VKEY_F1, 0, ui::VKEY_BROWSER_BACK, 0},
772           {ui::VKEY_F2, 0, ui::VKEY_BROWSER_FORWARD, 0},
773           {ui::VKEY_F3, 0, ui::VKEY_BROWSER_REFRESH, 0},
774           {ui::VKEY_F4, 0, ui::VKEY_MEDIA_LAUNCH_APP2, 0},
775           {ui::VKEY_F5, 0, ui::VKEY_MEDIA_LAUNCH_APP1, 0},
776           {ui::VKEY_F6, 0, ui::VKEY_BRIGHTNESS_DOWN, 0},
777           {ui::VKEY_F7, 0, ui::VKEY_BRIGHTNESS_UP, 0},
778           {ui::VKEY_F8, 0, ui::VKEY_VOLUME_MUTE, 0},
779           {ui::VKEY_F9, 0, ui::VKEY_VOLUME_DOWN, 0},
780           {ui::VKEY_F10, 0, ui::VKEY_VOLUME_UP, 0},
781       };
782       MutableKeyState incoming_without_command = incoming;
783       incoming_without_command.flags &= ~ui::EF_COMMAND_DOWN;
784       rewritten =
785           RewriteWithKeyboardRemappingsByKeyCode(kFkeysToSystemKeys,
786                                                  arraysize(kFkeysToSystemKeys),
787                                                  incoming_without_command,
788                                                  state);
789     } else if (search_is_pressed) {
790       // Allow Search to avoid rewriting F1-F12.
791       state->flags &= ~ui::EF_COMMAND_DOWN;
792       rewritten = true;
793     }
794   }
795 
796   if (!rewritten && (incoming.flags & ui::EF_COMMAND_DOWN)) {
797     // Remap Search+<number> to F<number>.
798     // We check the keycode here instead of the keysym, as these keys have
799     // different keysyms when modifiers are pressed, such as shift.
800 
801     // TODO(danakj): On some i18n keyboards, these choices will be bad and we
802     // should make layout-specific choices here. For eg. on a french keyboard
803     // "-" and "6" are the same key, so F11 will not be accessible.
804     static const KeyboardRemapping kNumberKeysToFkeys[] = {
805         {ui::VKEY_1, ui::EF_COMMAND_DOWN, ui::VKEY_F1, 0},
806         {ui::VKEY_2, ui::EF_COMMAND_DOWN, ui::VKEY_F2, 0},
807         {ui::VKEY_3, ui::EF_COMMAND_DOWN, ui::VKEY_F3, 0},
808         {ui::VKEY_4, ui::EF_COMMAND_DOWN, ui::VKEY_F4, 0},
809         {ui::VKEY_5, ui::EF_COMMAND_DOWN, ui::VKEY_F5, 0},
810         {ui::VKEY_6, ui::EF_COMMAND_DOWN, ui::VKEY_F6, 0},
811         {ui::VKEY_7, ui::EF_COMMAND_DOWN, ui::VKEY_F7, 0},
812         {ui::VKEY_8, ui::EF_COMMAND_DOWN, ui::VKEY_F8, 0},
813         {ui::VKEY_9, ui::EF_COMMAND_DOWN, ui::VKEY_F9, 0},
814         {ui::VKEY_0, ui::EF_COMMAND_DOWN, ui::VKEY_F10, 0},
815         {ui::VKEY_OEM_MINUS, ui::EF_COMMAND_DOWN, ui::VKEY_F11, 0},
816         {ui::VKEY_OEM_PLUS, ui::EF_COMMAND_DOWN, ui::VKEY_F12, 0}};
817     rewritten = RewriteWithKeyboardRemappingsByKeyCode(
818         kNumberKeysToFkeys, arraysize(kNumberKeysToFkeys), incoming, state);
819   }
820 }
821 
RewriteLocatedEvent(const ui::Event & event,int * flags)822 void EventRewriter::RewriteLocatedEvent(const ui::Event& event,
823                                         int* flags) {
824   const PrefService* pref_service = GetPrefService();
825   if (!pref_service)
826     return;
827   *flags = GetRemappedModifierMasks(*pref_service, event, *flags);
828 }
829 
RewriteModifierClick(const ui::MouseEvent & mouse_event,int * flags)830 int EventRewriter::RewriteModifierClick(const ui::MouseEvent& mouse_event,
831                                         int* flags) {
832   // Remap Alt+Button1 to Button3.
833   const int kAltLeftButton = (ui::EF_ALT_DOWN | ui::EF_LEFT_MOUSE_BUTTON);
834   if (((*flags & kAltLeftButton) == kAltLeftButton) &&
835       ((mouse_event.type() == ui::ET_MOUSE_PRESSED) ||
836        pressed_device_ids_.count(mouse_event.source_device_id()))) {
837     *flags &= ~kAltLeftButton;
838     *flags |= ui::EF_RIGHT_MOUSE_BUTTON;
839     if (mouse_event.type() == ui::ET_MOUSE_PRESSED)
840       pressed_device_ids_.insert(mouse_event.source_device_id());
841     else
842       pressed_device_ids_.erase(mouse_event.source_device_id());
843     return ui::EF_RIGHT_MOUSE_BUTTON;
844   }
845   return ui::EF_NONE;
846 }
847 
KeyboardDeviceAddedInternal(int device_id,const std::string & device_name)848 EventRewriter::DeviceType EventRewriter::KeyboardDeviceAddedInternal(
849     int device_id,
850     const std::string& device_name) {
851   const DeviceType type = GetDeviceType(device_name);
852   if (type == kDeviceAppleKeyboard) {
853     VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
854             << "id=" << device_id;
855   }
856   // Always overwrite the existing device_id since the X server may reuse a
857   // device id for an unattached device.
858   device_id_to_type_[device_id] = type;
859   return type;
860 }
861 
KeyboardDeviceAdded(int device_id)862 void EventRewriter::KeyboardDeviceAdded(int device_id) {
863 #if defined(USE_X11)
864   DCHECK_NE(XIAllDevices, device_id);
865   DCHECK_NE(XIAllMasterDevices, device_id);
866   if (device_id == XIAllDevices || device_id == XIAllMasterDevices) {
867     LOG(ERROR) << "Unexpected device_id passed: " << device_id;
868     return;
869   }
870 
871   int ndevices_return = 0;
872   XIDeviceInfo* device_info =
873       XIQueryDevice(gfx::GetXDisplay(), device_id, &ndevices_return);
874 
875   // Since |device_id| is neither XIAllDevices nor XIAllMasterDevices,
876   // the number of devices found should be either 0 (not found) or 1.
877   if (!device_info) {
878     LOG(ERROR) << "XIQueryDevice: Device ID " << device_id << " is unknown.";
879     return;
880   }
881 
882   DCHECK_EQ(1, ndevices_return);
883   for (int i = 0; i < ndevices_return; ++i) {
884     DCHECK_EQ(device_id, device_info[i].deviceid);  // see the comment above.
885     DCHECK(device_info[i].name);
886     KeyboardDeviceAddedInternal(device_info[i].deviceid, device_info[i].name);
887   }
888 
889   XIFreeDeviceInfo(device_info);
890 #else
891   KeyboardDeviceAddedInternal(device_id, "keyboard");
892 #endif
893 }
894 
895 }  // namespace chromeos
896