VirtualTouchpadEvdev.cpp revision b2990034866e4f2cce6166b1c1d77dec27770686
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 kDeviceNameFormat = "vr-virtual-touchpad-%d"; 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 31static constexpr float kScrollScale = 100.0f; 32 33int32_t scale_relative_scroll(float x) { 34 return kScrollScale * x; 35} 36 37} // anonymous namespace 38 39std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() { 40 std::unique_ptr<VirtualTouchpadEvdev> touchpad(new VirtualTouchpadEvdev()); 41 touchpad->Reset(); 42 return touchpad; 43} 44 45void 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 59status_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 87status_t VirtualTouchpadEvdev::Detach() { 88 Reset(); 89 return OK; 90} 91 92int 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 if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) { 98 return EINVAL; 99 } 100 int32_t device_x = x * kWidth; 101 int32_t device_y = y * kHeight; 102 Touchpad& touchpad = touchpad_[touchpad_id]; 103 touchpad.touches = ((touchpad.touches & 1) << 1) | (pressure > 0); 104 ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d", x, y, pressure, device_x, 105 device_y, touchpad.touches); 106 107 if (!touchpad.injector) { 108 return EvdevInjector::ERROR_SEQUENCING; 109 } 110 touchpad.injector->ResetError(); 111 switch (touchpad.touches) { 112 case 0b00: // Hover continues. 113 if (device_x != touchpad.last_device_x || 114 device_y != touchpad.last_device_y) { 115 touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y); 116 touchpad.injector->SendSynReport(); 117 } 118 break; 119 case 0b01: // Touch begins. 120 // Press. 121 touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y); 122 touchpad.injector->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS); 123 touchpad.injector->SendSynReport(); 124 break; 125 case 0b10: // Touch ends. 126 touchpad.injector->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE); 127 touchpad.injector->SendMultiTouchLift(0); 128 touchpad.injector->SendSynReport(); 129 break; 130 case 0b11: // Touch continues. 131 if (device_x != touchpad.last_device_x || 132 device_y != touchpad.last_device_y) { 133 touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y); 134 touchpad.injector->SendSynReport(); 135 } 136 break; 137 } 138 touchpad.last_device_x = device_x; 139 touchpad.last_device_y = device_y; 140 141 return touchpad.injector->GetError(); 142} 143 144int VirtualTouchpadEvdev::ButtonState(int touchpad_id, int buttons) { 145 if (touchpad_id < 0 || touchpad_id >= kTouchpads) { 146 return EINVAL; 147 } 148 Touchpad& touchpad = touchpad_[touchpad_id]; 149 const int changes = touchpad.last_motion_event_buttons ^ buttons; 150 if (!changes) { 151 return 0; 152 } 153 if (buttons & ~AMOTION_EVENT_BUTTON_BACK) { 154 return ENOTSUP; 155 } 156 ALOGV("change %X from %X to %X", changes, touchpad.last_motion_event_buttons, 157 buttons); 158 159 if (!touchpad.injector) { 160 return EvdevInjector::ERROR_SEQUENCING; 161 } 162 touchpad.injector->ResetError(); 163 if (changes & AMOTION_EVENT_BUTTON_BACK) { 164 touchpad.injector->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK) 165 ? EvdevInjector::KEY_PRESS 166 : EvdevInjector::KEY_RELEASE); 167 touchpad.injector->SendSynReport(); 168 } 169 touchpad.last_motion_event_buttons = buttons; 170 return touchpad.injector->GetError(); 171} 172 173int VirtualTouchpadEvdev::Scroll(int touchpad_id, float x, float y) { 174 if (touchpad_id < 0 || touchpad_id >= kTouchpads) { 175 return EINVAL; 176 } 177 if ((x < -1.0f) || (x > 1.0f) || (y < -1.0f) || (y > 1.0f)) { 178 return EINVAL; 179 } 180 Touchpad& touchpad = touchpad_[touchpad_id]; 181 if (!touchpad.injector) { 182 return EvdevInjector::ERROR_SEQUENCING; 183 } 184 touchpad.injector->ResetError(); 185 const int32_t scaled_x = scale_relative_scroll(x); 186 const int32_t scaled_y = scale_relative_scroll(y); 187 ALOGV("(%f,%f) -> (%" PRId32 ",%" PRId32 ")", x, y, scaled_x, scaled_y); 188 if (scaled_x) { 189 touchpad.injector->SendRel(REL_HWHEEL, scaled_x); 190 } 191 if (scaled_y) { 192 touchpad.injector->SendRel(REL_WHEEL, scaled_y); 193 } 194 if (scaled_x || scaled_y) { 195 touchpad.injector->SendSynReport(); 196 } 197 return touchpad.injector->GetError(); 198} 199 200void VirtualTouchpadEvdev::dumpInternal(String8& result) { 201 for (int i = 0; i < kTouchpads; ++i) { 202 const auto& touchpad = touchpad_[i]; 203 result.appendFormat("[virtual touchpad %d]\n", i); 204 if (!touchpad.injector) { 205 result.append("injector = none\n"); 206 return; 207 } 208 result.appendFormat("injector = %s\n", 209 touchpad.owned_injector ? "normal" : "test"); 210 result.appendFormat("touches = %d\n", touchpad.touches); 211 result.appendFormat("last_position = (%" PRId32 ", %" PRId32 ")\n", 212 touchpad.last_device_x, touchpad.last_device_y); 213 result.appendFormat("last_buttons = 0x%" PRIX32 "\n", 214 touchpad.last_motion_event_buttons); 215 touchpad.injector->dumpInternal(result); 216 result.append("\n"); 217 } 218} 219 220} // namespace dvr 221} // namespace android 222