Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / events / ozone / evdev / keyboard_evdev.cc
blob58be1c5cfadfe50e8852fc6391f2c11b4b8e38a9
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"
19 namespace ui {
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"
27 #undef USB_KEYMAP
28 #undef USB_KEYMAP_DECLARATION
30 namespace {
32 const int kRepeatDelayMs = 500;
33 const int kRepeatIntervalMs = 50;
35 int EventFlagToEvdevModifier(int flag) {
36 switch (flag) {
37 case EF_CAPS_LOCK_DOWN:
38 return EVDEV_MODIFIER_CAPS_LOCK;
39 case EF_SHIFT_DOWN:
40 return EVDEV_MODIFIER_SHIFT;
41 case EF_CONTROL_DOWN:
42 return EVDEV_MODIFIER_CONTROL;
43 case EF_ALT_DOWN:
44 return EVDEV_MODIFIER_ALT;
45 case EF_ALTGR_DOWN:
46 return EVDEV_MODIFIER_ALTGR;
47 case EF_MOD3_DOWN:
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;
59 case EF_COMMAND_DOWN:
60 return EVDEV_MODIFIER_COMMAND;
61 default:
62 return EVDEV_MODIFIER_NONE;
66 } // namespace
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,
83 bool down,
84 bool suppress_auto_repeat,
85 base::TimeDelta timestamp,
86 int device_id) {
87 if (key > KEY_MAX)
88 return;
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)
130 return;
132 int modifier = EventFlagToEvdevModifier(modifier_flag);
133 if (modifier == EVDEV_MODIFIER_NONE)
134 return;
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);
145 else
146 modifiers_->UpdateModifier(modifier, down);
149 void KeyboardEvdev::UpdateKeyRepeat(unsigned int key,
150 bool down,
151 bool suppress_auto_repeat,
152 int device_id) {
153 if (!auto_repeat_enabled_ || suppress_auto_repeat)
154 StopKeyRepeat();
155 else if (key != repeat_key_ && down)
156 StartKeyRepeat(key, device_id);
157 else if (key == repeat_key_ && !down)
158 StopKeyRepeat();
161 void KeyboardEvdev::StartKeyRepeat(unsigned int key, int device_id) {
162 repeat_key_ = key;
163 repeat_device_id_ = device_id;
164 repeat_sequence_++;
166 ScheduleKeyRepeat(repeat_delay_);
169 void KeyboardEvdev::StopKeyRepeat() {
170 repeat_key_ = KEY_RESERVED;
171 repeat_sequence_++;
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_),
178 delay);
181 void KeyboardEvdev::OnRepeatTimeout(unsigned int sequence) {
182 if (repeat_sequence_ != sequence)
183 return;
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
187 // thread jank.
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)
195 return;
197 DispatchKey(repeat_key_, true /* down */, true /* repeat */,
198 EventTimeForNow(), repeat_device_id_);
200 ScheduleKeyRepeat(repeat_interval_);
203 void KeyboardEvdev::DispatchKey(unsigned int key,
204 bool down,
205 bool repeat,
206 base::TimeDelta timestamp,
207 int device_id) {
208 DomCode dom_code =
209 KeycodeConverter::NativeKeycodeToDomCode(EvdevCodeToNativeCode(key));
210 if (dom_code == DomCode::DOM_CODE_NONE)
211 return;
212 int flags = modifiers_->GetModifierFlags();
213 DomKey dom_key;
214 KeyboardCode key_code;
215 uint16 character;
216 uint32 platform_keycode = 0;
217 if (!keyboard_layout_engine_->Lookup(dom_code, flags, &dom_key, &character,
218 &key_code, &platform_keycode)) {
219 return;
221 if (!repeat) {
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);
233 } // namespace ui