OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "ui/events/ozone/evdev/keyboard_evdev.h" |
| 6 |
| 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" |
| 18 |
| 19 namespace ui { |
| 20 |
| 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 |
| 29 |
| 30 namespace { |
| 31 |
| 32 const int kRepeatDelayMs = 500; |
| 33 const int kRepeatIntervalMs = 50; |
| 34 |
| 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; |
| 63 } |
| 64 } |
| 65 |
| 66 } // namespace |
| 67 |
| 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); |
| 77 } |
| 78 |
| 79 KeyboardEvdev::~KeyboardEvdev() { |
| 80 } |
| 81 |
| 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; |
| 89 |
| 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. |
| 94 |
| 95 key_state_.set(key, down); |
| 96 UpdateKeyRepeat(key, down, suppress_auto_repeat, device_id); |
| 97 DispatchKey(key, down, is_repeat, timestamp, device_id); |
| 98 } |
| 99 |
| 100 void KeyboardEvdev::SetCapsLockEnabled(bool enabled) { |
| 101 modifiers_->SetModifierLock(EVDEV_MODIFIER_CAPS_LOCK, enabled); |
| 102 } |
| 103 |
| 104 bool KeyboardEvdev::IsCapsLockEnabled() { |
| 105 return (modifiers_->GetModifierFlags() & EF_CAPS_LOCK_DOWN) != 0; |
| 106 } |
| 107 |
| 108 bool KeyboardEvdev::IsAutoRepeatEnabled() { |
| 109 return auto_repeat_enabled_; |
| 110 } |
| 111 |
| 112 void KeyboardEvdev::SetAutoRepeatEnabled(bool enabled) { |
| 113 auto_repeat_enabled_ = enabled; |
| 114 } |
| 115 |
| 116 void KeyboardEvdev::SetAutoRepeatRate(const base::TimeDelta& delay, |
| 117 const base::TimeDelta& interval) { |
| 118 repeat_delay_ = delay; |
| 119 repeat_interval_ = interval; |
| 120 } |
| 121 |
| 122 void KeyboardEvdev::GetAutoRepeatRate(base::TimeDelta* delay, |
| 123 base::TimeDelta* interval) { |
| 124 *delay = repeat_delay_; |
| 125 *interval = repeat_interval_; |
| 126 } |
| 127 |
| 128 void KeyboardEvdev::UpdateModifier(int modifier_flag, bool down) { |
| 129 if (modifier_flag == EF_NONE) |
| 130 return; |
| 131 |
| 132 int modifier = EventFlagToEvdevModifier(modifier_flag); |
| 133 if (modifier == EVDEV_MODIFIER_NONE) |
| 134 return; |
| 135 |
| 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); |
| 147 } |
| 148 |
| 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(); |
| 159 } |
| 160 |
| 161 void KeyboardEvdev::StartKeyRepeat(unsigned int key, int device_id) { |
| 162 repeat_key_ = key; |
| 163 repeat_device_id_ = device_id; |
| 164 repeat_sequence_++; |
| 165 |
| 166 ScheduleKeyRepeat(repeat_delay_); |
| 167 } |
| 168 |
| 169 void KeyboardEvdev::StopKeyRepeat() { |
| 170 repeat_key_ = KEY_RESERVED; |
| 171 repeat_sequence_++; |
| 172 } |
| 173 |
| 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); |
| 179 } |
| 180 |
| 181 void KeyboardEvdev::OnRepeatTimeout(unsigned int sequence) { |
| 182 if (repeat_sequence_ != sequence) |
| 183 return; |
| 184 |
| 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_)); |
| 191 } |
| 192 |
| 193 void KeyboardEvdev::OnRepeatCommit(unsigned int sequence) { |
| 194 if (repeat_sequence_ != sequence) |
| 195 return; |
| 196 |
| 197 DispatchKey(repeat_key_, true /* down */, true /* repeat */, |
| 198 EventTimeForNow(), repeat_device_id_); |
| 199 |
| 200 ScheduleKeyRepeat(repeat_interval_); |
| 201 } |
| 202 |
| 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; |
| 220 } |
| 221 if (!repeat) { |
| 222 int flag = ModifierDomKeyToEventFlag(dom_key); |
| 223 UpdateModifier(flag, down); |
| 224 // X11 XKB, using the configuration as modified for ChromeOS, always sets |
| 225 // EF_MOD3_DOWN for the physical CapsLock key, even if the layout maps |
| 226 // it to something else, so we imitate this to make certain layouts (e.g. |
| 227 // German Neo2) work. crbug.com/495277 |
| 228 if (dom_code == DomCode::DOM_CODE_CAPS_LOCK) |
| 229 UpdateModifier(EF_MOD3_DOWN, down); |
| 230 } |
| 231 |
| 232 KeyEvent event(down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code, dom_code, |
| 233 modifiers_->GetModifierFlags(), dom_key, character, timestamp); |
| 234 event.set_source_device_id(device_id); |
| 235 if (platform_keycode) |
| 236 event.set_platform_keycode(platform_keycode); |
| 237 callback_.Run(&event); |
| 238 } |
| 239 } // namespace ui |
OLD | NEW |