Adding wheel emulation, ported from evdev(4)

ok matthieu@
This commit is contained in:
shadchin 2011-11-28 23:49:59 +00:00
parent 2d087d2918
commit 86e4fbccae
7 changed files with 604 additions and 101 deletions

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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 $@ $<; \

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);