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
,
85 ui::DomCode::CONTROL_LEFT
,
89 {// kModifierRemappingNeoMod3 references this entry by index.
90 ui::EF_MOD3_DOWN
| ui::EF_ALTGR_DOWN
,
91 input_method::kNumModifierKeys
,
93 {ui::EF_MOD3_DOWN
| ui::EF_ALTGR_DOWN
,
94 ui::DomCode::CAPS_LOCK
,
95 ui::DomKey::ALT_GRAPH
,
99 input_method::kSearchKey
,
100 prefs::kLanguageRemapSearchKeyTo
,
101 {ui::EF_COMMAND_DOWN
,
102 ui::DomCode::OS_LEFT
,
107 input_method::kAltKey
,
108 prefs::kLanguageRemapAltKeyTo
,
110 ui::DomCode::ALT_LEFT
,
115 input_method::kVoidKey
,
117 {ui::EF_NONE
, ui::DomCode::NONE
, ui::DomKey::NONE
, 0, ui::VKEY_UNKNOWN
}},
119 input_method::kCapsLockKey
,
120 prefs::kLanguageRemapCapsLockKeyTo
,
122 ui::DomCode::CAPS_LOCK
,
123 ui::DomKey::CAPS_LOCK
,
127 input_method::kEscapeKey
,
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
];
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
))
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
,
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"))
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.
230 ui::KeyboardCode key_code
;
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
,
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
);
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
);
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
;
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
) {
320 EventRewriter::~EventRewriter() {
323 EventRewriter::DeviceType
EventRewriter::KeyboardDeviceAddedForTesting(
325 const std::string
& device_name
) {
326 // Tests must avoid XI2 reserved device IDs.
327 DCHECK((device_id
< 0) || (device_id
> 1));
328 return KeyboardDeviceAddedInternal(device_id
, device_name
, kUnknownVendorId
,
332 void EventRewriter::RewriteMouseButtonEventForTesting(
333 const ui::MouseEvent
& event
,
334 scoped_ptr
<ui::Event
>* rewritten_event
) {
335 RewriteMouseButtonEvent(event
, rewritten_event
);
338 ui::EventRewriteStatus
EventRewriter::RewriteEvent(
339 const ui::Event
& event
,
340 scoped_ptr
<ui::Event
>* rewritten_event
) {
341 if ((event
.type() == ui::ET_KEY_PRESSED
) ||
342 (event
.type() == ui::ET_KEY_RELEASED
)) {
343 return RewriteKeyEvent(static_cast<const ui::KeyEvent
&>(event
),
346 if ((event
.type() == ui::ET_MOUSE_PRESSED
) ||
347 (event
.type() == ui::ET_MOUSE_RELEASED
)) {
348 return RewriteMouseButtonEvent(static_cast<const ui::MouseEvent
&>(event
),
351 if (event
.type() == ui::ET_MOUSEWHEEL
) {
352 return RewriteMouseWheelEvent(
353 static_cast<const ui::MouseWheelEvent
&>(event
), rewritten_event
);
355 if ((event
.type() == ui::ET_TOUCH_PRESSED
) ||
356 (event
.type() == ui::ET_TOUCH_RELEASED
)) {
357 return RewriteTouchEvent(static_cast<const ui::TouchEvent
&>(event
),
360 if (event
.IsScrollEvent()) {
361 return RewriteScrollEvent(static_cast<const ui::ScrollEvent
&>(event
),
364 return ui::EVENT_REWRITE_CONTINUE
;
367 ui::EventRewriteStatus
EventRewriter::NextDispatchEvent(
368 const ui::Event
& last_event
,
369 scoped_ptr
<ui::Event
>* new_event
) {
370 if (sticky_keys_controller_
) {
371 // In the case of sticky keys, we know what the events obtained here are:
372 // modifier key releases that match the ones previously discarded. So, we
373 // know that they don't have to be passed through the post-sticky key
374 // rewriting phases, |RewriteExtendedKeys()| and |RewriteFunctionKeys()|,
375 // because those phases do nothing with modifier key releases.
376 return sticky_keys_controller_
->NextDispatchEvent(new_event
);
379 return ui::EVENT_REWRITE_CONTINUE
;
382 void EventRewriter::BuildRewrittenKeyEvent(
383 const ui::KeyEvent
& key_event
,
384 const MutableKeyState
& state
,
385 scoped_ptr
<ui::Event
>* rewritten_event
) {
386 ui::KeyEvent
* rewritten_key_event
= new ui::KeyEvent(
387 key_event
.type(), state
.key_code
, state
.code
, state
.flags
, state
.key
,
388 state
.character
, key_event
.time_stamp());
389 rewritten_event
->reset(rewritten_key_event
);
392 void EventRewriter::DeviceKeyPressedOrReleased(int device_id
) {
393 std::map
<int, DeviceType
>::const_iterator iter
=
394 device_id_to_type_
.find(device_id
);
396 if (iter
!= device_id_to_type_
.end())
399 type
= KeyboardDeviceAdded(device_id
);
401 // Ignore virtual Xorg keyboard (magic that generates key repeat
402 // events). Pretend that the previous real keyboard is the one that is still
404 if (type
== kDeviceVirtualCoreKeyboard
)
407 last_keyboard_device_id_
= device_id
;
410 const PrefService
* EventRewriter::GetPrefService() const {
411 if (pref_service_for_testing_
)
412 return pref_service_for_testing_
;
413 Profile
* profile
= ProfileManager::GetActiveUserProfile();
414 return profile
? profile
->GetPrefs() : NULL
;
417 bool EventRewriter::IsAppleKeyboard() const {
418 return IsLastKeyboardOfType(kDeviceAppleKeyboard
);
421 bool EventRewriter::IsHotrodRemote() const {
422 return IsLastKeyboardOfType(kDeviceHotrodRemote
);
425 bool EventRewriter::IsLastKeyboardOfType(DeviceType device_type
) const {
426 if (last_keyboard_device_id_
== ui::ED_UNKNOWN_DEVICE
)
429 // Check which device generated |event|.
430 std::map
<int, DeviceType
>::const_iterator iter
=
431 device_id_to_type_
.find(last_keyboard_device_id_
);
432 if (iter
== device_id_to_type_
.end()) {
433 LOG(ERROR
) << "Device ID " << last_keyboard_device_id_
<< " is unknown.";
437 const DeviceType type
= iter
->second
;
438 return type
== device_type
;
441 bool EventRewriter::TopRowKeysAreFunctionKeys(const ui::KeyEvent
& event
) const {
442 const PrefService
* prefs
= GetPrefService();
443 if (prefs
&& prefs
->FindPreference(prefs::kLanguageSendFunctionKeys
) &&
444 prefs
->GetBoolean(prefs::kLanguageSendFunctionKeys
))
447 ash::wm::WindowState
* state
= ash::wm::GetActiveWindowState();
448 return state
? state
->top_row_keys_are_function_keys() : false;
451 int EventRewriter::GetRemappedModifierMasks(const PrefService
& pref_service
,
452 const ui::Event
& event
,
453 int original_flags
) const {
454 int unmodified_flags
= original_flags
;
455 int rewritten_flags
= current_diamond_key_modifier_flags_
;
456 for (size_t i
= 0; unmodified_flags
&& (i
< arraysize(kModifierRemappings
));
458 const ModifierRemapping
* remapped_key
= NULL
;
459 if (!(unmodified_flags
& kModifierRemappings
[i
].flag
))
461 switch (kModifierRemappings
[i
].flag
) {
462 case ui::EF_COMMAND_DOWN
:
463 // Rewrite Command key presses on an Apple keyboard to Control.
464 if (IsAppleKeyboard()) {
465 DCHECK_EQ(ui::EF_CONTROL_DOWN
, kModifierRemappingCtrl
->flag
);
466 remapped_key
= kModifierRemappingCtrl
;
469 case ui::EF_MOD3_DOWN
:
470 // If EF_MOD3_DOWN is used by the current input method, leave it alone;
471 // it is not remappable.
472 if (IsISOLevel5ShiftUsedByCurrentInputMethod())
474 // Otherwise, Mod3Mask is set on X events when the Caps Lock key
475 // is down, but, if Caps Lock is remapped, CapsLock is NOT set,
476 // because pressing the key does not invoke caps lock. So, the
477 // kModifierRemappings[] table uses EF_MOD3_DOWN for the Caps
480 case ui::EF_MOD3_DOWN
| ui::EF_ALTGR_DOWN
:
481 if ((original_flags
& ui::EF_ALTGR_DOWN
) &&
482 IsISOLevel5ShiftUsedByCurrentInputMethod()) {
483 remapped_key
= kModifierRemappingNeoMod3
;
489 if (!remapped_key
&& kModifierRemappings
[i
].pref_name
) {
491 GetRemappedKey(kModifierRemappings
[i
].pref_name
, pref_service
);
494 unmodified_flags
&= ~kModifierRemappings
[i
].flag
;
495 rewritten_flags
|= remapped_key
->flag
;
498 return rewritten_flags
| unmodified_flags
;
501 ui::EventRewriteStatus
EventRewriter::RewriteKeyEvent(
502 const ui::KeyEvent
& key_event
,
503 scoped_ptr
<ui::Event
>* rewritten_event
) {
504 if (IsExtensionCommandRegistered(key_event
.key_code(), key_event
.flags()))
505 return ui::EVENT_REWRITE_CONTINUE
;
506 if (key_event
.source_device_id() != ui::ED_UNKNOWN_DEVICE
)
507 DeviceKeyPressedOrReleased(key_event
.source_device_id());
509 // Drop repeated keys from Hotrod remote.
510 if ((key_event
.flags() & ui::EF_IS_REPEAT
) &&
511 (key_event
.type() == ui::ET_KEY_PRESSED
) && IsHotrodRemote() &&
512 key_event
.key_code() != ui::VKEY_BACK
) {
513 return ui::EVENT_REWRITE_DISCARD
;
516 MutableKeyState state
= {key_event
.flags(),
518 key_event
.GetDomKey(),
519 key_event
.GetCharacter(),
520 key_event
.key_code()};
522 // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
524 if (!(key_event
.flags() & ui::EF_FINAL
)) {
525 RewriteModifierKeys(key_event
, &state
);
526 RewriteNumPadKeys(key_event
, &state
);
529 ui::EventRewriteStatus status
= ui::EVENT_REWRITE_CONTINUE
;
530 bool is_sticky_key_extension_command
= false;
531 if (sticky_keys_controller_
) {
532 status
= sticky_keys_controller_
->RewriteKeyEvent(key_event
, state
.key_code
,
534 if (status
== ui::EVENT_REWRITE_DISCARD
)
535 return ui::EVENT_REWRITE_DISCARD
;
536 is_sticky_key_extension_command
=
537 IsExtensionCommandRegistered(state
.key_code
, state
.flags
);
540 // If flags have changed, this may change the interpretation of the key,
541 // so reapply layout.
542 if (state
.flags
!= key_event
.flags())
543 SetMeaningForLayout(key_event
.type(), &state
);
545 // If sticky key rewrites the event, and it matches an extension command, do
546 // not further rewrite the event since it won't match the extension command
548 if (!is_sticky_key_extension_command
&& !(key_event
.flags() & ui::EF_FINAL
)) {
549 RewriteExtendedKeys(key_event
, &state
);
550 RewriteFunctionKeys(key_event
, &state
);
552 if ((key_event
.flags() == state
.flags
) &&
553 (key_event
.key_code() == state
.key_code
) &&
555 // TODO(kpschoedel): This test is present because several consumers of
556 // key events depend on having a native core X11 event, so we rewrite
557 // all XI2 key events (GenericEvent) into corresponding core X11 key
558 // events. Remove this when event consumers no longer care about
559 // native X11 event details (crbug.com/380349).
560 (!key_event
.HasNativeEvent() ||
561 (key_event
.native_event()->type
!= GenericEvent
)) &&
563 (status
== ui::EVENT_REWRITE_CONTINUE
)) {
564 return ui::EVENT_REWRITE_CONTINUE
;
566 // Sticky keys may have returned a result other than |EVENT_REWRITE_CONTINUE|,
567 // in which case we need to preserve that return status. Alternatively, we
568 // might be here because key_event changed, in which case we need to
569 // return |EVENT_REWRITE_REWRITTEN|.
570 if (status
== ui::EVENT_REWRITE_CONTINUE
)
571 status
= ui::EVENT_REWRITE_REWRITTEN
;
572 BuildRewrittenKeyEvent(key_event
, state
, rewritten_event
);
576 ui::EventRewriteStatus
EventRewriter::RewriteMouseButtonEvent(
577 const ui::MouseEvent
& mouse_event
,
578 scoped_ptr
<ui::Event
>* rewritten_event
) {
579 int flags
= mouse_event
.flags();
580 RewriteLocatedEvent(mouse_event
, &flags
);
581 ui::EventRewriteStatus status
= ui::EVENT_REWRITE_CONTINUE
;
582 if (sticky_keys_controller_
)
583 status
= sticky_keys_controller_
->RewriteMouseEvent(mouse_event
, &flags
);
584 int changed_button
= ui::EF_NONE
;
585 if ((mouse_event
.type() == ui::ET_MOUSE_PRESSED
) ||
586 (mouse_event
.type() == ui::ET_MOUSE_RELEASED
)) {
587 changed_button
= RewriteModifierClick(mouse_event
, &flags
);
589 if ((mouse_event
.flags() == flags
) &&
590 (status
== ui::EVENT_REWRITE_CONTINUE
)) {
591 return ui::EVENT_REWRITE_CONTINUE
;
593 if (status
== ui::EVENT_REWRITE_CONTINUE
)
594 status
= ui::EVENT_REWRITE_REWRITTEN
;
595 ui::MouseEvent
* rewritten_mouse_event
= new ui::MouseEvent(mouse_event
);
596 rewritten_event
->reset(rewritten_mouse_event
);
597 rewritten_mouse_event
->set_flags(flags
);
599 ui::UpdateX11EventForFlags(rewritten_mouse_event
);
601 if (changed_button
!= ui::EF_NONE
) {
602 rewritten_mouse_event
->set_changed_button_flags(changed_button
);
604 ui::UpdateX11EventForChangedButtonFlags(rewritten_mouse_event
);
610 ui::EventRewriteStatus
EventRewriter::RewriteMouseWheelEvent(
611 const ui::MouseWheelEvent
& wheel_event
,
612 scoped_ptr
<ui::Event
>* rewritten_event
) {
613 if (!sticky_keys_controller_
)
614 return ui::EVENT_REWRITE_CONTINUE
;
615 int flags
= wheel_event
.flags();
616 ui::EventRewriteStatus status
=
617 sticky_keys_controller_
->RewriteMouseEvent(wheel_event
, &flags
);
618 if ((wheel_event
.flags() == flags
) &&
619 (status
== ui::EVENT_REWRITE_CONTINUE
)) {
620 return ui::EVENT_REWRITE_CONTINUE
;
622 if (status
== ui::EVENT_REWRITE_CONTINUE
)
623 status
= ui::EVENT_REWRITE_REWRITTEN
;
624 ui::MouseWheelEvent
* rewritten_wheel_event
=
625 new ui::MouseWheelEvent(wheel_event
);
626 rewritten_event
->reset(rewritten_wheel_event
);
627 rewritten_wheel_event
->set_flags(flags
);
629 ui::UpdateX11EventForFlags(rewritten_wheel_event
);
634 ui::EventRewriteStatus
EventRewriter::RewriteTouchEvent(
635 const ui::TouchEvent
& touch_event
,
636 scoped_ptr
<ui::Event
>* rewritten_event
) {
637 int flags
= touch_event
.flags();
638 RewriteLocatedEvent(touch_event
, &flags
);
639 if (touch_event
.flags() == flags
)
640 return ui::EVENT_REWRITE_CONTINUE
;
641 ui::TouchEvent
* rewritten_touch_event
= new ui::TouchEvent(touch_event
);
642 rewritten_event
->reset(rewritten_touch_event
);
643 rewritten_touch_event
->set_flags(flags
);
645 ui::UpdateX11EventForFlags(rewritten_touch_event
);
647 return ui::EVENT_REWRITE_REWRITTEN
;
650 ui::EventRewriteStatus
EventRewriter::RewriteScrollEvent(
651 const ui::ScrollEvent
& scroll_event
,
652 scoped_ptr
<ui::Event
>* rewritten_event
) {
653 int flags
= scroll_event
.flags();
654 ui::EventRewriteStatus status
= ui::EVENT_REWRITE_CONTINUE
;
655 if (sticky_keys_controller_
)
656 status
= sticky_keys_controller_
->RewriteScrollEvent(scroll_event
, &flags
);
657 if (status
== ui::EVENT_REWRITE_CONTINUE
)
659 ui::ScrollEvent
* rewritten_scroll_event
= new ui::ScrollEvent(scroll_event
);
660 rewritten_event
->reset(rewritten_scroll_event
);
661 rewritten_scroll_event
->set_flags(flags
);
663 ui::UpdateX11EventForFlags(rewritten_scroll_event
);
668 void EventRewriter::RewriteModifierKeys(const ui::KeyEvent
& key_event
,
669 MutableKeyState
* state
) {
670 DCHECK(key_event
.type() == ui::ET_KEY_PRESSED
||
671 key_event
.type() == ui::ET_KEY_RELEASED
);
673 // Do nothing if we have just logged in as guest but have not restarted chrome
674 // process yet (so we are still on the login screen). In this situations we
675 // have no user profile so can not do anything useful.
676 // Note that currently, unlike other accounts, when user logs in as guest, we
677 // restart chrome process. In future this is to be changed.
678 // TODO(glotov): remove the following condition when we do not restart chrome
679 // when user logs in as guest.
680 // TODO(kpschoedel): check whether this is still necessary.
681 if (user_manager::UserManager::Get()->IsLoggedInAsGuest() &&
682 LoginDisplayHostImpl::default_host())
685 const PrefService
* pref_service
= GetPrefService();
689 MutableKeyState incoming
= *state
;
690 state
->flags
= ui::EF_NONE
;
691 int characteristic_flag
= ui::EF_NONE
;
693 // First, remap the key code.
694 const ModifierRemapping
* remapped_key
= NULL
;
695 switch (incoming
.key_code
) {
696 // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent
697 // when Diamond key is pressed.
699 // When diamond key is not available, the configuration UI for Diamond
700 // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo
704 GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo
, *pref_service
);
705 // Default behavior of F15 is Control, even if --has-chromeos-diamond-key
706 // is absent, according to unit test comments.
708 DCHECK_EQ(ui::VKEY_CONTROL
, kModifierRemappingCtrl
->result
.key_code
);
709 remapped_key
= kModifierRemappingCtrl
;
711 // F15 is not a modifier key, so we need to track its state directly.
712 if (key_event
.type() == ui::ET_KEY_PRESSED
) {
713 int remapped_flag
= remapped_key
->flag
;
714 if (remapped_key
->remap_to
== input_method::kCapsLockKey
)
715 remapped_flag
|= ui::EF_CAPS_LOCK_DOWN
;
716 current_diamond_key_modifier_flags_
= remapped_flag
;
718 current_diamond_key_modifier_flags_
= ui::EF_NONE
;
721 // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock
722 // is pressed (with one exception: when
723 // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates
724 // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7).
726 characteristic_flag
= ui::EF_CAPS_LOCK_DOWN
;
728 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo
, *pref_service
);
732 characteristic_flag
= ui::EF_COMMAND_DOWN
;
733 // Rewrite Command-L/R key presses on an Apple keyboard to Control.
734 if (IsAppleKeyboard()) {
735 DCHECK_EQ(ui::VKEY_CONTROL
, kModifierRemappingCtrl
->result
.key_code
);
736 remapped_key
= kModifierRemappingCtrl
;
739 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo
, *pref_service
);
741 // Default behavior is Super key, hence don't remap the event if the pref
744 case ui::VKEY_CONTROL
:
745 characteristic_flag
= ui::EF_CONTROL_DOWN
;
747 GetRemappedKey(prefs::kLanguageRemapControlKeyTo
, *pref_service
);
751 characteristic_flag
= ui::EF_ALT_DOWN
;
753 GetRemappedKey(prefs::kLanguageRemapAltKeyTo
, *pref_service
);
756 // The Neo2 codes modifiers such that CapsLock appears as VKEY_ALTGR,
757 // but AltGraph (right Alt) also appears as VKEY_ALTGR in Neo2,
758 // as it does in other layouts. Neo2's "Mod3" is represented in
759 // EventFlags by a combination of AltGr+Mod3, while its "Mod4" is
761 if (IsISOLevel5ShiftUsedByCurrentInputMethod()) {
762 if (incoming
.code
== ui::DomCode::CAPS_LOCK
) {
763 characteristic_flag
= ui::EF_ALTGR_DOWN
| ui::EF_MOD3_DOWN
;
765 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo
, *pref_service
);
767 characteristic_flag
= ui::EF_ALTGR_DOWN
;
769 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo
, *pref_service
);
772 if (remapped_key
&& remapped_key
->result
.key_code
== ui::VKEY_CAPITAL
)
773 remapped_key
= kModifierRemappingNeoMod3
;
780 state
->key_code
= remapped_key
->result
.key_code
;
781 state
->code
= remapped_key
->result
.code
;
782 state
->key
= remapped_key
->result
.key
;
783 state
->character
= remapped_key
->result
.character
;
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 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL.
799 if (key_event
.type() == ui::ET_KEY_PRESSED
&&
801 // ... but for X11, do nothing if the original key is ui::VKEY_CAPITAL
802 // (i.e. a Caps Lock key on an external keyboard is pressed) since X
803 // handles that itself.
804 incoming
.key_code
!= ui::VKEY_CAPITAL
&&
806 state
->key_code
== ui::VKEY_CAPITAL
) {
807 chromeos::input_method::ImeKeyboard
* ime_keyboard
=
808 ime_keyboard_for_testing_
809 ? ime_keyboard_for_testing_
810 : chromeos::input_method::InputMethodManager::Get()
812 ime_keyboard
->SetCapsLockEnabled(!ime_keyboard
->CapsLockIsEnabled());
816 void EventRewriter::RewriteNumPadKeys(const ui::KeyEvent
& key_event
,
817 MutableKeyState
* state
) {
818 DCHECK(key_event
.type() == ui::ET_KEY_PRESSED
||
819 key_event
.type() == ui::ET_KEY_RELEASED
);
820 static const struct NumPadRemapping
{
821 ui::KeyboardCode input_key_code
;
822 EventRewriter::MutableKeyState result
;
823 } kNumPadRemappings
[] = {{ui::VKEY_DELETE
,
826 ui::DomKey::CHARACTER
,
832 ui::DomKey::CHARACTER
,
838 ui::DomKey::CHARACTER
,
844 ui::DomKey::CHARACTER
,
850 ui::DomKey::CHARACTER
,
856 ui::DomKey::CHARACTER
,
862 ui::DomKey::CHARACTER
,
868 ui::DomKey::CHARACTER
,
874 ui::DomKey::CHARACTER
,
880 ui::DomKey::CHARACTER
,
886 ui::DomKey::CHARACTER
,
889 for (const auto& map
: kNumPadRemappings
) {
890 if (state
->key_code
== map
.input_key_code
) {
891 if (ui::KeycodeConverter::DomCodeToLocation(state
->code
) ==
892 ui::DomKeyLocation::NUMPAD
) {
893 ApplyRemapping(map
.result
, state
);
900 void EventRewriter::RewriteExtendedKeys(const ui::KeyEvent
& key_event
,
901 MutableKeyState
* state
) {
902 DCHECK(key_event
.type() == ui::ET_KEY_PRESSED
||
903 key_event
.type() == ui::ET_KEY_RELEASED
);
904 MutableKeyState incoming
= *state
;
906 if ((incoming
.flags
& (ui::EF_COMMAND_DOWN
| ui::EF_ALT_DOWN
)) ==
907 (ui::EF_COMMAND_DOWN
| ui::EF_ALT_DOWN
)) {
908 // Allow Search to avoid rewriting extended keys.
909 // For these, we only remove the EF_COMMAND_DOWN flag.
910 static const KeyboardRemapping::Condition kAvoidRemappings
[] = {
912 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
,
915 ui::EF_ALT_DOWN
| ui::EF_CONTROL_DOWN
| ui::EF_COMMAND_DOWN
,
918 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
,
921 ui::EF_ALT_DOWN
| ui::EF_CONTROL_DOWN
| ui::EF_COMMAND_DOWN
,
924 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
,
926 for (const auto& condition
: kAvoidRemappings
) {
927 if (MatchKeyboardRemapping(*state
, condition
)) {
928 state
->flags
= incoming
.flags
& ~ui::EF_COMMAND_DOWN
;
934 if (incoming
.flags
& ui::EF_COMMAND_DOWN
) {
935 static const KeyboardRemapping kSearchRemappings
[] = {
936 {// Search+BackSpace -> Delete
937 {ui::EF_COMMAND_DOWN
, ui::VKEY_BACK
},
943 {// Search+Left -> Home
944 {ui::EF_COMMAND_DOWN
, ui::VKEY_LEFT
},
945 {ui::EF_NONE
, ui::DomCode::HOME
, ui::DomKey::HOME
, 0, ui::VKEY_HOME
}},
946 {// Search+Up -> Prior (aka PageUp)
947 {ui::EF_COMMAND_DOWN
, ui::VKEY_UP
},
949 ui::DomCode::PAGE_UP
,
953 {// Search+Right -> End
954 {ui::EF_COMMAND_DOWN
, ui::VKEY_RIGHT
},
955 {ui::EF_NONE
, ui::DomCode::END
, ui::DomKey::END
, 0, ui::VKEY_END
}},
956 {// Search+Down -> Next (aka PageDown)
957 {ui::EF_COMMAND_DOWN
, ui::VKEY_DOWN
},
959 ui::DomCode::PAGE_DOWN
,
960 ui::DomKey::PAGE_DOWN
,
963 {// Search+Period -> Insert
964 {ui::EF_COMMAND_DOWN
, ui::VKEY_OEM_PERIOD
},
970 if (RewriteWithKeyboardRemappings(
971 kSearchRemappings
, arraysize(kSearchRemappings
), incoming
, state
)) {
976 if (incoming
.flags
& ui::EF_ALT_DOWN
) {
977 static const KeyboardRemapping kNonSearchRemappings
[] = {
978 {// Alt+BackSpace -> Delete
979 {ui::EF_ALT_DOWN
, ui::VKEY_BACK
},
985 {// Control+Alt+Up -> Home
986 {ui::EF_ALT_DOWN
| ui::EF_CONTROL_DOWN
, ui::VKEY_UP
},
987 {ui::EF_NONE
, ui::DomCode::HOME
, ui::DomKey::HOME
, 0, ui::VKEY_HOME
}},
988 {// Alt+Up -> Prior (aka PageUp)
989 {ui::EF_ALT_DOWN
, ui::VKEY_UP
},
991 ui::DomCode::PAGE_UP
,
995 {// Control+Alt+Down -> End
996 {ui::EF_ALT_DOWN
| ui::EF_CONTROL_DOWN
, ui::VKEY_DOWN
},
997 {ui::EF_NONE
, ui::DomCode::END
, ui::DomKey::END
, 0, ui::VKEY_END
}},
998 {// Alt+Down -> Next (aka PageDown)
999 {ui::EF_ALT_DOWN
, ui::VKEY_DOWN
},
1001 ui::DomCode::PAGE_DOWN
,
1002 ui::DomKey::PAGE_DOWN
,
1005 if (RewriteWithKeyboardRemappings(kNonSearchRemappings
,
1006 arraysize(kNonSearchRemappings
), incoming
,
1013 void EventRewriter::RewriteFunctionKeys(const ui::KeyEvent
& key_event
,
1014 MutableKeyState
* state
) {
1015 CHECK(key_event
.type() == ui::ET_KEY_PRESSED
||
1016 key_event
.type() == ui::ET_KEY_RELEASED
);
1018 if ((state
->key_code
>= ui::VKEY_F1
) && (state
->key_code
<= ui::VKEY_F12
)) {
1019 // By default the top row (F1-F12) keys are system keys for back, forward,
1020 // brightness, volume, etc. However, windows for v2 apps can optionally
1021 // request raw function keys for these keys.
1022 bool top_row_keys_are_function_keys
= TopRowKeysAreFunctionKeys(key_event
);
1023 bool search_is_pressed
= (state
->flags
& ui::EF_COMMAND_DOWN
) != 0;
1025 // Search? Top Row Result
1026 // ------- -------- ------
1028 // No System Fn -> System
1029 // Yes Fn Fn -> System
1030 // Yes System Search+Fn -> Fn
1031 if (top_row_keys_are_function_keys
== search_is_pressed
) {
1032 // Rewrite the F1-F12 keys on a Chromebook keyboard to system keys.
1033 static const KeyboardRemapping kFkeysToSystemKeys
[] = {
1034 {{ui::EF_NONE
, ui::VKEY_F1
},
1036 ui::DomCode::BROWSER_BACK
,
1037 ui::DomKey::BROWSER_BACK
,
1039 ui::VKEY_BROWSER_BACK
}},
1040 {{ui::EF_NONE
, ui::VKEY_F2
},
1042 ui::DomCode::BROWSER_FORWARD
,
1043 ui::DomKey::BROWSER_FORWARD
,
1045 ui::VKEY_BROWSER_FORWARD
}},
1046 {{ui::EF_NONE
, ui::VKEY_F3
},
1048 ui::DomCode::BROWSER_REFRESH
,
1049 ui::DomKey::BROWSER_REFRESH
,
1051 ui::VKEY_BROWSER_REFRESH
}},
1052 {{ui::EF_NONE
, ui::VKEY_F4
},
1054 ui::DomCode::ZOOM_TOGGLE
,
1055 ui::DomKey::ZOOM_TOGGLE
,
1057 ui::VKEY_MEDIA_LAUNCH_APP2
}},
1058 {{ui::EF_NONE
, ui::VKEY_F5
},
1060 ui::DomCode::SELECT_TASK
,
1061 ui::DomKey::LAUNCH_MY_COMPUTER
,
1063 ui::VKEY_MEDIA_LAUNCH_APP1
}},
1064 {{ui::EF_NONE
, ui::VKEY_F6
},
1066 ui::DomCode::BRIGHTNESS_DOWN
,
1067 ui::DomKey::BRIGHTNESS_DOWN
,
1069 ui::VKEY_BRIGHTNESS_DOWN
}},
1070 {{ui::EF_NONE
, ui::VKEY_F7
},
1072 ui::DomCode::BRIGHTNESS_UP
,
1073 ui::DomKey::BRIGHTNESS_UP
,
1075 ui::VKEY_BRIGHTNESS_UP
}},
1076 {{ui::EF_NONE
, ui::VKEY_F8
},
1078 ui::DomCode::VOLUME_MUTE
,
1079 ui::DomKey::VOLUME_MUTE
,
1081 ui::VKEY_VOLUME_MUTE
}},
1082 {{ui::EF_NONE
, ui::VKEY_F9
},
1084 ui::DomCode::VOLUME_DOWN
,
1085 ui::DomKey::VOLUME_DOWN
,
1087 ui::VKEY_VOLUME_DOWN
}},
1088 {{ui::EF_NONE
, ui::VKEY_F10
},
1090 ui::DomCode::VOLUME_UP
,
1091 ui::DomKey::VOLUME_UP
,
1093 ui::VKEY_VOLUME_UP
}},
1095 MutableKeyState incoming_without_command
= *state
;
1096 incoming_without_command
.flags
&= ~ui::EF_COMMAND_DOWN
;
1097 if (RewriteWithKeyboardRemappings(kFkeysToSystemKeys
,
1098 arraysize(kFkeysToSystemKeys
),
1099 incoming_without_command
, state
)) {
1102 } else if (search_is_pressed
) {
1103 // Allow Search to avoid rewriting F1-F12.
1104 state
->flags
&= ~ui::EF_COMMAND_DOWN
;
1109 if (state
->flags
& ui::EF_COMMAND_DOWN
) {
1110 // Remap Search+<number> to F<number>.
1111 // We check the DOM3 |code| here instead of the VKEY, as these keys may
1112 // have different |KeyboardCode|s when modifiers are pressed, such as shift.
1113 static const struct {
1114 ui::DomCode input_dom_code
;
1115 EventRewriter::MutableKeyState result
;
1116 } kNumberKeysToFkeys
[] = {
1117 {ui::DomCode::DIGIT1
,
1118 {ui::EF_NONE
, ui::DomCode::F1
, ui::DomKey::F1
, 0, ui::VKEY_F1
}},
1119 {ui::DomCode::DIGIT2
,
1120 {ui::EF_NONE
, ui::DomCode::F2
, ui::DomKey::F2
, 0, ui::VKEY_F2
}},
1121 {ui::DomCode::DIGIT3
,
1122 {ui::EF_NONE
, ui::DomCode::F3
, ui::DomKey::F3
, 0, ui::VKEY_F3
}},
1123 {ui::DomCode::DIGIT4
,
1124 {ui::EF_NONE
, ui::DomCode::F4
, ui::DomKey::F4
, 0, ui::VKEY_F4
}},
1125 {ui::DomCode::DIGIT5
,
1126 {ui::EF_NONE
, ui::DomCode::F5
, ui::DomKey::F5
, 0, ui::VKEY_F5
}},
1127 {ui::DomCode::DIGIT6
,
1128 {ui::EF_NONE
, ui::DomCode::F6
, ui::DomKey::F6
, 0, ui::VKEY_F6
}},
1129 {ui::DomCode::DIGIT7
,
1130 {ui::EF_NONE
, ui::DomCode::F7
, ui::DomKey::F7
, 0, ui::VKEY_F7
}},
1131 {ui::DomCode::DIGIT8
,
1132 {ui::EF_NONE
, ui::DomCode::F8
, ui::DomKey::F8
, 0, ui::VKEY_F8
}},
1133 {ui::DomCode::DIGIT9
,
1134 {ui::EF_NONE
, ui::DomCode::F9
, ui::DomKey::F9
, 0, ui::VKEY_F9
}},
1135 {ui::DomCode::DIGIT0
,
1136 {ui::EF_NONE
, ui::DomCode::F10
, ui::DomKey::F10
, 0, ui::VKEY_F10
}},
1137 {ui::DomCode::MINUS
,
1138 {ui::EF_NONE
, ui::DomCode::F11
, ui::DomKey::F11
, 0, ui::VKEY_F11
}},
1139 {ui::DomCode::EQUAL
,
1140 {ui::EF_NONE
, ui::DomCode::F12
, ui::DomKey::F12
, 0, ui::VKEY_F12
}}};
1141 for (const auto& map
: kNumberKeysToFkeys
) {
1142 if (state
->code
== map
.input_dom_code
) {
1143 state
->flags
&= ~ui::EF_COMMAND_DOWN
;
1144 ApplyRemapping(map
.result
, state
);
1151 void EventRewriter::RewriteLocatedEvent(const ui::Event
& event
, int* flags
) {
1152 const PrefService
* pref_service
= GetPrefService();
1155 *flags
= GetRemappedModifierMasks(*pref_service
, event
, *flags
);
1158 int EventRewriter::RewriteModifierClick(const ui::MouseEvent
& mouse_event
,
1160 // Remap Alt+Button1 to Button3.
1161 const int kAltLeftButton
= (ui::EF_ALT_DOWN
| ui::EF_LEFT_MOUSE_BUTTON
);
1162 if (((*flags
& kAltLeftButton
) == kAltLeftButton
) &&
1163 ((mouse_event
.type() == ui::ET_MOUSE_PRESSED
) ||
1164 pressed_device_ids_
.count(mouse_event
.source_device_id()))) {
1165 *flags
&= ~kAltLeftButton
;
1166 *flags
|= ui::EF_RIGHT_MOUSE_BUTTON
;
1167 if (mouse_event
.type() == ui::ET_MOUSE_PRESSED
)
1168 pressed_device_ids_
.insert(mouse_event
.source_device_id());
1170 pressed_device_ids_
.erase(mouse_event
.source_device_id());
1171 return ui::EF_RIGHT_MOUSE_BUTTON
;
1176 EventRewriter::DeviceType
EventRewriter::KeyboardDeviceAddedInternal(
1178 const std::string
& device_name
,
1181 const DeviceType type
= GetDeviceType(device_name
, vendor_id
, product_id
);
1182 if (type
== kDeviceAppleKeyboard
) {
1183 VLOG(1) << "Apple keyboard '" << device_name
<< "' connected: "
1184 << "id=" << device_id
;
1185 } else if (type
== kDeviceHotrodRemote
) {
1186 VLOG(1) << "Hotrod remote '" << device_name
<< "' connected: "
1187 << "id=" << device_id
;
1188 } else if (type
== kDeviceVirtualCoreKeyboard
) {
1189 VLOG(1) << "Xorg virtual '" << device_name
<< "' connected: "
1190 << "id=" << device_id
;
1192 VLOG(1) << "Unknown keyboard '" << device_name
<< "' connected: "
1193 << "id=" << device_id
;
1195 // Always overwrite the existing device_id since the X server may reuse a
1196 // device id for an unattached device.
1197 device_id_to_type_
[device_id
] = type
;
1201 EventRewriter::DeviceType
EventRewriter::KeyboardDeviceAdded(int device_id
) {
1202 if (!ui::DeviceDataManager::HasInstance())
1203 return kDeviceUnknown
;
1204 const std::vector
<ui::KeyboardDevice
>& keyboards
=
1205 ui::DeviceDataManager::GetInstance()->keyboard_devices();
1206 for (const auto& keyboard
: keyboards
) {
1207 if (keyboard
.id
== device_id
) {
1208 return KeyboardDeviceAddedInternal(
1209 keyboard
.id
, keyboard
.name
, keyboard
.vendor_id
, keyboard
.product_id
);
1212 return kDeviceUnknown
;
1215 } // namespace chromeos