VirtualTouchpadEvdev.cpp revision 89af70bce420f011adfeb0f80984b3895c4d7d9b
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 kDeviceName = "vr window manager virtual touchpad"; 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 31} // anonymous namespace 32 33sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() { 34 VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev(); 35 const status_t status = touchpad->Initialize(); 36 if (status) { 37 ALOGE("initialization failed: %d", status); 38 return sp<VirtualTouchpad>(); 39 } 40 return sp<VirtualTouchpad>(touchpad); 41} 42 43int VirtualTouchpadEvdev::Initialize() { 44 if (!injector_) { 45 owned_injector_.reset(new EvdevInjector()); 46 injector_ = owned_injector_.get(); 47 } 48 injector_->ConfigureBegin(kDeviceName, kDeviceBusType, kDeviceVendor, 49 kDeviceProduct, kDeviceVersion); 50 injector_->ConfigureInputProperty(INPUT_PROP_DIRECT); 51 injector_->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1); 52 injector_->ConfigureAbsSlots(kSlots); 53 injector_->ConfigureKey(BTN_TOUCH); 54 injector_->ConfigureKey(BTN_BACK); 55 injector_->ConfigureEnd(); 56 return injector_->GetError(); 57} 58 59int VirtualTouchpadEvdev::Touch(float x, float y, float pressure) { 60 if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) { 61 return EINVAL; 62 } 63 int32_t device_x = x * kWidth; 64 int32_t device_y = y * kHeight; 65 touches_ = ((touches_ & 1) << 1) | (pressure > 0); 66 ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d", 67 x, y, pressure, device_x, device_y, touches_); 68 69 if (!injector_) { 70 return EvdevInjector::ERROR_SEQUENCING; 71 } 72 injector_->ResetError(); 73 switch (touches_) { 74 case 0b00: // Hover continues. 75 if (device_x != last_device_x_ || device_y != last_device_y_) { 76 injector_->SendMultiTouchXY(0, 0, device_x, device_y); 77 injector_->SendSynReport(); 78 } 79 break; 80 case 0b01: // Touch begins. 81 // Press. 82 injector_->SendMultiTouchXY(0, 0, device_x, device_y); 83 injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS); 84 injector_->SendSynReport(); 85 break; 86 case 0b10: // Touch ends. 87 injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE); 88 injector_->SendMultiTouchLift(0); 89 injector_->SendSynReport(); 90 break; 91 case 0b11: // Touch continues. 92 if (device_x != last_device_x_ || device_y != last_device_y_) { 93 injector_->SendMultiTouchXY(0, 0, device_x, device_y); 94 injector_->SendSynReport(); 95 } 96 break; 97 } 98 last_device_x_ = device_x; 99 last_device_y_ = device_y; 100 101 return injector_->GetError(); 102} 103 104int VirtualTouchpadEvdev::ButtonState(int buttons) { 105 const int changes = last_motion_event_buttons_ ^ buttons; 106 if (!changes) { 107 return 0; 108 } 109 if (buttons & ~AMOTION_EVENT_BUTTON_BACK) { 110 return ENOTSUP; 111 } 112 ALOGV("change %X from %X to %X", changes, last_motion_event_buttons_, 113 buttons); 114 115 if (!injector_) { 116 return EvdevInjector::ERROR_SEQUENCING; 117 } 118 injector_->ResetError(); 119 if (changes & AMOTION_EVENT_BUTTON_BACK) { 120 injector_->SendKey(BTN_BACK, 121 (buttons & AMOTION_EVENT_BUTTON_BACK) 122 ? EvdevInjector::KEY_PRESS 123 : EvdevInjector::KEY_RELEASE); 124 } 125 last_motion_event_buttons_ = buttons; 126 return injector_->GetError(); 127} 128 129} // namespace dvr 130} // namespace android 131