[Android] Allow multiple --install in bb_device_steps.py.
[chromium-blink-merge.git] / chrome / browser / chromeos / events / event_rewriter.cc
blob75d97c43990edcdb603011077cd0ef385e1ae138
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.
5 #include "chrome/browser/chromeos/events/event_rewriter.h"
7 #include <vector>
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 "components/user_manager/user_manager.h"
24 #include "ui/base/ime/chromeos/ime_keyboard.h"
25 #include "ui/base/ime/chromeos/input_method_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"
31 #if defined(USE_X11)
32 #include <X11/extensions/XInput2.h>
33 #include <X11/Xatom.h>
34 #include <X11/Xlib.h>
36 #ifndef XI_PROP_PRODUCT_ID
37 #define XI_PROP_PRODUCT_ID "Device Product ID"
38 #endif
40 // Get rid of macros from Xlib.h that conflicts with other parts of the code.
41 #undef RootWindow
42 #undef Status
44 #include "ui/base/x/x11_util.h"
45 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
46 #endif
48 namespace chromeos {
50 namespace {
52 // Hotrod controller vendor/product ids.
53 const int kHotrodRemoteVendorId = 0x0471;
54 const int kHotrodRemoteProductId = 0x21cc;
55 const int kUnknownVendorId = -1;
56 const int kUnknownProductId = -1;
58 // Table of key properties of remappable keys and/or remapping targets.
59 // This is searched in two distinct ways:
60 // - |remap_to| is an |input_method::ModifierKey|, which is the form
61 // held in user preferences. |GetRemappedKey()| maps this to the
62 // corresponding |key_code| and characterstic event |flag|.
63 // - |flag| is a |ui::EventFlags|. |GetRemappedModifierMasks()| maps this
64 // to the corresponding user preference |pref_name| for that flag's
65 // key, so that it can then be remapped as above.
66 // In addition |kModifierRemappingCtrl| is a direct reference to the
67 // Control key entry in the table, used in handling Chromebook Diamond
68 // and Apple Command keys.
69 const struct ModifierRemapping {
70 int remap_to;
71 int flag;
72 ui::KeyboardCode key_code;
73 const char* pref_name;
74 } kModifierRemappings[] = {
75 {input_method::kSearchKey, ui::EF_COMMAND_DOWN, ui::VKEY_LWIN,
76 prefs::kLanguageRemapSearchKeyTo},
77 {input_method::kControlKey, ui::EF_CONTROL_DOWN, ui::VKEY_CONTROL,
78 prefs::kLanguageRemapControlKeyTo},
79 {input_method::kAltKey, ui::EF_ALT_DOWN, ui::VKEY_MENU,
80 prefs::kLanguageRemapAltKeyTo},
81 {input_method::kVoidKey, 0, ui::VKEY_UNKNOWN, NULL},
82 {input_method::kCapsLockKey, ui::EF_MOD3_DOWN, ui::VKEY_CAPITAL,
83 prefs::kLanguageRemapCapsLockKeyTo},
84 {input_method::kEscapeKey, 0, ui::VKEY_ESCAPE, NULL},
85 {0, 0, ui::VKEY_F15, prefs::kLanguageRemapDiamondKeyTo},
88 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1];
90 // Gets a remapped key for |pref_name| key. For example, to find out which
91 // key Search is currently remapped to, call the function with
92 // prefs::kLanguageRemapSearchKeyTo.
93 const ModifierRemapping* GetRemappedKey(const std::string& pref_name,
94 const PrefService& pref_service) {
95 if (!pref_service.FindPreference(pref_name.c_str()))
96 return NULL; // The |pref_name| hasn't been registered. On login screen?
97 const int value = pref_service.GetInteger(pref_name.c_str());
98 for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
99 if (value == kModifierRemappings[i].remap_to)
100 return &kModifierRemappings[i];
102 return NULL;
105 bool HasDiamondKey() {
106 return CommandLine::ForCurrentProcess()->HasSwitch(
107 chromeos::switches::kHasChromeOSDiamondKey);
110 bool IsISOLevel5ShiftUsedByCurrentInputMethod() {
111 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
112 // it's not possible to make both features work. For now, we don't remap
113 // Mod3Mask when Neo2 is in use.
114 // TODO(yusukes): Remove the restriction.
115 input_method::InputMethodManager* manager =
116 input_method::InputMethodManager::Get();
117 return manager->IsISOLevel5ShiftUsedByCurrentInputMethod();
120 bool IsExtensionCommandRegistered(ui::KeyboardCode key_code, int flags) {
121 // Some keyboard events for ChromeOS get rewritten, such as:
122 // Search+Shift+Left gets converted to Shift+Home (BeginDocument).
123 // This doesn't make sense if the user has assigned that shortcut
124 // to an extension. Because:
125 // 1) The extension would, upon seeing a request for Ctrl+Shift+Home have
126 // to register for Shift+Home, instead.
127 // 2) The conversion is unnecessary, because Shift+Home (BeginDocument) isn't
128 // going to be executed.
129 // Therefore, we skip converting the accelerator if an extension has
130 // registered for this shortcut.
131 Profile* profile = ProfileManager::GetActiveUserProfile();
132 if (!profile || !extensions::ExtensionCommandsGlobalRegistry::Get(profile))
133 return false;
135 int modifiers = flags & (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
136 ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
137 ui::Accelerator accelerator(key_code, modifiers);
138 return extensions::ExtensionCommandsGlobalRegistry::Get(profile)
139 ->IsRegistered(accelerator);
142 EventRewriter::DeviceType GetDeviceType(const std::string& device_name,
143 int vendor_id,
144 int product_id) {
145 if (vendor_id == kHotrodRemoteVendorId &&
146 product_id == kHotrodRemoteProductId) {
147 return EventRewriter::kDeviceHotrodRemote;
150 if (LowerCaseEqualsASCII(device_name, "virtual core keyboard"))
151 return EventRewriter::kDeviceVirtualCoreKeyboard;
153 std::vector<std::string> tokens;
154 Tokenize(device_name, " .", &tokens);
157 // If the |device_name| contains the two words, "apple" and "keyboard", treat
158 // it as an Apple keyboard.
159 bool found_apple = false;
160 bool found_keyboard = false;
161 for (size_t i = 0; i < tokens.size(); ++i) {
162 if (!found_apple && LowerCaseEqualsASCII(tokens[i], "apple"))
163 found_apple = true;
164 if (!found_keyboard && LowerCaseEqualsASCII(tokens[i], "keyboard"))
165 found_keyboard = true;
166 if (found_apple && found_keyboard)
167 return EventRewriter::kDeviceAppleKeyboard;
170 return EventRewriter::kDeviceUnknown;
173 } // namespace
175 EventRewriter::EventRewriter(ash::StickyKeysController* sticky_keys_controller)
176 : last_keyboard_device_id_(ui::ED_UNKNOWN_DEVICE),
177 ime_keyboard_for_testing_(NULL),
178 pref_service_for_testing_(NULL),
179 sticky_keys_controller_(sticky_keys_controller),
180 current_diamond_key_modifier_flags_(ui::EF_NONE) {
183 EventRewriter::~EventRewriter() {
186 EventRewriter::DeviceType EventRewriter::KeyboardDeviceAddedForTesting(
187 int device_id,
188 const std::string& device_name) {
189 // Tests must avoid XI2 reserved device IDs.
190 DCHECK((device_id < 0) || (device_id > 1));
191 return KeyboardDeviceAddedInternal(device_id,
192 device_name,
193 kUnknownVendorId,
194 kUnknownProductId);
197 void EventRewriter::RewriteMouseButtonEventForTesting(
198 const ui::MouseEvent& event,
199 scoped_ptr<ui::Event>* rewritten_event) {
200 RewriteMouseButtonEvent(event, rewritten_event);
203 ui::EventRewriteStatus EventRewriter::RewriteEvent(
204 const ui::Event& event,
205 scoped_ptr<ui::Event>* rewritten_event) {
206 if ((event.type() == ui::ET_KEY_PRESSED) ||
207 (event.type() == ui::ET_KEY_RELEASED)) {
208 return RewriteKeyEvent(static_cast<const ui::KeyEvent&>(event),
209 rewritten_event);
211 if ((event.type() == ui::ET_MOUSE_PRESSED) ||
212 (event.type() == ui::ET_MOUSE_RELEASED)) {
213 return RewriteMouseButtonEvent(static_cast<const ui::MouseEvent&>(event),
214 rewritten_event);
216 if (event.type() == ui::ET_MOUSEWHEEL) {
217 return RewriteMouseWheelEvent(
218 static_cast<const ui::MouseWheelEvent&>(event), rewritten_event);
220 if ((event.type() == ui::ET_TOUCH_PRESSED) ||
221 (event.type() == ui::ET_TOUCH_RELEASED)) {
222 return RewriteTouchEvent(static_cast<const ui::TouchEvent&>(event),
223 rewritten_event);
225 if (event.IsScrollEvent()) {
226 return RewriteScrollEvent(static_cast<const ui::ScrollEvent&>(event),
227 rewritten_event);
229 return ui::EVENT_REWRITE_CONTINUE;
232 ui::EventRewriteStatus EventRewriter::NextDispatchEvent(
233 const ui::Event& last_event,
234 scoped_ptr<ui::Event>* new_event) {
235 if (sticky_keys_controller_) {
236 // In the case of sticky keys, we know what the events obtained here are:
237 // modifier key releases that match the ones previously discarded. So, we
238 // know that they don't have to be passed through the post-sticky key
239 // rewriting phases, |RewriteExtendedKeys()| and |RewriteFunctionKeys()|,
240 // because those phases do nothing with modifier key releases.
241 return sticky_keys_controller_->NextDispatchEvent(new_event);
243 NOTREACHED();
244 return ui::EVENT_REWRITE_CONTINUE;
247 void EventRewriter::BuildRewrittenKeyEvent(
248 const ui::KeyEvent& key_event,
249 ui::KeyboardCode key_code,
250 int flags,
251 scoped_ptr<ui::Event>* rewritten_event) {
252 ui::KeyEvent* rewritten_key_event = NULL;
253 #if defined(USE_X11)
254 XEvent* xev = key_event.native_event();
255 if (xev) {
256 XEvent xkeyevent;
257 // Convert all XI2-based key events into X11 core-based key events,
258 // until consumers no longer depend on receiving X11 core events.
259 if (xev->type == GenericEvent)
260 ui::InitXKeyEventFromXIDeviceEvent(*xev, &xkeyevent);
261 else
262 xkeyevent.xkey = xev->xkey;
264 unsigned int original_x11_keycode = xkeyevent.xkey.keycode;
265 // Update native event to match rewritten |ui::Event|.
266 // The X11 keycode represents a physical key position, so it shouldn't
267 // change unless we have actually changed keys, not just modifiers.
268 // This is one guard against problems like crbug.com/390263.
269 if (key_event.key_code() != key_code) {
270 xkeyevent.xkey.keycode =
271 XKeyCodeForWindowsKeyCode(key_code, flags, gfx::GetXDisplay());
273 ui::KeyEvent x11_key_event(&xkeyevent);
274 rewritten_key_event = new ui::KeyEvent(x11_key_event);
276 // For numpad keys, the key char should always NOT be changed because
277 // XKeyCodeForWindowsKeyCode method cannot handle non-US keyboard layout.
278 // The correct key char can be got from original X11 keycode but not for the
279 // rewritten X11 keycode.
280 // For Shift+NumpadKey cases, use the rewritten X11 keycode (US layout).
281 // Please see crbug.com/335644.
282 if (key_code >= ui::VKEY_NUMPAD0 && key_code <= ui::VKEY_DIVIDE) {
283 XEvent numpad_xevent;
284 numpad_xevent.xkey = xkeyevent.xkey;
285 // Remove the shift state before getting key char.
286 // Because X11/XKB sometimes returns unexpected key char for
287 // Shift+NumpadKey. e.g. Shift+Numpad_4 returns 'D', etc.
288 numpad_xevent.xkey.state &= ~ShiftMask;
289 numpad_xevent.xkey.state |= Mod2Mask; // Always set NumLock mask.
290 if (!(flags & ui::EF_SHIFT_DOWN))
291 numpad_xevent.xkey.keycode = original_x11_keycode;
292 rewritten_key_event->set_character(
293 ui::GetCharacterFromXEvent(&numpad_xevent));
296 #endif
297 if (!rewritten_key_event)
298 rewritten_key_event = new ui::KeyEvent(key_event);
299 rewritten_key_event->set_flags(flags);
300 rewritten_key_event->set_key_code(key_code);
301 #if defined(USE_X11)
302 ui::UpdateX11EventForFlags(rewritten_key_event);
303 rewritten_key_event->NormalizeFlags();
304 #endif
305 rewritten_event->reset(rewritten_key_event);
308 void EventRewriter::DeviceKeyPressedOrReleased(int device_id) {
309 std::map<int, DeviceType>::const_iterator iter =
310 device_id_to_type_.find(device_id);
311 DeviceType type;
312 if (iter != device_id_to_type_.end())
313 type = iter->second;
314 else
315 type = KeyboardDeviceAdded(device_id);
317 // Ignore virtual Xorg keyboard (magic that generates key repeat
318 // events). Pretend that the previous real keyboard is the one that is still
319 // in use.
320 if (type == kDeviceVirtualCoreKeyboard)
321 return;
323 last_keyboard_device_id_ = device_id;
326 const PrefService* EventRewriter::GetPrefService() const {
327 if (pref_service_for_testing_)
328 return pref_service_for_testing_;
329 Profile* profile = ProfileManager::GetActiveUserProfile();
330 return profile ? profile->GetPrefs() : NULL;
333 bool EventRewriter::IsAppleKeyboard() const {
334 return IsLastKeyboardOfType(kDeviceAppleKeyboard);
337 bool EventRewriter::IsHotrodRemote() const {
338 return IsLastKeyboardOfType(kDeviceHotrodRemote);
341 bool EventRewriter::IsLastKeyboardOfType(DeviceType device_type) const {
342 if (last_keyboard_device_id_ == ui::ED_UNKNOWN_DEVICE)
343 return false;
345 // Check which device generated |event|.
346 std::map<int, DeviceType>::const_iterator iter =
347 device_id_to_type_.find(last_keyboard_device_id_);
348 if (iter == device_id_to_type_.end()) {
349 LOG(ERROR) << "Device ID " << last_keyboard_device_id_ << " is unknown.";
350 return false;
353 const DeviceType type = iter->second;
354 return type == device_type;
357 bool EventRewriter::TopRowKeysAreFunctionKeys(const ui::KeyEvent& event) const {
358 const PrefService* prefs = GetPrefService();
359 if (prefs && prefs->FindPreference(prefs::kLanguageSendFunctionKeys) &&
360 prefs->GetBoolean(prefs::kLanguageSendFunctionKeys))
361 return true;
363 ash::wm::WindowState* state = ash::wm::GetActiveWindowState();
364 return state ? state->top_row_keys_are_function_keys() : false;
367 int EventRewriter::GetRemappedModifierMasks(const PrefService& pref_service,
368 const ui::Event& event,
369 int original_flags) const {
370 int unmodified_flags = original_flags;
371 int rewritten_flags = current_diamond_key_modifier_flags_;
372 for (size_t i = 0; unmodified_flags && (i < arraysize(kModifierRemappings));
373 ++i) {
374 const ModifierRemapping* remapped_key = NULL;
375 if (!(unmodified_flags & kModifierRemappings[i].flag))
376 continue;
377 switch (kModifierRemappings[i].flag) {
378 case ui::EF_COMMAND_DOWN:
379 // Rewrite Command key presses on an Apple keyboard to Control.
380 if (IsAppleKeyboard()) {
381 DCHECK_EQ(ui::EF_CONTROL_DOWN, kModifierRemappingCtrl->flag);
382 remapped_key = kModifierRemappingCtrl;
384 break;
385 case ui::EF_MOD3_DOWN:
386 // If EF_MOD3_DOWN is used by the current input method, leave it alone;
387 // it is not remappable.
388 if (IsISOLevel5ShiftUsedByCurrentInputMethod())
389 continue;
390 // Otherwise, Mod3Mask is set on X events when the Caps Lock key
391 // is down, but, if Caps Lock is remapped, CapsLock is NOT set,
392 // because pressing the key does not invoke caps lock. So, the
393 // kModifierRemappings[] table uses EF_MOD3_DOWN for the Caps
394 // Lock remapping.
395 break;
396 default:
397 break;
399 if (!remapped_key && kModifierRemappings[i].pref_name) {
400 remapped_key =
401 GetRemappedKey(kModifierRemappings[i].pref_name, pref_service);
403 if (remapped_key) {
404 unmodified_flags &= ~kModifierRemappings[i].flag;
405 rewritten_flags |= remapped_key->flag;
408 return rewritten_flags | unmodified_flags;
411 bool EventRewriter::RewriteWithKeyboardRemappingsByKeyCode(
412 const KeyboardRemapping* remappings,
413 size_t num_remappings,
414 const MutableKeyState& input,
415 MutableKeyState* remapped_state) {
416 for (size_t i = 0; i < num_remappings; ++i) {
417 const KeyboardRemapping& map = remappings[i];
418 if (input.key_code != map.input_key_code)
419 continue;
420 if ((input.flags & map.input_flags) != map.input_flags)
421 continue;
422 remapped_state->key_code = map.output_key_code;
423 remapped_state->flags = (input.flags & ~map.input_flags) | map.output_flags;
424 return true;
426 return false;
429 ui::EventRewriteStatus EventRewriter::RewriteKeyEvent(
430 const ui::KeyEvent& key_event,
431 scoped_ptr<ui::Event>* rewritten_event) {
432 if (IsExtensionCommandRegistered(key_event.key_code(), key_event.flags()))
433 return ui::EVENT_REWRITE_CONTINUE;
434 if (key_event.source_device_id() != ui::ED_UNKNOWN_DEVICE)
435 DeviceKeyPressedOrReleased(key_event.source_device_id());
437 // Drop repeated keys from Hotrod remote.
438 if ((key_event.flags() & ui::EF_IS_REPEAT) &&
439 (key_event.type() == ui::ET_KEY_PRESSED) &&
440 IsHotrodRemote() && key_event.key_code() != ui::VKEY_BACK) {
441 return ui::EVENT_REWRITE_DISCARD;
444 MutableKeyState state = {key_event.flags(), key_event.key_code()};
445 // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
446 // crbug.com/136465.
447 if (!(key_event.flags() & ui::EF_FINAL)) {
448 RewriteModifierKeys(key_event, &state);
449 RewriteNumPadKeys(key_event, &state);
452 ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
453 bool is_sticky_key_extension_command = false;
454 if (sticky_keys_controller_) {
455 status = sticky_keys_controller_->RewriteKeyEvent(
456 key_event, state.key_code, &state.flags);
457 if (status == ui::EVENT_REWRITE_DISCARD)
458 return ui::EVENT_REWRITE_DISCARD;
459 is_sticky_key_extension_command =
460 IsExtensionCommandRegistered(state.key_code, state.flags);
463 // If sticky key rewrites the event, and it matches an extension command, do
464 // not further rewrite the event since it won't match the extension command
465 // thereafter.
466 if (!is_sticky_key_extension_command && !(key_event.flags() & ui::EF_FINAL)) {
467 RewriteExtendedKeys(key_event, &state);
468 RewriteFunctionKeys(key_event, &state);
470 if ((key_event.flags() == state.flags) &&
471 (key_event.key_code() == state.key_code) &&
472 #if defined(USE_X11)
473 // TODO(kpschoedel): This test is present because several consumers of
474 // key events depend on having a native core X11 event, so we rewrite
475 // all XI2 key events (GenericEvent) into corresponding core X11 key
476 // events. Remove this when event consumers no longer care about
477 // native X11 event details (crbug.com/380349).
478 (!key_event.HasNativeEvent() ||
479 (key_event.native_event()->type != GenericEvent)) &&
480 #endif
481 (status == ui::EVENT_REWRITE_CONTINUE)) {
482 return ui::EVENT_REWRITE_CONTINUE;
484 // Sticky keys may have returned a result other than |EVENT_REWRITE_CONTINUE|,
485 // in which case we need to preserve that return status. Alternatively, we
486 // might be here because key_event changed, in which case we need to
487 // return |EVENT_REWRITE_REWRITTEN|.
488 if (status == ui::EVENT_REWRITE_CONTINUE)
489 status = ui::EVENT_REWRITE_REWRITTEN;
490 BuildRewrittenKeyEvent(
491 key_event, state.key_code, state.flags, rewritten_event);
492 return status;
495 ui::EventRewriteStatus EventRewriter::RewriteMouseButtonEvent(
496 const ui::MouseEvent& mouse_event,
497 scoped_ptr<ui::Event>* rewritten_event) {
498 int flags = mouse_event.flags();
499 RewriteLocatedEvent(mouse_event, &flags);
500 ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
501 if (sticky_keys_controller_)
502 status = sticky_keys_controller_->RewriteMouseEvent(mouse_event, &flags);
503 int changed_button = ui::EF_NONE;
504 if ((mouse_event.type() == ui::ET_MOUSE_PRESSED) ||
505 (mouse_event.type() == ui::ET_MOUSE_RELEASED)) {
506 changed_button = RewriteModifierClick(mouse_event, &flags);
508 if ((mouse_event.flags() == flags) &&
509 (status == ui::EVENT_REWRITE_CONTINUE)) {
510 return ui::EVENT_REWRITE_CONTINUE;
512 if (status == ui::EVENT_REWRITE_CONTINUE)
513 status = ui::EVENT_REWRITE_REWRITTEN;
514 ui::MouseEvent* rewritten_mouse_event = new ui::MouseEvent(mouse_event);
515 rewritten_event->reset(rewritten_mouse_event);
516 rewritten_mouse_event->set_flags(flags);
517 #if defined(USE_X11)
518 ui::UpdateX11EventForFlags(rewritten_mouse_event);
519 #endif
520 if (changed_button != ui::EF_NONE) {
521 rewritten_mouse_event->set_changed_button_flags(changed_button);
522 #if defined(USE_X11)
523 ui::UpdateX11EventForChangedButtonFlags(rewritten_mouse_event);
524 #endif
526 return status;
529 ui::EventRewriteStatus EventRewriter::RewriteMouseWheelEvent(
530 const ui::MouseWheelEvent& wheel_event,
531 scoped_ptr<ui::Event>* rewritten_event) {
532 if (!sticky_keys_controller_)
533 return ui::EVENT_REWRITE_CONTINUE;
534 int flags = wheel_event.flags();
535 ui::EventRewriteStatus status =
536 sticky_keys_controller_->RewriteMouseEvent(wheel_event, &flags);
537 if ((wheel_event.flags() == flags) &&
538 (status == ui::EVENT_REWRITE_CONTINUE)) {
539 return ui::EVENT_REWRITE_CONTINUE;
541 if (status == ui::EVENT_REWRITE_CONTINUE)
542 status = ui::EVENT_REWRITE_REWRITTEN;
543 ui::MouseWheelEvent* rewritten_wheel_event =
544 new ui::MouseWheelEvent(wheel_event);
545 rewritten_event->reset(rewritten_wheel_event);
546 rewritten_wheel_event->set_flags(flags);
547 #if defined(USE_X11)
548 ui::UpdateX11EventForFlags(rewritten_wheel_event);
549 #endif
550 return status;
553 ui::EventRewriteStatus EventRewriter::RewriteTouchEvent(
554 const ui::TouchEvent& touch_event,
555 scoped_ptr<ui::Event>* rewritten_event) {
556 int flags = touch_event.flags();
557 RewriteLocatedEvent(touch_event, &flags);
558 if (touch_event.flags() == flags)
559 return ui::EVENT_REWRITE_CONTINUE;
560 ui::TouchEvent* rewritten_touch_event = new ui::TouchEvent(touch_event);
561 rewritten_event->reset(rewritten_touch_event);
562 rewritten_touch_event->set_flags(flags);
563 #if defined(USE_X11)
564 ui::UpdateX11EventForFlags(rewritten_touch_event);
565 #endif
566 return ui::EVENT_REWRITE_REWRITTEN;
569 ui::EventRewriteStatus EventRewriter::RewriteScrollEvent(
570 const ui::ScrollEvent& scroll_event,
571 scoped_ptr<ui::Event>* rewritten_event) {
572 int flags = scroll_event.flags();
573 ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
574 if (sticky_keys_controller_)
575 status = sticky_keys_controller_->RewriteScrollEvent(scroll_event, &flags);
576 if (status == ui::EVENT_REWRITE_CONTINUE)
577 return status;
578 ui::ScrollEvent* rewritten_scroll_event = new ui::ScrollEvent(scroll_event);
579 rewritten_event->reset(rewritten_scroll_event);
580 rewritten_scroll_event->set_flags(flags);
581 #if defined(USE_X11)
582 ui::UpdateX11EventForFlags(rewritten_scroll_event);
583 #endif
584 return status;
587 void EventRewriter::RewriteModifierKeys(const ui::KeyEvent& key_event,
588 MutableKeyState* state) {
589 DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
590 key_event.type() == ui::ET_KEY_RELEASED);
592 // Do nothing if we have just logged in as guest but have not restarted chrome
593 // process yet (so we are still on the login screen). In this situations we
594 // have no user profile so can not do anything useful.
595 // Note that currently, unlike other accounts, when user logs in as guest, we
596 // restart chrome process. In future this is to be changed.
597 // TODO(glotov): remove the following condition when we do not restart chrome
598 // when user logs in as guest.
599 // TODO(kpschoedel): check whether this is still necessary.
600 if (user_manager::UserManager::Get()->IsLoggedInAsGuest() &&
601 LoginDisplayHostImpl::default_host())
602 return;
604 const PrefService* pref_service = GetPrefService();
605 if (!pref_service)
606 return;
608 MutableKeyState incoming = *state;
609 state->flags = ui::EF_NONE;
610 int characteristic_flag = ui::EF_NONE;
612 // First, remap the key code.
613 const ModifierRemapping* remapped_key = NULL;
614 switch (incoming.key_code) {
615 // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent
616 // when Diamond key is pressed.
617 case ui::VKEY_F15:
618 // When diamond key is not available, the configuration UI for Diamond
619 // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo
620 // syncable pref.
621 if (HasDiamondKey())
622 remapped_key =
623 GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service);
624 // Default behavior of F15 is Control, even if --has-chromeos-diamond-key
625 // is absent, according to unit test comments.
626 if (!remapped_key) {
627 DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code);
628 remapped_key = kModifierRemappingCtrl;
630 // F15 is not a modifier key, so we need to track its state directly.
631 if (key_event.type() == ui::ET_KEY_PRESSED) {
632 int remapped_flag = remapped_key->flag;
633 if (remapped_key->remap_to == input_method::kCapsLockKey)
634 remapped_flag |= ui::EF_CAPS_LOCK_DOWN;
635 current_diamond_key_modifier_flags_ = remapped_flag;
636 } else {
637 current_diamond_key_modifier_flags_ = ui::EF_NONE;
639 break;
640 // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock
641 // is pressed (with one exception: when
642 // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates
643 // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7).
644 case ui::VKEY_F16:
645 characteristic_flag = ui::EF_CAPS_LOCK_DOWN;
646 remapped_key =
647 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service);
648 break;
649 case ui::VKEY_LWIN:
650 case ui::VKEY_RWIN:
651 characteristic_flag = ui::EF_COMMAND_DOWN;
652 // Rewrite Command-L/R key presses on an Apple keyboard to Control.
653 if (IsAppleKeyboard()) {
654 DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code);
655 remapped_key = kModifierRemappingCtrl;
656 } else {
657 remapped_key =
658 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service);
660 // Default behavior is Super key, hence don't remap the event if the pref
661 // is unavailable.
662 break;
663 case ui::VKEY_CONTROL:
664 characteristic_flag = ui::EF_CONTROL_DOWN;
665 remapped_key =
666 GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service);
667 break;
668 case ui::VKEY_MENU:
669 // ALT key
670 characteristic_flag = ui::EF_ALT_DOWN;
671 remapped_key =
672 GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service);
673 break;
674 default:
675 break;
678 if (remapped_key) {
679 state->key_code = remapped_key->key_code;
680 incoming.flags |= characteristic_flag;
681 characteristic_flag = remapped_key->flag;
684 // Next, remap modifier bits.
685 state->flags |=
686 GetRemappedModifierMasks(*pref_service, key_event, incoming.flags);
687 if (key_event.type() == ui::ET_KEY_PRESSED)
688 state->flags |= characteristic_flag;
689 else
690 state->flags &= ~characteristic_flag;
692 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if
693 // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external
694 // keyboard is pressed) since X can handle that case.
695 if (key_event.type() == ui::ET_KEY_PRESSED &&
696 incoming.key_code != ui::VKEY_CAPITAL &&
697 state->key_code == ui::VKEY_CAPITAL) {
698 chromeos::input_method::ImeKeyboard* ime_keyboard =
699 ime_keyboard_for_testing_
700 ? ime_keyboard_for_testing_
701 : chromeos::input_method::InputMethodManager::Get()
702 ->GetImeKeyboard();
703 ime_keyboard->SetCapsLockEnabled(!ime_keyboard->CapsLockIsEnabled());
707 void EventRewriter::RewriteNumPadKeys(const ui::KeyEvent& key_event,
708 MutableKeyState* state) {
709 DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
710 key_event.type() == ui::ET_KEY_RELEASED);
711 if (!(state->flags & ui::EF_NUMPAD_KEY))
712 return;
713 MutableKeyState incoming = *state;
715 static const KeyboardRemapping kNumPadRemappings[] = {
716 {ui::VKEY_INSERT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD0, ui::EF_NUMPAD_KEY},
717 {ui::VKEY_DELETE, ui::EF_NUMPAD_KEY, ui::VKEY_DECIMAL, ui::EF_NUMPAD_KEY},
718 {ui::VKEY_END, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD1, ui::EF_NUMPAD_KEY},
719 {ui::VKEY_DOWN, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD2, ui::EF_NUMPAD_KEY},
720 {ui::VKEY_NEXT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD3, ui::EF_NUMPAD_KEY},
721 {ui::VKEY_LEFT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD4, ui::EF_NUMPAD_KEY},
722 {ui::VKEY_CLEAR, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD5, ui::EF_NUMPAD_KEY},
723 {ui::VKEY_RIGHT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD6, ui::EF_NUMPAD_KEY},
724 {ui::VKEY_HOME, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD7, ui::EF_NUMPAD_KEY},
725 {ui::VKEY_UP, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD8, ui::EF_NUMPAD_KEY},
726 {ui::VKEY_PRIOR, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD9, ui::EF_NUMPAD_KEY},
729 RewriteWithKeyboardRemappingsByKeyCode(
730 kNumPadRemappings, arraysize(kNumPadRemappings), incoming, state);
733 void EventRewriter::RewriteExtendedKeys(const ui::KeyEvent& key_event,
734 MutableKeyState* state) {
735 DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
736 key_event.type() == ui::ET_KEY_RELEASED);
738 MutableKeyState incoming = *state;
739 bool rewritten = false;
741 if ((incoming.flags & (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) ==
742 (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) {
743 // Allow Search to avoid rewriting extended keys.
744 static const KeyboardRemapping kAvoidRemappings[] = {
745 { // Alt+Backspace
746 ui::VKEY_BACK, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, ui::VKEY_BACK,
747 ui::EF_ALT_DOWN,
749 { // Control+Alt+Up
750 ui::VKEY_UP,
751 ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN,
752 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
754 { // Alt+Up
755 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, ui::VKEY_UP,
756 ui::EF_ALT_DOWN,
758 { // Control+Alt+Down
759 ui::VKEY_DOWN,
760 ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN,
761 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
763 { // Alt+Down
764 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, ui::VKEY_DOWN,
765 ui::EF_ALT_DOWN,
768 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
769 kAvoidRemappings, arraysize(kAvoidRemappings), incoming, state);
772 if (!rewritten && (incoming.flags & ui::EF_COMMAND_DOWN)) {
773 static const KeyboardRemapping kSearchRemappings[] = {
774 { // Search+BackSpace -> Delete
775 ui::VKEY_BACK, ui::EF_COMMAND_DOWN, ui::VKEY_DELETE, 0},
776 { // Search+Left -> Home
777 ui::VKEY_LEFT, ui::EF_COMMAND_DOWN, ui::VKEY_HOME, 0},
778 { // Search+Up -> Prior (aka PageUp)
779 ui::VKEY_UP, ui::EF_COMMAND_DOWN, ui::VKEY_PRIOR, 0},
780 { // Search+Right -> End
781 ui::VKEY_RIGHT, ui::EF_COMMAND_DOWN, ui::VKEY_END, 0},
782 { // Search+Down -> Next (aka PageDown)
783 ui::VKEY_DOWN, ui::EF_COMMAND_DOWN, ui::VKEY_NEXT, 0},
784 { // Search+Period -> Insert
785 ui::VKEY_OEM_PERIOD, ui::EF_COMMAND_DOWN, ui::VKEY_INSERT, 0}};
787 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
788 kSearchRemappings, arraysize(kSearchRemappings), incoming, state);
791 if (!rewritten && (incoming.flags & ui::EF_ALT_DOWN)) {
792 static const KeyboardRemapping kNonSearchRemappings[] = {
793 { // Alt+BackSpace -> Delete
794 ui::VKEY_BACK, ui::EF_ALT_DOWN, ui::VKEY_DELETE, 0},
795 { // Control+Alt+Up -> Home
796 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, ui::VKEY_HOME, 0},
797 { // Alt+Up -> Prior (aka PageUp)
798 ui::VKEY_UP, ui::EF_ALT_DOWN, ui::VKEY_PRIOR, 0},
799 { // Control+Alt+Down -> End
800 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, ui::VKEY_END, 0},
801 { // Alt+Down -> Next (aka PageDown)
802 ui::VKEY_DOWN, ui::EF_ALT_DOWN, ui::VKEY_NEXT, 0}};
804 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
805 kNonSearchRemappings, arraysize(kNonSearchRemappings), incoming, state);
809 void EventRewriter::RewriteFunctionKeys(const ui::KeyEvent& key_event,
810 MutableKeyState* state) {
811 CHECK(key_event.type() == ui::ET_KEY_PRESSED ||
812 key_event.type() == ui::ET_KEY_RELEASED);
813 MutableKeyState incoming = *state;
814 bool rewritten = false;
816 if ((incoming.key_code >= ui::VKEY_F1) &&
817 (incoming.key_code <= ui::VKEY_F24)) {
818 // By default the top row (F1-F12) keys are system keys for back, forward,
819 // brightness, volume, etc. However, windows for v2 apps can optionally
820 // request raw function keys for these keys.
821 bool top_row_keys_are_function_keys = TopRowKeysAreFunctionKeys(key_event);
822 bool search_is_pressed = (incoming.flags & ui::EF_COMMAND_DOWN) != 0;
824 // Search? Top Row Result
825 // ------- -------- ------
826 // No Fn Unchanged
827 // No System Fn -> System
828 // Yes Fn Fn -> System
829 // Yes System Search+Fn -> Fn
830 if (top_row_keys_are_function_keys == search_is_pressed) {
831 // Rewrite the F1-F12 keys on a Chromebook keyboard to system keys.
832 static const KeyboardRemapping kFkeysToSystemKeys[] = {
833 {ui::VKEY_F1, 0, ui::VKEY_BROWSER_BACK, 0},
834 {ui::VKEY_F2, 0, ui::VKEY_BROWSER_FORWARD, 0},
835 {ui::VKEY_F3, 0, ui::VKEY_BROWSER_REFRESH, 0},
836 {ui::VKEY_F4, 0, ui::VKEY_MEDIA_LAUNCH_APP2, 0},
837 {ui::VKEY_F5, 0, ui::VKEY_MEDIA_LAUNCH_APP1, 0},
838 {ui::VKEY_F6, 0, ui::VKEY_BRIGHTNESS_DOWN, 0},
839 {ui::VKEY_F7, 0, ui::VKEY_BRIGHTNESS_UP, 0},
840 {ui::VKEY_F8, 0, ui::VKEY_VOLUME_MUTE, 0},
841 {ui::VKEY_F9, 0, ui::VKEY_VOLUME_DOWN, 0},
842 {ui::VKEY_F10, 0, ui::VKEY_VOLUME_UP, 0},
844 MutableKeyState incoming_without_command = incoming;
845 incoming_without_command.flags &= ~ui::EF_COMMAND_DOWN;
846 rewritten =
847 RewriteWithKeyboardRemappingsByKeyCode(kFkeysToSystemKeys,
848 arraysize(kFkeysToSystemKeys),
849 incoming_without_command,
850 state);
851 } else if (search_is_pressed) {
852 // Allow Search to avoid rewriting F1-F12.
853 state->flags &= ~ui::EF_COMMAND_DOWN;
854 rewritten = true;
858 if (!rewritten && (incoming.flags & ui::EF_COMMAND_DOWN)) {
859 // Remap Search+<number> to F<number>.
860 // We check the keycode here instead of the keysym, as these keys have
861 // different keysyms when modifiers are pressed, such as shift.
863 // TODO(danakj): On some i18n keyboards, these choices will be bad and we
864 // should make layout-specific choices here. For eg. on a french keyboard
865 // "-" and "6" are the same key, so F11 will not be accessible.
866 static const KeyboardRemapping kNumberKeysToFkeys[] = {
867 {ui::VKEY_1, ui::EF_COMMAND_DOWN, ui::VKEY_F1, 0},
868 {ui::VKEY_2, ui::EF_COMMAND_DOWN, ui::VKEY_F2, 0},
869 {ui::VKEY_3, ui::EF_COMMAND_DOWN, ui::VKEY_F3, 0},
870 {ui::VKEY_4, ui::EF_COMMAND_DOWN, ui::VKEY_F4, 0},
871 {ui::VKEY_5, ui::EF_COMMAND_DOWN, ui::VKEY_F5, 0},
872 {ui::VKEY_6, ui::EF_COMMAND_DOWN, ui::VKEY_F6, 0},
873 {ui::VKEY_7, ui::EF_COMMAND_DOWN, ui::VKEY_F7, 0},
874 {ui::VKEY_8, ui::EF_COMMAND_DOWN, ui::VKEY_F8, 0},
875 {ui::VKEY_9, ui::EF_COMMAND_DOWN, ui::VKEY_F9, 0},
876 {ui::VKEY_0, ui::EF_COMMAND_DOWN, ui::VKEY_F10, 0},
877 {ui::VKEY_OEM_MINUS, ui::EF_COMMAND_DOWN, ui::VKEY_F11, 0},
878 {ui::VKEY_OEM_PLUS, ui::EF_COMMAND_DOWN, ui::VKEY_F12, 0}};
879 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
880 kNumberKeysToFkeys, arraysize(kNumberKeysToFkeys), incoming, state);
884 void EventRewriter::RewriteLocatedEvent(const ui::Event& event,
885 int* flags) {
886 const PrefService* pref_service = GetPrefService();
887 if (!pref_service)
888 return;
889 *flags = GetRemappedModifierMasks(*pref_service, event, *flags);
892 int EventRewriter::RewriteModifierClick(const ui::MouseEvent& mouse_event,
893 int* flags) {
894 // Remap Alt+Button1 to Button3.
895 const int kAltLeftButton = (ui::EF_ALT_DOWN | ui::EF_LEFT_MOUSE_BUTTON);
896 if (((*flags & kAltLeftButton) == kAltLeftButton) &&
897 ((mouse_event.type() == ui::ET_MOUSE_PRESSED) ||
898 pressed_device_ids_.count(mouse_event.source_device_id()))) {
899 *flags &= ~kAltLeftButton;
900 *flags |= ui::EF_RIGHT_MOUSE_BUTTON;
901 if (mouse_event.type() == ui::ET_MOUSE_PRESSED)
902 pressed_device_ids_.insert(mouse_event.source_device_id());
903 else
904 pressed_device_ids_.erase(mouse_event.source_device_id());
905 return ui::EF_RIGHT_MOUSE_BUTTON;
907 return ui::EF_NONE;
910 EventRewriter::DeviceType EventRewriter::KeyboardDeviceAddedInternal(
911 int device_id,
912 const std::string& device_name,
913 int vendor_id,
914 int product_id) {
915 const DeviceType type = GetDeviceType(device_name, vendor_id, product_id);
916 if (type == kDeviceAppleKeyboard) {
917 VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
918 << "id=" << device_id;
919 } else if (type == kDeviceHotrodRemote) {
920 VLOG(1) << "Hotrod remote '" << device_name << "' connected: "
921 << "id=" << device_id;
922 } else if (type == kDeviceVirtualCoreKeyboard) {
923 VLOG(1) << "Xorg virtual '" << device_name << "' connected: "
924 << "id=" << device_id;
925 } else {
926 VLOG(1) << "Unknown keyboard '" << device_name << "' connected: "
927 << "id=" << device_id;
929 // Always overwrite the existing device_id since the X server may reuse a
930 // device id for an unattached device.
931 device_id_to_type_[device_id] = type;
932 return type;
935 EventRewriter::DeviceType EventRewriter::KeyboardDeviceAdded(int device_id) {
936 #if defined(USE_X11)
937 DCHECK_NE(XIAllDevices, device_id);
938 DCHECK_NE(XIAllMasterDevices, device_id);
939 if (device_id == XIAllDevices || device_id == XIAllMasterDevices) {
940 LOG(ERROR) << "Unexpected device_id passed: " << device_id;
941 return kDeviceUnknown;
944 Atom product_id_atom =
945 XInternAtom(gfx::GetXDisplay(), XI_PROP_PRODUCT_ID, 1);
947 int ndevices_return = 0;
948 XIDeviceInfo* device_info =
949 XIQueryDevice(gfx::GetXDisplay(), device_id, &ndevices_return);
951 // Since |device_id| is neither XIAllDevices nor XIAllMasterDevices,
952 // the number of devices found should be either 0 (not found) or 1.
953 if (!device_info) {
954 LOG(ERROR) << "XIQueryDevice: Device ID " << device_id << " is unknown.";
955 return kDeviceUnknown;
958 DeviceType dev_type = kDeviceUnknown;
959 DCHECK_EQ(1, ndevices_return);
960 for (int i = 0; i < ndevices_return; ++i) {
961 // Get keyboard product and vendor id.
962 int vendor_id = kUnknownVendorId;
963 int product_id = kUnknownProductId;
964 uint32* product_info = NULL;
965 Atom type;
966 int format_return;
967 unsigned long num_items_return;
968 unsigned long bytes_after_return;
969 if (XIGetProperty(gfx::GetXDisplay(),
970 device_info[i].deviceid,
971 product_id_atom,
975 XA_INTEGER,
976 &type,
977 &format_return,
978 &num_items_return,
979 &bytes_after_return,
980 reinterpret_cast<unsigned char **>(&product_info)) == 0 &&
981 product_info) {
982 vendor_id = product_info[0];
983 product_id = product_info[1];
986 DCHECK_EQ(device_id, device_info[i].deviceid); // see the comment above.
987 DCHECK(device_info[i].name);
988 dev_type = KeyboardDeviceAddedInternal(device_info[i].deviceid,
989 device_info[i].name,
990 vendor_id,
991 product_id);
993 XIFreeDeviceInfo(device_info);
994 return dev_type;
995 #else
996 // TODO(spang): Figure out where we can get keyboard vendor/product id from in
997 // Ozone/Freon version.
998 return KeyboardDeviceAddedInternal(device_id,
999 "keyboard",
1000 kUnknownVendorId,
1001 kUnknownProductId);
1002 #endif
1005 } // namespace chromeos