| Index: ui/events/ozone/evdev/keyboard_evdev.cc
|
| diff --git a/ui/events/ozone/evdev/keyboard_evdev.cc b/ui/events/ozone/evdev/keyboard_evdev.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..93f5b3320b7f867e337ed1926b9d62ddcef283e2
|
| --- /dev/null
|
| +++ b/ui/events/ozone/evdev/keyboard_evdev.cc
|
| @@ -0,0 +1,239 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "ui/events/ozone/evdev/keyboard_evdev.h"
|
| +
|
| +#include "base/single_thread_task_runner.h"
|
| +#include "base/thread_task_runner_handle.h"
|
| +#include "ui/events/event.h"
|
| +#include "ui/events/event_constants.h"
|
| +#include "ui/events/event_utils.h"
|
| +#include "ui/events/keycodes/dom/keycode_converter.h"
|
| +#include "ui/events/ozone/evdev/event_modifiers_evdev.h"
|
| +#include "ui/events/ozone/evdev/keyboard_util_evdev.h"
|
| +#include "ui/events/ozone/layout/keyboard_layout_engine.h"
|
| +#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
|
| +#include "ui/events/ozone/layout/layout_util.h"
|
| +
|
| +namespace ui {
|
| +
|
| +// We can't include ui/events/keycodes/dom/dom_code.h here because of
|
| +// conflicts with preprocessor macros in <linux/input.h>, so we use the
|
| +// same underlying data with an additional prefix.
|
| +#define USB_KEYMAP(usb, xkb, win, mac, code, id) DOM_CODE_ ## id = usb
|
| +#define USB_KEYMAP_DECLARATION enum class DomCode
|
| +#include "ui/events/keycodes/dom/keycode_converter_data.inc"
|
| +#undef USB_KEYMAP
|
| +#undef USB_KEYMAP_DECLARATION
|
| +
|
| +namespace {
|
| +
|
| +const int kRepeatDelayMs = 500;
|
| +const int kRepeatIntervalMs = 50;
|
| +
|
| +int EventFlagToEvdevModifier(int flag) {
|
| + switch (flag) {
|
| + case EF_CAPS_LOCK_DOWN:
|
| + return EVDEV_MODIFIER_CAPS_LOCK;
|
| + case EF_SHIFT_DOWN:
|
| + return EVDEV_MODIFIER_SHIFT;
|
| + case EF_CONTROL_DOWN:
|
| + return EVDEV_MODIFIER_CONTROL;
|
| + case EF_ALT_DOWN:
|
| + return EVDEV_MODIFIER_ALT;
|
| + case EF_ALTGR_DOWN:
|
| + return EVDEV_MODIFIER_ALTGR;
|
| + case EF_MOD3_DOWN:
|
| + return EVDEV_MODIFIER_MOD3;
|
| + case EF_LEFT_MOUSE_BUTTON:
|
| + return EVDEV_MODIFIER_LEFT_MOUSE_BUTTON;
|
| + case EF_MIDDLE_MOUSE_BUTTON:
|
| + return EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON;
|
| + case EF_RIGHT_MOUSE_BUTTON:
|
| + return EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON;
|
| + case EF_BACK_MOUSE_BUTTON:
|
| + return EVDEV_MODIFIER_BACK_MOUSE_BUTTON;
|
| + case EF_FORWARD_MOUSE_BUTTON:
|
| + return EVDEV_MODIFIER_FORWARD_MOUSE_BUTTON;
|
| + case EF_COMMAND_DOWN:
|
| + return EVDEV_MODIFIER_COMMAND;
|
| + default:
|
| + return EVDEV_MODIFIER_NONE;
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +KeyboardEvdev::KeyboardEvdev(EventModifiersEvdev* modifiers,
|
| + KeyboardLayoutEngine* keyboard_layout_engine,
|
| + const EventDispatchCallback& callback)
|
| + : callback_(callback),
|
| + modifiers_(modifiers),
|
| + keyboard_layout_engine_(keyboard_layout_engine),
|
| + weak_ptr_factory_(this) {
|
| + repeat_delay_ = base::TimeDelta::FromMilliseconds(kRepeatDelayMs);
|
| + repeat_interval_ = base::TimeDelta::FromMilliseconds(kRepeatIntervalMs);
|
| +}
|
| +
|
| +KeyboardEvdev::~KeyboardEvdev() {
|
| +}
|
| +
|
| +void KeyboardEvdev::OnKeyChange(unsigned int key,
|
| + bool down,
|
| + bool suppress_auto_repeat,
|
| + base::TimeDelta timestamp,
|
| + int device_id) {
|
| + if (key > KEY_MAX)
|
| + return;
|
| +
|
| + bool was_down = key_state_.test(key);
|
| + bool is_repeat = down && was_down;
|
| + if (!down && !was_down)
|
| + return; // Key already released.
|
| +
|
| + key_state_.set(key, down);
|
| + UpdateKeyRepeat(key, down, suppress_auto_repeat, device_id);
|
| + DispatchKey(key, down, is_repeat, timestamp, device_id);
|
| +}
|
| +
|
| +void KeyboardEvdev::SetCapsLockEnabled(bool enabled) {
|
| + modifiers_->SetModifierLock(EVDEV_MODIFIER_CAPS_LOCK, enabled);
|
| +}
|
| +
|
| +bool KeyboardEvdev::IsCapsLockEnabled() {
|
| + return (modifiers_->GetModifierFlags() & EF_CAPS_LOCK_DOWN) != 0;
|
| +}
|
| +
|
| +bool KeyboardEvdev::IsAutoRepeatEnabled() {
|
| + return auto_repeat_enabled_;
|
| +}
|
| +
|
| +void KeyboardEvdev::SetAutoRepeatEnabled(bool enabled) {
|
| + auto_repeat_enabled_ = enabled;
|
| +}
|
| +
|
| +void KeyboardEvdev::SetAutoRepeatRate(const base::TimeDelta& delay,
|
| + const base::TimeDelta& interval) {
|
| + repeat_delay_ = delay;
|
| + repeat_interval_ = interval;
|
| +}
|
| +
|
| +void KeyboardEvdev::GetAutoRepeatRate(base::TimeDelta* delay,
|
| + base::TimeDelta* interval) {
|
| + *delay = repeat_delay_;
|
| + *interval = repeat_interval_;
|
| +}
|
| +
|
| +void KeyboardEvdev::UpdateModifier(int modifier_flag, bool down) {
|
| + if (modifier_flag == EF_NONE)
|
| + return;
|
| +
|
| + int modifier = EventFlagToEvdevModifier(modifier_flag);
|
| + if (modifier == EVDEV_MODIFIER_NONE)
|
| + return;
|
| +
|
| + // TODO post-X11: Revise remapping to not use EF_MOD3_DOWN.
|
| + // Currently EF_MOD3_DOWN means that the CapsLock key is currently down,
|
| + // and EF_CAPS_LOCK_DOWN means the caps lock state is enabled (and the
|
| + // key may or may not be down, but usually isn't). There does need to
|
| + // to be two different flags, since the physical CapsLock key is subject
|
| + // to remapping, but the caps lock state (which can be triggered in a
|
| + // variety of ways) is not.
|
| + if (modifier == EVDEV_MODIFIER_CAPS_LOCK)
|
| + modifiers_->UpdateModifier(EVDEV_MODIFIER_MOD3, down);
|
| + else
|
| + modifiers_->UpdateModifier(modifier, down);
|
| +}
|
| +
|
| +void KeyboardEvdev::UpdateKeyRepeat(unsigned int key,
|
| + bool down,
|
| + bool suppress_auto_repeat,
|
| + int device_id) {
|
| + if (!auto_repeat_enabled_ || suppress_auto_repeat)
|
| + StopKeyRepeat();
|
| + else if (key != repeat_key_ && down)
|
| + StartKeyRepeat(key, device_id);
|
| + else if (key == repeat_key_ && !down)
|
| + StopKeyRepeat();
|
| +}
|
| +
|
| +void KeyboardEvdev::StartKeyRepeat(unsigned int key, int device_id) {
|
| + repeat_key_ = key;
|
| + repeat_device_id_ = device_id;
|
| + repeat_sequence_++;
|
| +
|
| + ScheduleKeyRepeat(repeat_delay_);
|
| +}
|
| +
|
| +void KeyboardEvdev::StopKeyRepeat() {
|
| + repeat_key_ = KEY_RESERVED;
|
| + repeat_sequence_++;
|
| +}
|
| +
|
| +void KeyboardEvdev::ScheduleKeyRepeat(const base::TimeDelta& delay) {
|
| + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
|
| + FROM_HERE, base::Bind(&KeyboardEvdev::OnRepeatTimeout,
|
| + weak_ptr_factory_.GetWeakPtr(), repeat_sequence_),
|
| + delay);
|
| +}
|
| +
|
| +void KeyboardEvdev::OnRepeatTimeout(unsigned int sequence) {
|
| + if (repeat_sequence_ != sequence)
|
| + return;
|
| +
|
| + // Post a task behind any pending key releases in the message loop
|
| + // FIFO. This ensures there's no spurious repeats during periods of UI
|
| + // thread jank.
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::Bind(&KeyboardEvdev::OnRepeatCommit,
|
| + weak_ptr_factory_.GetWeakPtr(), repeat_sequence_));
|
| +}
|
| +
|
| +void KeyboardEvdev::OnRepeatCommit(unsigned int sequence) {
|
| + if (repeat_sequence_ != sequence)
|
| + return;
|
| +
|
| + DispatchKey(repeat_key_, true /* down */, true /* repeat */,
|
| + EventTimeForNow(), repeat_device_id_);
|
| +
|
| + ScheduleKeyRepeat(repeat_interval_);
|
| +}
|
| +
|
| +void KeyboardEvdev::DispatchKey(unsigned int key,
|
| + bool down,
|
| + bool repeat,
|
| + base::TimeDelta timestamp,
|
| + int device_id) {
|
| + DomCode dom_code =
|
| + KeycodeConverter::NativeKeycodeToDomCode(EvdevCodeToNativeCode(key));
|
| + if (dom_code == DomCode::DOM_CODE_NONE)
|
| + return;
|
| + int flags = modifiers_->GetModifierFlags();
|
| + DomKey dom_key;
|
| + KeyboardCode key_code;
|
| + uint16 character;
|
| + uint32 platform_keycode = 0;
|
| + if (!keyboard_layout_engine_->Lookup(dom_code, flags, &dom_key, &character,
|
| + &key_code, &platform_keycode)) {
|
| + return;
|
| + }
|
| + if (!repeat) {
|
| + int flag = ModifierDomKeyToEventFlag(dom_key);
|
| + UpdateModifier(flag, down);
|
| + // X11 XKB, using the configuration as modified for ChromeOS, always sets
|
| + // EF_MOD3_DOWN for the physical CapsLock key, even if the layout maps
|
| + // it to something else, so we imitate this to make certain layouts (e.g.
|
| + // German Neo2) work. crbug.com/495277
|
| + if (dom_code == DomCode::DOM_CODE_CAPS_LOCK)
|
| + UpdateModifier(EF_MOD3_DOWN, down);
|
| + }
|
| +
|
| + KeyEvent event(down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code, dom_code,
|
| + modifiers_->GetModifierFlags(), dom_key, character, timestamp);
|
| + event.set_source_device_id(device_id);
|
| + if (platform_keycode)
|
| + event.set_platform_keycode(platform_keycode);
|
| + callback_.Run(&event);
|
| +}
|
| +} // namespace ui
|
|
|