root/ui/events/ozone/evdev/key_event_converter_evdev.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. KeyboardCodeFromButton
  2. ModifierFromButton
  3. IsLockButton
  4. modifiers_
  5. Start
  6. Stop
  7. OnFileCanReadWithoutBlocking
  8. OnFileCanWriteWithoutBlocking
  9. ProcessEvents
  10. ConvertKeyEvent

// 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_pump_ozone.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)
    : fd_(fd), path_(path), modifiers_(modifiers) {
  // TODO(spang): Initialize modifiers using EVIOCGKEY.
}

KeyEventConverterEvdev::~KeyEventConverterEvdev() {
  Stop();
  close(fd_);
}

void KeyEventConverterEvdev::Start() {
  base::MessagePumpOzone::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, true);
  DispatchEventToCallback(&key_event);
}

}  // namespace ui

/* [<][>][^][v][top][bottom][index][help] */