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"
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"
37 #include <X11/extensions/XInput2.h>
40 // Get rid of macros from Xlib.h that conflicts with other parts of the code.
44 #include "ui/base/x/x11_util.h"
45 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
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
{
77 const char* pref_name
;
78 EventRewriter::MutableKeyState result
;
79 } kModifierRemappings
[] = {
80 {// kModifierRemappingCtrl references this entry by index.
82 input_method::kControlKey
,
83 prefs::kLanguageRemapControlKeyTo
,
84 {ui::EF_CONTROL_DOWN
, ui::DomCode::CONTROL_LEFT
, ui::DomKey::CONTROL
,
86 {// kModifierRemappingNeoMod3 references this entry by index.
87 ui::EF_MOD3_DOWN
| ui::EF_ALTGR_DOWN
,
88 input_method::kNumModifierKeys
,
90 {ui::EF_MOD3_DOWN
| ui::EF_ALTGR_DOWN
, ui::DomCode::CAPS_LOCK
,
91 ui::DomKey::ALT_GRAPH
, ui::VKEY_ALTGR
}},
93 input_method::kSearchKey
,
94 prefs::kLanguageRemapSearchKeyTo
,
95 {ui::EF_COMMAND_DOWN
, ui::DomCode::OS_LEFT
, ui::DomKey::OS
,
98 input_method::kAltKey
,
99 prefs::kLanguageRemapAltKeyTo
,
100 {ui::EF_ALT_DOWN
, ui::DomCode::ALT_LEFT
, ui::DomKey::ALT
, ui::VKEY_MENU
}},
102 input_method::kVoidKey
,
104 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::NONE
, ui::VKEY_UNKNOWN
}},
106 input_method::kCapsLockKey
,
107 prefs::kLanguageRemapCapsLockKeyTo
,
108 {ui::EF_MOD3_DOWN
, ui::DomCode::CAPS_LOCK
, ui::DomKey::CAPS_LOCK
,
111 input_method::kEscapeKey
,
113 {ui::EF_NONE
, ui::DomCode::ESCAPE
, ui::DomKey::ESCAPE
, ui::VKEY_ESCAPE
}},
115 input_method::kNumModifierKeys
,
116 prefs::kLanguageRemapDiamondKeyTo
,
117 {ui::EF_NONE
, ui::DomCode::F15
, ui::DomKey::F15
, ui::VKEY_F15
}}};
119 const ModifierRemapping
* kModifierRemappingCtrl
= &kModifierRemappings
[0];
120 const ModifierRemapping
* kModifierRemappingNeoMod3
= &kModifierRemappings
[1];
122 // Gets a remapped key for |pref_name| key. For example, to find out which
123 // key Search is currently remapped to, call the function with
124 // prefs::kLanguageRemapSearchKeyTo.
125 const ModifierRemapping
* GetRemappedKey(const std::string
& pref_name
,
126 const PrefService
& pref_service
) {
127 if (!pref_service
.FindPreference(pref_name
.c_str()))
128 return NULL
; // The |pref_name| hasn't been registered. On login screen?
129 const int value
= pref_service
.GetInteger(pref_name
.c_str());
130 for (size_t i
= 0; i
< arraysize(kModifierRemappings
); ++i
) {
131 if (value
== kModifierRemappings
[i
].remap_to
)
132 return &kModifierRemappings
[i
];
137 bool HasDiamondKey() {
138 return base::CommandLine::ForCurrentProcess()->HasSwitch(
139 chromeos::switches::kHasChromeOSDiamondKey
);
142 bool IsISOLevel5ShiftUsedByCurrentInputMethod() {
143 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
144 // it's not possible to make both features work. For now, we don't remap
145 // Mod3Mask when Neo2 is in use.
146 // TODO(yusukes): Remove the restriction.
147 input_method::InputMethodManager
* manager
=
148 input_method::InputMethodManager::Get();
149 return manager
->IsISOLevel5ShiftUsedByCurrentInputMethod();
152 bool IsExtensionCommandRegistered(ui::KeyboardCode key_code
, int flags
) {
153 // Some keyboard events for ChromeOS get rewritten, such as:
154 // Search+Shift+Left gets converted to Shift+Home (BeginDocument).
155 // This doesn't make sense if the user has assigned that shortcut
156 // to an extension. Because:
157 // 1) The extension would, upon seeing a request for Ctrl+Shift+Home have
158 // to register for Shift+Home, instead.
159 // 2) The conversion is unnecessary, because Shift+Home (BeginDocument) isn't
160 // going to be executed.
161 // Therefore, we skip converting the accelerator if an extension has
162 // registered for this shortcut.
163 Profile
* profile
= ProfileManager::GetActiveUserProfile();
164 if (!profile
|| !extensions::ExtensionCommandsGlobalRegistry::Get(profile
))
167 int modifiers
= flags
& (ui::EF_SHIFT_DOWN
| ui::EF_CONTROL_DOWN
|
168 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
);
169 ui::Accelerator
accelerator(key_code
, modifiers
);
170 return extensions::ExtensionCommandsGlobalRegistry::Get(profile
)
171 ->IsRegistered(accelerator
);
174 EventRewriter::DeviceType
GetDeviceType(const std::string
& device_name
,
177 if (vendor_id
== kHotrodRemoteVendorId
&&
178 product_id
== kHotrodRemoteProductId
) {
179 return EventRewriter::kDeviceHotrodRemote
;
182 if (base::LowerCaseEqualsASCII(device_name
, "virtual core keyboard"))
183 return EventRewriter::kDeviceVirtualCoreKeyboard
;
185 std::vector
<std::string
> tokens
= base::SplitString(
186 device_name
, " .", base::KEEP_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
);
188 // If the |device_name| contains the two words, "apple" and "keyboard", treat
189 // it as an Apple keyboard.
190 bool found_apple
= false;
191 bool found_keyboard
= false;
192 for (size_t i
= 0; i
< tokens
.size(); ++i
) {
193 if (!found_apple
&& base::LowerCaseEqualsASCII(tokens
[i
], "apple"))
195 if (!found_keyboard
&& base::LowerCaseEqualsASCII(tokens
[i
], "keyboard"))
196 found_keyboard
= true;
197 if (found_apple
&& found_keyboard
)
198 return EventRewriter::kDeviceAppleKeyboard
;
201 return EventRewriter::kDeviceUnknown
;
204 struct KeyboardRemapping
{
205 // MatchKeyboardRemapping() succeeds if the tested has all of the specified
206 // flags (and possibly other flags), and either the key_code matches or the
207 // condition's key_code is VKEY_UNKNOWN.
210 ui::KeyboardCode key_code
;
212 // ApplyRemapping(), which is the primary user of this structure,
213 // conditionally sets the output fields from the |result| here.
214 // - |dom_code| is set if |result.dom_code| is not NONE.
215 // - |dom_key| and |character| are set if |result.dom_key| is not NONE.
216 // -|key_code| is set if |result.key_code| is not VKEY_UNKNOWN.
217 // - |flags| are always set from |result.flags|, but this can be |EF_NONE|.
218 EventRewriter::MutableKeyState result
;
221 bool MatchKeyboardRemapping(const EventRewriter::MutableKeyState
& suspect
,
222 const KeyboardRemapping::Condition
& test
) {
223 return ((test
.key_code
== ui::VKEY_UNKNOWN
) ||
224 (test
.key_code
== suspect
.key_code
)) &&
225 ((suspect
.flags
& test
.flags
) == test
.flags
);
228 void ApplyRemapping(const EventRewriter::MutableKeyState
& changes
,
229 EventRewriter::MutableKeyState
* state
) {
230 state
->flags
|= changes
.flags
;
231 if (changes
.code
!= ui::DomCode::NONE
)
232 state
->code
= changes
.code
;
233 if (changes
.key
!= ui::DomKey::NONE
)
234 state
->key
= changes
.key
;
235 if (changes
.key_code
!= ui::VKEY_UNKNOWN
)
236 state
->key_code
= changes
.key_code
;
239 // Given a set of KeyboardRemapping structs, finds a matching struct
240 // if possible, and updates the remapped event values. Returns true if a
241 // remapping was found and remapped values were updated.
242 bool RewriteWithKeyboardRemappings(
243 const KeyboardRemapping
* mappings
,
245 const EventRewriter::MutableKeyState
& input_state
,
246 EventRewriter::MutableKeyState
* remapped_state
) {
247 for (size_t i
= 0; i
< num_mappings
; ++i
) {
248 const KeyboardRemapping
& map
= mappings
[i
];
249 if (MatchKeyboardRemapping(input_state
, map
.condition
)) {
250 remapped_state
->flags
= (input_state
.flags
& ~map
.condition
.flags
);
251 ApplyRemapping(map
.result
, remapped_state
);
258 void SetMeaningForLayout(ui::EventType type
,
259 EventRewriter::MutableKeyState
* state
) {
260 // Currently layout is applied by creating a temporary key event with the
261 // current physical state, and extracting the layout results.
262 ui::KeyEvent
key(type
, state
->key_code
, state
->code
, state
->flags
);
263 state
->key
= key
.GetDomKey();
266 ui::DomCode
RelocateModifier(ui::DomCode code
, ui::DomKeyLocation location
) {
267 bool right
= (location
== ui::DomKeyLocation::RIGHT
);
269 case ui::DomCode::CONTROL_LEFT
:
270 case ui::DomCode::CONTROL_RIGHT
:
271 return right
? ui::DomCode::CONTROL_RIGHT
: ui::DomCode::CONTROL_LEFT
;
272 case ui::DomCode::SHIFT_LEFT
:
273 case ui::DomCode::SHIFT_RIGHT
:
274 return right
? ui::DomCode::SHIFT_RIGHT
: ui::DomCode::SHIFT_LEFT
;
275 case ui::DomCode::ALT_LEFT
:
276 case ui::DomCode::ALT_RIGHT
:
277 return right
? ui::DomCode::ALT_RIGHT
: ui::DomCode::ALT_LEFT
;
278 case ui::DomCode::OS_LEFT
:
279 case ui::DomCode::OS_RIGHT
:
280 return right
? ui::DomCode::OS_RIGHT
: ui::DomCode::OS_LEFT
;
289 EventRewriter::EventRewriter(ash::StickyKeysController
* sticky_keys_controller
)
290 : last_keyboard_device_id_(ui::ED_UNKNOWN_DEVICE
),
291 ime_keyboard_for_testing_(NULL
),
292 pref_service_for_testing_(NULL
),
293 sticky_keys_controller_(sticky_keys_controller
),
294 current_diamond_key_modifier_flags_(ui::EF_NONE
),
295 pressed_modifier_latches_(ui::EF_NONE
),
296 latched_modifier_latches_(ui::EF_NONE
),
297 used_modifier_latches_(ui::EF_NONE
) {}
299 EventRewriter::~EventRewriter() {}
301 EventRewriter::DeviceType
EventRewriter::KeyboardDeviceAddedForTesting(
303 const std::string
& device_name
) {
304 // Tests must avoid XI2 reserved device IDs.
305 DCHECK((device_id
< 0) || (device_id
> 1));
306 return KeyboardDeviceAddedInternal(device_id
, device_name
, kUnknownVendorId
,
310 void EventRewriter::RewriteMouseButtonEventForTesting(
311 const ui::MouseEvent
& event
,
312 scoped_ptr
<ui::Event
>* rewritten_event
) {
313 RewriteMouseButtonEvent(event
, rewritten_event
);
316 ui::EventRewriteStatus
EventRewriter::RewriteEvent(
317 const ui::Event
& event
,
318 scoped_ptr
<ui::Event
>* rewritten_event
) {
319 if ((event
.type() == ui::ET_KEY_PRESSED
) ||
320 (event
.type() == ui::ET_KEY_RELEASED
)) {
321 return RewriteKeyEvent(static_cast<const ui::KeyEvent
&>(event
),
324 if ((event
.type() == ui::ET_MOUSE_PRESSED
) ||
325 (event
.type() == ui::ET_MOUSE_RELEASED
)) {
326 return RewriteMouseButtonEvent(static_cast<const ui::MouseEvent
&>(event
),
329 if (event
.type() == ui::ET_MOUSEWHEEL
) {
330 return RewriteMouseWheelEvent(
331 static_cast<const ui::MouseWheelEvent
&>(event
), rewritten_event
);
333 if ((event
.type() == ui::ET_TOUCH_PRESSED
) ||
334 (event
.type() == ui::ET_TOUCH_RELEASED
)) {
335 return RewriteTouchEvent(static_cast<const ui::TouchEvent
&>(event
),
338 if (event
.IsScrollEvent()) {
339 return RewriteScrollEvent(static_cast<const ui::ScrollEvent
&>(event
),
342 return ui::EVENT_REWRITE_CONTINUE
;
345 ui::EventRewriteStatus
EventRewriter::NextDispatchEvent(
346 const ui::Event
& last_event
,
347 scoped_ptr
<ui::Event
>* new_event
) {
348 if (sticky_keys_controller_
) {
349 // In the case of sticky keys, we know what the events obtained here are:
350 // modifier key releases that match the ones previously discarded. So, we
351 // know that they don't have to be passed through the post-sticky key
352 // rewriting phases, |RewriteExtendedKeys()| and |RewriteFunctionKeys()|,
353 // because those phases do nothing with modifier key releases.
354 return sticky_keys_controller_
->NextDispatchEvent(new_event
);
357 return ui::EVENT_REWRITE_CONTINUE
;
360 void EventRewriter::BuildRewrittenKeyEvent(
361 const ui::KeyEvent
& key_event
,
362 const MutableKeyState
& state
,
363 scoped_ptr
<ui::Event
>* rewritten_event
) {
364 ui::KeyEvent
* rewritten_key_event
=
365 new ui::KeyEvent(key_event
.type(), state
.key_code
, state
.code
,
366 state
.flags
, state
.key
, key_event
.time_stamp());
367 rewritten_event
->reset(rewritten_key_event
);
370 void EventRewriter::DeviceKeyPressedOrReleased(int device_id
) {
371 std::map
<int, DeviceType
>::const_iterator iter
=
372 device_id_to_type_
.find(device_id
);
374 if (iter
!= device_id_to_type_
.end())
377 type
= KeyboardDeviceAdded(device_id
);
379 // Ignore virtual Xorg keyboard (magic that generates key repeat
380 // events). Pretend that the previous real keyboard is the one that is still
382 if (type
== kDeviceVirtualCoreKeyboard
)
385 last_keyboard_device_id_
= device_id
;
388 const PrefService
* EventRewriter::GetPrefService() const {
389 if (pref_service_for_testing_
)
390 return pref_service_for_testing_
;
391 Profile
* profile
= ProfileManager::GetActiveUserProfile();
392 return profile
? profile
->GetPrefs() : NULL
;
395 bool EventRewriter::IsAppleKeyboard() const {
396 return IsLastKeyboardOfType(kDeviceAppleKeyboard
);
399 bool EventRewriter::IsHotrodRemote() const {
400 return IsLastKeyboardOfType(kDeviceHotrodRemote
);
403 bool EventRewriter::IsLastKeyboardOfType(DeviceType device_type
) const {
404 if (last_keyboard_device_id_
== ui::ED_UNKNOWN_DEVICE
)
407 // Check which device generated |event|.
408 std::map
<int, DeviceType
>::const_iterator iter
=
409 device_id_to_type_
.find(last_keyboard_device_id_
);
410 if (iter
== device_id_to_type_
.end()) {
411 LOG(ERROR
) << "Device ID " << last_keyboard_device_id_
<< " is unknown.";
415 const DeviceType type
= iter
->second
;
416 return type
== device_type
;
419 bool EventRewriter::TopRowKeysAreFunctionKeys(const ui::KeyEvent
& event
) const {
420 const PrefService
* prefs
= GetPrefService();
421 if (prefs
&& prefs
->FindPreference(prefs::kLanguageSendFunctionKeys
) &&
422 prefs
->GetBoolean(prefs::kLanguageSendFunctionKeys
))
425 ash::wm::WindowState
* state
= ash::wm::GetActiveWindowState();
426 return state
? state
->top_row_keys_are_function_keys() : false;
429 int EventRewriter::GetRemappedModifierMasks(const PrefService
& pref_service
,
430 const ui::Event
& event
,
431 int original_flags
) const {
432 int unmodified_flags
= original_flags
;
433 int rewritten_flags
= current_diamond_key_modifier_flags_
|
434 pressed_modifier_latches_
| latched_modifier_latches_
;
435 for (size_t i
= 0; unmodified_flags
&& (i
< arraysize(kModifierRemappings
));
437 const ModifierRemapping
* remapped_key
= NULL
;
438 if (!(unmodified_flags
& kModifierRemappings
[i
].flag
))
440 switch (kModifierRemappings
[i
].flag
) {
441 case ui::EF_COMMAND_DOWN
:
442 // Rewrite Command key presses on an Apple keyboard to Control.
443 if (IsAppleKeyboard()) {
444 DCHECK_EQ(ui::EF_CONTROL_DOWN
, kModifierRemappingCtrl
->flag
);
445 remapped_key
= kModifierRemappingCtrl
;
448 case ui::EF_MOD3_DOWN
:
449 // If EF_MOD3_DOWN is used by the current input method, leave it alone;
450 // it is not remappable.
451 if (IsISOLevel5ShiftUsedByCurrentInputMethod())
453 // Otherwise, Mod3Mask is set on X events when the Caps Lock key
454 // is down, but, if Caps Lock is remapped, CapsLock is NOT set,
455 // because pressing the key does not invoke caps lock. So, the
456 // kModifierRemappings[] table uses EF_MOD3_DOWN for the Caps
459 case ui::EF_MOD3_DOWN
| ui::EF_ALTGR_DOWN
:
460 if ((original_flags
& ui::EF_ALTGR_DOWN
) &&
461 IsISOLevel5ShiftUsedByCurrentInputMethod()) {
462 remapped_key
= kModifierRemappingNeoMod3
;
468 if (!remapped_key
&& kModifierRemappings
[i
].pref_name
) {
470 GetRemappedKey(kModifierRemappings
[i
].pref_name
, pref_service
);
473 unmodified_flags
&= ~kModifierRemappings
[i
].flag
;
474 rewritten_flags
|= remapped_key
->flag
;
477 return rewritten_flags
| unmodified_flags
;
480 ui::EventRewriteStatus
EventRewriter::RewriteKeyEvent(
481 const ui::KeyEvent
& key_event
,
482 scoped_ptr
<ui::Event
>* rewritten_event
) {
483 if (IsExtensionCommandRegistered(key_event
.key_code(), key_event
.flags()))
484 return ui::EVENT_REWRITE_CONTINUE
;
485 if (key_event
.source_device_id() != ui::ED_UNKNOWN_DEVICE
)
486 DeviceKeyPressedOrReleased(key_event
.source_device_id());
488 // Drop repeated keys from Hotrod remote.
489 if ((key_event
.flags() & ui::EF_IS_REPEAT
) &&
490 (key_event
.type() == ui::ET_KEY_PRESSED
) && IsHotrodRemote() &&
491 key_event
.key_code() != ui::VKEY_BACK
) {
492 return ui::EVENT_REWRITE_DISCARD
;
495 MutableKeyState state
= {key_event
.flags(), key_event
.code(),
496 key_event
.GetDomKey(), key_event
.key_code()};
498 // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
500 if (!(key_event
.flags() & ui::EF_FINAL
)) {
501 if (RewriteModifierKeys(key_event
, &state
)) {
502 // Early exit with completed event.
503 BuildRewrittenKeyEvent(key_event
, state
, rewritten_event
);
504 return ui::EVENT_REWRITE_REWRITTEN
;
506 RewriteNumPadKeys(key_event
, &state
);
509 ui::EventRewriteStatus status
= ui::EVENT_REWRITE_CONTINUE
;
510 bool is_sticky_key_extension_command
= false;
511 if (sticky_keys_controller_
) {
512 status
= sticky_keys_controller_
->RewriteKeyEvent(key_event
, state
.key_code
,
514 if (status
== ui::EVENT_REWRITE_DISCARD
)
515 return ui::EVENT_REWRITE_DISCARD
;
516 is_sticky_key_extension_command
=
517 IsExtensionCommandRegistered(state
.key_code
, state
.flags
);
520 // If flags have changed, this may change the interpretation of the key,
521 // so reapply layout.
522 if (state
.flags
!= key_event
.flags())
523 SetMeaningForLayout(key_event
.type(), &state
);
525 // If sticky key rewrites the event, and it matches an extension command, do
526 // not further rewrite the event since it won't match the extension command
528 if (!is_sticky_key_extension_command
&& !(key_event
.flags() & ui::EF_FINAL
)) {
529 RewriteExtendedKeys(key_event
, &state
);
530 RewriteFunctionKeys(key_event
, &state
);
532 if ((key_event
.flags() == state
.flags
) &&
533 (key_event
.key_code() == state
.key_code
) &&
535 // TODO(kpschoedel): This test is present because several consumers of
536 // key events depend on having a native core X11 event, so we rewrite
537 // all XI2 key events (GenericEvent) into corresponding core X11 key
538 // events. Remove this when event consumers no longer care about
539 // native X11 event details (crbug.com/380349).
540 (!key_event
.HasNativeEvent() ||
541 (key_event
.native_event()->type
!= GenericEvent
)) &&
543 (status
== ui::EVENT_REWRITE_CONTINUE
)) {
544 return ui::EVENT_REWRITE_CONTINUE
;
546 // Sticky keys may have returned a result other than |EVENT_REWRITE_CONTINUE|,
547 // in which case we need to preserve that return status. Alternatively, we
548 // might be here because key_event changed, in which case we need to
549 // return |EVENT_REWRITE_REWRITTEN|.
550 if (status
== ui::EVENT_REWRITE_CONTINUE
)
551 status
= ui::EVENT_REWRITE_REWRITTEN
;
552 BuildRewrittenKeyEvent(key_event
, state
, rewritten_event
);
556 ui::EventRewriteStatus
EventRewriter::RewriteMouseButtonEvent(
557 const ui::MouseEvent
& mouse_event
,
558 scoped_ptr
<ui::Event
>* rewritten_event
) {
559 int flags
= mouse_event
.flags();
560 RewriteLocatedEvent(mouse_event
, &flags
);
561 ui::EventRewriteStatus status
= ui::EVENT_REWRITE_CONTINUE
;
562 if (sticky_keys_controller_
)
563 status
= sticky_keys_controller_
->RewriteMouseEvent(mouse_event
, &flags
);
564 int changed_button
= ui::EF_NONE
;
565 if ((mouse_event
.type() == ui::ET_MOUSE_PRESSED
) ||
566 (mouse_event
.type() == ui::ET_MOUSE_RELEASED
)) {
567 changed_button
= RewriteModifierClick(mouse_event
, &flags
);
569 if ((mouse_event
.flags() == flags
) &&
570 (status
== ui::EVENT_REWRITE_CONTINUE
)) {
571 return ui::EVENT_REWRITE_CONTINUE
;
573 if (status
== ui::EVENT_REWRITE_CONTINUE
)
574 status
= ui::EVENT_REWRITE_REWRITTEN
;
575 ui::MouseEvent
* rewritten_mouse_event
= new ui::MouseEvent(mouse_event
);
576 rewritten_event
->reset(rewritten_mouse_event
);
577 rewritten_mouse_event
->set_flags(flags
);
579 ui::UpdateX11EventForFlags(rewritten_mouse_event
);
581 if (changed_button
!= ui::EF_NONE
) {
582 rewritten_mouse_event
->set_changed_button_flags(changed_button
);
584 ui::UpdateX11EventForChangedButtonFlags(rewritten_mouse_event
);
590 ui::EventRewriteStatus
EventRewriter::RewriteMouseWheelEvent(
591 const ui::MouseWheelEvent
& wheel_event
,
592 scoped_ptr
<ui::Event
>* rewritten_event
) {
593 if (!sticky_keys_controller_
)
594 return ui::EVENT_REWRITE_CONTINUE
;
595 int flags
= wheel_event
.flags();
596 ui::EventRewriteStatus status
=
597 sticky_keys_controller_
->RewriteMouseEvent(wheel_event
, &flags
);
598 if ((wheel_event
.flags() == flags
) &&
599 (status
== ui::EVENT_REWRITE_CONTINUE
)) {
600 return ui::EVENT_REWRITE_CONTINUE
;
602 if (status
== ui::EVENT_REWRITE_CONTINUE
)
603 status
= ui::EVENT_REWRITE_REWRITTEN
;
604 ui::MouseWheelEvent
* rewritten_wheel_event
=
605 new ui::MouseWheelEvent(wheel_event
);
606 rewritten_event
->reset(rewritten_wheel_event
);
607 rewritten_wheel_event
->set_flags(flags
);
609 ui::UpdateX11EventForFlags(rewritten_wheel_event
);
614 ui::EventRewriteStatus
EventRewriter::RewriteTouchEvent(
615 const ui::TouchEvent
& touch_event
,
616 scoped_ptr
<ui::Event
>* rewritten_event
) {
617 int flags
= touch_event
.flags();
618 RewriteLocatedEvent(touch_event
, &flags
);
619 if (touch_event
.flags() == flags
)
620 return ui::EVENT_REWRITE_CONTINUE
;
621 ui::TouchEvent
* rewritten_touch_event
= new ui::TouchEvent(touch_event
);
622 rewritten_event
->reset(rewritten_touch_event
);
623 rewritten_touch_event
->set_flags(flags
);
625 ui::UpdateX11EventForFlags(rewritten_touch_event
);
627 return ui::EVENT_REWRITE_REWRITTEN
;
630 ui::EventRewriteStatus
EventRewriter::RewriteScrollEvent(
631 const ui::ScrollEvent
& scroll_event
,
632 scoped_ptr
<ui::Event
>* rewritten_event
) {
633 int flags
= scroll_event
.flags();
634 ui::EventRewriteStatus status
= ui::EVENT_REWRITE_CONTINUE
;
635 if (sticky_keys_controller_
)
636 status
= sticky_keys_controller_
->RewriteScrollEvent(scroll_event
, &flags
);
637 if (status
== ui::EVENT_REWRITE_CONTINUE
)
639 ui::ScrollEvent
* rewritten_scroll_event
= new ui::ScrollEvent(scroll_event
);
640 rewritten_event
->reset(rewritten_scroll_event
);
641 rewritten_scroll_event
->set_flags(flags
);
643 ui::UpdateX11EventForFlags(rewritten_scroll_event
);
648 bool EventRewriter::RewriteModifierKeys(const ui::KeyEvent
& key_event
,
649 MutableKeyState
* state
) {
650 DCHECK(key_event
.type() == ui::ET_KEY_PRESSED
||
651 key_event
.type() == ui::ET_KEY_RELEASED
);
653 // Do nothing if we have just logged in as guest but have not restarted chrome
654 // process yet (so we are still on the login screen). In this situations we
655 // have no user profile so can not do anything useful.
656 // Note that currently, unlike other accounts, when user logs in as guest, we
657 // restart chrome process. In future this is to be changed.
658 // TODO(glotov): remove the following condition when we do not restart chrome
659 // when user logs in as guest.
660 // TODO(kpschoedel): check whether this is still necessary.
661 if (user_manager::UserManager::Get()->IsLoggedInAsGuest() &&
662 LoginDisplayHostImpl::default_host())
665 const PrefService
* pref_service
= GetPrefService();
669 MutableKeyState incoming
= *state
;
670 state
->flags
= ui::EF_NONE
;
671 int characteristic_flag
= ui::EF_NONE
;
672 bool exact_event
= false;
674 // First, remap the key code.
675 const ModifierRemapping
* remapped_key
= NULL
;
676 switch (incoming
.key
) {
677 // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent
678 // when Diamond key is pressed.
679 case ui::DomKey::F15
:
680 // When diamond key is not available, the configuration UI for Diamond
681 // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo
685 GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo
, *pref_service
);
686 // Default behavior of F15 is Control, even if --has-chromeos-diamond-key
687 // is absent, according to unit test comments.
689 DCHECK_EQ(ui::VKEY_CONTROL
, kModifierRemappingCtrl
->result
.key_code
);
690 remapped_key
= kModifierRemappingCtrl
;
692 // F15 is not a modifier key, so we need to track its state directly.
693 if (key_event
.type() == ui::ET_KEY_PRESSED
) {
694 int remapped_flag
= remapped_key
->flag
;
695 if (remapped_key
->remap_to
== input_method::kCapsLockKey
)
696 remapped_flag
|= ui::EF_CAPS_LOCK_DOWN
;
697 current_diamond_key_modifier_flags_
= remapped_flag
;
699 current_diamond_key_modifier_flags_
= ui::EF_NONE
;
702 // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock
703 // is pressed (with one exception: when
704 // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates
705 // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7).
706 case ui::DomKey::F16
:
707 characteristic_flag
= ui::EF_CAPS_LOCK_DOWN
;
709 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo
, *pref_service
);
712 characteristic_flag
= ui::EF_COMMAND_DOWN
;
713 // Rewrite Command-L/R key presses on an Apple keyboard to Control.
714 if (IsAppleKeyboard()) {
715 DCHECK_EQ(ui::VKEY_CONTROL
, kModifierRemappingCtrl
->result
.key_code
);
716 remapped_key
= kModifierRemappingCtrl
;
719 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo
, *pref_service
);
721 // Default behavior is Super key, hence don't remap the event if the pref
724 case ui::DomKey::CONTROL
:
725 characteristic_flag
= ui::EF_CONTROL_DOWN
;
727 GetRemappedKey(prefs::kLanguageRemapControlKeyTo
, *pref_service
);
729 case ui::DomKey::ALT
:
731 characteristic_flag
= ui::EF_ALT_DOWN
;
733 GetRemappedKey(prefs::kLanguageRemapAltKeyTo
, *pref_service
);
735 case ui::DomKey::ALT_GRAPH
:
736 // The Neo2 codes modifiers such that CapsLock appears as VKEY_ALTGR,
737 // but AltGraph (right Alt) also appears as VKEY_ALTGR in Neo2,
738 // as it does in other layouts. Neo2's "Mod3" is represented in
739 // EventFlags by a combination of AltGr+Mod3, while its "Mod4" is
741 if (IsISOLevel5ShiftUsedByCurrentInputMethod()) {
742 if (incoming
.code
== ui::DomCode::CAPS_LOCK
) {
743 characteristic_flag
= ui::EF_ALTGR_DOWN
| ui::EF_MOD3_DOWN
;
745 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo
, *pref_service
);
747 characteristic_flag
= ui::EF_ALTGR_DOWN
;
749 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo
, *pref_service
);
752 if (remapped_key
&& remapped_key
->result
.key_code
== ui::VKEY_CAPITAL
)
753 remapped_key
= kModifierRemappingNeoMod3
;
755 #if !defined(USE_X11)
756 case ui::DomKey::ALT_GRAPH_LATCH
:
757 if (key_event
.type() == ui::ET_KEY_PRESSED
) {
758 pressed_modifier_latches_
|= ui::EF_ALTGR_DOWN
;
760 pressed_modifier_latches_
&= ~ui::EF_ALTGR_DOWN
;
761 if (used_modifier_latches_
& ui::EF_ALTGR_DOWN
)
762 used_modifier_latches_
&= ~ui::EF_ALTGR_DOWN
;
764 latched_modifier_latches_
|= ui::EF_ALTGR_DOWN
;
766 // Rewrite to AltGraph. When this key is used like a regular modifier,
767 // the web-exposed result looks like a use of the regular modifier.
768 // When it's used as a latch, the web-exposed result is a vacuous
769 // modifier press-and-release, which should be harmless, but preserves
770 // the event for applications using the |code| (e.g. remoting).
771 state
->key
= ui::DomKey::ALT_GRAPH
;
772 state
->key_code
= ui::VKEY_ALTGR
;
781 state
->key_code
= remapped_key
->result
.key_code
;
782 state
->code
= remapped_key
->result
.code
;
783 state
->key
= remapped_key
->result
.key
;
784 incoming
.flags
|= characteristic_flag
;
785 characteristic_flag
= remapped_key
->flag
;
786 state
->code
= RelocateModifier(
787 state
->code
, ui::KeycodeConverter::DomCodeToLocation(incoming
.code
));
790 // Next, remap modifier bits.
792 GetRemappedModifierMasks(*pref_service
, key_event
, incoming
.flags
);
793 if (key_event
.type() == ui::ET_KEY_PRESSED
)
794 state
->flags
|= characteristic_flag
;
796 state
->flags
&= ~characteristic_flag
;
798 if (key_event
.type() == ui::ET_KEY_PRESSED
) {
799 if (!ui::KeycodeConverter::IsDomKeyForModifier(state
->key
)) {
800 used_modifier_latches_
|= pressed_modifier_latches_
;
801 latched_modifier_latches_
= ui::EF_NONE
;
803 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL.
804 if (state
->key_code
== ui::VKEY_CAPITAL
806 // ... but for X11, do nothing if the original key is ui::VKEY_CAPITAL
807 // (i.e. a Caps Lock key on an external keyboard is pressed) since X
808 // handles that itself.
809 && incoming
.key_code
!= ui::VKEY_CAPITAL
812 chromeos::input_method::ImeKeyboard
* ime_keyboard
=
813 ime_keyboard_for_testing_
814 ? ime_keyboard_for_testing_
815 : chromeos::input_method::InputMethodManager::Get()
817 ime_keyboard
->SetCapsLockEnabled(!ime_keyboard
->CapsLockIsEnabled());
823 void EventRewriter::RewriteNumPadKeys(const ui::KeyEvent
& key_event
,
824 MutableKeyState
* state
) {
825 DCHECK(key_event
.type() == ui::ET_KEY_PRESSED
||
826 key_event
.type() == ui::ET_KEY_RELEASED
);
827 static const struct NumPadRemapping
{
828 ui::KeyboardCode input_key_code
;
829 EventRewriter::MutableKeyState result
;
830 } kNumPadRemappings
[] = {
832 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'.'>::Character
,
835 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'0'>::Character
,
838 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'1'>::Character
,
841 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'2'>::Character
,
844 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'3'>::Character
,
847 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'4'>::Character
,
850 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'5'>::Character
,
853 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'6'>::Character
,
856 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'7'>::Character
,
859 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'8'>::Character
,
862 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::Constant
<'9'>::Character
,
864 for (const auto& map
: kNumPadRemappings
) {
865 if (state
->key_code
== map
.input_key_code
) {
866 if (ui::KeycodeConverter::DomCodeToLocation(state
->code
) ==
867 ui::DomKeyLocation::NUMPAD
) {
868 ApplyRemapping(map
.result
, state
);
875 void EventRewriter::RewriteExtendedKeys(const ui::KeyEvent
& key_event
,
876 MutableKeyState
* state
) {
877 DCHECK(key_event
.type() == ui::ET_KEY_PRESSED
||
878 key_event
.type() == ui::ET_KEY_RELEASED
);
879 MutableKeyState incoming
= *state
;
881 if ((incoming
.flags
& (ui::EF_COMMAND_DOWN
| ui::EF_ALT_DOWN
)) ==
882 (ui::EF_COMMAND_DOWN
| ui::EF_ALT_DOWN
)) {
883 // Allow Search to avoid rewriting extended keys.
884 // For these, we only remove the EF_COMMAND_DOWN flag.
885 static const KeyboardRemapping::Condition kAvoidRemappings
[] = {
887 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
, ui::VKEY_BACK
},
889 ui::EF_ALT_DOWN
| ui::EF_CONTROL_DOWN
| ui::EF_COMMAND_DOWN
,
892 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
, ui::VKEY_UP
},
894 ui::EF_ALT_DOWN
| ui::EF_CONTROL_DOWN
| ui::EF_COMMAND_DOWN
,
897 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
, ui::VKEY_DOWN
}};
898 for (const auto& condition
: kAvoidRemappings
) {
899 if (MatchKeyboardRemapping(*state
, condition
)) {
900 state
->flags
= incoming
.flags
& ~ui::EF_COMMAND_DOWN
;
906 if (incoming
.flags
& ui::EF_COMMAND_DOWN
) {
907 static const KeyboardRemapping kSearchRemappings
[] = {
908 {// Search+BackSpace -> Delete
909 {ui::EF_COMMAND_DOWN
, ui::VKEY_BACK
},
910 {ui::EF_NONE
, ui::DomCode::DEL
, ui::DomKey::DEL
, ui::VKEY_DELETE
}},
911 {// Search+Left -> Home
912 {ui::EF_COMMAND_DOWN
, ui::VKEY_LEFT
},
913 {ui::EF_NONE
, ui::DomCode::HOME
, ui::DomKey::HOME
, ui::VKEY_HOME
}},
914 {// Search+Up -> Prior (aka PageUp)
915 {ui::EF_COMMAND_DOWN
, ui::VKEY_UP
},
916 {ui::EF_NONE
, ui::DomCode::PAGE_UP
, ui::DomKey::PAGE_UP
,
918 {// Search+Right -> End
919 {ui::EF_COMMAND_DOWN
, ui::VKEY_RIGHT
},
920 {ui::EF_NONE
, ui::DomCode::END
, ui::DomKey::END
, ui::VKEY_END
}},
921 {// Search+Down -> Next (aka PageDown)
922 {ui::EF_COMMAND_DOWN
, ui::VKEY_DOWN
},
923 {ui::EF_NONE
, ui::DomCode::PAGE_DOWN
, ui::DomKey::PAGE_DOWN
,
925 {// Search+Period -> Insert
926 {ui::EF_COMMAND_DOWN
, ui::VKEY_OEM_PERIOD
},
927 {ui::EF_NONE
, ui::DomCode::INSERT
, ui::DomKey::INSERT
,
929 if (RewriteWithKeyboardRemappings(
930 kSearchRemappings
, arraysize(kSearchRemappings
), incoming
, state
)) {
935 if (incoming
.flags
& ui::EF_ALT_DOWN
) {
936 static const KeyboardRemapping kNonSearchRemappings
[] = {
937 {// Alt+BackSpace -> Delete
938 {ui::EF_ALT_DOWN
, ui::VKEY_BACK
},
939 {ui::EF_NONE
, ui::DomCode::DEL
, ui::DomKey::DEL
, ui::VKEY_DELETE
}},
940 {// Control+Alt+Up -> Home
941 {ui::EF_ALT_DOWN
| ui::EF_CONTROL_DOWN
, ui::VKEY_UP
},
942 {ui::EF_NONE
, ui::DomCode::HOME
, ui::DomKey::HOME
, ui::VKEY_HOME
}},
943 {// Alt+Up -> Prior (aka PageUp)
944 {ui::EF_ALT_DOWN
, ui::VKEY_UP
},
945 {ui::EF_NONE
, ui::DomCode::PAGE_UP
, ui::DomKey::PAGE_UP
,
947 {// Control+Alt+Down -> End
948 {ui::EF_ALT_DOWN
| ui::EF_CONTROL_DOWN
, ui::VKEY_DOWN
},
949 {ui::EF_NONE
, ui::DomCode::END
, ui::DomKey::END
, ui::VKEY_END
}},
950 {// Alt+Down -> Next (aka PageDown)
951 {ui::EF_ALT_DOWN
, ui::VKEY_DOWN
},
952 {ui::EF_NONE
, ui::DomCode::PAGE_DOWN
, ui::DomKey::PAGE_DOWN
,
954 if (RewriteWithKeyboardRemappings(kNonSearchRemappings
,
955 arraysize(kNonSearchRemappings
), incoming
,
962 void EventRewriter::RewriteFunctionKeys(const ui::KeyEvent
& key_event
,
963 MutableKeyState
* state
) {
964 CHECK(key_event
.type() == ui::ET_KEY_PRESSED
||
965 key_event
.type() == ui::ET_KEY_RELEASED
);
967 if ((state
->key_code
>= ui::VKEY_F1
) && (state
->key_code
<= ui::VKEY_F12
)) {
968 // By default the top row (F1-F12) keys are system keys for back, forward,
969 // brightness, volume, etc. However, windows for v2 apps can optionally
970 // request raw function keys for these keys.
971 bool top_row_keys_are_function_keys
= TopRowKeysAreFunctionKeys(key_event
);
972 bool search_is_pressed
= (state
->flags
& ui::EF_COMMAND_DOWN
) != 0;
974 // Search? Top Row Result
975 // ------- -------- ------
977 // No System Fn -> System
978 // Yes Fn Fn -> System
979 // Yes System Search+Fn -> Fn
980 if (top_row_keys_are_function_keys
== search_is_pressed
) {
981 // Rewrite the F1-F12 keys on a Chromebook keyboard to system keys.
982 static const KeyboardRemapping kFkeysToSystemKeys
[] = {
983 {{ui::EF_NONE
, ui::VKEY_F1
},
984 {ui::EF_NONE
, ui::DomCode::BROWSER_BACK
, ui::DomKey::BROWSER_BACK
,
985 ui::VKEY_BROWSER_BACK
}},
986 {{ui::EF_NONE
, ui::VKEY_F2
},
987 {ui::EF_NONE
, ui::DomCode::BROWSER_FORWARD
,
988 ui::DomKey::BROWSER_FORWARD
, ui::VKEY_BROWSER_FORWARD
}},
989 {{ui::EF_NONE
, ui::VKEY_F3
},
990 {ui::EF_NONE
, ui::DomCode::BROWSER_REFRESH
,
991 ui::DomKey::BROWSER_REFRESH
, ui::VKEY_BROWSER_REFRESH
}},
992 {{ui::EF_NONE
, ui::VKEY_F4
},
993 {ui::EF_NONE
, ui::DomCode::ZOOM_TOGGLE
, ui::DomKey::ZOOM_TOGGLE
,
994 ui::VKEY_MEDIA_LAUNCH_APP2
}},
995 {{ui::EF_NONE
, ui::VKEY_F5
},
996 {ui::EF_NONE
, ui::DomCode::SELECT_TASK
,
997 ui::DomKey::LAUNCH_MY_COMPUTER
, ui::VKEY_MEDIA_LAUNCH_APP1
}},
998 {{ui::EF_NONE
, ui::VKEY_F6
},
999 {ui::EF_NONE
, ui::DomCode::BRIGHTNESS_DOWN
,
1000 ui::DomKey::BRIGHTNESS_DOWN
, ui::VKEY_BRIGHTNESS_DOWN
}},
1001 {{ui::EF_NONE
, ui::VKEY_F7
},
1002 {ui::EF_NONE
, ui::DomCode::BRIGHTNESS_UP
, ui::DomKey::BRIGHTNESS_UP
,
1003 ui::VKEY_BRIGHTNESS_UP
}},
1004 {{ui::EF_NONE
, ui::VKEY_F8
},
1005 {ui::EF_NONE
, ui::DomCode::VOLUME_MUTE
, ui::DomKey::VOLUME_MUTE
,
1006 ui::VKEY_VOLUME_MUTE
}},
1007 {{ui::EF_NONE
, ui::VKEY_F9
},
1008 {ui::EF_NONE
, ui::DomCode::VOLUME_DOWN
, ui::DomKey::VOLUME_DOWN
,
1009 ui::VKEY_VOLUME_DOWN
}},
1010 {{ui::EF_NONE
, ui::VKEY_F10
},
1011 {ui::EF_NONE
, ui::DomCode::VOLUME_UP
, ui::DomKey::VOLUME_UP
,
1012 ui::VKEY_VOLUME_UP
}},
1014 MutableKeyState incoming_without_command
= *state
;
1015 incoming_without_command
.flags
&= ~ui::EF_COMMAND_DOWN
;
1016 if (RewriteWithKeyboardRemappings(kFkeysToSystemKeys
,
1017 arraysize(kFkeysToSystemKeys
),
1018 incoming_without_command
, state
)) {
1021 } else if (search_is_pressed
) {
1022 // Allow Search to avoid rewriting F1-F12.
1023 state
->flags
&= ~ui::EF_COMMAND_DOWN
;
1028 if (state
->flags
& ui::EF_COMMAND_DOWN
) {
1029 // Remap Search+<number> to F<number>.
1030 // We check the DOM3 |code| here instead of the VKEY, as these keys may
1031 // have different |KeyboardCode|s when modifiers are pressed, such as shift.
1032 static const struct {
1033 ui::DomCode input_dom_code
;
1034 EventRewriter::MutableKeyState result
;
1035 } kNumberKeysToFkeys
[] = {
1036 {ui::DomCode::DIGIT1
,
1037 {ui::EF_NONE
, ui::DomCode::F1
, ui::DomKey::F1
, ui::VKEY_F1
}},
1038 {ui::DomCode::DIGIT2
,
1039 {ui::EF_NONE
, ui::DomCode::F2
, ui::DomKey::F2
, ui::VKEY_F2
}},
1040 {ui::DomCode::DIGIT3
,
1041 {ui::EF_NONE
, ui::DomCode::F3
, ui::DomKey::F3
, ui::VKEY_F3
}},
1042 {ui::DomCode::DIGIT4
,
1043 {ui::EF_NONE
, ui::DomCode::F4
, ui::DomKey::F4
, ui::VKEY_F4
}},
1044 {ui::DomCode::DIGIT5
,
1045 {ui::EF_NONE
, ui::DomCode::F5
, ui::DomKey::F5
, ui::VKEY_F5
}},
1046 {ui::DomCode::DIGIT6
,
1047 {ui::EF_NONE
, ui::DomCode::F6
, ui::DomKey::F6
, ui::VKEY_F6
}},
1048 {ui::DomCode::DIGIT7
,
1049 {ui::EF_NONE
, ui::DomCode::F7
, ui::DomKey::F7
, ui::VKEY_F7
}},
1050 {ui::DomCode::DIGIT8
,
1051 {ui::EF_NONE
, ui::DomCode::F8
, ui::DomKey::F8
, ui::VKEY_F8
}},
1052 {ui::DomCode::DIGIT9
,
1053 {ui::EF_NONE
, ui::DomCode::F9
, ui::DomKey::F9
, ui::VKEY_F9
}},
1054 {ui::DomCode::DIGIT0
,
1055 {ui::EF_NONE
, ui::DomCode::F10
, ui::DomKey::F10
, ui::VKEY_F10
}},
1056 {ui::DomCode::MINUS
,
1057 {ui::EF_NONE
, ui::DomCode::F11
, ui::DomKey::F11
, ui::VKEY_F11
}},
1058 {ui::DomCode::EQUAL
,
1059 {ui::EF_NONE
, ui::DomCode::F12
, ui::DomKey::F12
, ui::VKEY_F12
}}};
1060 for (const auto& map
: kNumberKeysToFkeys
) {
1061 if (state
->code
== map
.input_dom_code
) {
1062 state
->flags
&= ~ui::EF_COMMAND_DOWN
;
1063 ApplyRemapping(map
.result
, state
);
1070 void EventRewriter::RewriteLocatedEvent(const ui::Event
& event
, int* flags
) {
1071 const PrefService
* pref_service
= GetPrefService();
1074 *flags
= GetRemappedModifierMasks(*pref_service
, event
, *flags
);
1077 int EventRewriter::RewriteModifierClick(const ui::MouseEvent
& mouse_event
,
1079 // Remap Alt+Button1 to Button3.
1080 const int kAltLeftButton
= (ui::EF_ALT_DOWN
| ui::EF_LEFT_MOUSE_BUTTON
);
1081 if (((*flags
& kAltLeftButton
) == kAltLeftButton
) &&
1082 ((mouse_event
.type() == ui::ET_MOUSE_PRESSED
) ||
1083 pressed_device_ids_
.count(mouse_event
.source_device_id()))) {
1084 *flags
&= ~kAltLeftButton
;
1085 *flags
|= ui::EF_RIGHT_MOUSE_BUTTON
;
1086 if (mouse_event
.type() == ui::ET_MOUSE_PRESSED
)
1087 pressed_device_ids_
.insert(mouse_event
.source_device_id());
1089 pressed_device_ids_
.erase(mouse_event
.source_device_id());
1090 return ui::EF_RIGHT_MOUSE_BUTTON
;
1095 EventRewriter::DeviceType
EventRewriter::KeyboardDeviceAddedInternal(
1097 const std::string
& device_name
,
1100 const DeviceType type
= GetDeviceType(device_name
, vendor_id
, product_id
);
1101 if (type
== kDeviceAppleKeyboard
) {
1102 VLOG(1) << "Apple keyboard '" << device_name
<< "' connected: "
1103 << "id=" << device_id
;
1104 } else if (type
== kDeviceHotrodRemote
) {
1105 VLOG(1) << "Hotrod remote '" << device_name
<< "' connected: "
1106 << "id=" << device_id
;
1107 } else if (type
== kDeviceVirtualCoreKeyboard
) {
1108 VLOG(1) << "Xorg virtual '" << device_name
<< "' connected: "
1109 << "id=" << device_id
;
1111 VLOG(1) << "Unknown keyboard '" << device_name
<< "' connected: "
1112 << "id=" << device_id
;
1114 // Always overwrite the existing device_id since the X server may reuse a
1115 // device id for an unattached device.
1116 device_id_to_type_
[device_id
] = type
;
1120 EventRewriter::DeviceType
EventRewriter::KeyboardDeviceAdded(int device_id
) {
1121 if (!ui::DeviceDataManager::HasInstance())
1122 return kDeviceUnknown
;
1123 const std::vector
<ui::KeyboardDevice
>& keyboards
=
1124 ui::DeviceDataManager::GetInstance()->keyboard_devices();
1125 for (const auto& keyboard
: keyboards
) {
1126 if (keyboard
.id
== device_id
) {
1127 return KeyboardDeviceAddedInternal(
1128 keyboard
.id
, keyboard
.name
, keyboard
.vendor_id
, keyboard
.product_id
);
1131 return kDeviceUnknown
;
1134 } // namespace chromeos