Home | History | Annotate | Download | only in virtual_touchpad
      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 
     33 std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
     34   std::unique_ptr<VirtualTouchpadEvdev> touchpad(new VirtualTouchpadEvdev());
     35   touchpad->Reset();
     36   return touchpad;
     37 }
     38 
     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 
     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 
     79 status_t VirtualTouchpadEvdev::Detach() {
     80   Reset();
     81   return OK;
     82 }
     83 
     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 
    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 
    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