From 5594ad4a0953d1da36952d0bacdafe2beca42b77 Mon Sep 17 00:00:00 2001 From: jules Date: Wed, 30 Jul 2008 00:42:13 -0500 Subject: [PATCH] Adding in mouse wheel emulation code --- src/Makefile.am | 4 +- src/emuWheel.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/evdev.c | 12 +++ src/evdev.h | 21 +++++ 4 files changed, 275 insertions(+), 1 deletions(-) create mode 100644 src/emuWheel.c 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..67d419a --- /dev/null +++ b/src/emuWheel.c @@ -0,0 +1,239 @@ +/* + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * Copyright 1993 by David Dawes + * 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 University of South Australia + * + * 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" +#include "xf86OSmouse.h" + +/* Local Funciton Prototypes */ +BOOL EvdevWheelEmuHandleButtonMap(InputInfoPtr pInfo, WheelAxisPtr pAxis, char *axis_name); + +/* Filter mouse wheel events */ +BOOL +EvdevWheelEmuFilterEvent(InputInfoPtr pInfo, struct input_event *pEv) { + EvdevPtr pEvdev=(EvdevPtr)pInfo->private; + WheelAxisPtr pAxis=NULL; + int value=pEv->value; + + /* Would it be better to handle this a two separate function calls? */ + + /* Handle our motion events */ + switch (pEv->type) { + case EV_REL: + 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; + } + } + + break; + + case EV_ABS: + /*if(!pEvedev->emualteWheel.button_state) + break;*/ + /* need to add code to handle absolute events */ + break; + case EV_KEY: + if ((pEv->code-BTN_LEFT+5) == pEvdev->emulateWheel.button) { + pEvdev->emulateWheel.button_state=value; + return TRUE; + } + + break; + } + + /* if we set an axix, mouse wheel emulation is active */ + if(pAxis) { + EvdevWheelEmuInertia(pInfo, pAxis, value); + return TRUE; + } + + return FALSE; +} + +/* Simulate inertia for our emulated mouse wheel */ +void +EvdevWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value ) { + int button; + int inertia; + + /* if this axis has not been configured, just eat the motion */ + if(!axis->configured) { + return; + } + + axis->traveled_distance+=value; + + if(axis->traveled_distance<0) { + button=axis->up_button; + inertia=-axis->inertia; + } else { + button=axis->down_button; + inertia=axis->inertia; + } + + while(abs(axis->traveled_distance) > axis->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. */ +BOOL +EvdevWheelEmuHandleButtonMap(InputInfoPtr pInfo, WheelAxisPtr pAxis, char* axis_name) { + EvdevPtr pEvdev=(EvdevPtr)pInfo->private; + char *option_string; + + option_string=xf86SetStrOption(pInfo->options, axis_name, NULL); + if(option_string) { + int up_button=0, 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) { + 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)) { + Bool yFromConfig = FALSE; + int wheelButton; + int inertia; /* will need to expand this latter for multiple axis */ + + pEvdev->emulateWheel.enabled = TRUE; + wheelButton = xf86SetIntOption(pInfo->options, + "EmulateWheelButton", 4); + /* This should have a constant not a numeric 32 */ + if (wheelButton < 0 || wheelButton > MSE_MAXBUTTONS) { + xf86Msg(X_WARNING, "%s: Invalid EmulateWheelButton value: %d\n", + pInfo->name, wheelButton); + wheelButton = 4; + } + + 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); + inertia = 10; + } + + pEvdev->emulateWheel.X.inertia = inertia; + pEvdev->emulateWheel.Y.inertia = inertia; + + /* The axis configuration code will not leave us with + an inconsistent state, so this should be safe. */ + pEvdev->emulateWheel.Y.configured=TRUE; + + if(!EvdevWheelEmuHandleButtonMap(pInfo, &(pEvdev->emulateWheel.Y),"YAxisMapping")) { + pEvdev->emulateWheel.Y.up_button = 4; + pEvdev->emulateWheel.Y.down_button = 5; + if( 5 > pEvdev->buttons) { + pEvdev->buttons=5; + } + xf86Msg(X_DEFAULT, "%s: YAxisMapping: buttons %d and %d\n", + pInfo->name, pEvdev->emulateWheel.Y.up_button, + pEvdev->emulateWheel.Y.down_button); + } + + + pEvdev->emulateWheel.X.configured=EvdevWheelEmuHandleButtonMap(pInfo, &(pEvdev->emulateWheel.X),"XAxisMapping"); + /* + pEvdev->emulateWheel.X.up_button = 6; + pEvdev->emulateWheel.X.down_button = 7;*/ + + pEvdev->emulateWheel.X.traveled_distance = 0; + pEvdev->emulateWheel.Y.traveled_distance = 0; + + + pEvdev->emulateWheel.timeout = xf86SetIntOption(pInfo->options, + "EmulateWheelTimeout", 200); + if (pEvdev->emulateWheel.timeout <= 0) { + xf86Msg(X_WARNING, "%s: Invalid EmulateWheelTimeout value: %d\n", + pInfo->name, pEvdev->emulateWheel.timeout); + pEvdev->emulateWheel.timeout = 200; + } + + xf86Msg(X_CONFIG, "%s: EmulateWheel, EmulateWheelButton: %d, " + "EmulateWheelInertia: %d, " + "EmulateWheelTimeout: %d\n", + pInfo->name, pEvdev->emulateWheel.button, inertia, + pEvdev->emulateWheel.timeout); + } +} + + diff --git a/src/evdev.c b/src/evdev.c index f831081..29844b4 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -206,11 +206,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(EvdevWheelEmuFilterEvent(pInfo, &ev)) + break; + switch (ev.code) { case REL_X: dx += value; @@ -256,6 +261,10 @@ EvdevReadInput(InputInfoPtr pInfo) if (value == 2) break; + /* Handle mouse wheel emulation */ + if(EvdevWheelEmuFilterEvent(pInfo, &ev)) + break; + switch (ev.code) { /* swap here, pretend we're an X-conformant device. */ case BTN_LEFT: @@ -955,7 +964,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 bc79287..0b1f367 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -40,6 +40,15 @@ #include #endif +/* axis specific data for wheel emulation */ +typedef struct { + int configured; + int up_button; + int down_button; + int traveled_distance; + int inertia; +} WheelAxis, *WheelAxisPtr; + typedef struct { int kernel24; int screen; @@ -68,6 +77,14 @@ typedef struct { Time expires; /* time of expiry */ Time timeout; } emulateMB; + struct { + BOOL enabled; + int button; + int button_state; + int timeout; + WheelAxis X; + WheelAxis Y; + } emulateWheel; unsigned char btnmap[32]; /* config-file specified button mapping */ } EvdevRec, *EvdevPtr; @@ -86,4 +103,8 @@ Atom EvdevMBEmuInitPropertyTimeout(DeviceIntPtr, char*); BOOL EvdevMBEmuSetProperty(DeviceIntPtr, Atom, XIPropertyValuePtr); #endif +/* Mouse Wheel emulation */ +void EvdevWheelEmuPreInit(InputInfoPtr pInfo); +void EvdevWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value); +BOOL EvdevWheelEmuFilterEvent(InputInfoPtr pInfo, struct input_event *pEv); #endif -- 1.5.6.3