Home | History | Annotate | Download | only in evdev
      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/key_event_converter_evdev.h"
      6 
      7 #include <errno.h>
      8 #include <linux/input.h>
      9 
     10 #include "base/message_loop/message_loop.h"
     11 #include "ui/events/event.h"
     12 #include "ui/events/keycodes/dom4/keycode_converter.h"
     13 #include "ui/events/keycodes/keyboard_codes.h"
     14 #include "ui/events/ozone/evdev/event_modifiers_evdev.h"
     15 
     16 namespace ui {
     17 
     18 namespace {
     19 
     20 const int kXkbKeycodeOffset = 8;
     21 
     22 ui::KeyboardCode KeyboardCodeFromButton(unsigned int code) {
     23   static const ui::KeyboardCode kLinuxBaseKeyMap[] = {
     24       ui::VKEY_UNKNOWN,            // KEY_RESERVED
     25       ui::VKEY_ESCAPE,             // KEY_ESC
     26       ui::VKEY_1,                  // KEY_1
     27       ui::VKEY_2,                  // KEY_2
     28       ui::VKEY_3,                  // KEY_3
     29       ui::VKEY_4,                  // KEY_4
     30       ui::VKEY_5,                  // KEY_5
     31       ui::VKEY_6,                  // KEY_6
     32       ui::VKEY_7,                  // KEY_7
     33       ui::VKEY_8,                  // KEY_8
     34       ui::VKEY_9,                  // KEY_9
     35       ui::VKEY_0,                  // KEY_0
     36       ui::VKEY_OEM_MINUS,          // KEY_MINUS
     37       ui::VKEY_OEM_PLUS,           // KEY_EQUAL
     38       ui::VKEY_BACK,               // KEY_BACKSPACE
     39       ui::VKEY_TAB,                // KEY_TAB
     40       ui::VKEY_Q,                  // KEY_Q
     41       ui::VKEY_W,                  // KEY_W
     42       ui::VKEY_E,                  // KEY_E
     43       ui::VKEY_R,                  // KEY_R
     44       ui::VKEY_T,                  // KEY_T
     45       ui::VKEY_Y,                  // KEY_Y
     46       ui::VKEY_U,                  // KEY_U
     47       ui::VKEY_I,                  // KEY_I
     48       ui::VKEY_O,                  // KEY_O
     49       ui::VKEY_P,                  // KEY_P
     50       ui::VKEY_OEM_4,              // KEY_LEFTBRACE
     51       ui::VKEY_OEM_6,              // KEY_RIGHTBRACE
     52       ui::VKEY_RETURN,             // KEY_ENTER
     53       ui::VKEY_CONTROL,            // KEY_LEFTCTRL
     54       ui::VKEY_A,                  // KEY_A
     55       ui::VKEY_S,                  // KEY_S
     56       ui::VKEY_D,                  // KEY_D
     57       ui::VKEY_F,                  // KEY_F
     58       ui::VKEY_G,                  // KEY_G
     59       ui::VKEY_H,                  // KEY_H
     60       ui::VKEY_J,                  // KEY_J
     61       ui::VKEY_K,                  // KEY_K
     62       ui::VKEY_L,                  // KEY_L
     63       ui::VKEY_OEM_1,              // KEY_SEMICOLON
     64       ui::VKEY_OEM_7,              // KEY_APOSTROPHE
     65       ui::VKEY_OEM_3,              // KEY_GRAVE
     66       ui::VKEY_SHIFT,              // KEY_LEFTSHIFT
     67       ui::VKEY_OEM_5,              // KEY_BACKSLASH
     68       ui::VKEY_Z,                  // KEY_Z
     69       ui::VKEY_X,                  // KEY_X
     70       ui::VKEY_C,                  // KEY_C
     71       ui::VKEY_V,                  // KEY_V
     72       ui::VKEY_B,                  // KEY_B
     73       ui::VKEY_N,                  // KEY_N
     74       ui::VKEY_M,                  // KEY_M
     75       ui::VKEY_OEM_COMMA,          // KEY_COMMA
     76       ui::VKEY_OEM_PERIOD,         // KEY_DOT
     77       ui::VKEY_OEM_2,              // KEY_SLASH
     78       ui::VKEY_SHIFT,              // KEY_RIGHTSHIFT
     79       ui::VKEY_MULTIPLY,           // KEY_KPASTERISK
     80       ui::VKEY_MENU,               // KEY_LEFTALT
     81       ui::VKEY_SPACE,              // KEY_SPACE
     82       ui::VKEY_CAPITAL,            // KEY_CAPSLOCK
     83       ui::VKEY_F1,                 // KEY_F1
     84       ui::VKEY_F2,                 // KEY_F2
     85       ui::VKEY_F3,                 // KEY_F3
     86       ui::VKEY_F4,                 // KEY_F4
     87       ui::VKEY_F5,                 // KEY_F5
     88       ui::VKEY_F6,                 // KEY_F6
     89       ui::VKEY_F7,                 // KEY_F7
     90       ui::VKEY_F8,                 // KEY_F8
     91       ui::VKEY_F9,                 // KEY_F9
     92       ui::VKEY_F10,                // KEY_F10
     93       ui::VKEY_NUMLOCK,            // KEY_NUMLOCK
     94       ui::VKEY_SCROLL,             // KEY_SCROLLLOCK
     95       ui::VKEY_NUMPAD7,            // KEY_KP7
     96       ui::VKEY_NUMPAD8,            // KEY_KP8
     97       ui::VKEY_NUMPAD9,            // KEY_KP9
     98       ui::VKEY_SUBTRACT,           // KEY_KPMINUS
     99       ui::VKEY_NUMPAD4,            // KEY_KP4
    100       ui::VKEY_NUMPAD5,            // KEY_KP5
    101       ui::VKEY_NUMPAD6,            // KEY_KP6
    102       ui::VKEY_ADD,                // KEY_KPPLUS
    103       ui::VKEY_NUMPAD1,            // KEY_KP1
    104       ui::VKEY_NUMPAD2,            // KEY_KP2
    105       ui::VKEY_NUMPAD3,            // KEY_KP3
    106       ui::VKEY_NUMPAD0,            // KEY_KP0
    107       ui::VKEY_DECIMAL,            // KEY_KPDOT
    108       ui::VKEY_UNKNOWN,            // (unassigned)
    109       ui::VKEY_DBE_DBCSCHAR,       // KEY_ZENKAKUHANKAKU
    110       ui::VKEY_OEM_102,            // KEY_102ND
    111       ui::VKEY_F11,                // KEY_F11
    112       ui::VKEY_F12,                // KEY_F12
    113       ui::VKEY_UNKNOWN,            // KEY_RO
    114       ui::VKEY_UNKNOWN,            // KEY_KATAKANA
    115       ui::VKEY_UNKNOWN,            // KEY_HIRAGANA
    116       ui::VKEY_CONVERT,            // KEY_HENKAN
    117       ui::VKEY_UNKNOWN,            // KEY_KATAKANAHIRAGANA
    118       ui::VKEY_NONCONVERT,         // KEY_MUHENKAN
    119       ui::VKEY_UNKNOWN,            // KEY_KPJPCOMMA
    120       ui::VKEY_RETURN,             // KEY_KPENTER
    121       ui::VKEY_CONTROL,            // KEY_RIGHTCTRL
    122       ui::VKEY_DIVIDE,             // KEY_KPSLASH
    123       ui::VKEY_PRINT,              // KEY_SYSRQ
    124       ui::VKEY_MENU,               // KEY_RIGHTALT
    125       ui::VKEY_RETURN,             // KEY_LINEFEED
    126       ui::VKEY_HOME,               // KEY_HOME
    127       ui::VKEY_UP,                 // KEY_UP
    128       ui::VKEY_PRIOR,              // KEY_PAGEUP
    129       ui::VKEY_LEFT,               // KEY_LEFT
    130       ui::VKEY_RIGHT,              // KEY_RIGHT
    131       ui::VKEY_END,                // KEY_END
    132       ui::VKEY_DOWN,               // KEY_DOWN
    133       ui::VKEY_NEXT,               // KEY_PAGEDOWN
    134       ui::VKEY_INSERT,             // KEY_INSERT
    135       ui::VKEY_DELETE,             // KEY_DELETE
    136       ui::VKEY_UNKNOWN,            // KEY_MACRO
    137       ui::VKEY_VOLUME_MUTE,        // KEY_MUTE
    138       ui::VKEY_VOLUME_DOWN,        // KEY_VOLUMEDOWN
    139       ui::VKEY_VOLUME_UP,          // KEY_VOLUMEUP
    140       ui::VKEY_POWER,              // KEY_POWER
    141       ui::VKEY_OEM_PLUS,           // KEY_KPEQUAL
    142       ui::VKEY_UNKNOWN,            // KEY_KPPLUSMINUS
    143       ui::VKEY_PAUSE,              // KEY_PAUSE
    144       ui::VKEY_MEDIA_LAUNCH_APP1,  // KEY_SCALE
    145       ui::VKEY_DECIMAL,            // KEY_KPCOMMA
    146       ui::VKEY_HANGUL,             // KEY_HANGEUL
    147       ui::VKEY_HANJA,              // KEY_HANJA
    148       ui::VKEY_UNKNOWN,            // KEY_YEN
    149       ui::VKEY_LWIN,               // KEY_LEFTMETA
    150       ui::VKEY_RWIN,               // KEY_RIGHTMETA
    151       ui::VKEY_APPS,               // KEY_COMPOSE
    152   };
    153 
    154   if (code < arraysize(kLinuxBaseKeyMap))
    155     return kLinuxBaseKeyMap[code];
    156 
    157   LOG(ERROR) << "Unknown key code: " << code;
    158   return ui::VKEY_UNKNOWN;
    159 }
    160 
    161 int ModifierFromButton(unsigned int code) {
    162   switch (code) {
    163     case KEY_CAPSLOCK:
    164       return EVDEV_MODIFIER_CAPS_LOCK;
    165     case KEY_LEFTSHIFT:
    166     case KEY_RIGHTSHIFT:
    167       return EVDEV_MODIFIER_SHIFT;
    168     case KEY_LEFTCTRL:
    169     case KEY_RIGHTCTRL:
    170       return EVDEV_MODIFIER_CONTROL;
    171     case KEY_LEFTALT:
    172     case KEY_RIGHTALT:
    173       return EVDEV_MODIFIER_ALT;
    174     case BTN_LEFT:
    175       return EVDEV_MODIFIER_LEFT_MOUSE_BUTTON;
    176     case BTN_MIDDLE:
    177       return EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON;
    178     case BTN_RIGHT:
    179       return EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON;
    180     case KEY_LEFTMETA:
    181     case KEY_RIGHTMETA:
    182       return EVDEV_MODIFIER_COMMAND;
    183     default:
    184       return EVDEV_MODIFIER_NONE;
    185   }
    186 }
    187 
    188 bool IsLockButton(unsigned int code) { return code == KEY_CAPSLOCK; }
    189 
    190 }  // namespace
    191 
    192 KeyEventConverterEvdev::KeyEventConverterEvdev(
    193     int fd,
    194     base::FilePath path,
    195     EventModifiersEvdev* modifiers,
    196     const EventDispatchCallback& callback)
    197     : EventConverterEvdev(fd, path),
    198       callback_(callback),
    199       modifiers_(modifiers) {
    200   // TODO(spang): Initialize modifiers using EVIOCGKEY.
    201 }
    202 
    203 KeyEventConverterEvdev::~KeyEventConverterEvdev() {
    204   Stop();
    205   close(fd_);
    206 }
    207 
    208 void KeyEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
    209   input_event inputs[4];
    210   ssize_t read_size = read(fd, inputs, sizeof(inputs));
    211   if (read_size < 0) {
    212     if (errno == EINTR || errno == EAGAIN)
    213       return;
    214     if (errno != ENODEV)
    215       PLOG(ERROR) << "error reading device " << path_.value();
    216     Stop();
    217     return;
    218   }
    219 
    220   DCHECK_EQ(read_size % sizeof(*inputs), 0u);
    221   ProcessEvents(inputs, read_size / sizeof(*inputs));
    222 }
    223 
    224 void KeyEventConverterEvdev::ProcessEvents(const input_event* inputs,
    225                                            int count) {
    226   for (int i = 0; i < count; ++i) {
    227     const input_event& input = inputs[i];
    228     if (input.type == EV_KEY) {
    229       ConvertKeyEvent(input.code, input.value);
    230     } else if (input.type == EV_SYN) {
    231       // TODO(sadrul): Handle this case appropriately.
    232     }
    233   }
    234 }
    235 
    236 void KeyEventConverterEvdev::ConvertKeyEvent(int key, int value) {
    237   int down = (value != 0);
    238   int repeat = (value == 2);
    239   int modifier = ModifierFromButton(key);
    240   ui::KeyboardCode code = KeyboardCodeFromButton(key);
    241 
    242   if (!repeat && (modifier != EVDEV_MODIFIER_NONE)) {
    243     if (IsLockButton(key)) {
    244       // Locking modifier keys: CapsLock.
    245       modifiers_->UpdateModifierLock(modifier, down);
    246     } else {
    247       // Regular modifier keys: Shift, Ctrl, Alt, etc.
    248       modifiers_->UpdateModifier(modifier, down);
    249     }
    250   }
    251 
    252   int flags = modifiers_->GetModifierFlags();
    253 
    254   KeyEvent key_event(
    255       down ? ET_KEY_PRESSED : ET_KEY_RELEASED,
    256       code,
    257       KeycodeConverter::NativeKeycodeToCode(key + kXkbKeycodeOffset),
    258       flags);
    259   callback_.Run(&key_event);
    260 }
    261 
    262 }  // namespace ui
    263