189af70bce420f011adfeb0f80984b3895c4d7d9bKevin Schoedel#include "VirtualTouchpadEvdev.h"
2e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
343b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel#include <android/input.h>
4e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <inttypes.h>
5e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <linux/input.h>
64fe60582f314e381098f8f3bc2e39c5880e9243aAlex Vakulenko#include <log/log.h>
7e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
843b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel// References:
943b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel//  [0] Multi-touch (MT) Protocol,
1043b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel//      https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
1143b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel
12e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace android {
13e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace dvr {
14e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
15e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace {
16e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
1743b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel// Virtual evdev device properties. The name is arbitrary, but Android can
1843b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel// use it to look up device configuration, so it must be unique. Vendor and
1943b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel// product values must be 0 to indicate an internal device and prevent a
2043b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel// similar lookup that could conflict with a physical device.
21fa5cf46ac7b84cc20bf29e5b8c298a84b407b1e3Santos Cordonstatic const char* const kDeviceNameFormat = "vr-virtual-touchpad-%d";
22e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostatic constexpr int16_t kDeviceBusType = BUS_VIRTUAL;
2343b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedelstatic constexpr int16_t kDeviceVendor = 0;
2443b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedelstatic constexpr int16_t kDeviceProduct = 0;
25e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostatic constexpr int16_t kDeviceVersion = 0x0001;
2643b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel
27e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostatic constexpr int32_t kWidth = 0x10000;
28e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostatic constexpr int32_t kHeight = 0x10000;
29e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostatic constexpr int32_t kSlots = 2;
30e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
31b2990034866e4f2cce6166b1c1d77dec27770686Kevin Schoedelstatic constexpr float kScrollScale = 100.0f;
32b2990034866e4f2cce6166b1c1d77dec27770686Kevin Schoedel
33d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedelint32_t scale_relative_scroll(float x) {
34b2990034866e4f2cce6166b1c1d77dec27770686Kevin Schoedel  return kScrollScale * x;
35d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel}
36d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel
37e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}  // anonymous namespace
38e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
39de1cdaebc9b8fdbc5348e6c07f849b74bacc485dKevin Schoedelstd::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
40de1cdaebc9b8fdbc5348e6c07f849b74bacc485dKevin Schoedel  std::unique_ptr<VirtualTouchpadEvdev> touchpad(new VirtualTouchpadEvdev());
410108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  touchpad->Reset();
42de1cdaebc9b8fdbc5348e6c07f849b74bacc485dKevin Schoedel  return touchpad;
4389af70bce420f011adfeb0f80984b3895c4d7d9bKevin Schoedel}
4489af70bce420f011adfeb0f80984b3895c4d7d9bKevin Schoedel
450108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedelvoid VirtualTouchpadEvdev::Reset() {
460108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  for (auto& touchpad : touchpad_) {
470108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    if (touchpad.injector) {
480108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      touchpad.injector->Close();
490108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    }
500108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector = nullptr;
510108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.owned_injector.reset();
520108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.last_device_x = INT32_MIN;
530108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.last_device_y = INT32_MIN;
540108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.touches = 0;
550108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.last_motion_event_buttons = 0;
560108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  }
570108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel}
580108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel
594b64dd48b6896d6b963f0a3a0259d3d2a7076a9eKevin Schoedelstatus_t VirtualTouchpadEvdev::Attach() {
600108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  status_t status = OK;
610108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  for (int i = 0; i < kTouchpads; ++i) {
620108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    Touchpad& touchpad = touchpad_[i];
630108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    if (!touchpad.injector) {
640108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      touchpad.owned_injector.reset(new EvdevInjector());
650108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      touchpad.injector = touchpad.owned_injector.get();
660108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    }
670108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    String8 DeviceName;
680108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    DeviceName.appendFormat(kDeviceNameFormat, i);
690108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector->ConfigureBegin(DeviceName, kDeviceBusType,
700108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel                                      kDeviceVendor, kDeviceProduct,
710108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel                                      kDeviceVersion);
720108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector->ConfigureInputProperty(INPUT_PROP_DIRECT);
730108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
740108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector->ConfigureAbsSlots(kSlots);
75b2990034866e4f2cce6166b1c1d77dec27770686Kevin Schoedel    touchpad.injector->ConfigureRel(REL_WHEEL);
76b2990034866e4f2cce6166b1c1d77dec27770686Kevin Schoedel    touchpad.injector->ConfigureRel(REL_HWHEEL);
770108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector->ConfigureKey(BTN_TOUCH);
780108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector->ConfigureKey(BTN_BACK);
790108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector->ConfigureEnd();
800108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    if (const status_t configuration_status =  touchpad.injector->GetError()) {
810108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      status = configuration_status;
820108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    }
83e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  }
840108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  return status;
85e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}
86e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
874b64dd48b6896d6b963f0a3a0259d3d2a7076a9eKevin Schoedelstatus_t VirtualTouchpadEvdev::Detach() {
880108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  Reset();
894b64dd48b6896d6b963f0a3a0259d3d2a7076a9eKevin Schoedel  return OK;
904b64dd48b6896d6b963f0a3a0259d3d2a7076a9eKevin Schoedel}
914b64dd48b6896d6b963f0a3a0259d3d2a7076a9eKevin Schoedel
920108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedelint VirtualTouchpadEvdev::Touch(int touchpad_id, float x, float y,
933002b8a74431dd7c005269cf9306443a4b4963f1Kevin Schoedel                                float pressure) {
940108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
950108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    return EINVAL;
960108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  }
97e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  int32_t device_x = x * kWidth;
98e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  int32_t device_y = y * kHeight;
990108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  Touchpad& touchpad = touchpad_[touchpad_id];
1000108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  touchpad.touches = ((touchpad.touches & 1) << 1) | (pressure > 0);
1013002b8a74431dd7c005269cf9306443a4b4963f1Kevin Schoedel  ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d", x, y, pressure, device_x,
1020108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel        device_y, touchpad.touches);
103e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
1040108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  if (!touchpad.injector) {
10543b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel    return EvdevInjector::ERROR_SEQUENCING;
10643b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel  }
1070108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  touchpad.injector->ResetError();
1080108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  switch (touchpad.touches) {
109e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    case 0b00:  // Hover continues.
1100108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      if (device_x != touchpad.last_device_x ||
1110108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel          device_y != touchpad.last_device_y) {
1120108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel        touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
1130108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel        touchpad.injector->SendSynReport();
114e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko      }
115e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko      break;
116e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    case 0b01:  // Touch begins.
117e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko      // Press.
1180108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
1190108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      touchpad.injector->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS);
1200108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      touchpad.injector->SendSynReport();
121e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko      break;
122e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    case 0b10:  // Touch ends.
1230108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      touchpad.injector->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE);
1240108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      touchpad.injector->SendMultiTouchLift(0);
1250108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      touchpad.injector->SendSynReport();
126e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko      break;
127e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    case 0b11:  // Touch continues.
1280108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      if (device_x != touchpad.last_device_x ||
1290108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel          device_y != touchpad.last_device_y) {
1300108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel        touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
1310108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel        touchpad.injector->SendSynReport();
132e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko      }
133e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko      break;
134e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  }
1350108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  touchpad.last_device_x = device_x;
1360108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  touchpad.last_device_y = device_y;
137e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
1380108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  return touchpad.injector->GetError();
139e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}
140e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
1410108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedelint VirtualTouchpadEvdev::ButtonState(int touchpad_id, int buttons) {
1420108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
1430108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    return EINVAL;
1440108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  }
1450108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  Touchpad& touchpad = touchpad_[touchpad_id];
1460108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  const int changes = touchpad.last_motion_event_buttons ^ buttons;
14743b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel  if (!changes) {
14843b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel    return 0;
14943b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel  }
15043b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel  if (buttons & ~AMOTION_EVENT_BUTTON_BACK) {
15143b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel    return ENOTSUP;
15243b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel  }
1530108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  ALOGV("change %X from %X to %X", changes, touchpad.last_motion_event_buttons,
15443b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel        buttons);
15543b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel
1560108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  if (!touchpad.injector) {
15743b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel    return EvdevInjector::ERROR_SEQUENCING;
15843b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel  }
1590108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  touchpad.injector->ResetError();
16043b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel  if (changes & AMOTION_EVENT_BUTTON_BACK) {
1610108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK)
1620108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel                                             ? EvdevInjector::KEY_PRESS
1630108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel                                             : EvdevInjector::KEY_RELEASE);
1640108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector->SendSynReport();
16543b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel  }
1660108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  touchpad.last_motion_event_buttons = buttons;
1670108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  return touchpad.injector->GetError();
16843b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel}
16943b5b06c8be24e465bd6a7b22a8d341db1ad50a2Kevin Schoedel
170d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedelint VirtualTouchpadEvdev::Scroll(int touchpad_id, float x, float y) {
171d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
172d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel    return EINVAL;
173d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  }
174d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  if ((x < -1.0f) || (x > 1.0f) || (y < -1.0f) || (y > 1.0f)) {
175d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel    return EINVAL;
176d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  }
177d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  Touchpad& touchpad = touchpad_[touchpad_id];
178d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  if (!touchpad.injector) {
179d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel    return EvdevInjector::ERROR_SEQUENCING;
180d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  }
181d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  touchpad.injector->ResetError();
182d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  const int32_t scaled_x = scale_relative_scroll(x);
183d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  const int32_t scaled_y = scale_relative_scroll(y);
184b2990034866e4f2cce6166b1c1d77dec27770686Kevin Schoedel  ALOGV("(%f,%f) -> (%" PRId32 ",%" PRId32 ")", x, y, scaled_x, scaled_y);
185d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  if (scaled_x) {
186d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel    touchpad.injector->SendRel(REL_HWHEEL, scaled_x);
187d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  }
188d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  if (scaled_y) {
189d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel    touchpad.injector->SendRel(REL_WHEEL, scaled_y);
190d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  }
191d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  if (scaled_x || scaled_y) {
192d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel    touchpad.injector->SendSynReport();
193d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  }
194d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel  return touchpad.injector->GetError();
195d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel}
196d8fccf0124b78230ae2071fecc6bc6aebe8c540cKevin Schoedel
1974b64dd48b6896d6b963f0a3a0259d3d2a7076a9eKevin Schoedelvoid VirtualTouchpadEvdev::dumpInternal(String8& result) {
1980108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel  for (int i = 0; i < kTouchpads; ++i) {
1990108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    const auto& touchpad = touchpad_[i];
2000108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    result.appendFormat("[virtual touchpad %d]\n", i);
2010108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    if (!touchpad.injector) {
2020108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      result.append("injector = none\n");
2030108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel      return;
2040108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    }
2050108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    result.appendFormat("injector = %s\n",
2060108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel                        touchpad.owned_injector ? "normal" : "test");
2070108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    result.appendFormat("touches = %d\n", touchpad.touches);
2080108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    result.appendFormat("last_position = (%" PRId32 ", %" PRId32 ")\n",
2090108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel                        touchpad.last_device_x, touchpad.last_device_y);
2100108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    result.appendFormat("last_buttons = 0x%" PRIX32 "\n",
2110108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel                        touchpad.last_motion_event_buttons);
2120108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    touchpad.injector->dumpInternal(result);
2130108af72a8d8d2ee2af127b4c099b340ad63e3f8Kevin Schoedel    result.append("\n");
2144b64dd48b6896d6b963f0a3a0259d3d2a7076a9eKevin Schoedel  }
2154b64dd48b6896d6b963f0a3a0259d3d2a7076a9eKevin Schoedel}
2164b64dd48b6896d6b963f0a3a0259d3d2a7076a9eKevin Schoedel
217e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}  // namespace dvr
218e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}  // namespace android
219