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 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