blob: 3bc98ab5efd30cfa7e74319fe7afd639cf2a6e54 [file] [log] [blame]
From: Chung-yih Wang <cywang@chromium.org>
Date: Wed, 14 Nov 2012 15:42:36 +0800
Subject: [PATCH] Accelerate emulated wheel events
Use the Chromium OS Mouse Wheel acceleration for Emulated Wheel
events. This acceleration replaces the simpler "accumulated inertia
mapped to number of button clicks" approach.
The main motivation of this change is to send Emulated Wheel events to
Chrome using the scroll valuators instead of legacy button events.
---
src/emuWheel.c | 48 +++++++++---------------------------------------
src/evdev.c | 20 +++++++++++++++++++-
src/evdev.h | 4 ++++
3 files changed, 32 insertions(+), 40 deletions(-)
diff --git a/src/emuWheel.c b/src/emuWheel.c
index db989c5..dae4031 100644
--- a/src/emuWheel.c
+++ b/src/emuWheel.c
@@ -50,9 +50,6 @@ static Atom prop_wheel_inertia = 0;
static Atom prop_wheel_timeout = 0;
static Atom prop_wheel_button = 0;
-/* Local Funciton Prototypes */
-static int EvdevWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value);
-
/* Filter mouse button events */
BOOL
EvdevWheelEmuFilterButton(InputInfoPtr pInfo, unsigned int button, int value)
@@ -148,8 +145,15 @@ EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv)
*/
if (pAxis)
{
- if (EvdevWheelEmuInertia(pInfo, pAxis, value))
- pOtherAxis->traveled_distance = 0;
+ if (pAxis->up_button) {
+ /*
+ * Try to emit an emulated wheel event. For REL_Y, up is -
+ * and down is + but, for REL_WHEEL, up is + and down is -.
+ */
+ pEv->code = (pEv->code == REL_Y) ? REL_WHEEL : REL_HWHEEL;
+ pEv->value *= (pEv->code == REL_WHEEL) ? -1 : 1;
+ EvdevProcessRelativeMotionEvent(pInfo, pEv);
+ }
}
/* Eat motion events while emulateWheel button pressed. */
@@ -159,40 +163,6 @@ EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv)
return FALSE;
}
-/* Simulate inertia for our emulated mouse wheel.
- Returns the number of wheel events generated.
- */
-static int
-EvdevWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value)
-{
- EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
- int button;
- int inertia;
- int rc = 0;
-
- /* if this axis has not been configured, just eat the motion */
- if (!axis->up_button)
- return rc;
-
- axis->traveled_distance += value;
-
- if (axis->traveled_distance < 0) {
- button = axis->up_button;
- inertia = -pEvdev->emulateWheel.inertia;
- } else {
- button = axis->down_button;
- inertia = pEvdev->emulateWheel.inertia;
- }
-
- /* Produce button press events for wheel motion */
- while(abs(axis->traveled_distance) > pEvdev->emulateWheel.inertia) {
- axis->traveled_distance -= inertia;
- EvdevQueueButtonClicks(pInfo, button, 1);
- rc++;
- }
- return rc;
-}
-
/* Handle button mapping here to avoid code duplication,
returns true if a button mapping was found. */
static BOOL
diff --git a/src/evdev.c b/src/evdev.c
index 986519c..f2cba5e 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -131,6 +131,7 @@ static BOOL EvdevGrabDevice(InputInfoPtr pInfo, int grab, int ungrab);
static void EvdevSetCalibration(InputInfoPtr pInfo, int num_calibration, int calibration[4]);
static int EvdevOpenDevice(InputInfoPtr pInfo);
static void EvdevCloseDevice(InputInfoPtr pInfo);
+static void EvdevForceWheel(InputInfoPtr pInfo);
static int EvdevInjectEvent(InputInfoPtr pInfo, uint16_t type,
uint16_t code, int32_t value);
@@ -787,6 +788,8 @@ EvdevAccelWheel(InputInfoPtr pInfo, struct input_event *ev)
/* If start_time == end_time, compute click_speed using dt = 1 second */
dt = (end_time - start_time) ?: 1.0;
+ if (pEvdev->emulateWheel.enabled)
+ dt *= pEvdev->emulateWheel.inertia;
click_speed = ev->value / dt;
wheel->value = ev->value;
@@ -812,7 +815,7 @@ EvdevAccelWheel(InputInfoPtr pInfo, struct input_event *ev)
/**
* Take the relative motion input event and process it accordingly.
*/
-static void
+void
EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
{
int value;
@@ -2052,6 +2055,8 @@ EvdevAddRelValuatorClass(DeviceIntPtr device)
if (!EvdevBitIsSet(pEvdev->bitmask, EV_REL))
goto out;
+ EvdevForceWheel(pInfo);
+
num_axes = EvdevCountBits(pEvdev->rel_bitmask, NLONGS(REL_MAX));
if (num_axes < 1)
goto out;
@@ -2589,6 +2594,19 @@ EvdevGrabDevice(InputInfoPtr pInfo, int grab, int ungrab)
}
/**
+ * Some devices require REL_WHEEL and REL_HWHEEL axes to emulate wheel
+ * activities.
+ */
+static void
+EvdevForceWheel(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = pInfo->private;
+
+ EvdevSetBit(pEvdev->rel_bitmask, REL_WHEEL);
+ EvdevSetBit(pEvdev->rel_bitmask, REL_HWHEEL);
+}
+
+/**
* Some devices only have other axes (e.g. wheels), but we
* still need x/y for these. The server relies on devices having
* x/y as axes 0/1 and core/XI 1.x clients expect it too (#44655)
diff --git a/src/evdev.h b/src/evdev.h
index 7b7ca8d..38beb98 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -314,6 +314,10 @@ void EvdevPostAbsoluteMotionEvents(InputInfoPtr pInfo, int num_v, int first_v,
int v[MAX_VALUATORS]);
unsigned int EvdevUtilButtonEventToButtonNumber(EvdevPtr pEvdev, int code);
+/* Event processing functions */
+void EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo,
+ struct input_event *ev);
+
/* Middle Button emulation */
int EvdevMBEmuTimer(InputInfoPtr);
BOOL EvdevMBEmuFilterEvent(InputInfoPtr, int, BOOL);
--
1.8.4.1