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..a4e4b7d --- /dev/null +++ b/src/emuWheel.c @@ -0,0 +1,186 @@ +/* + * 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 axis, char *axis_name); + +/* 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 axis, 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); + } + axis->up_button=up_button; + axis->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..53e77a4 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -213,11 +213,19 @@ EvdevReadInput(InputInfoPtr pInfo) case EV_REL: switch (ev.code) { case REL_X: - dx += value; + if (pEvdev->emulateWheel.button_state) { + EvdevWheelEmuInertia(pInfo, &(pEvdev->emulateWheel.X), value); + } else { + dx += value; + } break; case REL_Y: - dy += value; + if (pEvdev->emulateWheel.button_state) { + EvdevWheelEmuInertia(pInfo, &(pEvdev->emulateWheel.Y), value); + } else { + dy += value; + } break; case REL_WHEEL: @@ -255,57 +263,61 @@ EvdevReadInput(InputInfoPtr pInfo) if (ev.code >= BTN_MOUSE && ev.code < KEY_OK) if (value == 2) break; + if ((ev.code-BTN_LEFT+5)== pEvdev->emulateWheel.button) { + pEvdev->emulateWheel.button_state=value; + } else { + + switch (ev.code) { + /* swap here, pretend we're an X-conformant device. */ + case BTN_LEFT: + if (!EvdevMBEmuFilterEvent(pInfo, ev.code, value)) + xf86PostButtonEvent(pInfo->dev, 0, 1, value, 0, 0); + break; + case BTN_RIGHT: + if (!EvdevMBEmuFilterEvent(pInfo, ev.code, value)) + xf86PostButtonEvent(pInfo->dev, 0, 3, value, 0, 0); + break; + case BTN_MIDDLE: + EvdevMBEmuEnable(pInfo, FALSE); + xf86PostButtonEvent(pInfo->dev, 0, 2, value, 0, 0); + break; - switch (ev.code) { - /* swap here, pretend we're an X-conformant device. */ - case BTN_LEFT: - if (!EvdevMBEmuFilterEvent(pInfo, ev.code, value)) - xf86PostButtonEvent(pInfo->dev, 0, 1, value, 0, 0); - break; - case BTN_RIGHT: - if (!EvdevMBEmuFilterEvent(pInfo, ev.code, value)) - xf86PostButtonEvent(pInfo->dev, 0, 3, value, 0, 0); - break; - case BTN_MIDDLE: - EvdevMBEmuEnable(pInfo, FALSE); - xf86PostButtonEvent(pInfo->dev, 0, 2, value, 0, 0); - break; - - case BTN_SIDE: - case BTN_EXTRA: - case BTN_FORWARD: - case BTN_BACK: - case BTN_TASK: - xf86PostButtonEvent(pInfo->dev, 0, ev.code - BTN_LEFT + 5, - value, 0, 0); - break; + case BTN_SIDE: + case BTN_EXTRA: + case BTN_FORWARD: + case BTN_BACK: + case BTN_TASK: + xf86PostButtonEvent(pInfo->dev, 0, ev.code - BTN_LEFT + 5, + value, 0, 0); + break; - case BTN_TOUCH: - case BTN_TOOL_PEN: - case BTN_TOOL_RUBBER: - case BTN_TOOL_BRUSH: - case BTN_TOOL_PENCIL: - case BTN_TOOL_AIRBRUSH: - case BTN_TOOL_FINGER: - case BTN_TOOL_MOUSE: - case BTN_TOOL_LENS: - pEvdev->tool = value ? ev.code : 0; - break; + case BTN_TOUCH: + case BTN_TOOL_PEN: + case BTN_TOOL_RUBBER: + case BTN_TOOL_BRUSH: + case BTN_TOOL_PENCIL: + case BTN_TOOL_AIRBRUSH: + case BTN_TOOL_FINGER: + case BTN_TOOL_MOUSE: + case BTN_TOOL_LENS: + pEvdev->tool = value ? ev.code : 0; + break; - default: - if (ev.code > BTN_TASK && ev.code < KEY_OK) { - /* Some fancy mice with a lot of buttons generate - * button events between BTN_TASK and BTN_JOYSTICK */ - if (ev.code < BTN_JOYSTICK) - xf86PostButtonEvent(pInfo->dev, 0, - ev.code - BTN_LEFT + 5, - value, 0, 0); + default: + if (ev.code > BTN_TASK && ev.code < KEY_OK) { + /* Some fancy mice with a lot of buttons generate + * button events between BTN_TASK and BTN_JOYSTICK */ + if (ev.code < BTN_JOYSTICK) + xf86PostButtonEvent(pInfo->dev, 0, + ev.code - BTN_LEFT + 5, + value, 0, 0); + break; + } + + PostKbdEvent(pInfo, &ev, value); break; } - - PostKbdEvent(pInfo, &ev, value); - break; - } + } break; case EV_SYN: @@ -328,8 +340,9 @@ EvdevReadInput(InputInfoPtr pInfo) } } + if (dx != 0 || dy != 0) - xf86PostMotionEvent(pInfo->dev, FALSE, 0, 2, dx, dy); + xf86PostMotionEvent(pInfo->dev, FALSE, 0, 2, dx, dy); /* * Some devices only generate valid abs coords when BTN_DIGI is @@ -344,6 +357,7 @@ EvdevReadInput(InputInfoPtr pInfo) xf86PostMotionEvent(pInfo->dev, TRUE, 0, 2, pEvdev->abs_x, pEvdev->abs_y); } + } #define TestBit(bit, array) (array[(bit) / 8] & (1 << ((bit) % 8))) @@ -954,8 +968,10 @@ EvdevProc(DeviceIntPtr device, int what) if (errno != ENODEV) { xf86AddEnabledDevice(pInfo); - if (pEvdev->flags & EVDEV_BUTTON_EVENTS) + if (pEvdev->flags & EVDEV_BUTTON_EVENTS) { EvdevMBEmuPreInit(pInfo); + EvdevWheelEmuPreInit(pInfo); + } device->public.on = TRUE; } break; @@ -1213,3 +1229,4 @@ _X_EXPORT XF86ModuleData evdevModuleData = EvdevPlug, EvdevUnplug }; + diff --git a/src/evdev.h b/src/evdev.h index bc79287..1c28873 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); + #endif