VirtualTouchpadEvdev.cpp revision 3002b8a74431dd7c005269cf9306443a4b4963f1
1#include "VirtualTouchpadEvdev.h"
2
3#include <android/input.h>
4#include <inttypes.h>
5#include <linux/input.h>
6#include <log/log.h>
7
8// References:
9//  [0] Multi-touch (MT) Protocol,
10//      https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
11
12namespace android {
13namespace dvr {
14
15namespace {
16
17// Virtual evdev device properties. The name is arbitrary, but Android can
18// use it to look up device configuration, so it must be unique. Vendor and
19// product values must be 0 to indicate an internal device and prevent a
20// similar lookup that could conflict with a physical device.
21static const char* const kDeviceName = "vr window manager virtual touchpad";
22static constexpr int16_t kDeviceBusType = BUS_VIRTUAL;
23static constexpr int16_t kDeviceVendor = 0;
24static constexpr int16_t kDeviceProduct = 0;
25static constexpr int16_t kDeviceVersion = 0x0001;
26
27static constexpr int32_t kWidth = 0x10000;
28static constexpr int32_t kHeight = 0x10000;
29static constexpr int32_t kSlots = 2;
30
31}  // anonymous namespace
32
33sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
34  VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev();
35  const status_t status = touchpad->Initialize();
36  if (status) {
37    ALOGE("initialization failed: %d", status);
38    return sp<VirtualTouchpad>();
39  }
40  return sp<VirtualTouchpad>(touchpad);
41}
42
43int VirtualTouchpadEvdev::Initialize() {
44  if (!injector_) {
45    owned_injector_.reset(new EvdevInjector());
46    injector_ = owned_injector_.get();
47  }
48  injector_->ConfigureBegin(kDeviceName, kDeviceBusType, kDeviceVendor,
49                            kDeviceProduct, kDeviceVersion);
50  injector_->ConfigureInputProperty(INPUT_PROP_DIRECT);
51  injector_->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
52  injector_->ConfigureAbsSlots(kSlots);
53  injector_->ConfigureKey(BTN_TOUCH);
54  injector_->ConfigureKey(BTN_BACK);
55  injector_->ConfigureEnd();
56  return injector_->GetError();
57}
58
59int VirtualTouchpadEvdev::Touch(int touchpad, float x, float y,
60                                float pressure) {
61  (void)touchpad; // TODO(b/35992608) Support multiple virtual touchpad devices.
62  if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
63    return EINVAL;
64  }
65  int32_t device_x = x * kWidth;
66  int32_t device_y = y * kHeight;
67  touches_ = ((touches_ & 1) << 1) | (pressure > 0);
68  ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d", x, y, pressure, device_x,
69        device_y, touches_);
70
71  if (!injector_) {
72    return EvdevInjector::ERROR_SEQUENCING;
73  }
74  injector_->ResetError();
75  switch (touches_) {
76    case 0b00:  // Hover continues.
77      if (device_x != last_device_x_ || device_y != last_device_y_) {
78        injector_->SendMultiTouchXY(0, 0, device_x, device_y);
79        injector_->SendSynReport();
80      }
81      break;
82    case 0b01:  // Touch begins.
83      // Press.
84      injector_->SendMultiTouchXY(0, 0, device_x, device_y);
85      injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS);
86      injector_->SendSynReport();
87      break;
88    case 0b10:  // Touch ends.
89      injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE);
90      injector_->SendMultiTouchLift(0);
91      injector_->SendSynReport();
92      break;
93    case 0b11:  // Touch continues.
94      if (device_x != last_device_x_ || device_y != last_device_y_) {
95        injector_->SendMultiTouchXY(0, 0, device_x, device_y);
96        injector_->SendSynReport();
97      }
98      break;
99  }
100  last_device_x_ = device_x;
101  last_device_y_ = device_y;
102
103  return injector_->GetError();
104}
105
106int VirtualTouchpadEvdev::ButtonState(int touchpad, int buttons) {
107  (void)touchpad; // TODO(b/35992608) Support multiple virtual touchpad devices.
108  const int changes = last_motion_event_buttons_ ^ buttons;
109  if (!changes) {
110    return 0;
111  }
112  if (buttons & ~AMOTION_EVENT_BUTTON_BACK) {
113    return ENOTSUP;
114  }
115  ALOGV("change %X from %X to %X", changes, last_motion_event_buttons_,
116        buttons);
117
118  if (!injector_) {
119    return EvdevInjector::ERROR_SEQUENCING;
120  }
121  injector_->ResetError();
122  if (changes & AMOTION_EVENT_BUTTON_BACK) {
123    injector_->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK)
124                                     ? EvdevInjector::KEY_PRESS
125                                     : EvdevInjector::KEY_RELEASE);
126  }
127  last_motion_event_buttons_ = buttons;
128  return injector_->GetError();
129}
130
131}  // namespace dvr
132}  // namespace android
133