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 33 int32_t scale_relative_scroll(float x) { 34 return kScrollScale * x; 35 } 36 37 } // anonymous namespace 38 39 std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() { 40 std::unique_ptr<VirtualTouchpadEvdev> touchpad(new VirtualTouchpadEvdev()); 41 touchpad->Reset(); 42 return touchpad; 43 } 44 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 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 87 status_t VirtualTouchpadEvdev::Detach() { 88 Reset(); 89 return OK; 90 } 91 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 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 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 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