summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Salch <emeraldd.chris@gmail.com>2008-08-06 22:08:13 -0500
committerPeter Hutterer <peter.hutterer@who-t.net>2008-08-07 16:04:31 +0930
commita9d72b40fbe178fa4fbb9d0e7c02dc6c5250969a (patch)
tree2eccade8fe136a632e5be72332b2145e5af5e6cb
parentc1f7f8c3d22ecae7839f82ea8b584069f54f1f5e (diff)
Adding mouse wheel emulation code.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--man/evdev.man44
-rw-r--r--src/Makefile.am4
-rw-r--r--src/emuWheel.c257
-rw-r--r--src/evdev.c11
-rw-r--r--src/evdev.h20
5 files changed, 334 insertions, 2 deletions
diff --git a/man/evdev.man b/man/evdev.man
index 0a4b71a..3b0f3b1 100644
--- a/man/evdev.man
+++ b/man/evdev.man
@@ -77,7 +77,49 @@ buttons can have the same mapping.
For example, a left-handed mouse with deactivated scroll-wheel would use a
mapping of "3 2 1 0 0". Invalid mappings are ignored and the default mapping
is used. Buttons not specified in the user's mapping use the default mapping.
-
+.TP 7
+.BI "Option \*qEmulateWheel\*q \*q" boolean \*q
+Enable/disable "wheel" emulation. Wheel emulation means emulating button
+press/release events when the mouse is moved while a specific real button
+is pressed. Wheel button events (typically buttons 4 and 5) are
+usually used for scrolling. Wheel emulation is useful for getting wheel-like
+behaviour with trackballs. It can also be useful for mice with 4 or
+more buttons but no wheel. See the description of the
+.BR EmulateWheelButton ,
+.BR EmulateWheelInertia ,
+.BR XAxisMapping ,
+and
+.B YAxisMapping
+options below. Default: off.
+.TP 7
+.BI "Option \*qEmulateWheelButton\*q \*q" integer \*q
+Specifies which button must be held down to enable wheel emulation mode.
+While this button is down, X and/or Y pointer movement will generate button
+press/release events as specified for the
+.B XAxisMapping
+and
+.B YAxisMapping
+settings. Default: 4.
+.TP 7
+.BI "Option \*qEmulateWheelInertia\*q \*q" integer \*q
+Specifies how far (in pixels) the pointer must move to generate button
+press/release events in wheel emulation mode. Default: 10.
+.TP 7
+.BI "Option \*qXAxisMapping\*q \*q" "N1 N2" \*q
+Specifies which buttons are mapped to motion in the X direction in wheel
+emulation mode. Button number
+.I N1
+is mapped to the negative X axis motion and button number
+.I N2
+is mapped to the positive X axis motion. Default: no mapping.
+.TP 7
+.BI "Option \*qYAxisMapping\*q \*q" "N1 N2" \*q
+Specifies which buttons are mapped to motion in the Y direction in wheel
+emulation mode. Button number
+.I N1
+is mapped to the negative Y axis motion and button number
+.I N2
+is mapped to the positive Y axis motion. Default: "4 5"
.SH AUTHORS
Kristian Høgsberg.
.SH "SEE ALSO"
diff --git a/src/Makefile.am b/src/Makefile.am
index d0b9b63..e6bb64e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,4 +30,6 @@
@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c \
@DRIVER_NAME@.h \
- emuMB.c
+ emuMB.c \
+ emuWheel.c
+
diff --git a/src/emuWheel.c b/src/emuWheel.c
new file mode 100644
index 0000000..e6c7f6e
--- /dev/null
+++ b/src/emuWheel.c
@@ -0,0 +1,257 @@
+/*
+* Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+* Copyright 1993 by David Dawes <dawes@xfree86.org>
+* Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
+* Copyright 1994-2002 by The XFree86 Project, Inc.
+* Copyright 2002 by Paul Elliott
+* (Ported from xf86-input-mouse, above copyrights taken from there)
+* Copyright 2008 by Chris Salch
+*
+* Permission to use, copy, modify, distribute, and sell this software
+* and its documentation for any purpose is hereby granted without
+* fee, provided that the above copyright notice appear in all copies
+* and that both that copyright notice and this permission notice
+* appear in supporting documentation, and that the name of the authors
+* not be used in advertising or publicity pertaining to distribution of the
+* software without specific, written prior permission. The authors make no
+* representations about the suitability of this software for any
+* purpose. It is provided "as is" without express or implied
+* warranty.
+*
+* THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+* NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*
+*/
+
+/* Mouse wheel emulation code. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "evdev.h"
+
+#define MSE_MAXBUTTONS 32
+#define WHEEL_NOT_CONFIGURED 0
+
+/* Local Funciton Prototypes */
+static BOOL EvdevWheelEmuHandleButtonMap(InputInfoPtr pInfo, WheelAxisPtr pAxis, char *axis_name);
+static void EvdevWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value);
+
+/* Filter mouse button events */
+BOOL
+EvdevWheelEmuFilterButton(InputInfoPtr pInfo, unsigned int button, int value)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+
+ /* Has wheel emulation been configured to be enabled? */
+ if (!pEvdev->emulateWheel.enabled)
+ return FALSE;
+
+ /* Check for EmulateWheelButton */
+ if (pEvdev->emulateWheel.button == button) {
+ pEvdev->emulateWheel.button_state = value;
+
+ return TRUE;
+ }
+
+ /* Don't care about this event */
+ return FALSE;
+}
+
+/* Filter mouse wheel events */
+BOOL
+EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ WheelAxisPtr pAxis = NULL;
+ int value = pEv->value;
+
+ /* Has wheel emulation been configured to be enabled? */
+ if (!pEvdev->emulateWheel.enabled)
+ return FALSE;
+
+ /* Handle our motion events if the emuWheel button is pressed*/
+ if (pEvdev->emulateWheel.button_state) {
+ /* We don't want to intercept real mouse wheel events */
+ switch(pEv->code) {
+ case REL_X:
+ pAxis = &(pEvdev->emulateWheel.X);
+ break;
+
+ case REL_Y:
+ pAxis = &(pEvdev->emulateWheel.Y);
+ break;
+
+ default:
+ break;
+ }
+
+ /* If we found REL_X or REL_Y, emulate a mouse wheel */
+ if (pAxis)
+ EvdevWheelEmuInertia(pInfo, pAxis, value);
+
+ /* Eat motion events while emulateWheel button pressed. */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Simulate inertia for our emulated mouse wheel */
+static void
+EvdevWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ int button;
+ int inertia;
+
+ /* if this axis has not been configured, just eat the motion */
+ if (!axis->up_button)
+ return;
+
+ 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;
+ xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
+ xf86PostButtonEvent(pInfo->dev, 0, button, 0, 0, 0);
+ }
+}
+
+/* Handle button mapping here to avoid code duplication,
+returns true if a button mapping was found. */
+static BOOL
+EvdevWheelEmuHandleButtonMap(InputInfoPtr pInfo, WheelAxisPtr pAxis, char* axis_name)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ char *option_string;
+
+ pAxis->up_button = WHEEL_NOT_CONFIGURED;
+
+ /* Check to see if there is configuration for this axis */
+ option_string = xf86SetStrOption(pInfo->options, axis_name, NULL);
+ if (option_string) {
+ int up_button = 0;
+ int down_button = 0;
+ char *msg = NULL;
+
+ if ((sscanf(option_string, "%d %d", &up_button, &down_button) == 2) &&
+ ((up_button > 0) && (up_button <= MSE_MAXBUTTONS)) &&
+ ((down_button > 0) && (down_button <= MSE_MAXBUTTONS))) {
+
+ /* Use xstrdup to allocate a string for us */
+ msg = xstrdup("buttons XX and YY");
+
+ if (msg)
+ sprintf(msg, "buttons %d and %d", up_button, down_button);
+
+ pAxis->up_button = up_button;
+ pAxis->down_button = down_button;
+
+ /* Update the number of buttons if needed */
+ if (up_button > pEvdev->buttons) pEvdev->buttons = up_button;
+ if (down_button > pEvdev->buttons) pEvdev->buttons = down_button;
+
+ } else {
+ xf86Msg(X_WARNING, "%s: Invalid %s value:\"%s\"\n",
+ pInfo->name, axis_name, option_string);
+
+ }
+
+ /* Clean up and log what happened */
+ if (msg) {
+ xf86Msg(X_CONFIG, "%s: %s: %s\n",pInfo->name, axis_name, msg);
+ xfree(msg);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* Setup the basic configuration options used by mouse wheel emulation */
+void
+EvdevWheelEmuPreInit(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ pEvdev->emulateWheel.enabled = FALSE;
+
+ if (xf86SetBoolOption(pInfo->options, "EmulateWheel", FALSE)) {
+ int wheelButton;
+ int inertia;
+
+ pEvdev->emulateWheel.enabled = TRUE;
+ wheelButton = xf86SetIntOption(pInfo->options,
+ "EmulateWheelButton", 4);
+
+ if ((wheelButton < 0) || (wheelButton > MSE_MAXBUTTONS)) {
+ xf86Msg(X_WARNING, "%s: Invalid EmulateWheelButton value: %d\n",
+ pInfo->name, wheelButton);
+ xf86Msg(X_WARNING, "%s: Wheel emulation disabled.\n", pInfo->name);
+
+ pEvdev->emulateWheel.enabled = FALSE;
+ return;
+ }
+
+ pEvdev->emulateWheel.button = wheelButton;
+
+ inertia = xf86SetIntOption(pInfo->options, "EmulateWheelInertia", 10);
+
+ if (inertia <= 0) {
+ xf86Msg(X_WARNING, "%s: Invalid EmulateWheelInertia value: %d\n",
+ pInfo->name, inertia);
+ xf86Msg(X_WARNING, "%s: Using built-in inertia value.\n",
+ pInfo->name);
+
+ inertia = 10;
+ }
+
+ pEvdev->emulateWheel.inertia = inertia;
+
+ /* Configure the Y axis or default it */
+ if (!EvdevWheelEmuHandleButtonMap(pInfo, &(pEvdev->emulateWheel.Y),
+ "YAxisMapping")) {
+ /* Default the Y axis to sane values */
+ pEvdev->emulateWheel.Y.up_button = 4;
+ pEvdev->emulateWheel.Y.down_button = 5;
+
+ /* Simpler to check just the largest value in this case */
+ /* XXX: we should post this to the server */
+ if (5 > pEvdev->buttons)
+ pEvdev->buttons = 5;
+
+ /* Display default Configuration */
+ xf86Msg(X_CONFIG, "%s: YAxisMapping: buttons %d and %d\n",
+ pInfo->name, pEvdev->emulateWheel.Y.up_button,
+ pEvdev->emulateWheel.Y.down_button);
+ }
+
+
+ /* This axis should default to an unconfigured state as most people
+ are not going to expect a Horizontal wheel. */
+ EvdevWheelEmuHandleButtonMap(pInfo, &(pEvdev->emulateWheel.X),
+ "XAxisMapping");
+
+ /* Used by the inertia code */
+ pEvdev->emulateWheel.X.traveled_distance = 0;
+ pEvdev->emulateWheel.Y.traveled_distance = 0;
+
+ xf86Msg(X_CONFIG, "%s: EmulateWheelButton: %d, EmulateWheelInertia: %d\n",
+ pInfo->name, pEvdev->emulateWheel.button, inertia);
+ }
+}
+
diff --git a/src/evdev.c b/src/evdev.c
index bbabb56..5bc562a 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -217,11 +217,16 @@ EvdevReadInput(InputInfoPtr pInfo)
break;
}
+
/* Get the signed value, earlier kernels had this as unsigned */
value = ev.value;
switch (ev.type) {
case EV_REL:
+ /* Handle mouse wheel emulation */
+ if (EvdevWheelEmuFilterMotion(pInfo, &ev))
+ break;
+
switch (ev.code) {
case REL_X:
dx += value;
@@ -286,6 +291,9 @@ EvdevReadInput(InputInfoPtr pInfo)
if (EvdevMBEmuFilterEvent(pInfo, button, value))
break;
+ if (EvdevWheelEmuFilterButton(pInfo, button, value))
+ break;
+
if (button)
xf86PostButtonEvent(pInfo->dev, 0, button, value, 0, 0);
else
@@ -943,7 +951,10 @@ EvdevProc(DeviceIntPtr device, int what)
{
xf86AddEnabledDevice(pInfo);
if (pEvdev->flags & EVDEV_BUTTON_EVENTS)
+ {
EvdevMBEmuPreInit(pInfo);
+ EvdevWheelEmuPreInit(pInfo);
+ }
device->public.on = TRUE;
}
break;
diff --git a/src/evdev.h b/src/evdev.h
index 56983c2..83f03f4 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -40,6 +40,13 @@
#include <X11/extensions/XKBstr.h>
#endif
+/* axis specific data for wheel emulation */
+typedef struct {
+ int up_button;
+ int down_button;
+ int traveled_distance;
+} WheelAxis, *WheelAxisPtr;
+
typedef struct {
int kernel24;
int screen;
@@ -68,6 +75,14 @@ typedef struct {
Time expires; /* time of expiry */
Time timeout;
} emulateMB;
+ struct {
+ BOOL enabled;
+ int button;
+ int button_state;
+ int inertia;
+ WheelAxis X;
+ WheelAxis Y;
+ } emulateWheel;
unsigned char btnmap[32]; /* config-file specified button mapping */
} EvdevRec, *EvdevPtr;
@@ -89,4 +104,9 @@ Atom EvdevMBEmuInitPropertyTimeout(DeviceIntPtr, char*);
BOOL EvdevMBEmuSetProperty(DeviceIntPtr, Atom, XIPropertyValuePtr);
#endif
+/* Mouse Wheel emulation */
+void EvdevWheelEmuPreInit(InputInfoPtr pInfo);
+BOOL EvdevWheelEmuFilterButton(InputInfoPtr pInfo, unsigned int button, int value);
+BOOL EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv);
+
#endif