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