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 "ui/events/ozone/evdev/keyboard_evdev.h"
7 #include "base/single_thread_task_runner.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "ui/events/event.h"
10 #include "ui/events/event_constants.h"
11 #include "ui/events/event_utils.h"
12 #include "ui/events/keycodes/dom/keycode_converter.h"
13 #include "ui/events/ozone/evdev/event_modifiers_evdev.h"
14 #include "ui/events/ozone/evdev/keyboard_util_evdev.h"
15 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
16 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
17 #include "ui/events/ozone/layout/layout_util.h"
21 // We can't include ui/events/keycodes/dom/dom_code.h here because of
22 // conflicts with preprocessor macros in <linux/input.h>, so we use the
23 // same underlying data with an additional prefix.
24 #define USB_KEYMAP(usb, xkb, win, mac, code, id) DOM_CODE_ ## id = usb
25 #define USB_KEYMAP_DECLARATION enum class DomCode
26 #include "ui/events/keycodes/dom/keycode_converter_data.inc"
28 #undef USB_KEYMAP_DECLARATION
32 const int kRepeatDelayMs
= 500;
33 const int kRepeatIntervalMs
= 50;
35 int EventFlagToEvdevModifier(int flag
) {
37 case EF_CAPS_LOCK_DOWN
:
38 return EVDEV_MODIFIER_CAPS_LOCK
;
40 return EVDEV_MODIFIER_SHIFT
;
42 return EVDEV_MODIFIER_CONTROL
;
44 return EVDEV_MODIFIER_ALT
;
46 return EVDEV_MODIFIER_ALTGR
;
48 return EVDEV_MODIFIER_MOD3
;
49 case EF_LEFT_MOUSE_BUTTON
:
50 return EVDEV_MODIFIER_LEFT_MOUSE_BUTTON
;
51 case EF_MIDDLE_MOUSE_BUTTON
:
52 return EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON
;
53 case EF_RIGHT_MOUSE_BUTTON
:
54 return EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON
;
55 case EF_BACK_MOUSE_BUTTON
:
56 return EVDEV_MODIFIER_BACK_MOUSE_BUTTON
;
57 case EF_FORWARD_MOUSE_BUTTON
:
58 return EVDEV_MODIFIER_FORWARD_MOUSE_BUTTON
;
60 return EVDEV_MODIFIER_COMMAND
;
62 return EVDEV_MODIFIER_NONE
;
68 KeyboardEvdev::KeyboardEvdev(EventModifiersEvdev
* modifiers
,
69 KeyboardLayoutEngine
* keyboard_layout_engine
,
70 const EventDispatchCallback
& callback
)
71 : callback_(callback
),
72 modifiers_(modifiers
),
73 keyboard_layout_engine_(keyboard_layout_engine
),
74 weak_ptr_factory_(this) {
75 repeat_delay_
= base::TimeDelta::FromMilliseconds(kRepeatDelayMs
);
76 repeat_interval_
= base::TimeDelta::FromMilliseconds(kRepeatIntervalMs
);
79 KeyboardEvdev::~KeyboardEvdev() {
82 void KeyboardEvdev::OnKeyChange(unsigned int key
,
84 bool suppress_auto_repeat
,
85 base::TimeDelta timestamp
,
90 bool was_down
= key_state_
.test(key
);
91 bool is_repeat
= down
&& was_down
;
92 if (!down
&& !was_down
)
93 return; // Key already released.
95 key_state_
.set(key
, down
);
96 UpdateKeyRepeat(key
, down
, suppress_auto_repeat
, device_id
);
97 DispatchKey(key
, down
, is_repeat
, timestamp
, device_id
);
100 void KeyboardEvdev::SetCapsLockEnabled(bool enabled
) {
101 modifiers_
->SetModifierLock(EVDEV_MODIFIER_CAPS_LOCK
, enabled
);
104 bool KeyboardEvdev::IsCapsLockEnabled() {
105 return (modifiers_
->GetModifierFlags() & EF_CAPS_LOCK_DOWN
) != 0;
108 bool KeyboardEvdev::IsAutoRepeatEnabled() {
109 return auto_repeat_enabled_
;
112 void KeyboardEvdev::SetAutoRepeatEnabled(bool enabled
) {
113 auto_repeat_enabled_
= enabled
;
116 void KeyboardEvdev::SetAutoRepeatRate(const base::TimeDelta
& delay
,
117 const base::TimeDelta
& interval
) {
118 repeat_delay_
= delay
;
119 repeat_interval_
= interval
;
122 void KeyboardEvdev::GetAutoRepeatRate(base::TimeDelta
* delay
,
123 base::TimeDelta
* interval
) {
124 *delay
= repeat_delay_
;
125 *interval
= repeat_interval_
;
128 void KeyboardEvdev::UpdateModifier(int modifier_flag
, bool down
) {
129 if (modifier_flag
== EF_NONE
)
132 int modifier
= EventFlagToEvdevModifier(modifier_flag
);
133 if (modifier
== EVDEV_MODIFIER_NONE
)
136 // TODO post-X11: Revise remapping to not use EF_MOD3_DOWN.
137 // Currently EF_MOD3_DOWN means that the CapsLock key is currently down,
138 // and EF_CAPS_LOCK_DOWN means the caps lock state is enabled (and the
139 // key may or may not be down, but usually isn't). There does need to
140 // to be two different flags, since the physical CapsLock key is subject
141 // to remapping, but the caps lock state (which can be triggered in a
142 // variety of ways) is not.
143 if (modifier
== EVDEV_MODIFIER_CAPS_LOCK
)
144 modifiers_
->UpdateModifier(EVDEV_MODIFIER_MOD3
, down
);
146 modifiers_
->UpdateModifier(modifier
, down
);
149 void KeyboardEvdev::UpdateKeyRepeat(unsigned int key
,
151 bool suppress_auto_repeat
,
153 if (!auto_repeat_enabled_
|| suppress_auto_repeat
)
155 else if (key
!= repeat_key_
&& down
)
156 StartKeyRepeat(key
, device_id
);
157 else if (key
== repeat_key_
&& !down
)
161 void KeyboardEvdev::StartKeyRepeat(unsigned int key
, int device_id
) {
163 repeat_device_id_
= device_id
;
166 ScheduleKeyRepeat(repeat_delay_
);
169 void KeyboardEvdev::StopKeyRepeat() {
170 repeat_key_
= KEY_RESERVED
;
174 void KeyboardEvdev::ScheduleKeyRepeat(const base::TimeDelta
& delay
) {
175 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
176 FROM_HERE
, base::Bind(&KeyboardEvdev::OnRepeatTimeout
,
177 weak_ptr_factory_
.GetWeakPtr(), repeat_sequence_
),
181 void KeyboardEvdev::OnRepeatTimeout(unsigned int sequence
) {
182 if (repeat_sequence_
!= sequence
)
185 // Post a task behind any pending key releases in the message loop
186 // FIFO. This ensures there's no spurious repeats during periods of UI
188 base::ThreadTaskRunnerHandle::Get()->PostTask(
189 FROM_HERE
, base::Bind(&KeyboardEvdev::OnRepeatCommit
,
190 weak_ptr_factory_
.GetWeakPtr(), repeat_sequence_
));
193 void KeyboardEvdev::OnRepeatCommit(unsigned int sequence
) {
194 if (repeat_sequence_
!= sequence
)
197 DispatchKey(repeat_key_
, true /* down */, true /* repeat */,
198 EventTimeForNow(), repeat_device_id_
);
200 ScheduleKeyRepeat(repeat_interval_
);
203 void KeyboardEvdev::DispatchKey(unsigned int key
,
206 base::TimeDelta timestamp
,
209 KeycodeConverter::NativeKeycodeToDomCode(EvdevCodeToNativeCode(key
));
210 if (dom_code
== DomCode::DOM_CODE_NONE
)
212 int flags
= modifiers_
->GetModifierFlags();
214 KeyboardCode key_code
;
216 uint32 platform_keycode
= 0;
217 if (!keyboard_layout_engine_
->Lookup(dom_code
, flags
, &dom_key
, &character
,
218 &key_code
, &platform_keycode
)) {
222 int flag
= ModifierDomKeyToEventFlag(dom_key
);
223 UpdateModifier(flag
, down
);
226 KeyEvent
event(down
? ET_KEY_PRESSED
: ET_KEY_RELEASED
, key_code
, dom_code
,
227 modifiers_
->GetModifierFlags(), dom_key
, character
, timestamp
);
228 event
.set_source_device_id(device_id
);
229 if (platform_keycode
)
230 event
.set_platform_keycode(platform_keycode
);
231 callback_
.Run(&event
);