diff options
-rw-r--r-- | driver/xf86-input-ws/include/ws-properties.h | 12 | ||||
-rw-r--r-- | driver/xf86-input-ws/man/ws.man | 82 | ||||
-rw-r--r-- | driver/xf86-input-ws/src/Makefile.am | 3 | ||||
-rw-r--r-- | driver/xf86-input-ws/src/Makefile.in | 7 | ||||
-rw-r--r-- | driver/xf86-input-ws/src/emuwheel.c | 380 | ||||
-rw-r--r-- | driver/xf86-input-ws/src/ws.c | 186 | ||||
-rw-r--r-- | driver/xf86-input-ws/src/ws.h | 35 |
7 files changed, 604 insertions, 101 deletions
diff --git a/driver/xf86-input-ws/include/ws-properties.h b/driver/xf86-input-ws/include/ws-properties.h index dd58eab99..f6d902859 100644 --- a/driver/xf86-input-ws/include/ws-properties.h +++ b/driver/xf86-input-ws/include/ws-properties.h @@ -23,6 +23,18 @@ /* CARD32 */ #define WS_PROP_MIDBUTTON_TIMEOUT "WS Pointer Middle Button Timeout" +/* Mouse wheel emulation */ +/* BOOL */ +#define WS_PROP_WHEEL "WS Pointer Wheel Emulation" +/* CARD8, 4 values [x up, x down, y up, y down], 0 to disable a value */ +#define WS_PROP_WHEEL_AXES "WS Pointer Wheel Emulation Axes" +/* CARD16 */ +#define WS_PROP_WHEEL_INERTIA "WS Pointer Wheel Emulation Inertia" +/* CARD32 */ +#define WS_PROP_WHEEL_TIMEOUT "WS Pointer Wheel Emulation Timeout" +/* CARD8, value range 0-32, 0 to always scroll */ +#define WS_PROP_WHEEL_BUTTON "WS Pointer Wheel Emulation Button" + /* Run-time calibration */ /* CARD32, 4 values [minx, maxx, miny, maxy], or no values for unset */ #define WS_PROP_CALIBRATION "WS Pointer Axis Calibration" diff --git a/driver/xf86-input-ws/man/ws.man b/driver/xf86-input-ws/man/ws.man index 2e4acea20..09c23c15e 100644 --- a/driver/xf86-input-ws/man/ws.man +++ b/driver/xf86-input-ws/man/ws.man @@ -1,4 +1,4 @@ -.\" $OpenBSD: ws.man,v 1.11 2011/11/19 12:28:10 shadchin Exp $ +.\" $OpenBSD: ws.man,v 1.12 2011/11/28 23:49:59 shadchin Exp $ .\" .\" Copyright (c) 2005,2009,2011 Matthieu Herrb .\" @@ -69,6 +69,51 @@ Sets the timeout (in milliseconds) that the driver waits before deciding if two buttons where pressed "simultaneously" when 3 button emulation is enabled. Default: 50. .TP 4 +.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 EmulateWheelTimeout , +.BR XAxisMapping , +and +.B YAxisMapping +options. +Default: off. +.TP 4 +.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. +If the button is 0 and +.BR EmulateWheel +is on, any motion of the device is converted into wheel events. +Default:\ 4. +.TP 4 +.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 4 +.BI "Option \*qEmulateWheelTimeout\*q \*q" integer \*q +Specifies the time in milliseconds the +.BR EmulateWheelButton +must be pressed before wheel emulation is started. +If the +.BR EmulateWheelButton +is released before this timeout, the original button press/release event +is sent. +Default:\ 200. +.TP 4 .BI "Option \*qDebugLevel\*q \*q" integer \*q This option sets the verbosity level of the driver. It defaults to 0, which means no extra debug output. @@ -107,6 +152,26 @@ clockwise, counter-clockwise, or upside-down respectively. .BI "Option \*qSwapXY\*q \*q" boolean \*q swaps the X and Y axis of the input device if set. Default: false. .TP 4 +.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 4 +.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". +.TP 4 .BI "Option \*qZAxisMapping\*q \*q" "N1 N2" \*q Set the mapping for the Z axis (wheel) motion to buttons. Button number @@ -135,6 +200,21 @@ driver. .BI "WS Pointer Middle Button Timeout" 1 32-bit positive value (unit: milliseconds) .TP 7 +.BI "WS Pointer Wheel Emulation" +1 boolean value (8 bit, 0 or 1). +.TP 7 +.BI "WS Pointer Wheel Emulation Axes" +4 8-bit values, order X up, X down, Y up, Y down. 0 disables a value. +.TP 7 +.BI "WS Pointer Wheel Emulation Button" +1 8-bit value, allowed range 0-32, 0 to always scroll. +.TP 7 +.BI "WS Pointer Wheel Emulation Inertia" +1 16-bit positive value. +.TP 7 +.BI "WS Pointer Wheel Emulation Timeout" +1 32-bit positive value (unit: milliseconds). +.TP 7 .BI "WS Pointer Axis Calibration" 4 32 bits values, in the order min-x, max-x, min-y, max-y. This property is present only for devices with absolute coordinates (ie diff --git a/driver/xf86-input-ws/src/Makefile.am b/driver/xf86-input-ws/src/Makefile.am index 989f2457c..a400d3f40 100644 --- a/driver/xf86-input-ws/src/Makefile.am +++ b/driver/xf86-input-ws/src/Makefile.am @@ -24,4 +24,5 @@ INCLUDES=-I$(top_srcdir)/include/ @DRIVER_NAME@_drv_la_SOURCES = \ @DRIVER_NAME@.c \ @DRIVER_NAME@.h \ - emumb.c + emumb.c \ + emuwheel.c diff --git a/driver/xf86-input-ws/src/Makefile.in b/driver/xf86-input-ws/src/Makefile.in index 562c9698f..c9e098b27 100644 --- a/driver/xf86-input-ws/src/Makefile.in +++ b/driver/xf86-input-ws/src/Makefile.in @@ -55,7 +55,8 @@ am__installdirs = "$(DESTDIR)$(@DRIVER_NAME@_drv_ladir)" @DRIVER_NAME@_drv_laLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(@DRIVER_NAME@_drv_la_LTLIBRARIES) @DRIVER_NAME@_drv_la_LIBADD = -am_@DRIVER_NAME@_drv_la_OBJECTS = @DRIVER_NAME@.lo emumb.lo +am_@DRIVER_NAME@_drv_la_OBJECTS = @DRIVER_NAME@.lo emumb.lo \ + emuwheel.lo @DRIVER_NAME@_drv_la_OBJECTS = $(am_@DRIVER_NAME@_drv_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -230,7 +231,8 @@ INCLUDES = -I$(top_srcdir)/include/ @DRIVER_NAME@_drv_la_SOURCES = \ @DRIVER_NAME@.c \ @DRIVER_NAME@.h \ - emumb.c + emumb.c \ + emuwheel.c all: all-am @@ -303,6 +305,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/@DRIVER_NAME@.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emumb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emuwheel.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ diff --git a/driver/xf86-input-ws/src/emuwheel.c b/driver/xf86-input-ws/src/emuwheel.c new file mode 100644 index 000000000..0be81a576 --- /dev/null +++ b/driver/xf86-input-ws/src/emuwheel.c @@ -0,0 +1,380 @@ +/* $OpenBSD: emuwheel.c,v 1.1 2011/11/28 23:49:59 shadchin Exp $ */ +/* +* 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 +* Copyright © 2008 Red Hat, Inc. +* +* 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 <xorg-server.h> +#include <X11/Xatom.h> +#include <xf86.h> +#include <xf86_OSproc.h> +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include <xf86Xinput.h> +#include <exevents.h> + +#include <ws-properties.h> + +#include "ws.h" + +static Atom prop_wheel_emu; +static Atom prop_wheel_axismap; +static Atom prop_wheel_inertia; +static Atom prop_wheel_timeout; +static Atom prop_wheel_button; + +static int wsWheelEmuInertia(InputInfoPtr, WheelAxisPtr, int); +static int wsWheelEmuSetProperty(DeviceIntPtr, Atom, XIPropertyValuePtr, BOOL); + +BOOL +wsWheelEmuFilterButton(InputInfoPtr pInfo, unsigned int button, int press) +{ + WSDevicePtr priv = (WSDevicePtr)pInfo->private; + int ms; + + if (!priv->emulateWheel.enabled) + return FALSE; + + if (priv->emulateWheel.button == button) { + priv->emulateWheel.button_state = press; + + if (press) { + priv->emulateWheel.expires = GetTimeInMillis() + + priv->emulateWheel.timeout; + } else { + ms = priv->emulateWheel.expires - GetTimeInMillis(); + + if (ms > 0) { + /* + * If the button is released early enough emit + * the button press/release events + */ + wsButtonClicks(pInfo, button, 1); + } + } + + return TRUE; + } + + return FALSE; +} + +BOOL +wsWheelEmuFilterMotion(InputInfoPtr pInfo, int dx, int dy) +{ + WSDevicePtr priv = (WSDevicePtr)pInfo->private; + WheelAxisPtr pAxis = NULL, pOtherAxis = NULL; + int value; + + if (!priv->emulateWheel.enabled) + return FALSE; + + /* + * Handle our motion events if the emuWheel button is pressed. + * Wheel button of 0 means always emulate wheel. + */ + if (priv->emulateWheel.button_state || priv->emulateWheel.button == 0) { + if (priv->emulateWheel.button) { + int ms = priv->emulateWheel.expires - GetTimeInMillis(); + + if (ms > 0) + return TRUE; + } + + if (dx) { + pAxis = &(priv->emulateWheel.X); + pOtherAxis = &(priv->emulateWheel.Y); + value = dx; + } else if (dy) { + pAxis = &(priv->emulateWheel.Y); + pOtherAxis = &(priv->emulateWheel.X); + value = dy; + } else + return FALSE; + + /* + * Reset the inertia of the other axis when a scroll event + * was sent to avoid the buildup of erroneous scroll events if the + * user doesn't move in a perfectly straight line. + */ + if (pAxis) { + if (wsWheelEmuInertia(pInfo, pAxis, value)) + pOtherAxis->traveled_distance = 0; + } + + return TRUE; + } + + return FALSE; +} + +static int +wsWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value) +{ + WSDevicePtr priv = (WSDevicePtr)pInfo->private; + int button, inertia; + int rc = 0; + + if (axis->negative == WS_NOMAP) + return rc; + + axis->traveled_distance += value; + + if (axis->traveled_distance < 0) { + button = axis->negative; + inertia = -priv->emulateWheel.inertia; + } else { + button = axis->positive; + inertia = priv->emulateWheel.inertia; + } + + while (abs(axis->traveled_distance) > priv->emulateWheel.inertia) { + axis->traveled_distance -= inertia; + wsButtonClicks(pInfo, button, 1); + rc++; + } + + return rc; +} + +void +wsWheelEmuPreInit(InputInfoPtr pInfo) +{ + WSDevicePtr priv = (WSDevicePtr)pInfo->private; + int button, inertia, timeout; + + priv->emulateWheel.enabled = xf86SetBoolOption(pInfo->options, + "EmulateWheel", FALSE); + + button = xf86SetIntOption(pInfo->options, "EmulateWheelButton", 4); + if (button < 0 || button > NBUTTONS) { + xf86IDrvMsg(pInfo, X_WARNING, + "Invalid EmulateWheelButton value: %d\n", button); + xf86IDrvMsg(pInfo, X_WARNING, "Wheel emulation disabled\n"); + priv->emulateWheel.enabled = FALSE; + button = 4; + } + priv->emulateWheel.button = button; + + inertia = xf86SetIntOption(pInfo->options, "EmulateWheelInertia", 10); + if (inertia <= 0) { + xf86IDrvMsg(pInfo, X_WARNING, + "Invalid EmulateWheelInertia value: %d\n", inertia); + xf86IDrvMsg(pInfo, X_WARNING, "Using built-in inertia value\n"); + inertia = 10; + } + priv->emulateWheel.inertia = inertia; + + timeout = xf86SetIntOption(pInfo->options, "EmulateWheelTimeout", 200); + if (timeout < 0) { + xf86IDrvMsg(pInfo, X_WARNING, + "Invalid EmulateWheelTimeout value: %d\n", timeout); + xf86IDrvMsg(pInfo, X_WARNING, "Using built-in timeout value\n"); + timeout = 200; + } + priv->emulateWheel.timeout = timeout; + + wsWheelHandleButtonMap(pInfo, &(priv->emulateWheel.Y), + "YAxisMapping", "4 5"); + wsWheelHandleButtonMap(pInfo, &(priv->emulateWheel.X), + "XAxisMapping", NULL); +} + +static int +wsWheelEmuSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, + BOOL checkonly) +{ + InputInfoPtr pInfo = (InputInfoPtr)dev->public.devicePrivate; + WSDevicePtr priv = (WSDevicePtr)pInfo->private; + + if (atom == prop_wheel_emu) { + if (val->format != 8 || val->size != 1 || + val->type != XA_INTEGER) + return BadMatch; + + if (!checkonly) + priv->emulateWheel.enabled = *((BOOL*)val->data) != 0; + } else if (atom == prop_wheel_button) { + int button; + + if (val->format != 8 || val->size != 1 || + val->type != XA_INTEGER) + return BadMatch; + + button = *((CARD8*)val->data); + + if (button < 0 || button > NBUTTONS) + return BadValue; + + if (!checkonly) + priv->emulateWheel.button = button; + } else if (atom == prop_wheel_axismap) { + int x_negative, x_positive; + int y_negative, y_positive; + + if (val->format != 8 || val->size != 4 || + val->type != XA_INTEGER) + return BadMatch; + + x_negative = *((CARD8*)val->data); + x_positive = *(((CARD8*)val->data) + 1); + y_negative = *(((CARD8*)val->data) + 2); + y_positive = *(((CARD8*)val->data) + 3); + + if (x_negative < 0 || x_negative > NBUTTONS || + x_positive < 0 || x_positive > NBUTTONS || + y_negative < 0 || y_negative > NBUTTONS || + y_positive < 0 || y_positive > NBUTTONS) + return BadValue; + + if ((x_negative == WS_NOMAP && x_positive != WS_NOMAP) || + (x_negative != WS_NOMAP && x_positive == WS_NOMAP) || + (y_negative == WS_NOMAP && y_positive != WS_NOMAP) || + (y_negative != WS_NOMAP && y_positive == WS_NOMAP)) + return BadValue; + + if (!checkonly) { + priv->emulateWheel.X.negative = x_negative; + priv->emulateWheel.X.positive = x_positive; + priv->emulateWheel.Y.negative = y_negative; + priv->emulateWheel.Y.positive = y_positive; + } + } else if (atom == prop_wheel_inertia) { + int inertia; + + if (val->format != 16 || val->size != 1 || + val->type != XA_INTEGER) + return BadMatch; + + inertia = *((CARD16*)val->data); + + if (inertia <= 0) + return BadValue; + + if (!checkonly) + priv->emulateWheel.inertia = inertia; + } else if (atom == prop_wheel_timeout) { + int timeout; + + if (val->format != 32 || val->size != 1 || + val->type != XA_INTEGER) + return BadMatch; + + timeout = *((CARD32*)val->data); + + if (timeout < 0) + return BadValue; + + if (!checkonly) + priv->emulateWheel.timeout = timeout; + } + + return Success; +} + +void +wsWheelEmuInitProperty(DeviceIntPtr dev) +{ + InputInfoPtr pInfo = (InputInfoPtr)dev->public.devicePrivate; + WSDevicePtr priv = (WSDevicePtr)pInfo->private; + char vals[4]; + int rc; + + prop_wheel_emu = MakeAtom(WS_PROP_WHEEL, strlen(WS_PROP_WHEEL), TRUE); + rc = XIChangeDeviceProperty(dev, prop_wheel_emu, XA_INTEGER, 8, + PropModeReplace, 1, &priv->emulateWheel.enabled, FALSE); + if (rc != Success) { + xf86IDrvMsg(pInfo, X_ERROR, + "cannot create device property %s: %d\n", + WS_PROP_WHEEL, rc); + return; + } + XISetDevicePropertyDeletable(dev, prop_wheel_emu, FALSE); + + vals[0] = priv->emulateWheel.X.negative; + vals[1] = priv->emulateWheel.X.positive; + vals[2] = priv->emulateWheel.Y.negative; + vals[3] = priv->emulateWheel.Y.positive; + + prop_wheel_axismap = MakeAtom(WS_PROP_WHEEL_AXES, + strlen(WS_PROP_WHEEL_AXES), TRUE); + rc = XIChangeDeviceProperty(dev, prop_wheel_axismap, XA_INTEGER, 8, + PropModeReplace, 4, vals, FALSE); + if (rc != Success) { + xf86IDrvMsg(pInfo, X_ERROR, + "cannot create device property %s: %d\n", + WS_PROP_WHEEL_AXES, rc); + return; + } + XISetDevicePropertyDeletable(dev, prop_wheel_axismap, FALSE); + + prop_wheel_inertia = MakeAtom(WS_PROP_WHEEL_INERTIA, + strlen(WS_PROP_WHEEL_INERTIA), TRUE); + rc = XIChangeDeviceProperty(dev, prop_wheel_inertia, XA_INTEGER, 16, + PropModeReplace, 1, &priv->emulateWheel.inertia, FALSE); + if (rc != Success) { + xf86IDrvMsg(pInfo, X_ERROR, + "cannot create device property %s: %d\n", + WS_PROP_WHEEL_INERTIA, rc); + return; + } + XISetDevicePropertyDeletable(dev, prop_wheel_inertia, FALSE); + + prop_wheel_timeout = MakeAtom(WS_PROP_WHEEL_TIMEOUT, + strlen(WS_PROP_WHEEL_TIMEOUT), TRUE); + rc = XIChangeDeviceProperty(dev, prop_wheel_timeout, XA_INTEGER, 32, + PropModeReplace, 1, &priv->emulateWheel.timeout, FALSE); + if (rc != Success) { + xf86IDrvMsg(pInfo, X_ERROR, + "cannot create device property %s: %d\n", + WS_PROP_WHEEL_TIMEOUT, rc); + return; + } + XISetDevicePropertyDeletable(dev, prop_wheel_timeout, FALSE); + + prop_wheel_button = MakeAtom(WS_PROP_WHEEL_BUTTON, + strlen(WS_PROP_WHEEL_BUTTON), TRUE); + rc = XIChangeDeviceProperty(dev, prop_wheel_button, XA_INTEGER, 8, + PropModeReplace, 1, &priv->emulateWheel.button, FALSE); + if (rc != Success) { + xf86IDrvMsg(pInfo, X_ERROR, + "cannot create device property %s: %d\n", + WS_PROP_WHEEL_BUTTON, rc); + return; + } + XISetDevicePropertyDeletable(dev, prop_wheel_button, FALSE); + + XIRegisterPropertyHandler(dev, wsWheelEmuSetProperty, NULL, NULL); +} diff --git a/driver/xf86-input-ws/src/ws.c b/driver/xf86-input-ws/src/ws.c index dae88fbe1..301f316a0 100644 --- a/driver/xf86-input-ws/src/ws.c +++ b/driver/xf86-input-ws/src/ws.c @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $OpenBSD: ws.c,v 1.49 2011/11/19 13:12:49 shadchin Exp $ */ +/* $OpenBSD: ws.c,v 1.50 2011/11/28 23:49:59 shadchin Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -144,52 +144,9 @@ wsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags) priv->buttons = DFLTBUTTONS; buttons_from = X_DEFAULT; } - priv->negativeZ = priv->positiveZ = WS_NOMAP; - s = xf86SetStrOption(pInfo->options, "ZAxisMapping", "4 5"); - if (s) { - int b1, b2; - if (sscanf(s, "%d %d", &b1, &b2) == 2 && - b1 > 0 && b1 <= NBUTTONS && - b2 > 0 && b2 <= NBUTTONS) { - priv->negativeZ = 1 << (b1 - 1); - priv->positiveZ = 1 << (b2 - 1); - xf86IDrvMsg(pInfo, X_CONFIG, - "ZAxisMapping: buttons %d and %d\n", - b1, b2); - if (max(b1, b2) > priv->buttons) { - priv->buttons = max(b1, b2); - buttons_from = X_CONFIG; - } - } else { - xf86IDrvMsg(pInfo, X_WARNING, - "invalid ZAxisMapping value: \"%s\"\n", s); - } - free(s); - } - priv->negativeW = priv->positiveW = WS_NOMAP; - s = xf86SetStrOption(pInfo->options, "WAxisMapping", "6 7"); - if (s) { - int b1, b2; - - if (sscanf(s, "%d %d", &b1, &b2) == 2 && - b1 > 0 && b1 <= NBUTTONS && - b2 > 0 && b2 <= NBUTTONS) { - priv->negativeW = 1 << (b1 - 1); - priv->positiveW = 1 << (b2 - 1); - xf86IDrvMsg(pInfo, X_CONFIG, - "WAxisMapping: buttons %d and %d\n", - b1, b2); - if (max(b1, b2) > priv->buttons) { - priv->buttons = max(b1, b2); - buttons_from = X_CONFIG; - } - } else { - xf86IDrvMsg(pInfo, X_WARNING, - "invalid WAxisMapping value: \"%s\"\n", s); - } - free(s); - } + wsWheelHandleButtonMap(pInfo, &(priv->Z), "ZAxisMapping", "4 5"); + wsWheelHandleButtonMap(pInfo, &(priv->W), "WAxisMapping", "6 7"); priv->screen_no = xf86SetIntOption(pInfo->options, "ScreenNo", 0); xf86IDrvMsg(pInfo, X_CONFIG, "associated screen: %d\n", @@ -280,6 +237,7 @@ wsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags) wsClose(pInfo); wsmbEmuPreInit(pInfo); + wsWheelEmuPreInit(pInfo); return Success; fail: @@ -413,6 +371,7 @@ wsDeviceInit(DeviceIntPtr pWS) if (priv->type == WSMOUSE_TYPE_TPANEL) wsInitCalibProperty(pWS); wsmbEmuInitProperty(pWS); + wsWheelEmuInitProperty(pWS); return Success; } @@ -498,7 +457,6 @@ wsReadInput(InputInfoPtr pInfo) int n, c; struct wscons_event *event = eventList; unsigned char *pBuf; - int ax, ay; priv = pInfo->private; @@ -515,10 +473,9 @@ wsReadInput(InputInfoPtr pInfo) n /= sizeof(struct wscons_event); while( n-- ) { int buttons = priv->lastButtons; - int dx = 0, dy = 0, dz = 0, dw = 0; + int dx = 0, dy = 0, dz = 0, dw = 0, ax = 0, ay = 0; int zbutton = 0, wbutton = 0; - ax = 0; ay = 0; switch (event->type) { case WSCONS_EVENT_MOUSE_UP: @@ -572,53 +529,35 @@ wsReadInput(InputInfoPtr pInfo) ++event; continue; } /* case */ + ++event; if (dx || dy) { + if (wsWheelEmuFilterMotion(pInfo, dx, dy)) + continue; + /* relative motion event */ DBG(3, ErrorF("postMotionEvent dX %d dY %d\n", - dx, dy)); - xf86PostMotionEvent(pInfo->dev, 0, 0, 2, - dx, dy); + dx, dy)); + xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy); } - if (dz && priv->negativeZ != WS_NOMAP - && priv->positiveZ != WS_NOMAP) { - buttons &= ~(priv->negativeZ | priv->positiveZ); - if (dz < 0) { - DBG(4, ErrorF("Z -> button %d\n", - ffs(priv->negativeZ))); - zbutton = priv->negativeZ; - } else { - DBG(4, ErrorF("Z -> button %d\n", - ffs(priv->positiveZ))); - zbutton = priv->positiveZ; - } - buttons |= zbutton; - dz = 0; + if (dz && priv->Z.negative != WS_NOMAP + && priv->Z.positive != WS_NOMAP) { + zbutton = (dz < 0) ? priv->Z.negative : + priv->Z.positive; + DBG(4, ErrorF("Z -> button %d\n", zbutton)); + wsButtonClicks(pInfo, zbutton, abs(dz)); } - if (dw && priv->negativeW != WS_NOMAP - && priv->positiveW != WS_NOMAP) { - buttons &= ~(priv->negativeW | priv->positiveW); - if (dw < 0) { - DBG(4, ErrorF("W -> button %d\n", - ffs(priv->negativeW))); - wbutton = priv->negativeW; - } else { - DBG(4, ErrorF("W -> button %d\n", - ffs(priv->positiveW))); - wbutton = priv->positiveW; - } - buttons |= wbutton; - dw = 0; + if (dw && priv->W.negative != WS_NOMAP + && priv->W.positive != WS_NOMAP) { + wbutton = (dw < 0) ? priv->W.negative : + priv->W.positive; + DBG(4, ErrorF("W -> button %d\n", wbutton)); + wsButtonClicks(pInfo, wbutton, abs(dw)); } if (priv->lastButtons != buttons) { /* button event */ wsSendButtons(pInfo, buttons); } - if (zbutton != 0) { - /* generate a button up event */ - buttons &= ~zbutton; - wsSendButtons(pInfo, buttons); - } if (priv->swap_axes) { int tmp; @@ -627,16 +566,25 @@ wsReadInput(InputInfoPtr pInfo) ay = tmp; } if (ax) { + dx = ax - priv->old_ax; + priv->old_ax = ax; + if (wsWheelEmuFilterMotion(pInfo, dx, 0)) + continue; + /* absolute position event */ DBG(3, ErrorF("postMotionEvent X %d\n", ax)); xf86PostMotionEvent(pInfo->dev, 1, 0, 1, ax); } if (ay) { + dy = ay - priv->old_ay; + priv->old_ay = ay; + if (wsWheelEmuFilterMotion(pInfo, 0, dy)) + continue; + /* absolute position event */ DBG(3, ErrorF("postMotionEvent y %d\n", ay)); xf86PostMotionEvent(pInfo->dev, 1, 1, 1, ay); } - ++event; } return; } /* wsReadInput */ @@ -645,19 +593,22 @@ static void wsSendButtons(InputInfoPtr pInfo, int buttons) { WSDevicePtr priv = (WSDevicePtr)pInfo->private; - int change, button, mask; + int change, button, press; change = buttons ^ priv->lastButtons; while (change) { button = ffs(change); - mask = 1 << (button - 1); - change &= ~mask; - if (!wsmbEmuFilterEvent(pInfo, button, (buttons & mask) != 0)) { - xf86PostButtonEvent(pInfo->dev, TRUE, - button, (buttons & mask) != 0, 0, 0); - DBG(3, ErrorF("post button event %d %d\n", - button, (buttons & mask) != 0)) - } + press = buttons & (1 << (button - 1)); + change &= ~(1 << (button - 1)); + + if (wsWheelEmuFilterButton(pInfo, button, press)) + continue; + + if (wsmbEmuFilterEvent(pInfo, button, press)) + continue; + + xf86PostButtonEvent(pInfo->dev, TRUE, button, press, 0, 0); + DBG(3, ErrorF("post button event %d %d\n", button, press)); } priv->lastButtons = buttons; } /* wsSendButtons */ @@ -818,3 +769,48 @@ wsSetCalibProperty(DeviceIntPtr device, Atom atom, XIPropertyValuePtr val, } return Success; } + +void +wsWheelHandleButtonMap(InputInfoPtr pInfo, WheelAxisPtr pAxis, + char* axis_name, char* default_value) +{ + WSDevicePtr priv = (WSDevicePtr)pInfo->private; + char *option_string; + int b1, b2; + + pAxis->negative = pAxis->positive = WS_NOMAP; + pAxis->traveled_distance = 0; + + option_string = xf86SetStrOption(pInfo->options, axis_name, + default_value); + if (option_string) { + if (sscanf(option_string, "%d %d", &b1, &b2) == 2 && + b1 > 0 && b1 <= NBUTTONS && + b2 > 0 && b2 <= NBUTTONS) { + xf86IDrvMsg(pInfo, X_CONFIG, "%s: buttons %d and %d\n", + axis_name, b1, b2); + + pAxis->negative = b1; + pAxis->positive = b2; + + if (max(b1, b2) > priv->buttons) + priv->buttons = max(b1, b2); + } else { + xf86IDrvMsg(pInfo, X_WARNING, + "Invalid %s value: \"%s\"\n", + axis_name, option_string); + } + free(option_string); + } +} + +void +wsButtonClicks(InputInfoPtr pInfo, int button, int count) +{ + int i; + + for (i = 0; i < count; i++) { + xf86PostButtonEvent(pInfo->dev, TRUE, button, 1, 0, 0); + xf86PostButtonEvent(pInfo->dev, TRUE, button, 0, 0, 0); + } +} diff --git a/driver/xf86-input-ws/src/ws.h b/driver/xf86-input-ws/src/ws.h index 6aaee9061..512648c2a 100644 --- a/driver/xf86-input-ws/src/ws.h +++ b/driver/xf86-input-ws/src/ws.h @@ -33,20 +33,29 @@ extern int ws_debug_level; #define WS_NOMAP 0 +/* axis specific data for wheel */ +typedef struct { + int negative; + int positive; + int traveled_distance; +} WheelAxis, *WheelAxisPtr; + typedef struct WSDevice { char *devName; /* device name */ int type; /* ws device type */ unsigned int buttons; /* # of buttons */ unsigned int lastButtons; /* last state of buttons */ + int old_ax, old_ay; int min_x, max_x, min_y, max_y; /* coord space */ int swap_axes; int raw; int inv_x, inv_y; int screen_no; pointer buffer; - int negativeZ, positiveZ; /* mappings for Z axis */ - int negativeW, positiveW; /* mappings for W axis */ + WheelAxis Z; + WheelAxis W; struct wsmouse_calibcoords coords; /* mirror of the kernel values */ + /* Middle mouse button emulation */ struct { BOOL enabled; @@ -56,8 +65,21 @@ typedef struct WSDevice { Time expires; /* time of expiry */ Time timeout; } emulateMB; + + /* Mouse wheel emulation */ + struct { + BOOL enabled; + int button; + int button_state; + int inertia; + WheelAxis X; + WheelAxis Y; + Time expires; /* time of expiry */ + Time timeout; + } emulateWheel; } WSDeviceRec, *WSDevicePtr; +/* Middle mouse button emulation */ extern int wsmbEmuTimer(InputInfoPtr); extern BOOL wsmbEmuFilterEvent(InputInfoPtr, int, BOOL); extern void wsmbEmuWakeupHandler(pointer, int, pointer); @@ -66,3 +88,12 @@ extern void wsmbEmuPreInit(InputInfoPtr); extern void wsmbEmuOn(InputInfoPtr); extern void wsmbEmuFinalize(InputInfoPtr); extern void wsmbEmuInitProperty(DeviceIntPtr); + +/* Mouse wheel emulation */ +extern void wsWheelEmuPreInit(InputInfoPtr); +extern BOOL wsWheelEmuFilterButton(InputInfoPtr, unsigned int, int); +extern BOOL wsWheelEmuFilterMotion(InputInfoPtr, int, int); +extern void wsWheelEmuInitProperty(DeviceIntPtr); + +extern void wsWheelHandleButtonMap(InputInfoPtr, WheelAxisPtr, char *, char *); +extern void wsButtonClicks(InputInfoPtr, int, int); |