blob: 2b738cf2a565ad43ab0ee0e17136fac488c6b0d5 [file] [log] [blame]
// 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/key_event_converter_evdev.h"
#include <errno.h>
#include <linux/input.h>
#include "base/message_loop/message_loop.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/ozone/evdev/event_modifiers_evdev.h"
#include "ui/events/ozone/event_factory_ozone.h"
namespace ui {
namespace {
ui::KeyboardCode KeyboardCodeFromButton(unsigned int code) {
static const ui::KeyboardCode kLinuxBaseKeyMap[] = {
ui::VKEY_UNKNOWN, // KEY_RESERVED
ui::VKEY_ESCAPE, // KEY_ESC
ui::VKEY_1, // KEY_1
ui::VKEY_2, // KEY_2
ui::VKEY_3, // KEY_3
ui::VKEY_4, // KEY_4
ui::VKEY_5, // KEY_5
ui::VKEY_6, // KEY_6
ui::VKEY_7, // KEY_7
ui::VKEY_8, // KEY_8
ui::VKEY_9, // KEY_9
ui::VKEY_0, // KEY_0
ui::VKEY_OEM_MINUS, // KEY_MINUS
ui::VKEY_OEM_PLUS, // KEY_EQUAL
ui::VKEY_BACK, // KEY_BACKSPACE
ui::VKEY_TAB, // KEY_TAB
ui::VKEY_Q, // KEY_Q
ui::VKEY_W, // KEY_W
ui::VKEY_E, // KEY_E
ui::VKEY_R, // KEY_R
ui::VKEY_T, // KEY_T
ui::VKEY_Y, // KEY_Y
ui::VKEY_U, // KEY_U
ui::VKEY_I, // KEY_I
ui::VKEY_O, // KEY_O
ui::VKEY_P, // KEY_P
ui::VKEY_OEM_4, // KEY_LEFTBRACE
ui::VKEY_OEM_6, // KEY_RIGHTBRACE
ui::VKEY_RETURN, // KEY_ENTER
ui::VKEY_CONTROL, // KEY_LEFTCTRL
ui::VKEY_A, // KEY_A
ui::VKEY_S, // KEY_S
ui::VKEY_D, // KEY_D
ui::VKEY_F, // KEY_F
ui::VKEY_G, // KEY_G
ui::VKEY_H, // KEY_H
ui::VKEY_J, // KEY_J
ui::VKEY_K, // KEY_K
ui::VKEY_L, // KEY_L
ui::VKEY_OEM_1, // KEY_SEMICOLON
ui::VKEY_OEM_7, // KEY_APOSTROPHE
ui::VKEY_OEM_3, // KEY_GRAVE
ui::VKEY_SHIFT, // KEY_LEFTSHIFT
ui::VKEY_OEM_5, // KEY_BACKSLASH
ui::VKEY_Z, // KEY_Z
ui::VKEY_X, // KEY_X
ui::VKEY_C, // KEY_C
ui::VKEY_V, // KEY_V
ui::VKEY_B, // KEY_B
ui::VKEY_N, // KEY_N
ui::VKEY_M, // KEY_M
ui::VKEY_OEM_COMMA, // KEY_COMMA
ui::VKEY_OEM_PERIOD, // KEY_DOT
ui::VKEY_OEM_2, // KEY_SLASH
ui::VKEY_SHIFT, // KEY_RIGHTSHIFT
ui::VKEY_MULTIPLY, // KEY_KPASTERISK
ui::VKEY_MENU, // KEY_LEFTALT
ui::VKEY_SPACE, // KEY_SPACE
ui::VKEY_CAPITAL, // KEY_CAPSLOCK
ui::VKEY_F1, // KEY_F1
ui::VKEY_F2, // KEY_F2
ui::VKEY_F3, // KEY_F3
ui::VKEY_F4, // KEY_F4
ui::VKEY_F5, // KEY_F5
ui::VKEY_F6, // KEY_F6
ui::VKEY_F7, // KEY_F7
ui::VKEY_F8, // KEY_F8
ui::VKEY_F9, // KEY_F9
ui::VKEY_F10, // KEY_F10
ui::VKEY_NUMLOCK, // KEY_NUMLOCK
ui::VKEY_SCROLL, // KEY_SCROLLLOCK
ui::VKEY_NUMPAD7, // KEY_KP7
ui::VKEY_NUMPAD8, // KEY_KP8
ui::VKEY_NUMPAD9, // KEY_KP9
ui::VKEY_SUBTRACT, // KEY_KPMINUS
ui::VKEY_NUMPAD4, // KEY_KP4
ui::VKEY_NUMPAD5, // KEY_KP5
ui::VKEY_NUMPAD6, // KEY_KP6
ui::VKEY_ADD, // KEY_KPPLUS
ui::VKEY_NUMPAD1, // KEY_KP1
ui::VKEY_NUMPAD2, // KEY_KP2
ui::VKEY_NUMPAD3, // KEY_KP3
ui::VKEY_NUMPAD0, // KEY_KP0
ui::VKEY_DECIMAL, // KEY_KPDOT
ui::VKEY_UNKNOWN, // (unassigned)
ui::VKEY_DBE_DBCSCHAR, // KEY_ZENKAKUHANKAKU
ui::VKEY_OEM_102, // KEY_102ND
ui::VKEY_F11, // KEY_F11
ui::VKEY_F12, // KEY_F12
ui::VKEY_UNKNOWN, // KEY_RO
ui::VKEY_UNKNOWN, // KEY_KATAKANA
ui::VKEY_UNKNOWN, // KEY_HIRAGANA
ui::VKEY_CONVERT, // KEY_HENKAN
ui::VKEY_UNKNOWN, // KEY_KATAKANAHIRAGANA
ui::VKEY_NONCONVERT, // KEY_MUHENKAN
ui::VKEY_UNKNOWN, // KEY_KPJPCOMMA
ui::VKEY_RETURN, // KEY_KPENTER
ui::VKEY_CONTROL, // KEY_RIGHTCTRL
ui::VKEY_DIVIDE, // KEY_KPSLASH
ui::VKEY_PRINT, // KEY_SYSRQ
ui::VKEY_MENU, // KEY_RIGHTALT
ui::VKEY_RETURN, // KEY_LINEFEED
ui::VKEY_HOME, // KEY_HOME
ui::VKEY_UP, // KEY_UP
ui::VKEY_PRIOR, // KEY_PAGEUP
ui::VKEY_LEFT, // KEY_LEFT
ui::VKEY_RIGHT, // KEY_RIGHT
ui::VKEY_END, // KEY_END
ui::VKEY_DOWN, // KEY_DOWN
ui::VKEY_NEXT, // KEY_PAGEDOWN
ui::VKEY_INSERT, // KEY_INSERT
ui::VKEY_DELETE, // KEY_DELETE
ui::VKEY_UNKNOWN, // KEY_MACRO
ui::VKEY_VOLUME_MUTE, // KEY_MUTE
ui::VKEY_VOLUME_DOWN, // KEY_VOLUMEDOWN
ui::VKEY_VOLUME_UP, // KEY_VOLUMEUP
ui::VKEY_POWER, // KEY_POWER
ui::VKEY_OEM_PLUS, // KEY_KPEQUAL
ui::VKEY_UNKNOWN, // KEY_KPPLUSMINUS
ui::VKEY_PAUSE, // KEY_PAUSE
ui::VKEY_MEDIA_LAUNCH_APP1, // KEY_SCALE
ui::VKEY_DECIMAL, // KEY_KPCOMMA
ui::VKEY_HANGUL, // KEY_HANGEUL
ui::VKEY_HANJA, // KEY_HANJA
ui::VKEY_UNKNOWN, // KEY_YEN
ui::VKEY_LWIN, // KEY_LEFTMETA
ui::VKEY_RWIN, // KEY_RIGHTMETA
ui::VKEY_APPS, // KEY_COMPOSE
};
if (code < arraysize(kLinuxBaseKeyMap))
return kLinuxBaseKeyMap[code];
LOG(ERROR) << "Unknown key code: " << code;
return ui::VKEY_UNKNOWN;
}
int ModifierFromButton(unsigned int code) {
switch (code) {
case KEY_CAPSLOCK:
return EVDEV_MODIFIER_CAPS_LOCK;
case KEY_LEFTSHIFT:
case KEY_RIGHTSHIFT:
return EVDEV_MODIFIER_SHIFT;
case KEY_LEFTCTRL:
case KEY_RIGHTCTRL:
return EVDEV_MODIFIER_CONTROL;
case KEY_LEFTALT:
case KEY_RIGHTALT:
return EVDEV_MODIFIER_ALT;
case BTN_LEFT:
return EVDEV_MODIFIER_LEFT_MOUSE_BUTTON;
case BTN_MIDDLE:
return EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON;
case BTN_RIGHT:
return EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON;
case KEY_LEFTMETA:
case KEY_RIGHTMETA:
return EVDEV_MODIFIER_COMMAND;
default:
return EVDEV_MODIFIER_NONE;
}
}
bool IsLockButton(unsigned int code) { return code == KEY_CAPSLOCK; }
} // namespace
KeyEventConverterEvdev::KeyEventConverterEvdev(
int fd,
base::FilePath path,
EventModifiersEvdev* modifiers,
const EventDispatchCallback& callback)
: EventConverterEvdev(callback),
fd_(fd),
path_(path),
modifiers_(modifiers) {
// TODO(spang): Initialize modifiers using EVIOCGKEY.
}
KeyEventConverterEvdev::~KeyEventConverterEvdev() {
Stop();
close(fd_);
}
void KeyEventConverterEvdev::Start() {
base::MessageLoopForUI::current()->WatchFileDescriptor(
fd_, true, base::MessagePumpLibevent::WATCH_READ, &controller_, this);
}
void KeyEventConverterEvdev::Stop() {
controller_.StopWatchingFileDescriptor();
}
void KeyEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
input_event inputs[4];
ssize_t read_size = read(fd, inputs, sizeof(inputs));
if (read_size < 0) {
if (errno == EINTR || errno == EAGAIN)
return;
if (errno != ENODEV)
PLOG(ERROR) << "error reading device " << path_.value();
Stop();
return;
}
CHECK_EQ(read_size % sizeof(*inputs), 0u);
ProcessEvents(inputs, read_size / sizeof(*inputs));
}
void KeyEventConverterEvdev::OnFileCanWriteWithoutBlocking(int fd) {
NOTREACHED();
}
void KeyEventConverterEvdev::ProcessEvents(const input_event* inputs,
int count) {
for (int i = 0; i < count; ++i) {
const input_event& input = inputs[i];
if (input.type == EV_KEY) {
ConvertKeyEvent(input.code, input.value);
} else if (input.type == EV_SYN) {
// TODO(sadrul): Handle this case appropriately.
}
}
}
void KeyEventConverterEvdev::ConvertKeyEvent(int key, int value) {
int down = (value != 0);
int repeat = (value == 2);
int modifier = ModifierFromButton(key);
ui::KeyboardCode code = KeyboardCodeFromButton(key);
if (!repeat && (modifier != EVDEV_MODIFIER_NONE)) {
if (IsLockButton(key)) {
// Locking modifier keys: CapsLock.
modifiers_->UpdateModifierLock(modifier, down);
} else {
// Regular modifier keys: Shift, Ctrl, Alt, etc.
modifiers_->UpdateModifier(modifier, down);
}
}
int flags = modifiers_->GetModifierFlags();
KeyEvent key_event(
down ? ET_KEY_PRESSED : ET_KEY_RELEASED, code, flags, false);
DispatchEventToCallback(&key_event);
}
} // namespace ui