blob: 47930588a2a325f2df5c4507206563b599a59391 [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#include "VirtualTouchpad.h"
2
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
33int VirtualTouchpad::Initialize() {
34 if (!injector_) {
35 owned_injector_.reset(new EvdevInjector());
36 injector_ = owned_injector_.get();
37 }
38 injector_->ConfigureBegin(kDeviceName, kDeviceBusType, kDeviceVendor,
39 kDeviceProduct, kDeviceVersion);
40 injector_->ConfigureInputProperty(INPUT_PROP_DIRECT);
41 injector_->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
42 injector_->ConfigureAbsSlots(kSlots);
43 injector_->ConfigureKey(BTN_TOUCH);
Kevin Schoedel43b5b062017-01-19 13:46:17 -050044 injector_->ConfigureKey(BTN_BACK);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080045 injector_->ConfigureEnd();
46 return injector_->GetError();
47}
48
49int VirtualTouchpad::Touch(float x, float y, float pressure) {
Kevin Schoedel43b5b062017-01-19 13:46:17 -050050 if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
51 return EINVAL;
52 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080053 int32_t device_x = x * kWidth;
54 int32_t device_y = y * kHeight;
55 touches_ = ((touches_ & 1) << 1) | (pressure > 0);
56 ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d",
57 x, y, pressure, device_x, device_y, touches_);
58
Kevin Schoedel43b5b062017-01-19 13:46:17 -050059 if (!injector_) {
60 return EvdevInjector::ERROR_SEQUENCING;
61 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080062 injector_->ResetError();
63 switch (touches_) {
64 case 0b00: // Hover continues.
65 if (device_x != last_device_x_ || device_y != last_device_y_) {
66 injector_->SendMultiTouchXY(0, 0, device_x, device_y);
67 injector_->SendSynReport();
68 }
69 break;
70 case 0b01: // Touch begins.
71 // Press.
72 injector_->SendMultiTouchXY(0, 0, device_x, device_y);
73 injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS);
74 injector_->SendSynReport();
75 break;
76 case 0b10: // Touch ends.
77 injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE);
78 injector_->SendMultiTouchLift(0);
79 injector_->SendSynReport();
80 break;
81 case 0b11: // Touch continues.
82 if (device_x != last_device_x_ || device_y != last_device_y_) {
83 injector_->SendMultiTouchXY(0, 0, device_x, device_y);
84 injector_->SendSynReport();
85 }
86 break;
87 }
88 last_device_x_ = device_x;
89 last_device_y_ = device_y;
90
91 return injector_->GetError();
92}
93
Kevin Schoedel43b5b062017-01-19 13:46:17 -050094int VirtualTouchpad::ButtonState(int buttons) {
95 const int changes = last_motion_event_buttons_ ^ buttons;
96 if (!changes) {
97 return 0;
98 }
99 if (buttons & ~AMOTION_EVENT_BUTTON_BACK) {
100 return ENOTSUP;
101 }
102 ALOGV("change %X from %X to %X", changes, last_motion_event_buttons_,
103 buttons);
104
105 if (!injector_) {
106 return EvdevInjector::ERROR_SEQUENCING;
107 }
108 injector_->ResetError();
109 if (changes & AMOTION_EVENT_BUTTON_BACK) {
110 injector_->SendKey(BTN_BACK,
111 (buttons & AMOTION_EVENT_BUTTON_BACK)
112 ? EvdevInjector::KEY_PRESS
113 : EvdevInjector::KEY_RELEASE);
114 }
115 last_motion_event_buttons_ = buttons;
116 return injector_->GetError();
117}
118
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800119} // namespace dvr
120} // namespace android