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
),
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(
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
,
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
),
348 if ((event
.type() == ui::ET_MOUSE_PRESSED
) ||
349 (event
.type() == ui::ET_MOUSE_RELEASED
)) {
350 return RewriteMouseButtonEvent(static_cast<const ui::MouseEvent
&>(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
),
362 if (event
.IsScrollEvent()) {
363 return RewriteScrollEvent(static_cast<const ui::ScrollEvent
&>(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
);
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
);
398 if (iter
!= device_id_to_type_
.end())
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
406 if (type
== kDeviceVirtualCoreKeyboard
)
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
)
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.";
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
))
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
));
461 const ModifierRemapping
* remapped_key
= NULL
;
462 if (!(unmodified_flags
& kModifierRemappings
[i
].flag
))
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
;
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())
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
483 case ui::EF_MOD3_DOWN
| ui::EF_ALTGR_DOWN
:
484 if ((original_flags
& ui::EF_ALTGR_DOWN
) &&
485 IsISOLevel5ShiftUsedByCurrentInputMethod()) {
486 remapped_key
= kModifierRemappingNeoMod3
;
492 if (!remapped_key
&& kModifierRemappings
[i
].pref_name
) {
494 GetRemappedKey(kModifierRemappings
[i
].pref_name
, pref_service
);
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(),
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
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
,
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
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
) &&
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
)) &&
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
);
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
);
606 ui::UpdateX11EventForFlags(rewritten_mouse_event
);
608 if (changed_button
!= ui::EF_NONE
) {
609 rewritten_mouse_event
->set_changed_button_flags(changed_button
);
611 ui::UpdateX11EventForChangedButtonFlags(rewritten_mouse_event
);
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
);
636 ui::UpdateX11EventForFlags(rewritten_wheel_event
);
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
);
652 ui::UpdateX11EventForFlags(rewritten_touch_event
);
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
)
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
);
670 ui::UpdateX11EventForFlags(rewritten_scroll_event
);
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())
692 const PrefService
* pref_service
= GetPrefService();
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
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.
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
;
726 current_diamond_key_modifier_flags_
= ui::EF_NONE
;
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
;
736 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo
, *pref_service
);
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
;
746 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo
, *pref_service
);
748 // Default behavior is Super key, hence don't remap the event if the pref
751 case ui::DomKey::CONTROL
:
752 characteristic_flag
= ui::EF_CONTROL_DOWN
;
754 GetRemappedKey(prefs::kLanguageRemapControlKeyTo
, *pref_service
);
756 case ui::DomKey::ALT
:
758 characteristic_flag
= ui::EF_ALT_DOWN
;
760 GetRemappedKey(prefs::kLanguageRemapAltKeyTo
, *pref_service
);
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
768 if (IsISOLevel5ShiftUsedByCurrentInputMethod()) {
769 if (incoming
.code
== ui::DomCode::CAPS_LOCK
) {
770 characteristic_flag
= ui::EF_ALTGR_DOWN
| ui::EF_MOD3_DOWN
;
772 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo
, *pref_service
);
774 characteristic_flag
= ui::EF_ALTGR_DOWN
;
776 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo
, *pref_service
);
779 if (remapped_key
&& remapped_key
->result
.key_code
== ui::VKEY_CAPITAL
)
780 remapped_key
= kModifierRemappingNeoMod3
;
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
;
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
;
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
;
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.
820 GetRemappedModifierMasks(*pref_service
, key_event
, incoming
.flags
);
821 if (key_event
.type() == ui::ET_KEY_PRESSED
)
822 state
->flags
|= characteristic_flag
;
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
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
840 chromeos::input_method::ImeKeyboard
* ime_keyboard
=
841 ime_keyboard_for_testing_
842 ? ime_keyboard_for_testing_
843 : chromeos::input_method::InputMethodManager::Get()
845 ime_keyboard
->SetCapsLockEnabled(!ime_keyboard
->CapsLockIsEnabled());
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
,
861 ui::DomKey::CHARACTER
,
867 ui::DomKey::CHARACTER
,
873 ui::DomKey::CHARACTER
,
879 ui::DomKey::CHARACTER
,
885 ui::DomKey::CHARACTER
,
891 ui::DomKey::CHARACTER
,
897 ui::DomKey::CHARACTER
,
903 ui::DomKey::CHARACTER
,
909 ui::DomKey::CHARACTER
,
915 ui::DomKey::CHARACTER
,
921 ui::DomKey::CHARACTER
,
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
);
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
[] = {
947 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
,
950 ui::EF_ALT_DOWN
| ui::EF_CONTROL_DOWN
| ui::EF_COMMAND_DOWN
,
953 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
,
956 ui::EF_ALT_DOWN
| ui::EF_CONTROL_DOWN
| ui::EF_COMMAND_DOWN
,
959 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
,
961 for (const auto& condition
: kAvoidRemappings
) {
962 if (MatchKeyboardRemapping(*state
, condition
)) {
963 state
->flags
= incoming
.flags
& ~ui::EF_COMMAND_DOWN
;
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
},
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
},
984 ui::DomCode::PAGE_UP
,
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
},
994 ui::DomCode::PAGE_DOWN
,
995 ui::DomKey::PAGE_DOWN
,
998 {// Search+Period -> Insert
999 {ui::EF_COMMAND_DOWN
, ui::VKEY_OEM_PERIOD
},
1001 ui::DomCode::INSERT
,
1005 if (RewriteWithKeyboardRemappings(
1006 kSearchRemappings
, arraysize(kSearchRemappings
), incoming
, state
)) {
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
},
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
},
1026 ui::DomCode::PAGE_UP
,
1027 ui::DomKey::PAGE_UP
,
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
},
1036 ui::DomCode::PAGE_DOWN
,
1037 ui::DomKey::PAGE_DOWN
,
1040 if (RewriteWithKeyboardRemappings(kNonSearchRemappings
,
1041 arraysize(kNonSearchRemappings
), incoming
,
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 // ------- -------- ------
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
},
1071 ui::DomCode::BROWSER_BACK
,
1072 ui::DomKey::BROWSER_BACK
,
1074 ui::VKEY_BROWSER_BACK
}},
1075 {{ui::EF_NONE
, ui::VKEY_F2
},
1077 ui::DomCode::BROWSER_FORWARD
,
1078 ui::DomKey::BROWSER_FORWARD
,
1080 ui::VKEY_BROWSER_FORWARD
}},
1081 {{ui::EF_NONE
, ui::VKEY_F3
},
1083 ui::DomCode::BROWSER_REFRESH
,
1084 ui::DomKey::BROWSER_REFRESH
,
1086 ui::VKEY_BROWSER_REFRESH
}},
1087 {{ui::EF_NONE
, ui::VKEY_F4
},
1089 ui::DomCode::ZOOM_TOGGLE
,
1090 ui::DomKey::ZOOM_TOGGLE
,
1092 ui::VKEY_MEDIA_LAUNCH_APP2
}},
1093 {{ui::EF_NONE
, ui::VKEY_F5
},
1095 ui::DomCode::SELECT_TASK
,
1096 ui::DomKey::LAUNCH_MY_COMPUTER
,
1098 ui::VKEY_MEDIA_LAUNCH_APP1
}},
1099 {{ui::EF_NONE
, ui::VKEY_F6
},
1101 ui::DomCode::BRIGHTNESS_DOWN
,
1102 ui::DomKey::BRIGHTNESS_DOWN
,
1104 ui::VKEY_BRIGHTNESS_DOWN
}},
1105 {{ui::EF_NONE
, ui::VKEY_F7
},
1107 ui::DomCode::BRIGHTNESS_UP
,
1108 ui::DomKey::BRIGHTNESS_UP
,
1110 ui::VKEY_BRIGHTNESS_UP
}},
1111 {{ui::EF_NONE
, ui::VKEY_F8
},
1113 ui::DomCode::VOLUME_MUTE
,
1114 ui::DomKey::VOLUME_MUTE
,
1116 ui::VKEY_VOLUME_MUTE
}},
1117 {{ui::EF_NONE
, ui::VKEY_F9
},
1119 ui::DomCode::VOLUME_DOWN
,
1120 ui::DomKey::VOLUME_DOWN
,
1122 ui::VKEY_VOLUME_DOWN
}},
1123 {{ui::EF_NONE
, ui::VKEY_F10
},
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
)) {
1137 } else if (search_is_pressed
) {
1138 // Allow Search to avoid rewriting F1-F12.
1139 state
->flags
&= ~ui::EF_COMMAND_DOWN
;
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
);
1186 void EventRewriter::RewriteLocatedEvent(const ui::Event
& event
, int* flags
) {
1187 const PrefService
* pref_service
= GetPrefService();
1190 *flags
= GetRemappedModifierMasks(*pref_service
, event
, *flags
);
1193 int EventRewriter::RewriteModifierClick(const ui::MouseEvent
& mouse_event
,
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());
1205 pressed_device_ids_
.erase(mouse_event
.source_device_id());
1206 return ui::EF_RIGHT_MOUSE_BUTTON
;
1211 EventRewriter::DeviceType
EventRewriter::KeyboardDeviceAddedInternal(
1213 const std::string
& device_name
,
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
;
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
;
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