Add DVR API for scroll event injection.

Bug: 62226675
Test: manual, vrcore build
Change-Id: Ic7d329eba8003b0e294b3a11a83ed5f868b801f8
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index f0bdcd9..ae56bf6 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -28,6 +28,22 @@
 static constexpr int32_t kHeight = 0x10000;
 static constexpr int32_t kSlots = 2;
 
+int32_t scale_relative_scroll(float x) {
+  // Guilty with an explanation, your honor.
+  // Ideally we should be able to communicate the full incoming precision
+  // to InputFlinger, through the evdev int32_t value, by scaling by a
+  // large factor, i.e. 2²³ for IEEE single precision floating point.
+  // However, although InputFlinger has |wheelVelocityControlParameters|,
+  // those parameters are currently hard coded, with a scale factor of 1.0.
+  // The observed evdev value for a physical mouse scroll wheel is usually
+  // ±1, with higher values up to ±4 for a very fast spin. So we imitate
+  // that. If the incoming value is not actually 0, the resulting magnitude
+  // should be at least 1, so that small movements are not lost.
+  // Adding IDC configurability of |VelocityControlParameters| may be
+  // desirable in the future.
+  return copysignf(ceilf(fabs(4.0f * x)), x);
+}
+
 }  // anonymous namespace
 
 std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
@@ -162,6 +178,32 @@
   return touchpad.injector->GetError();
 }
 
+int VirtualTouchpadEvdev::Scroll(int touchpad_id, float x, float y) {
+  if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
+    return EINVAL;
+  }
+  if ((x < -1.0f) || (x > 1.0f) || (y < -1.0f) || (y > 1.0f)) {
+    return EINVAL;
+  }
+  Touchpad& touchpad = touchpad_[touchpad_id];
+  if (!touchpad.injector) {
+    return EvdevInjector::ERROR_SEQUENCING;
+  }
+  touchpad.injector->ResetError();
+  const int32_t scaled_x = scale_relative_scroll(x);
+  const int32_t scaled_y = scale_relative_scroll(y);
+  if (scaled_x) {
+    touchpad.injector->SendRel(REL_HWHEEL, scaled_x);
+  }
+  if (scaled_y) {
+    touchpad.injector->SendRel(REL_WHEEL, scaled_y);
+  }
+  if (scaled_x || scaled_y) {
+    touchpad.injector->SendSynReport();
+  }
+  return touchpad.injector->GetError();
+}
+
 void VirtualTouchpadEvdev::dumpInternal(String8& result) {
   for (int i = 0; i < kTouchpads; ++i) {
     const auto& touchpad = touchpad_[i];