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 
12 namespace android {
13 namespace dvr {
14 
15 namespace {
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.
21 static const char* const kDeviceNameFormat = "vr-virtual-touchpad-%d";
22 static constexpr int16_t kDeviceBusType = BUS_VIRTUAL;
23 static constexpr int16_t kDeviceVendor = 0;
24 static constexpr int16_t kDeviceProduct = 0;
25 static constexpr int16_t kDeviceVersion = 0x0001;
26 
27 static constexpr int32_t kWidth = 0x10000;
28 static constexpr int32_t kHeight = 0x10000;
29 static constexpr int32_t kSlots = 2;
30 
31 }  // anonymous namespace
32 
Create()33 std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
34   std::unique_ptr<VirtualTouchpadEvdev> touchpad(new VirtualTouchpadEvdev());
35   touchpad->Reset();
36   return touchpad;
37 }
38 
Reset()39 void VirtualTouchpadEvdev::Reset() {
40   for (auto& touchpad : touchpad_) {
41     if (touchpad.injector) {
42       touchpad.injector->Close();
43     }
44     touchpad.injector = nullptr;
45     touchpad.owned_injector.reset();
46     touchpad.last_device_x = INT32_MIN;
47     touchpad.last_device_y = INT32_MIN;
48     touchpad.touches = 0;
49     touchpad.last_motion_event_buttons = 0;
50   }
51 }
52 
Attach()53 status_t VirtualTouchpadEvdev::Attach() {
54   status_t status = OK;
55   for (int i = 0; i < kTouchpads; ++i) {
56     Touchpad& touchpad = touchpad_[i];
57     if (!touchpad.injector) {
58       touchpad.owned_injector.reset(new EvdevInjector());
59       touchpad.injector = touchpad.owned_injector.get();
60     }
61     String8 DeviceName;
62     DeviceName.appendFormat(kDeviceNameFormat, i);
63     touchpad.injector->ConfigureBegin(DeviceName, kDeviceBusType,
64                                       kDeviceVendor, kDeviceProduct,
65                                       kDeviceVersion);
66     touchpad.injector->ConfigureInputProperty(INPUT_PROP_DIRECT);
67     touchpad.injector->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
68     touchpad.injector->ConfigureAbsSlots(kSlots);
69     touchpad.injector->ConfigureKey(BTN_TOUCH);
70     touchpad.injector->ConfigureKey(BTN_BACK);
71     touchpad.injector->ConfigureEnd();
72     if (const status_t configuration_status =  touchpad.injector->GetError()) {
73       status = configuration_status;
74     }
75   }
76   return status;
77 }
78 
Detach()79 status_t VirtualTouchpadEvdev::Detach() {
80   Reset();
81   return OK;
82 }
83 
Touch(int touchpad_id,float x,float y,float pressure)84 int VirtualTouchpadEvdev::Touch(int touchpad_id, float x, float y,
85                                 float pressure) {
86   if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
87     return EINVAL;
88   }
89   if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
90     return EINVAL;
91   }
92   int32_t device_x = x * kWidth;
93   int32_t device_y = y * kHeight;
94   Touchpad& touchpad = touchpad_[touchpad_id];
95   touchpad.touches = ((touchpad.touches & 1) << 1) | (pressure > 0);
96   ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d", x, y, pressure, device_x,
97         device_y, touchpad.touches);
98 
99   if (!touchpad.injector) {
100     return EvdevInjector::ERROR_SEQUENCING;
101   }
102   touchpad.injector->ResetError();
103   switch (touchpad.touches) {
104     case 0b00:  // Hover continues.
105       if (device_x != touchpad.last_device_x ||
106           device_y != touchpad.last_device_y) {
107         touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
108         touchpad.injector->SendSynReport();
109       }
110       break;
111     case 0b01:  // Touch begins.
112       // Press.
113       touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
114       touchpad.injector->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS);
115       touchpad.injector->SendSynReport();
116       break;
117     case 0b10:  // Touch ends.
118       touchpad.injector->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE);
119       touchpad.injector->SendMultiTouchLift(0);
120       touchpad.injector->SendSynReport();
121       break;
122     case 0b11:  // Touch continues.
123       if (device_x != touchpad.last_device_x ||
124           device_y != touchpad.last_device_y) {
125         touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
126         touchpad.injector->SendSynReport();
127       }
128       break;
129   }
130   touchpad.last_device_x = device_x;
131   touchpad.last_device_y = device_y;
132 
133   return touchpad.injector->GetError();
134 }
135 
ButtonState(int touchpad_id,int buttons)136 int VirtualTouchpadEvdev::ButtonState(int touchpad_id, int buttons) {
137   if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
138     return EINVAL;
139   }
140   Touchpad& touchpad = touchpad_[touchpad_id];
141   const int changes = touchpad.last_motion_event_buttons ^ buttons;
142   if (!changes) {
143     return 0;
144   }
145   if (buttons & ~AMOTION_EVENT_BUTTON_BACK) {
146     return ENOTSUP;
147   }
148   ALOGV("change %X from %X to %X", changes, touchpad.last_motion_event_buttons,
149         buttons);
150 
151   if (!touchpad.injector) {
152     return EvdevInjector::ERROR_SEQUENCING;
153   }
154   touchpad.injector->ResetError();
155   if (changes & AMOTION_EVENT_BUTTON_BACK) {
156     touchpad.injector->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK)
157                                              ? EvdevInjector::KEY_PRESS
158                                              : EvdevInjector::KEY_RELEASE);
159     touchpad.injector->SendSynReport();
160   }
161   touchpad.last_motion_event_buttons = buttons;
162   return touchpad.injector->GetError();
163 }
164 
dumpInternal(String8 & result)165 void VirtualTouchpadEvdev::dumpInternal(String8& result) {
166   for (int i = 0; i < kTouchpads; ++i) {
167     const auto& touchpad = touchpad_[i];
168     result.appendFormat("[virtual touchpad %d]\n", i);
169     if (!touchpad.injector) {
170       result.append("injector = none\n");
171       return;
172     }
173     result.appendFormat("injector = %s\n",
174                         touchpad.owned_injector ? "normal" : "test");
175     result.appendFormat("touches = %d\n", touchpad.touches);
176     result.appendFormat("last_position = (%" PRId32 ", %" PRId32 ")\n",
177                         touchpad.last_device_x, touchpad.last_device_y);
178     result.appendFormat("last_buttons = 0x%" PRIX32 "\n",
179                         touchpad.last_motion_event_buttons);
180     touchpad.injector->dumpInternal(result);
181     result.append("\n");
182   }
183 }
184 
185 }  // namespace dvr
186 }  // namespace android
187