[PATCH] mouse wheel acceleration
albert.zeyer at rwth-aachen.de
albert.zeyer at rwth-aachen.de
Thu Sep 2 05:44:00 PDT 2010
From: Albert Zeyer <albert.zeyer at rwth-aachen.de>
---
Xi/xiproperty.c | 2 +
dix/Makefile.am | 1 +
dix/devices.c | 23 ++++
dix/getevents.c | 34 ++++++-
dix/wheelveloc.c | 247 ++++++++++++++++++++++++++++++++++++++++++
hw/xfree86/loader/sdksyms.sh | 1 +
include/input.h | 7 ++
include/inputstr.h | 7 ++
include/wheelveloc.h | 61 +++++++++++
include/xserver-properties.h | 5 +
10 files changed, 387 insertions(+), 1 deletions(-)
create mode 100644 dix/wheelveloc.c
create mode 100644 include/wheelveloc.h
diff --git a/Xi/xiproperty.c b/Xi/xiproperty.c
index 2482171..ba6be2b 100644
--- a/Xi/xiproperty.c
+++ b/Xi/xiproperty.c
@@ -57,6 +57,8 @@ static struct dev_properties
{0, ACCEL_PROP_CONSTANT_DECELERATION},
{0, ACCEL_PROP_ADAPTIVE_DECELERATION},
{0, ACCEL_PROP_VELOCITY_SCALING},
+ {0, WHEELACCEL_PROP_SPEEDMULT},
+ {0, WHEELACCEL_PROP_MAXSPEED},
{0, AXIS_LABEL_PROP},
{0, AXIS_LABEL_PROP_REL_X},
{0, AXIS_LABEL_PROP_REL_Y},
diff --git a/dix/Makefile.am b/dix/Makefile.am
index 8917aea..03b9e4c 100644
--- a/dix/Makefile.am
+++ b/dix/Makefile.am
@@ -32,6 +32,7 @@ libdix_la_SOURCES = \
privates.c \
property.c \
ptrveloc.c \
+ wheelveloc.c \
registry.c \
resource.c \
selection.c \
diff --git a/dix/devices.c b/dix/devices.c
index 87b6dc7..59eeaba 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -62,6 +62,7 @@ SOFTWARE.
#include "cursorstr.h"
#include "dixstruct.h"
#include "ptrveloc.h"
+#include "wheelveloc.h"
#include "site.h"
#include "xkbsrv.h"
#include "privates.h"
@@ -843,6 +844,10 @@ CloseDevice(DeviceIntPtr dev)
if(dev->valuator && dev->valuator->accelScheme.AccelCleanupProc)
dev->valuator->accelScheme.AccelCleanupProc(dev);
+ /* free wheel acceleration info */
+ if(dev->button && dev->button->wheelAccelScheme.AccelCleanupProc)
+ dev->button->wheelAccelScheme.AccelCleanupProc(dev);
+
while (dev->xkb_interest)
XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource);
@@ -1152,6 +1157,8 @@ InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, Atom* labels,
{
ButtonClassPtr butc;
int i;
+
+ dev->button = NULL; /* reset it initially. some functions in InitWheelVelocityData rely on that */
butc = xcalloc(1, sizeof(ButtonClassRec));
if (!butc)
@@ -1163,6 +1170,22 @@ InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, Atom* labels,
for (i = numButtons + 1; i < MAP_LENGTH; i++)
butc->map[i] = i;
memcpy(butc->labels, labels, numButtons * sizeof(Atom));
+
+ /* wheel acceleration */
+ butc->wheelAccelScheme.AccelSchemeProc = NULL;
+ butc->wheelAccelScheme.accelData = NULL;
+ butc->wheelAccelScheme.AccelCleanupProc = NULL;
+ if (!IsMaster(dev) && /* do not accelerate master or xtest devices */
+ !IsXTestDevice(dev, NULL)) {
+ DeviceWheelVelocityPtr data = xalloc(sizeof(DeviceWheelVelocityRec));
+ if (data) {
+ InitWheelVelocityData(dev, data);
+ butc->wheelAccelScheme.AccelSchemeProc = ProcessWheelAccel;
+ butc->wheelAccelScheme.accelData = data;
+ butc->wheelAccelScheme.AccelCleanupProc = CleanupWheelAccel;
+ }
+ }
+
dev->button = butc;
return TRUE;
}
diff --git a/dix/getevents.c b/dix/getevents.c
index 82bb77b..a27f87c 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -65,6 +65,9 @@
/* Number of motion history events to store. */
#define MOTION_HISTORY_SIZE 256
+/* Wheel acceleration: maximum button press multiplier */
+#define MAX_WHEELBTN_MULTIPLIER 100
+
/* InputEventList is the container list for all input events generated by the
* DDX. The DDX is expected to call GetEventList() and then pass the list into
* Get{Pointer|Keyboard}Events.
@@ -565,9 +568,10 @@ int
GetMaximumEventsNum(void) {
/* One raw event
* One device event
+ * Evtl. additional events for wheel acceleration, MAX_WHEELBTN_MULTIPLIER * 2 (up + down)
* One possible device changed event
*/
- return 3;
+ return 1 + 1 + MAX_WHEELBTN_MULTIPLIER * 2 + 1;
}
@@ -1120,6 +1124,34 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
set_valuators(pDev, event, first_valuator, num_valuators, valuators);
+ /* wheel acceleration */
+ if(type == ButtonPress && (/* wheel scrolling */ buttons >= 4 && buttons < 8))
+ {
+ int add_num_button_presses = 0;
+ if (pDev->button->wheelAccelScheme.AccelSchemeProc)
+ pDev->button->wheelAccelScheme.AccelSchemeProc(pDev, buttons, &add_num_button_presses, ms);
+
+ if(add_num_button_presses > MAX_WHEELBTN_MULTIPLIER)
+ add_num_button_presses = MAX_WHEELBTN_MULTIPLIER;
+
+ add_num_button_presses *= 2; /* we handle even numbers as button release, odd as btn press */
+ while(add_num_button_presses > 0) {
+ events++;
+ num_events++;
+ event = (DeviceEvent*) events->event;
+
+ init_event(pDev, event, ms);
+ event->type = (add_num_button_presses % 2 == 0) ? ET_ButtonRelease : ET_ButtonPress;
+ event->detail.button = buttons;
+ event->root_x = cx; /* root_x/y always in screen coords */
+ event->root_y = cy;
+ event->root_x_frac = cx_frac;
+ event->root_y_frac = cy_frac;
+
+ add_num_button_presses--;
+ }
+ }
+
return num_events;
}
diff --git a/dix/wheelveloc.c b/dix/wheelveloc.c
new file mode 100644
index 0000000..9efc9a6
--- /dev/null
+++ b/dix/wheelveloc.c
@@ -0,0 +1,247 @@
+/*
+ *
+ * Copyright © 2010 Albert Zeyer albert . zeyer @ rwth - aachen . de
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <math.h>
+#include <wheelveloc.h>
+#include <exevents.h>
+#include <X11/Xatom.h>
+
+#include <xserver-properties.h>
+
+/*****************************************************************************
+ * mouse wheel acceleration
+ *
+ * 2010 by Albert Zeyer (albert . zeyer @ rwth - aachen . de)
+ *
+ * Because mouse wheel scrolling is done via button press/release events,
+ * we will post multiple such events to emulate a wheel scroll acceleration.
+ *
+ * The functions provided here will calculate a simple linear acceleration.
+ *
+ ****************************************************************************/
+
+/* fwd */
+
+static void
+InitializeWheelAccelerationProperties(DeviceIntPtr dev, DeviceWheelVelocityPtr vel);
+
+
+
+/********************************
+ * Init/Uninit
+ *******************************/
+
+/**
+ * Init struct so it should match the average case
+ */
+void
+InitWheelVelocityData(DeviceIntPtr dev, DeviceWheelVelocityPtr vel)
+{
+ memset(vel, 0, sizeof(DeviceWheelVelocityRec));
+
+ for(int i = 0; i < sizeof(vel->lastWheelEvent)/sizeof(vel->lastWheelEvent[0]); ++i) {
+ vel->lastWheelEvent[i].delta = 0;
+ vel->lastWheelEvent[i].time = 0;
+ }
+ vel->speed_mult = 1.0;
+ vel->max_speed = 0; /* no acceleration */
+
+ InitializeWheelAccelerationProperties(dev, vel);
+}
+
+
+/*
+ * dix uninit helper, called through scheme
+ */
+void
+CleanupWheelAccel(DeviceIntPtr dev)
+{
+ dev->button->wheelAccelScheme.AccelSchemeProc = NULL;
+
+ if (dev->button->wheelAccelScheme.accelData != NULL) {
+ xfree(dev->valuator->accelScheme.accelData);
+ dev->valuator->accelScheme.accelData = NULL;
+ }
+}
+
+
+/*************************
+ * Input property support
+ ************************/
+
+/**
+ * constant deceleration
+ */
+static int
+WheelAccelSetSpeedMultProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkOnly)
+{
+ DeviceWheelVelocityPtr vel;
+ float v, *ptr = &v;
+ int rc;
+ int nelem = 1;
+
+ if (atom != XIGetKnownProperty(WHEELACCEL_PROP_SPEEDMULT))
+ return Success;
+
+ if (!dev->button)
+ return BadValue;
+ vel = (DeviceWheelVelocityPtr)dev->button->wheelAccelScheme.accelData;
+ if (!vel)
+ return BadValue;
+ rc = XIPropToFloat(val, &nelem, &ptr);
+
+ if(checkOnly)
+ {
+ if (rc)
+ return rc;
+ return (v >= 0.0f) ? Success : BadValue;
+ }
+
+ if (v >= 0.0f)
+ vel->speed_mult = v;
+
+ return Success;
+}
+
+static void
+WheelAccelInitSpeedMultProperty(DeviceIntPtr dev, DeviceWheelVelocityPtr vel)
+{
+ float fval = vel->speed_mult;
+ Atom prop_speedmult = XIGetKnownProperty(WHEELACCEL_PROP_SPEEDMULT);
+ XIChangeDeviceProperty(dev, prop_speedmult,
+ XIGetKnownProperty(XATOM_FLOAT), 32,
+ PropModeReplace, 1, &fval, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_speedmult, FALSE);
+ XIRegisterPropertyHandler(dev, WheelAccelSetSpeedMultProperty, NULL, NULL);
+}
+
+
+/**
+ * choose profile
+ */
+static int
+WheelAccelSetMaxSpeedProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkOnly)
+{
+ DeviceWheelVelocityPtr vel;
+ int v, *ptr = &v;
+ int rc;
+ int nelem = 1;
+
+ if (atom != XIGetKnownProperty(WHEELACCEL_PROP_MAXSPEED))
+ return Success;
+
+ if (!dev->button)
+ return BadValue;
+ vel = (DeviceWheelVelocityPtr)dev->button->wheelAccelScheme.accelData;
+ if (!vel)
+ return BadValue;
+ rc = XIPropToInt(val, &nelem, &ptr);
+
+ if(checkOnly)
+ {
+ if (rc)
+ return rc;
+ return (v >= 0) ? Success : BadValue;
+ }
+
+ if (v >= 0)
+ vel->max_speed = v;
+
+ return Success;
+}
+
+static void
+WheelAccelInitMaxSpeedProperty(DeviceIntPtr dev, DeviceWheelVelocityPtr vel)
+{
+ int maxspeed = vel->max_speed;
+ Atom prop_maxspeed = XIGetKnownProperty(WHEELACCEL_PROP_MAXSPEED);
+
+ XIChangeDeviceProperty(dev, prop_maxspeed, XA_INTEGER, 32,
+ PropModeReplace, 1, &maxspeed, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_maxspeed, FALSE);
+ XIRegisterPropertyHandler(dev, WheelAccelSetMaxSpeedProperty, NULL, NULL);
+}
+
+static void
+InitializeWheelAccelerationProperties(DeviceIntPtr dev, DeviceWheelVelocityPtr vel)
+{
+ WheelAccelInitSpeedMultProperty(dev, vel);
+ WheelAccelInitMaxSpeedProperty(dev, vel);
+}
+
+
+/********************************
+ * acceleration proc
+ *******************************/
+
+
+void
+ProcessWheelAccel(
+ DeviceIntPtr dev,
+ int button,
+ int* add_num_button_presses,
+ int evtime)
+{
+ DeviceWheelVelocityPtr velocitydata =
+ (DeviceWheelVelocityPtr) dev->button->wheelAccelScheme.accelData;
+ int axeIndex = 0;
+ int delta = 0;
+ float dt;
+ *add_num_button_presses = 0;
+
+ if (!add_num_button_presses || !velocitydata)
+ return;
+
+ switch(button) {
+ case 4: axeIndex = 0; delta = -1; break;
+ case 5: axeIndex = 0; delta = 1; break;
+ case 6: axeIndex = 1; delta = -1; break;
+ case 7: axeIndex = 1; delta = 1; break;
+ default: /* unknown wheel button number */ return;
+ }
+
+ if(velocitydata->lastWheelEvent[axeIndex].delta != delta)
+ /* we scrolled in a different direction than before -> dont accel */
+ goto finish;
+
+ if(evtime < velocitydata->lastWheelEvent[axeIndex].time)
+ /* this should not happen */
+ goto finish;
+
+ dt = evtime - velocitydata->lastWheelEvent[axeIndex].time;
+ *add_num_button_presses = (int) (velocitydata->speed_mult / dt);
+ if(*add_num_button_presses > velocitydata->max_speed)
+ *add_num_button_presses = velocitydata->max_speed;
+
+finish:
+ velocitydata->lastWheelEvent[axeIndex].delta = delta;
+ velocitydata->lastWheelEvent[axeIndex].time = evtime;
+}
+
diff --git a/hw/xfree86/loader/sdksyms.sh b/hw/xfree86/loader/sdksyms.sh
index eea0240..fbe4663 100755
--- a/hw/xfree86/loader/sdksyms.sh
+++ b/hw/xfree86/loader/sdksyms.sh
@@ -296,6 +296,7 @@ cat > sdksyms.c << EOF
#include "property.h"
#include "propertyst.h"
#include "ptrveloc.h"
+#include "wheelveloc.h"
#include "region.h"
#include "regionstr.h"
#include "registry.h"
diff --git a/include/input.h b/include/input.h
index 4a845be..e3bc7f8 100644
--- a/include/input.h
+++ b/include/input.h
@@ -146,6 +146,13 @@ typedef void (*PointerAccelSchemeProc)(
int* /*valuators*/,
int /*evtime*/);
+/* wheel acceleration handling */
+typedef void (*WheelAccelSchemeProc)(
+ DeviceIntPtr /*pDev*/,
+ int /*button*/,
+ int* /*add_num_button_presses*/,
+ int /*evtime*/);
+
typedef void (*DeviceCallbackProc)(
DeviceIntPtr /*pDev*/);
diff --git a/include/inputstr.h b/include/inputstr.h
index 15184d0..3de7519 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -241,6 +241,12 @@ typedef struct _ValuatorClassRec {
ValuatorAccelerationRec accelScheme;
} ValuatorClassRec, *ValuatorClassPtr;
+typedef struct _WheelAccelerationRec {
+ WheelAccelSchemeProc AccelSchemeProc;
+ void *accelData; /* at disposal of AccelScheme */
+ DeviceCallbackProc AccelCleanupProc;
+} WheelAccelerationRec, *WheelAccelerationPtr;
+
typedef struct _ButtonClassRec {
int sourceid;
CARD8 numButtons;
@@ -256,6 +262,7 @@ typedef struct _ButtonClassRec {
CARD8 map[MAP_LENGTH];
union _XkbAction *xkb_acts;
Atom labels[MAX_BUTTONS];
+ WheelAccelerationRec wheelAccelScheme;
} ButtonClassRec, *ButtonClassPtr;
typedef struct _FocusClassRec {
diff --git a/include/wheelveloc.h b/include/wheelveloc.h
new file mode 100644
index 0000000..13c6146
--- /dev/null
+++ b/include/wheelveloc.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright © 2010 Albert Zeyer albert . zeyer @ rwth - aachen . de
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef WHEELVELOCITY_H
+#define WHEELVELOCITY_H
+
+#include <input.h> /* DeviceIntPtr */
+
+/**
+ * a motion history, with just enough information to
+ * calc mean velocity
+ */
+typedef struct _WheelTracker {
+ int delta; /* accumulated delta */
+ int time; /* time of creation */
+} WheelTrackerRec, *WheelTrackerPtr;
+
+/**
+ * Contains all data needed to implement wheel ballistics
+ */
+typedef struct _DeviceWheelVelocityRec {
+ WheelTrackerRec lastWheelEvent[2]; /* 2 for both Z and W axes */
+ int add_num_button_presses;
+ float speed_mult; /* config: speed multiplier */
+ int max_speed; /* config: max speed */
+} DeviceWheelVelocityRec, *DeviceWheelVelocityPtr;
+
+
+extern _X_EXPORT void
+InitWheelVelocityData(DeviceIntPtr dev, DeviceWheelVelocityPtr vel);
+
+extern _X_INTERNAL void
+CleanupWheelAccel(DeviceIntPtr dev);
+
+extern _X_INTERNAL void
+ProcessWheelAccel(DeviceIntPtr dev, int button,
+ int* add_num_button_presses, int evtime);
+
+
+#endif /* POINTERVELOCITY_H */
diff --git a/include/xserver-properties.h b/include/xserver-properties.h
index 626d0ad..fc0fe56 100644
--- a/include/xserver-properties.h
+++ b/include/xserver-properties.h
@@ -45,6 +45,11 @@
/* FLOAT, format 32 */
#define ACCEL_PROP_VELOCITY_SCALING "Device Accel Velocity Scaling"
+/* Wheel acceleration properties */
+/* FLOAT, format 32*/
+#define WHEELACCEL_PROP_SPEEDMULT "Device Wheel Accel Speed Multiplier"
+/* INTEGER of any format. 0 - no acceleration */
+#define WHEELACCEL_PROP_MAXSPEED "Device Wheel Accel Max Speed"
/* Axis labels */
#define AXIS_LABEL_PROP "Axis Labels"
--
1.7.0.4
More information about the xorg-devel
mailing list