Update broken references to image assets
[chromium-blink-merge.git] / chrome / browser / chromeos / events / event_rewriter.cc
blob69c2cfc5811c5c9743c6e51eef29fac2faf32298
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_split.h"
17 #include "base/strings/string_util.h"
18 #include "base/sys_info.h"
19 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
20 #include "chrome/browser/extensions/extension_commands_global_registry.h"
21 #include "chrome/browser/profiles/profile_manager.h"
22 #include "chrome/common/pref_names.h"
23 #include "chromeos/chromeos_switches.h"
24 #include "components/user_manager/user_manager.h"
25 #include "ui/base/ime/chromeos/ime_keyboard.h"
26 #include "ui/base/ime/chromeos/input_method_manager.h"
27 #include "ui/events/devices/device_data_manager.h"
28 #include "ui/events/event.h"
29 #include "ui/events/event_utils.h"
30 #include "ui/events/keycodes/dom/dom_code.h"
31 #include "ui/events/keycodes/dom/dom_key.h"
32 #include "ui/events/keycodes/dom/keycode_converter.h"
33 #include "ui/events/keycodes/keyboard_code_conversion.h"
34 #include "ui/wm/core/window_util.h"
36 #if defined(USE_X11)
37 #include <X11/extensions/XInput2.h>
38 #include <X11/Xlib.h>
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 properties of remappable keys and/or remapping targets.
60 // This is used in two distinct ways: for rewriting key up/down events,
61 // and for rewriting modifier EventFlags on any kind of event.
63 // For the first case, rewriting key up/down events, |RewriteModifierKeys()|
64 // determines the preference name |prefs::kLanguageRemap...KeyTo| for the
65 // incoming key and, using |GetRemappedKey()|, gets the user preference
66 // value |input_method::k...Key| for the incoming key, and finally finds that
67 // value in this table to obtain the |result| properties of the target key.
69 // For the second case, rewriting modifier EventFlags,
70 // |GetRemappedModifierMasks()| processes every table entry whose |flag|
71 // is set in the incoming event. Using the |pref_name| in the table entry,
72 // it likewise uses |GetRemappedKey()| to find the properties of the
73 // user preference target key, and replaces the flag accordingly.
74 const struct ModifierRemapping {
75 int flag;
76 int remap_to;
77 const char* pref_name;
78 EventRewriter::MutableKeyState result;
79 } kModifierRemappings[] = {
80 {// kModifierRemappingCtrl references this entry by index.
81 ui::EF_CONTROL_DOWN,
82 input_method::kControlKey,
83 prefs::kLanguageRemapControlKeyTo,
84 {ui::EF_CONTROL_DOWN,
85 ui::DomCode::CONTROL_LEFT,
86 ui::DomKey::CONTROL,
88 ui::VKEY_CONTROL}},
89 {// kModifierRemappingNeoMod3 references this entry by index.
90 ui::EF_MOD3_DOWN | ui::EF_ALTGR_DOWN,
91 input_method::kNumModifierKeys,
92 nullptr,
93 {ui::EF_MOD3_DOWN | ui::EF_ALTGR_DOWN,
94 ui::DomCode::CAPS_LOCK,
95 ui::DomKey::ALT_GRAPH,
97 ui::VKEY_ALTGR}},
98 {ui::EF_COMMAND_DOWN,
99 input_method::kSearchKey,
100 prefs::kLanguageRemapSearchKeyTo,
101 {ui::EF_COMMAND_DOWN,
102 ui::DomCode::OS_LEFT,
103 ui::DomKey::OS,
105 ui::VKEY_LWIN}},
106 {ui::EF_ALT_DOWN,
107 input_method::kAltKey,
108 prefs::kLanguageRemapAltKeyTo,
109 {ui::EF_ALT_DOWN,
110 ui::DomCode::ALT_LEFT,
111 ui::DomKey::ALT,
113 ui::VKEY_MENU}},
114 {ui::EF_NONE,
115 input_method::kVoidKey,
116 nullptr,
117 {ui::EF_NONE, ui::DomCode::NONE, ui::DomKey::NONE, 0, ui::VKEY_UNKNOWN}},
118 {ui::EF_MOD3_DOWN,
119 input_method::kCapsLockKey,
120 prefs::kLanguageRemapCapsLockKeyTo,
121 {ui::EF_MOD3_DOWN,
122 ui::DomCode::CAPS_LOCK,
123 ui::DomKey::CAPS_LOCK,
125 ui::VKEY_CAPITAL}},
126 {ui::EF_NONE,
127 input_method::kEscapeKey,
128 nullptr,
129 {ui::EF_NONE,
130 ui::DomCode::ESCAPE,
131 ui::DomKey::ESCAPE,
133 ui::VKEY_ESCAPE}},
134 {ui::EF_NONE,
135 input_method::kNumModifierKeys,
136 prefs::kLanguageRemapDiamondKeyTo,
137 {ui::EF_NONE, ui::DomCode::F15, ui::DomKey::F15, 0, ui::VKEY_F15}}};
139 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[0];
140 const ModifierRemapping* kModifierRemappingNeoMod3 = &kModifierRemappings[1];
142 // Gets a remapped key for |pref_name| key. For example, to find out which
143 // key Search is currently remapped to, call the function with
144 // prefs::kLanguageRemapSearchKeyTo.
145 const ModifierRemapping* GetRemappedKey(const std::string& pref_name,
146 const PrefService& pref_service) {
147 if (!pref_service.FindPreference(pref_name.c_str()))
148 return NULL; // The |pref_name| hasn't been registered. On login screen?
149 const int value = pref_service.GetInteger(pref_name.c_str());
150 for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
151 if (value == kModifierRemappings[i].remap_to)
152 return &kModifierRemappings[i];
154 return NULL;
157 bool HasDiamondKey() {
158 return base::CommandLine::ForCurrentProcess()->HasSwitch(
159 chromeos::switches::kHasChromeOSDiamondKey);
162 bool IsISOLevel5ShiftUsedByCurrentInputMethod() {
163 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
164 // it's not possible to make both features work. For now, we don't remap
165 // Mod3Mask when Neo2 is in use.
166 // TODO(yusukes): Remove the restriction.
167 input_method::InputMethodManager* manager =
168 input_method::InputMethodManager::Get();
169 return manager->IsISOLevel5ShiftUsedByCurrentInputMethod();
172 bool IsExtensionCommandRegistered(ui::KeyboardCode key_code, int flags) {
173 // Some keyboard events for ChromeOS get rewritten, such as:
174 // Search+Shift+Left gets converted to Shift+Home (BeginDocument).
175 // This doesn't make sense if the user has assigned that shortcut
176 // to an extension. Because:
177 // 1) The extension would, upon seeing a request for Ctrl+Shift+Home have
178 // to register for Shift+Home, instead.
179 // 2) The conversion is unnecessary, because Shift+Home (BeginDocument) isn't
180 // going to be executed.
181 // Therefore, we skip converting the accelerator if an extension has
182 // registered for this shortcut.
183 Profile* profile = ProfileManager::GetActiveUserProfile();
184 if (!profile || !extensions::ExtensionCommandsGlobalRegistry::Get(profile))
185 return false;
187 int modifiers = flags & (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
188 ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
189 ui::Accelerator accelerator(key_code, modifiers);
190 return extensions::ExtensionCommandsGlobalRegistry::Get(profile)
191 ->IsRegistered(accelerator);
194 EventRewriter::DeviceType GetDeviceType(const std::string& device_name,
195 int vendor_id,
196 int product_id) {
197 if (vendor_id == kHotrodRemoteVendorId &&
198 product_id == kHotrodRemoteProductId) {
199 return EventRewriter::kDeviceHotrodRemote;
202 if (base::LowerCaseEqualsASCII(device_name, "virtual core keyboard"))
203 return EventRewriter::kDeviceVirtualCoreKeyboard;
205 std::vector<std::string> tokens = base::SplitString(
206 device_name, " .", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
208 // If the |device_name| contains the two words, "apple" and "keyboard", treat
209 // it as an Apple keyboard.
210 bool found_apple = false;
211 bool found_keyboard = false;
212 for (size_t i = 0; i < tokens.size(); ++i) {
213 if (!found_apple && base::LowerCaseEqualsASCII(tokens[i], "apple"))
214 found_apple = true;
215 if (!found_keyboard && base::LowerCaseEqualsASCII(tokens[i], "keyboard"))
216 found_keyboard = true;
217 if (found_apple && found_keyboard)
218 return EventRewriter::kDeviceAppleKeyboard;
221 return EventRewriter::kDeviceUnknown;
224 struct KeyboardRemapping {
225 // MatchKeyboardRemapping() succeeds if the tested has all of the specified
226 // flags (and possibly other flags), and either the key_code matches or the
227 // condition's key_code is VKEY_UNKNOWN.
228 struct Condition {
229 int flags;
230 ui::KeyboardCode key_code;
231 } condition;
232 // ApplyRemapping(), which is the primary user of this structure,
233 // conditionally sets the output fields from the |result| here.
234 // - |dom_code| is set if |result.dom_code| is not NONE.
235 // - |dom_key| and |character| are set if |result.dom_key| is not NONE.
236 // -|key_code| is set if |result.key_code| is not VKEY_UNKNOWN.
237 // - |flags| are always set from |result.flags|, but this can be |EF_NONE|.
238 EventRewriter::MutableKeyState result;
241 bool MatchKeyboardRemapping(const EventRewriter::MutableKeyState& suspect,
242 const KeyboardRemapping::Condition& test) {
243 return ((test.key_code == ui::VKEY_UNKNOWN) ||
244 (test.key_code == suspect.key_code)) &&
245 ((suspect.flags & test.flags) == test.flags);
248 void ApplyRemapping(const EventRewriter::MutableKeyState& changes,
249 EventRewriter::MutableKeyState* state) {
250 state->flags |= changes.flags;
251 if (changes.code != ui::DomCode::NONE)
252 state->code = changes.code;
253 if (changes.key != ui::DomKey::NONE) {
254 state->key = changes.key;
255 state->character = changes.character;
257 if (changes.key_code != ui::VKEY_UNKNOWN)
258 state->key_code = changes.key_code;
261 // Given a set of KeyboardRemapping structs, finds a matching struct
262 // if possible, and updates the remapped event values. Returns true if a
263 // remapping was found and remapped values were updated.
264 bool RewriteWithKeyboardRemappings(
265 const KeyboardRemapping* mappings,
266 size_t num_mappings,
267 const EventRewriter::MutableKeyState& input_state,
268 EventRewriter::MutableKeyState* remapped_state) {
269 for (size_t i = 0; i < num_mappings; ++i) {
270 const KeyboardRemapping& map = mappings[i];
271 if (MatchKeyboardRemapping(input_state, map.condition)) {
272 remapped_state->flags = (input_state.flags & ~map.condition.flags);
273 ApplyRemapping(map.result, remapped_state);
274 return true;
277 return false;
280 void SetMeaningForLayout(ui::EventType type,
281 EventRewriter::MutableKeyState* state) {
282 // Currently layout is applied by creating a temporary key event with the
283 // current physical state, and extracting the layout results.
284 ui::KeyEvent key(type, state->key_code, state->code, state->flags);
285 state->key = key.GetDomKey();
286 state->character = key.GetCharacter();
289 ui::DomCode RelocateModifier(ui::DomCode code, ui::DomKeyLocation location) {
290 bool right = (location == ui::DomKeyLocation::RIGHT);
291 switch (code) {
292 case ui::DomCode::CONTROL_LEFT:
293 case ui::DomCode::CONTROL_RIGHT:
294 return right ? ui::DomCode::CONTROL_RIGHT : ui::DomCode::CONTROL_LEFT;
295 case ui::DomCode::SHIFT_LEFT:
296 case ui::DomCode::SHIFT_RIGHT:
297 return right ? ui::DomCode::SHIFT_RIGHT : ui::DomCode::SHIFT_LEFT;
298 case ui::DomCode::ALT_LEFT:
299 case ui::DomCode::ALT_RIGHT:
300 return right ? ui::DomCode::ALT_RIGHT : ui::DomCode::ALT_LEFT;
301 case ui::DomCode::OS_LEFT:
302 case ui::DomCode::OS_RIGHT:
303 return right ? ui::DomCode::OS_RIGHT : ui::DomCode::OS_LEFT;
304 default:
305 break;
307 return code;
310 } // namespace
312 EventRewriter::EventRewriter(ash::StickyKeysController* sticky_keys_controller)
313 : last_keyboard_device_id_(ui::ED_UNKNOWN_DEVICE),
314 ime_keyboard_for_testing_(NULL),
315 pref_service_for_testing_(NULL),
316 sticky_keys_controller_(sticky_keys_controller),
317 current_diamond_key_modifier_flags_(ui::EF_NONE),
318 pressed_modifier_latches_(ui::EF_NONE),
319 latched_modifier_latches_(ui::EF_NONE),
320 used_modifier_latches_(ui::EF_NONE) {}
322 EventRewriter::~EventRewriter() {
325 EventRewriter::DeviceType EventRewriter::KeyboardDeviceAddedForTesting(
326 int device_id,
327 const std::string& device_name) {
328 // Tests must avoid XI2 reserved device IDs.
329 DCHECK((device_id < 0) || (device_id > 1));
330 return KeyboardDeviceAddedInternal(device_id, device_name, kUnknownVendorId,
331 kUnknownProductId);
334 void EventRewriter::RewriteMouseButtonEventForTesting(
335 const ui::MouseEvent& event,
336 scoped_ptr<ui::Event>* rewritten_event) {
337 RewriteMouseButtonEvent(event, rewritten_event);
340 ui::EventRewriteStatus EventRewriter::RewriteEvent(
341 const ui::Event& event,
342 scoped_ptr<ui::Event>* rewritten_event) {
343 if ((event.type() == ui::ET_KEY_PRESSED) ||
344 (event.type() == ui::ET_KEY_RELEASED)) {
345 return RewriteKeyEvent(static_cast<const ui::KeyEvent&>(event),
346 rewritten_event);
348 if ((event.type() == ui::ET_MOUSE_PRESSED) ||
349 (event.type() == ui::ET_MOUSE_RELEASED)) {
350 return RewriteMouseButtonEvent(static_cast<const ui::MouseEvent&>(event),
351 rewritten_event);
353 if (event.type() == ui::ET_MOUSEWHEEL) {
354 return RewriteMouseWheelEvent(
355 static_cast<const ui::MouseWheelEvent&>(event), rewritten_event);
357 if ((event.type() == ui::ET_TOUCH_PRESSED) ||
358 (event.type() == ui::ET_TOUCH_RELEASED)) {
359 return RewriteTouchEvent(static_cast<const ui::TouchEvent&>(event),
360 rewritten_event);
362 if (event.IsScrollEvent()) {
363 return RewriteScrollEvent(static_cast<const ui::ScrollEvent&>(event),
364 rewritten_event);
366 return ui::EVENT_REWRITE_CONTINUE;
369 ui::EventRewriteStatus EventRewriter::NextDispatchEvent(
370 const ui::Event& last_event,
371 scoped_ptr<ui::Event>* new_event) {
372 if (sticky_keys_controller_) {
373 // In the case of sticky keys, we know what the events obtained here are:
374 // modifier key releases that match the ones previously discarded. So, we
375 // know that they don't have to be passed through the post-sticky key
376 // rewriting phases, |RewriteExtendedKeys()| and |RewriteFunctionKeys()|,
377 // because those phases do nothing with modifier key releases.
378 return sticky_keys_controller_->NextDispatchEvent(new_event);
380 NOTREACHED();
381 return ui::EVENT_REWRITE_CONTINUE;
384 void EventRewriter::BuildRewrittenKeyEvent(
385 const ui::KeyEvent& key_event,
386 const MutableKeyState& state,
387 scoped_ptr<ui::Event>* rewritten_event) {
388 ui::KeyEvent* rewritten_key_event = new ui::KeyEvent(
389 key_event.type(), state.key_code, state.code, state.flags, state.key,
390 state.character, key_event.time_stamp());
391 rewritten_event->reset(rewritten_key_event);
394 void EventRewriter::DeviceKeyPressedOrReleased(int device_id) {
395 std::map<int, DeviceType>::const_iterator iter =
396 device_id_to_type_.find(device_id);
397 DeviceType type;
398 if (iter != device_id_to_type_.end())
399 type = iter->second;
400 else
401 type = KeyboardDeviceAdded(device_id);
403 // Ignore virtual Xorg keyboard (magic that generates key repeat
404 // events). Pretend that the previous real keyboard is the one that is still
405 // in use.
406 if (type == kDeviceVirtualCoreKeyboard)
407 return;
409 last_keyboard_device_id_ = device_id;
412 const PrefService* EventRewriter::GetPrefService() const {
413 if (pref_service_for_testing_)
414 return pref_service_for_testing_;
415 Profile* profile = ProfileManager::GetActiveUserProfile();
416 return profile ? profile->GetPrefs() : NULL;
419 bool EventRewriter::IsAppleKeyboard() const {
420 return IsLastKeyboardOfType(kDeviceAppleKeyboard);
423 bool EventRewriter::IsHotrodRemote() const {
424 return IsLastKeyboardOfType(kDeviceHotrodRemote);
427 bool EventRewriter::IsLastKeyboardOfType(DeviceType device_type) const {
428 if (last_keyboard_device_id_ == ui::ED_UNKNOWN_DEVICE)
429 return false;
431 // Check which device generated |event|.
432 std::map<int, DeviceType>::const_iterator iter =
433 device_id_to_type_.find(last_keyboard_device_id_);
434 if (iter == device_id_to_type_.end()) {
435 LOG(ERROR) << "Device ID " << last_keyboard_device_id_ << " is unknown.";
436 return false;
439 const DeviceType type = iter->second;
440 return type == device_type;
443 bool EventRewriter::TopRowKeysAreFunctionKeys(const ui::KeyEvent& event) const {
444 const PrefService* prefs = GetPrefService();
445 if (prefs && prefs->FindPreference(prefs::kLanguageSendFunctionKeys) &&
446 prefs->GetBoolean(prefs::kLanguageSendFunctionKeys))
447 return true;
449 ash::wm::WindowState* state = ash::wm::GetActiveWindowState();
450 return state ? state->top_row_keys_are_function_keys() : false;
453 int EventRewriter::GetRemappedModifierMasks(const PrefService& pref_service,
454 const ui::Event& event,
455 int original_flags) const {
456 int unmodified_flags = original_flags;
457 int rewritten_flags = current_diamond_key_modifier_flags_ |
458 pressed_modifier_latches_ | latched_modifier_latches_;
459 for (size_t i = 0; unmodified_flags && (i < arraysize(kModifierRemappings));
460 ++i) {
461 const ModifierRemapping* remapped_key = NULL;
462 if (!(unmodified_flags & kModifierRemappings[i].flag))
463 continue;
464 switch (kModifierRemappings[i].flag) {
465 case ui::EF_COMMAND_DOWN:
466 // Rewrite Command key presses on an Apple keyboard to Control.
467 if (IsAppleKeyboard()) {
468 DCHECK_EQ(ui::EF_CONTROL_DOWN, kModifierRemappingCtrl->flag);
469 remapped_key = kModifierRemappingCtrl;
471 break;
472 case ui::EF_MOD3_DOWN:
473 // If EF_MOD3_DOWN is used by the current input method, leave it alone;
474 // it is not remappable.
475 if (IsISOLevel5ShiftUsedByCurrentInputMethod())
476 continue;
477 // Otherwise, Mod3Mask is set on X events when the Caps Lock key
478 // is down, but, if Caps Lock is remapped, CapsLock is NOT set,
479 // because pressing the key does not invoke caps lock. So, the
480 // kModifierRemappings[] table uses EF_MOD3_DOWN for the Caps
481 // Lock remapping.
482 break;
483 case ui::EF_MOD3_DOWN | ui::EF_ALTGR_DOWN:
484 if ((original_flags & ui::EF_ALTGR_DOWN) &&
485 IsISOLevel5ShiftUsedByCurrentInputMethod()) {
486 remapped_key = kModifierRemappingNeoMod3;
488 break;
489 default:
490 break;
492 if (!remapped_key && kModifierRemappings[i].pref_name) {
493 remapped_key =
494 GetRemappedKey(kModifierRemappings[i].pref_name, pref_service);
496 if (remapped_key) {
497 unmodified_flags &= ~kModifierRemappings[i].flag;
498 rewritten_flags |= remapped_key->flag;
501 return rewritten_flags | unmodified_flags;
504 ui::EventRewriteStatus EventRewriter::RewriteKeyEvent(
505 const ui::KeyEvent& key_event,
506 scoped_ptr<ui::Event>* rewritten_event) {
507 if (IsExtensionCommandRegistered(key_event.key_code(), key_event.flags()))
508 return ui::EVENT_REWRITE_CONTINUE;
509 if (key_event.source_device_id() != ui::ED_UNKNOWN_DEVICE)
510 DeviceKeyPressedOrReleased(key_event.source_device_id());
512 // Drop repeated keys from Hotrod remote.
513 if ((key_event.flags() & ui::EF_IS_REPEAT) &&
514 (key_event.type() == ui::ET_KEY_PRESSED) && IsHotrodRemote() &&
515 key_event.key_code() != ui::VKEY_BACK) {
516 return ui::EVENT_REWRITE_DISCARD;
519 MutableKeyState state = {key_event.flags(),
520 key_event.code(),
521 key_event.GetDomKey(),
522 key_event.GetCharacter(),
523 key_event.key_code()};
525 // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
526 // crbug.com/136465.
527 if (!(key_event.flags() & ui::EF_FINAL)) {
528 if (RewriteModifierKeys(key_event, &state)) {
529 // Early exit with completed event.
530 BuildRewrittenKeyEvent(key_event, state, rewritten_event);
531 return ui::EVENT_REWRITE_REWRITTEN;
533 RewriteNumPadKeys(key_event, &state);
536 ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
537 bool is_sticky_key_extension_command = false;
538 if (sticky_keys_controller_) {
539 status = sticky_keys_controller_->RewriteKeyEvent(key_event, state.key_code,
540 &state.flags);
541 if (status == ui::EVENT_REWRITE_DISCARD)
542 return ui::EVENT_REWRITE_DISCARD;
543 is_sticky_key_extension_command =
544 IsExtensionCommandRegistered(state.key_code, state.flags);
547 // If flags have changed, this may change the interpretation of the key,
548 // so reapply layout.
549 if (state.flags != key_event.flags())
550 SetMeaningForLayout(key_event.type(), &state);
552 // If sticky key rewrites the event, and it matches an extension command, do
553 // not further rewrite the event since it won't match the extension command
554 // thereafter.
555 if (!is_sticky_key_extension_command && !(key_event.flags() & ui::EF_FINAL)) {
556 RewriteExtendedKeys(key_event, &state);
557 RewriteFunctionKeys(key_event, &state);
559 if ((key_event.flags() == state.flags) &&
560 (key_event.key_code() == state.key_code) &&
561 #if defined(USE_X11)
562 // TODO(kpschoedel): This test is present because several consumers of
563 // key events depend on having a native core X11 event, so we rewrite
564 // all XI2 key events (GenericEvent) into corresponding core X11 key
565 // events. Remove this when event consumers no longer care about
566 // native X11 event details (crbug.com/380349).
567 (!key_event.HasNativeEvent() ||
568 (key_event.native_event()->type != GenericEvent)) &&
569 #endif
570 (status == ui::EVENT_REWRITE_CONTINUE)) {
571 return ui::EVENT_REWRITE_CONTINUE;
573 // Sticky keys may have returned a result other than |EVENT_REWRITE_CONTINUE|,
574 // in which case we need to preserve that return status. Alternatively, we
575 // might be here because key_event changed, in which case we need to
576 // return |EVENT_REWRITE_REWRITTEN|.
577 if (status == ui::EVENT_REWRITE_CONTINUE)
578 status = ui::EVENT_REWRITE_REWRITTEN;
579 BuildRewrittenKeyEvent(key_event, state, rewritten_event);
580 return status;
583 ui::EventRewriteStatus EventRewriter::RewriteMouseButtonEvent(
584 const ui::MouseEvent& mouse_event,
585 scoped_ptr<ui::Event>* rewritten_event) {
586 int flags = mouse_event.flags();
587 RewriteLocatedEvent(mouse_event, &flags);
588 ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
589 if (sticky_keys_controller_)
590 status = sticky_keys_controller_->RewriteMouseEvent(mouse_event, &flags);
591 int changed_button = ui::EF_NONE;
592 if ((mouse_event.type() == ui::ET_MOUSE_PRESSED) ||
593 (mouse_event.type() == ui::ET_MOUSE_RELEASED)) {
594 changed_button = RewriteModifierClick(mouse_event, &flags);
596 if ((mouse_event.flags() == flags) &&
597 (status == ui::EVENT_REWRITE_CONTINUE)) {
598 return ui::EVENT_REWRITE_CONTINUE;
600 if (status == ui::EVENT_REWRITE_CONTINUE)
601 status = ui::EVENT_REWRITE_REWRITTEN;
602 ui::MouseEvent* rewritten_mouse_event = new ui::MouseEvent(mouse_event);
603 rewritten_event->reset(rewritten_mouse_event);
604 rewritten_mouse_event->set_flags(flags);
605 #if defined(USE_X11)
606 ui::UpdateX11EventForFlags(rewritten_mouse_event);
607 #endif
608 if (changed_button != ui::EF_NONE) {
609 rewritten_mouse_event->set_changed_button_flags(changed_button);
610 #if defined(USE_X11)
611 ui::UpdateX11EventForChangedButtonFlags(rewritten_mouse_event);
612 #endif
614 return status;
617 ui::EventRewriteStatus EventRewriter::RewriteMouseWheelEvent(
618 const ui::MouseWheelEvent& wheel_event,
619 scoped_ptr<ui::Event>* rewritten_event) {
620 if (!sticky_keys_controller_)
621 return ui::EVENT_REWRITE_CONTINUE;
622 int flags = wheel_event.flags();
623 ui::EventRewriteStatus status =
624 sticky_keys_controller_->RewriteMouseEvent(wheel_event, &flags);
625 if ((wheel_event.flags() == flags) &&
626 (status == ui::EVENT_REWRITE_CONTINUE)) {
627 return ui::EVENT_REWRITE_CONTINUE;
629 if (status == ui::EVENT_REWRITE_CONTINUE)
630 status = ui::EVENT_REWRITE_REWRITTEN;
631 ui::MouseWheelEvent* rewritten_wheel_event =
632 new ui::MouseWheelEvent(wheel_event);
633 rewritten_event->reset(rewritten_wheel_event);
634 rewritten_wheel_event->set_flags(flags);
635 #if defined(USE_X11)
636 ui::UpdateX11EventForFlags(rewritten_wheel_event);
637 #endif
638 return status;
641 ui::EventRewriteStatus EventRewriter::RewriteTouchEvent(
642 const ui::TouchEvent& touch_event,
643 scoped_ptr<ui::Event>* rewritten_event) {
644 int flags = touch_event.flags();
645 RewriteLocatedEvent(touch_event, &flags);
646 if (touch_event.flags() == flags)
647 return ui::EVENT_REWRITE_CONTINUE;
648 ui::TouchEvent* rewritten_touch_event = new ui::TouchEvent(touch_event);
649 rewritten_event->reset(rewritten_touch_event);
650 rewritten_touch_event->set_flags(flags);
651 #if defined(USE_X11)
652 ui::UpdateX11EventForFlags(rewritten_touch_event);
653 #endif
654 return ui::EVENT_REWRITE_REWRITTEN;
657 ui::EventRewriteStatus EventRewriter::RewriteScrollEvent(
658 const ui::ScrollEvent& scroll_event,
659 scoped_ptr<ui::Event>* rewritten_event) {
660 int flags = scroll_event.flags();
661 ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
662 if (sticky_keys_controller_)
663 status = sticky_keys_controller_->RewriteScrollEvent(scroll_event, &flags);
664 if (status == ui::EVENT_REWRITE_CONTINUE)
665 return status;
666 ui::ScrollEvent* rewritten_scroll_event = new ui::ScrollEvent(scroll_event);
667 rewritten_event->reset(rewritten_scroll_event);
668 rewritten_scroll_event->set_flags(flags);
669 #if defined(USE_X11)
670 ui::UpdateX11EventForFlags(rewritten_scroll_event);
671 #endif
672 return status;
675 bool EventRewriter::RewriteModifierKeys(const ui::KeyEvent& key_event,
676 MutableKeyState* state) {
677 DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
678 key_event.type() == ui::ET_KEY_RELEASED);
680 // Do nothing if we have just logged in as guest but have not restarted chrome
681 // process yet (so we are still on the login screen). In this situations we
682 // have no user profile so can not do anything useful.
683 // Note that currently, unlike other accounts, when user logs in as guest, we
684 // restart chrome process. In future this is to be changed.
685 // TODO(glotov): remove the following condition when we do not restart chrome
686 // when user logs in as guest.
687 // TODO(kpschoedel): check whether this is still necessary.
688 if (user_manager::UserManager::Get()->IsLoggedInAsGuest() &&
689 LoginDisplayHostImpl::default_host())
690 return false;
692 const PrefService* pref_service = GetPrefService();
693 if (!pref_service)
694 return false;
696 MutableKeyState incoming = *state;
697 state->flags = ui::EF_NONE;
698 int characteristic_flag = ui::EF_NONE;
699 bool exact_event = false;
701 // First, remap the key code.
702 const ModifierRemapping* remapped_key = NULL;
703 switch (incoming.key) {
704 // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent
705 // when Diamond key is pressed.
706 case ui::DomKey::F15:
707 // When diamond key is not available, the configuration UI for Diamond
708 // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo
709 // syncable pref.
710 if (HasDiamondKey())
711 remapped_key =
712 GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service);
713 // Default behavior of F15 is Control, even if --has-chromeos-diamond-key
714 // is absent, according to unit test comments.
715 if (!remapped_key) {
716 DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->result.key_code);
717 remapped_key = kModifierRemappingCtrl;
719 // F15 is not a modifier key, so we need to track its state directly.
720 if (key_event.type() == ui::ET_KEY_PRESSED) {
721 int remapped_flag = remapped_key->flag;
722 if (remapped_key->remap_to == input_method::kCapsLockKey)
723 remapped_flag |= ui::EF_CAPS_LOCK_DOWN;
724 current_diamond_key_modifier_flags_ = remapped_flag;
725 } else {
726 current_diamond_key_modifier_flags_ = ui::EF_NONE;
728 break;
729 // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock
730 // is pressed (with one exception: when
731 // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates
732 // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7).
733 case ui::DomKey::F16:
734 characteristic_flag = ui::EF_CAPS_LOCK_DOWN;
735 remapped_key =
736 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service);
737 break;
738 case ui::DomKey::OS:
739 characteristic_flag = ui::EF_COMMAND_DOWN;
740 // Rewrite Command-L/R key presses on an Apple keyboard to Control.
741 if (IsAppleKeyboard()) {
742 DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->result.key_code);
743 remapped_key = kModifierRemappingCtrl;
744 } else {
745 remapped_key =
746 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service);
748 // Default behavior is Super key, hence don't remap the event if the pref
749 // is unavailable.
750 break;
751 case ui::DomKey::CONTROL:
752 characteristic_flag = ui::EF_CONTROL_DOWN;
753 remapped_key =
754 GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service);
755 break;
756 case ui::DomKey::ALT:
757 // ALT key
758 characteristic_flag = ui::EF_ALT_DOWN;
759 remapped_key =
760 GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service);
761 break;
762 case ui::DomKey::ALT_GRAPH:
763 // The Neo2 codes modifiers such that CapsLock appears as VKEY_ALTGR,
764 // but AltGraph (right Alt) also appears as VKEY_ALTGR in Neo2,
765 // as it does in other layouts. Neo2's "Mod3" is represented in
766 // EventFlags by a combination of AltGr+Mod3, while its "Mod4" is
767 // AltGr alone.
768 if (IsISOLevel5ShiftUsedByCurrentInputMethod()) {
769 if (incoming.code == ui::DomCode::CAPS_LOCK) {
770 characteristic_flag = ui::EF_ALTGR_DOWN | ui::EF_MOD3_DOWN;
771 remapped_key =
772 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service);
773 } else {
774 characteristic_flag = ui::EF_ALTGR_DOWN;
775 remapped_key =
776 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service);
779 if (remapped_key && remapped_key->result.key_code == ui::VKEY_CAPITAL)
780 remapped_key = kModifierRemappingNeoMod3;
781 break;
782 #if !defined(USE_X11)
783 case ui::DomKey::ALT_GRAPH_LATCH:
784 if (key_event.type() == ui::ET_KEY_PRESSED) {
785 pressed_modifier_latches_ |= ui::EF_ALTGR_DOWN;
786 } else {
787 pressed_modifier_latches_ &= ~ui::EF_ALTGR_DOWN;
788 if (used_modifier_latches_ & ui::EF_ALTGR_DOWN)
789 used_modifier_latches_ &= ~ui::EF_ALTGR_DOWN;
790 else
791 latched_modifier_latches_ |= ui::EF_ALTGR_DOWN;
793 // Rewrite to AltGraph. When this key is used like a regular modifier,
794 // the web-exposed result looks like a use of the regular modifier.
795 // When it's used as a latch, the web-exposed result is a vacuous
796 // modifier press-and-release, which should be harmless, but preserves
797 // the event for applications using the |code| (e.g. remoting).
798 state->key = ui::DomKey::ALT_GRAPH;
799 state->key_code = ui::VKEY_ALTGR;
800 exact_event = true;
801 break;
802 #endif
803 default:
804 break;
807 if (remapped_key) {
808 state->key_code = remapped_key->result.key_code;
809 state->code = remapped_key->result.code;
810 state->key = remapped_key->result.key;
811 state->character = remapped_key->result.character;
812 incoming.flags |= characteristic_flag;
813 characteristic_flag = remapped_key->flag;
814 state->code = RelocateModifier(
815 state->code, ui::KeycodeConverter::DomCodeToLocation(incoming.code));
818 // Next, remap modifier bits.
819 state->flags |=
820 GetRemappedModifierMasks(*pref_service, key_event, incoming.flags);
821 if (key_event.type() == ui::ET_KEY_PRESSED)
822 state->flags |= characteristic_flag;
823 else
824 state->flags &= ~characteristic_flag;
826 if (key_event.type() == ui::ET_KEY_PRESSED) {
827 if (!ui::KeycodeConverter::IsDomKeyForModifier(state->key)) {
828 used_modifier_latches_ |= pressed_modifier_latches_;
829 latched_modifier_latches_ = ui::EF_NONE;
831 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL.
832 if (state->key_code == ui::VKEY_CAPITAL
833 #if defined(USE_X11)
834 // ... but for X11, do nothing if the original key is ui::VKEY_CAPITAL
835 // (i.e. a Caps Lock key on an external keyboard is pressed) since X
836 // handles that itself.
837 && incoming.key_code != ui::VKEY_CAPITAL
838 #endif
840 chromeos::input_method::ImeKeyboard* ime_keyboard =
841 ime_keyboard_for_testing_
842 ? ime_keyboard_for_testing_
843 : chromeos::input_method::InputMethodManager::Get()
844 ->GetImeKeyboard();
845 ime_keyboard->SetCapsLockEnabled(!ime_keyboard->CapsLockIsEnabled());
848 return exact_event;
851 void EventRewriter::RewriteNumPadKeys(const ui::KeyEvent& key_event,
852 MutableKeyState* state) {
853 DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
854 key_event.type() == ui::ET_KEY_RELEASED);
855 static const struct NumPadRemapping {
856 ui::KeyboardCode input_key_code;
857 EventRewriter::MutableKeyState result;
858 } kNumPadRemappings[] = {{ui::VKEY_DELETE,
859 {ui::EF_NONE,
860 ui::DomCode::NONE,
861 ui::DomKey::CHARACTER,
862 '.',
863 ui::VKEY_DECIMAL}},
864 {ui::VKEY_INSERT,
865 {ui::EF_NONE,
866 ui::DomCode::NONE,
867 ui::DomKey::CHARACTER,
868 '0',
869 ui::VKEY_NUMPAD0}},
870 {ui::VKEY_END,
871 {ui::EF_NONE,
872 ui::DomCode::NONE,
873 ui::DomKey::CHARACTER,
874 '1',
875 ui::VKEY_NUMPAD1}},
876 {ui::VKEY_DOWN,
877 {ui::EF_NONE,
878 ui::DomCode::NONE,
879 ui::DomKey::CHARACTER,
880 '2',
881 ui::VKEY_NUMPAD2}},
882 {ui::VKEY_NEXT,
883 {ui::EF_NONE,
884 ui::DomCode::NONE,
885 ui::DomKey::CHARACTER,
886 '3',
887 ui::VKEY_NUMPAD3}},
888 {ui::VKEY_LEFT,
889 {ui::EF_NONE,
890 ui::DomCode::NONE,
891 ui::DomKey::CHARACTER,
892 '4',
893 ui::VKEY_NUMPAD4}},
894 {ui::VKEY_CLEAR,
895 {ui::EF_NONE,
896 ui::DomCode::NONE,
897 ui::DomKey::CHARACTER,
898 '5',
899 ui::VKEY_NUMPAD5}},
900 {ui::VKEY_RIGHT,
901 {ui::EF_NONE,
902 ui::DomCode::NONE,
903 ui::DomKey::CHARACTER,
904 '6',
905 ui::VKEY_NUMPAD6}},
906 {ui::VKEY_HOME,
907 {ui::EF_NONE,
908 ui::DomCode::NONE,
909 ui::DomKey::CHARACTER,
910 '7',
911 ui::VKEY_NUMPAD7}},
912 {ui::VKEY_UP,
913 {ui::EF_NONE,
914 ui::DomCode::NONE,
915 ui::DomKey::CHARACTER,
916 '8',
917 ui::VKEY_NUMPAD8}},
918 {ui::VKEY_PRIOR,
919 {ui::EF_NONE,
920 ui::DomCode::NONE,
921 ui::DomKey::CHARACTER,
922 '9',
923 ui::VKEY_NUMPAD9}}};
924 for (const auto& map : kNumPadRemappings) {
925 if (state->key_code == map.input_key_code) {
926 if (ui::KeycodeConverter::DomCodeToLocation(state->code) ==
927 ui::DomKeyLocation::NUMPAD) {
928 ApplyRemapping(map.result, state);
930 return;
935 void EventRewriter::RewriteExtendedKeys(const ui::KeyEvent& key_event,
936 MutableKeyState* state) {
937 DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
938 key_event.type() == ui::ET_KEY_RELEASED);
939 MutableKeyState incoming = *state;
941 if ((incoming.flags & (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) ==
942 (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) {
943 // Allow Search to avoid rewriting extended keys.
944 // For these, we only remove the EF_COMMAND_DOWN flag.
945 static const KeyboardRemapping::Condition kAvoidRemappings[] = {
946 {// Alt+Backspace
947 ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
948 ui::VKEY_BACK},
949 {// Control+Alt+Up
950 ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN,
951 ui::VKEY_UP},
952 {// Alt+Up
953 ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
954 ui::VKEY_UP},
955 {// Control+Alt+Down
956 ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN,
957 ui::VKEY_DOWN},
958 {// Alt+Down
959 ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
960 ui::VKEY_DOWN}};
961 for (const auto& condition : kAvoidRemappings) {
962 if (MatchKeyboardRemapping(*state, condition)) {
963 state->flags = incoming.flags & ~ui::EF_COMMAND_DOWN;
964 return;
969 if (incoming.flags & ui::EF_COMMAND_DOWN) {
970 static const KeyboardRemapping kSearchRemappings[] = {
971 {// Search+BackSpace -> Delete
972 {ui::EF_COMMAND_DOWN, ui::VKEY_BACK},
973 {ui::EF_NONE,
974 ui::DomCode::DEL,
975 ui::DomKey::DEL,
976 0x7F,
977 ui::VKEY_DELETE}},
978 {// Search+Left -> Home
979 {ui::EF_COMMAND_DOWN, ui::VKEY_LEFT},
980 {ui::EF_NONE, ui::DomCode::HOME, ui::DomKey::HOME, 0, ui::VKEY_HOME}},
981 {// Search+Up -> Prior (aka PageUp)
982 {ui::EF_COMMAND_DOWN, ui::VKEY_UP},
983 {ui::EF_NONE,
984 ui::DomCode::PAGE_UP,
985 ui::DomKey::PAGE_UP,
987 ui::VKEY_PRIOR}},
988 {// Search+Right -> End
989 {ui::EF_COMMAND_DOWN, ui::VKEY_RIGHT},
990 {ui::EF_NONE, ui::DomCode::END, ui::DomKey::END, 0, ui::VKEY_END}},
991 {// Search+Down -> Next (aka PageDown)
992 {ui::EF_COMMAND_DOWN, ui::VKEY_DOWN},
993 {ui::EF_NONE,
994 ui::DomCode::PAGE_DOWN,
995 ui::DomKey::PAGE_DOWN,
997 ui::VKEY_NEXT}},
998 {// Search+Period -> Insert
999 {ui::EF_COMMAND_DOWN, ui::VKEY_OEM_PERIOD},
1000 {ui::EF_NONE,
1001 ui::DomCode::INSERT,
1002 ui::DomKey::INSERT,
1004 ui::VKEY_INSERT}}};
1005 if (RewriteWithKeyboardRemappings(
1006 kSearchRemappings, arraysize(kSearchRemappings), incoming, state)) {
1007 return;
1011 if (incoming.flags & ui::EF_ALT_DOWN) {
1012 static const KeyboardRemapping kNonSearchRemappings[] = {
1013 {// Alt+BackSpace -> Delete
1014 {ui::EF_ALT_DOWN, ui::VKEY_BACK},
1015 {ui::EF_NONE,
1016 ui::DomCode::DEL,
1017 ui::DomKey::DEL,
1018 0x7F,
1019 ui::VKEY_DELETE}},
1020 {// Control+Alt+Up -> Home
1021 {ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, ui::VKEY_UP},
1022 {ui::EF_NONE, ui::DomCode::HOME, ui::DomKey::HOME, 0, ui::VKEY_HOME}},
1023 {// Alt+Up -> Prior (aka PageUp)
1024 {ui::EF_ALT_DOWN, ui::VKEY_UP},
1025 {ui::EF_NONE,
1026 ui::DomCode::PAGE_UP,
1027 ui::DomKey::PAGE_UP,
1029 ui::VKEY_PRIOR}},
1030 {// Control+Alt+Down -> End
1031 {ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, ui::VKEY_DOWN},
1032 {ui::EF_NONE, ui::DomCode::END, ui::DomKey::END, 0, ui::VKEY_END}},
1033 {// Alt+Down -> Next (aka PageDown)
1034 {ui::EF_ALT_DOWN, ui::VKEY_DOWN},
1035 {ui::EF_NONE,
1036 ui::DomCode::PAGE_DOWN,
1037 ui::DomKey::PAGE_DOWN,
1039 ui::VKEY_NEXT}}};
1040 if (RewriteWithKeyboardRemappings(kNonSearchRemappings,
1041 arraysize(kNonSearchRemappings), incoming,
1042 state)) {
1043 return;
1048 void EventRewriter::RewriteFunctionKeys(const ui::KeyEvent& key_event,
1049 MutableKeyState* state) {
1050 CHECK(key_event.type() == ui::ET_KEY_PRESSED ||
1051 key_event.type() == ui::ET_KEY_RELEASED);
1053 if ((state->key_code >= ui::VKEY_F1) && (state->key_code <= ui::VKEY_F12)) {
1054 // By default the top row (F1-F12) keys are system keys for back, forward,
1055 // brightness, volume, etc. However, windows for v2 apps can optionally
1056 // request raw function keys for these keys.
1057 bool top_row_keys_are_function_keys = TopRowKeysAreFunctionKeys(key_event);
1058 bool search_is_pressed = (state->flags & ui::EF_COMMAND_DOWN) != 0;
1060 // Search? Top Row Result
1061 // ------- -------- ------
1062 // No Fn Unchanged
1063 // No System Fn -> System
1064 // Yes Fn Fn -> System
1065 // Yes System Search+Fn -> Fn
1066 if (top_row_keys_are_function_keys == search_is_pressed) {
1067 // Rewrite the F1-F12 keys on a Chromebook keyboard to system keys.
1068 static const KeyboardRemapping kFkeysToSystemKeys[] = {
1069 {{ui::EF_NONE, ui::VKEY_F1},
1070 {ui::EF_NONE,
1071 ui::DomCode::BROWSER_BACK,
1072 ui::DomKey::BROWSER_BACK,
1074 ui::VKEY_BROWSER_BACK}},
1075 {{ui::EF_NONE, ui::VKEY_F2},
1076 {ui::EF_NONE,
1077 ui::DomCode::BROWSER_FORWARD,
1078 ui::DomKey::BROWSER_FORWARD,
1080 ui::VKEY_BROWSER_FORWARD}},
1081 {{ui::EF_NONE, ui::VKEY_F3},
1082 {ui::EF_NONE,
1083 ui::DomCode::BROWSER_REFRESH,
1084 ui::DomKey::BROWSER_REFRESH,
1086 ui::VKEY_BROWSER_REFRESH}},
1087 {{ui::EF_NONE, ui::VKEY_F4},
1088 {ui::EF_NONE,
1089 ui::DomCode::ZOOM_TOGGLE,
1090 ui::DomKey::ZOOM_TOGGLE,
1092 ui::VKEY_MEDIA_LAUNCH_APP2}},
1093 {{ui::EF_NONE, ui::VKEY_F5},
1094 {ui::EF_NONE,
1095 ui::DomCode::SELECT_TASK,
1096 ui::DomKey::LAUNCH_MY_COMPUTER,
1098 ui::VKEY_MEDIA_LAUNCH_APP1}},
1099 {{ui::EF_NONE, ui::VKEY_F6},
1100 {ui::EF_NONE,
1101 ui::DomCode::BRIGHTNESS_DOWN,
1102 ui::DomKey::BRIGHTNESS_DOWN,
1104 ui::VKEY_BRIGHTNESS_DOWN}},
1105 {{ui::EF_NONE, ui::VKEY_F7},
1106 {ui::EF_NONE,
1107 ui::DomCode::BRIGHTNESS_UP,
1108 ui::DomKey::BRIGHTNESS_UP,
1110 ui::VKEY_BRIGHTNESS_UP}},
1111 {{ui::EF_NONE, ui::VKEY_F8},
1112 {ui::EF_NONE,
1113 ui::DomCode::VOLUME_MUTE,
1114 ui::DomKey::VOLUME_MUTE,
1116 ui::VKEY_VOLUME_MUTE}},
1117 {{ui::EF_NONE, ui::VKEY_F9},
1118 {ui::EF_NONE,
1119 ui::DomCode::VOLUME_DOWN,
1120 ui::DomKey::VOLUME_DOWN,
1122 ui::VKEY_VOLUME_DOWN}},
1123 {{ui::EF_NONE, ui::VKEY_F10},
1124 {ui::EF_NONE,
1125 ui::DomCode::VOLUME_UP,
1126 ui::DomKey::VOLUME_UP,
1128 ui::VKEY_VOLUME_UP}},
1130 MutableKeyState incoming_without_command = *state;
1131 incoming_without_command.flags &= ~ui::EF_COMMAND_DOWN;
1132 if (RewriteWithKeyboardRemappings(kFkeysToSystemKeys,
1133 arraysize(kFkeysToSystemKeys),
1134 incoming_without_command, state)) {
1135 return;
1137 } else if (search_is_pressed) {
1138 // Allow Search to avoid rewriting F1-F12.
1139 state->flags &= ~ui::EF_COMMAND_DOWN;
1140 return;
1144 if (state->flags & ui::EF_COMMAND_DOWN) {
1145 // Remap Search+<number> to F<number>.
1146 // We check the DOM3 |code| here instead of the VKEY, as these keys may
1147 // have different |KeyboardCode|s when modifiers are pressed, such as shift.
1148 static const struct {
1149 ui::DomCode input_dom_code;
1150 EventRewriter::MutableKeyState result;
1151 } kNumberKeysToFkeys[] = {
1152 {ui::DomCode::DIGIT1,
1153 {ui::EF_NONE, ui::DomCode::F1, ui::DomKey::F1, 0, ui::VKEY_F1}},
1154 {ui::DomCode::DIGIT2,
1155 {ui::EF_NONE, ui::DomCode::F2, ui::DomKey::F2, 0, ui::VKEY_F2}},
1156 {ui::DomCode::DIGIT3,
1157 {ui::EF_NONE, ui::DomCode::F3, ui::DomKey::F3, 0, ui::VKEY_F3}},
1158 {ui::DomCode::DIGIT4,
1159 {ui::EF_NONE, ui::DomCode::F4, ui::DomKey::F4, 0, ui::VKEY_F4}},
1160 {ui::DomCode::DIGIT5,
1161 {ui::EF_NONE, ui::DomCode::F5, ui::DomKey::F5, 0, ui::VKEY_F5}},
1162 {ui::DomCode::DIGIT6,
1163 {ui::EF_NONE, ui::DomCode::F6, ui::DomKey::F6, 0, ui::VKEY_F6}},
1164 {ui::DomCode::DIGIT7,
1165 {ui::EF_NONE, ui::DomCode::F7, ui::DomKey::F7, 0, ui::VKEY_F7}},
1166 {ui::DomCode::DIGIT8,
1167 {ui::EF_NONE, ui::DomCode::F8, ui::DomKey::F8, 0, ui::VKEY_F8}},
1168 {ui::DomCode::DIGIT9,
1169 {ui::EF_NONE, ui::DomCode::F9, ui::DomKey::F9, 0, ui::VKEY_F9}},
1170 {ui::DomCode::DIGIT0,
1171 {ui::EF_NONE, ui::DomCode::F10, ui::DomKey::F10, 0, ui::VKEY_F10}},
1172 {ui::DomCode::MINUS,
1173 {ui::EF_NONE, ui::DomCode::F11, ui::DomKey::F11, 0, ui::VKEY_F11}},
1174 {ui::DomCode::EQUAL,
1175 {ui::EF_NONE, ui::DomCode::F12, ui::DomKey::F12, 0, ui::VKEY_F12}}};
1176 for (const auto& map : kNumberKeysToFkeys) {
1177 if (state->code == map.input_dom_code) {
1178 state->flags &= ~ui::EF_COMMAND_DOWN;
1179 ApplyRemapping(map.result, state);
1180 return;
1186 void EventRewriter::RewriteLocatedEvent(const ui::Event& event, int* flags) {
1187 const PrefService* pref_service = GetPrefService();
1188 if (!pref_service)
1189 return;
1190 *flags = GetRemappedModifierMasks(*pref_service, event, *flags);
1193 int EventRewriter::RewriteModifierClick(const ui::MouseEvent& mouse_event,
1194 int* flags) {
1195 // Remap Alt+Button1 to Button3.
1196 const int kAltLeftButton = (ui::EF_ALT_DOWN | ui::EF_LEFT_MOUSE_BUTTON);
1197 if (((*flags & kAltLeftButton) == kAltLeftButton) &&
1198 ((mouse_event.type() == ui::ET_MOUSE_PRESSED) ||
1199 pressed_device_ids_.count(mouse_event.source_device_id()))) {
1200 *flags &= ~kAltLeftButton;
1201 *flags |= ui::EF_RIGHT_MOUSE_BUTTON;
1202 if (mouse_event.type() == ui::ET_MOUSE_PRESSED)
1203 pressed_device_ids_.insert(mouse_event.source_device_id());
1204 else
1205 pressed_device_ids_.erase(mouse_event.source_device_id());
1206 return ui::EF_RIGHT_MOUSE_BUTTON;
1208 return ui::EF_NONE;
1211 EventRewriter::DeviceType EventRewriter::KeyboardDeviceAddedInternal(
1212 int device_id,
1213 const std::string& device_name,
1214 int vendor_id,
1215 int product_id) {
1216 const DeviceType type = GetDeviceType(device_name, vendor_id, product_id);
1217 if (type == kDeviceAppleKeyboard) {
1218 VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
1219 << "id=" << device_id;
1220 } else if (type == kDeviceHotrodRemote) {
1221 VLOG(1) << "Hotrod remote '" << device_name << "' connected: "
1222 << "id=" << device_id;
1223 } else if (type == kDeviceVirtualCoreKeyboard) {
1224 VLOG(1) << "Xorg virtual '" << device_name << "' connected: "
1225 << "id=" << device_id;
1226 } else {
1227 VLOG(1) << "Unknown keyboard '" << device_name << "' connected: "
1228 << "id=" << device_id;
1230 // Always overwrite the existing device_id since the X server may reuse a
1231 // device id for an unattached device.
1232 device_id_to_type_[device_id] = type;
1233 return type;
1236 EventRewriter::DeviceType EventRewriter::KeyboardDeviceAdded(int device_id) {
1237 if (!ui::DeviceDataManager::HasInstance())
1238 return kDeviceUnknown;
1239 const std::vector<ui::KeyboardDevice>& keyboards =
1240 ui::DeviceDataManager::GetInstance()->keyboard_devices();
1241 for (const auto& keyboard : keyboards) {
1242 if (keyboard.id == device_id) {
1243 return KeyboardDeviceAddedInternal(
1244 keyboard.id, keyboard.name, keyboard.vendor_id, keyboard.product_id);
1247 return kDeviceUnknown;
1250 } // namespace chromeos