blob: bc29408018731af118458fc591313cb07d85fa69 [file] [log] [blame]
Kevin Schoedel89af70b2017-03-03 18:11:37 -05001#include "VirtualTouchpadEvdev.h"
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08002
Kevin Schoedel43b5b062017-01-19 13:46:17 -05003#include <android/input.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08004#include <inttypes.h>
5#include <linux/input.h>
Alex Vakulenko4fe60582017-02-02 11:35:59 -08006#include <log/log.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08007
Kevin Schoedel43b5b062017-01-19 13:46:17 -05008// References:
9// [0] Multi-touch (MT) Protocol,
10// https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
11
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080012namespace android {
13namespace dvr {
14
15namespace {
16
Kevin Schoedel43b5b062017-01-19 13:46:17 -050017// 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.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080021static const char* const kDeviceName = "vr window manager virtual touchpad";
22static constexpr int16_t kDeviceBusType = BUS_VIRTUAL;
Kevin Schoedel43b5b062017-01-19 13:46:17 -050023static constexpr int16_t kDeviceVendor = 0;
24static constexpr int16_t kDeviceProduct = 0;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080025static constexpr int16_t kDeviceVersion = 0x0001;
Kevin Schoedel43b5b062017-01-19 13:46:17 -050026
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080027static constexpr int32_t kWidth = 0x10000;
28static constexpr int32_t kHeight = 0x10000;
29static constexpr int32_t kSlots = 2;
30
31} // anonymous namespace
32
Kevin Schoedel89af70b2017-03-03 18:11:37 -050033sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
34 VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev();
Kevin Schoedel89af70b2017-03-03 18:11:37 -050035 return sp<VirtualTouchpad>(touchpad);
36}
37
Kevin Schoedel4b64dd42017-03-07 13:06:25 -050038status_t VirtualTouchpadEvdev::Attach() {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080039 if (!injector_) {
40 owned_injector_.reset(new EvdevInjector());
41 injector_ = owned_injector_.get();
42 }
43 injector_->ConfigureBegin(kDeviceName, kDeviceBusType, kDeviceVendor,
44 kDeviceProduct, kDeviceVersion);
45 injector_->ConfigureInputProperty(INPUT_PROP_DIRECT);
46 injector_->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
47 injector_->ConfigureAbsSlots(kSlots);
48 injector_->ConfigureKey(BTN_TOUCH);
Kevin Schoedel43b5b062017-01-19 13:46:17 -050049 injector_->ConfigureKey(BTN_BACK);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080050 injector_->ConfigureEnd();
51 return injector_->GetError();
52}
53
Kevin Schoedel4b64dd42017-03-07 13:06:25 -050054status_t VirtualTouchpadEvdev::Detach() {
55 injector_->Close();
56 injector_ = nullptr;
57 owned_injector_.reset();
58 last_device_x_ = INT32_MIN;
59 last_device_y_ = INT32_MIN;
60 touches_ = 0;
61 last_motion_event_buttons_ = 0;
62 return OK;
63}
64
Kevin Schoedel3002b8a2017-03-06 14:34:39 -050065int VirtualTouchpadEvdev::Touch(int touchpad, float x, float y,
66 float pressure) {
Kevin Schoedel4b64dd42017-03-07 13:06:25 -050067 (void)touchpad; // TODO(b/35992608) Support multiple touchpad devices.
Kevin Schoedel43b5b062017-01-19 13:46:17 -050068 if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
69 return EINVAL;
70 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080071 int32_t device_x = x * kWidth;
72 int32_t device_y = y * kHeight;
73 touches_ = ((touches_ & 1) << 1) | (pressure > 0);
Kevin Schoedel3002b8a2017-03-06 14:34:39 -050074 ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d", x, y, pressure, device_x,
75 device_y, touches_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080076
Kevin Schoedel43b5b062017-01-19 13:46:17 -050077 if (!injector_) {
78 return EvdevInjector::ERROR_SEQUENCING;
79 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080080 injector_->ResetError();
81 switch (touches_) {
82 case 0b00: // Hover continues.
83 if (device_x != last_device_x_ || device_y != last_device_y_) {
84 injector_->SendMultiTouchXY(0, 0, device_x, device_y);
85 injector_->SendSynReport();
86 }
87 break;
88 case 0b01: // Touch begins.
89 // Press.
90 injector_->SendMultiTouchXY(0, 0, device_x, device_y);
91 injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS);
92 injector_->SendSynReport();
93 break;
94 case 0b10: // Touch ends.
95 injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE);
96 injector_->SendMultiTouchLift(0);
97 injector_->SendSynReport();
98 break;
99 case 0b11: // Touch continues.
100 if (device_x != last_device_x_ || device_y != last_device_y_) {
101 injector_->SendMultiTouchXY(0, 0, device_x, device_y);
102 injector_->SendSynReport();
103 }
104 break;
105 }
106 last_device_x_ = device_x;
107 last_device_y_ = device_y;
108
109 return injector_->GetError();
110}
111
Kevin Schoedel3002b8a2017-03-06 14:34:39 -0500112int VirtualTouchpadEvdev::ButtonState(int touchpad, int buttons) {
Kevin Schoedel4b64dd42017-03-07 13:06:25 -0500113 (void)touchpad; // TODO(b/35992608) Support multiple touchpad devices.
Kevin Schoedel43b5b062017-01-19 13:46:17 -0500114 const int changes = last_motion_event_buttons_ ^ buttons;
115 if (!changes) {
116 return 0;
117 }
118 if (buttons & ~AMOTION_EVENT_BUTTON_BACK) {
119 return ENOTSUP;
120 }
121 ALOGV("change %X from %X to %X", changes, last_motion_event_buttons_,
122 buttons);
123
124 if (!injector_) {
125 return EvdevInjector::ERROR_SEQUENCING;
126 }
127 injector_->ResetError();
128 if (changes & AMOTION_EVENT_BUTTON_BACK) {
Kevin Schoedel3002b8a2017-03-06 14:34:39 -0500129 injector_->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK)
130 ? EvdevInjector::KEY_PRESS
131 : EvdevInjector::KEY_RELEASE);
Kevin Schoedel4b64dd42017-03-07 13:06:25 -0500132 injector_->SendSynReport();
Kevin Schoedel43b5b062017-01-19 13:46:17 -0500133 }
134 last_motion_event_buttons_ = buttons;
135 return injector_->GetError();
136}
137
Kevin Schoedel4b64dd42017-03-07 13:06:25 -0500138void VirtualTouchpadEvdev::dumpInternal(String8& result) {
139 result.append("[virtual touchpad]\n");
140 if (!injector_) {
141 result.append("injector = none\n");
142 return;
143 }
144 result.appendFormat("injector = %s\n", owned_injector_ ? "normal" : "test");
145 result.appendFormat("touches = %d\n", touches_);
146 result.appendFormat("last_position = (%" PRId32 ", %" PRId32 ")\n",
147 last_device_x_, last_device_y_);
148 result.appendFormat("last_buttons = 0x%" PRIX32 "\n\n",
149 last_motion_event_buttons_);
150 injector_->dumpInternal(result);
151}
152
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800153} // namespace dvr
154} // namespace android