diff --git a/include/evdev-properties.h b/include/evdev-properties.h index 16f2af7..85b44c2 100644 --- a/include/evdev-properties.h +++ b/include/evdev-properties.h @@ -75,4 +75,8 @@ /* CARD32 */ #define EVDEV_PROP_THIRDBUTTON_THRESHOLD "Evdev Third Button Emulation Threshold" +/* Auto-release */ +/* CARD32, 1 value, bitmap, bit N set = button (N+1) is auto-released */ +#define EVDEV_PROP_AUTORELEASE "Evdev Auto-Release Buttons" + #endif diff --git a/man/evdev.man b/man/evdev.man index 931e1a1..2e847b5 100644 --- a/man/evdev.man +++ b/man/evdev.man @@ -81,6 +81,12 @@ Sets a \*qmaster drag lock button\*q that acts as a \*qMeta Key\*q indicating that the next button pressed is to be \*qdrag locked\*q. Property: "Evdev Drag Lock Buttons". .TP 7 +.BI "Option \*qAutoReleaseButtons\*q \*q" "Bn ..." \*q +Sets which buttons are to be treated as immediately released. This is +useful for mice which have buttons which do not generate events in the +normal way, generating a release event when the button is next clicked as +opposed to when it is released. +Property: "Evdev Auto Release Buttons". .TP 7 .BI "Option \*qEmulate3Buttons\*q \*q" boolean \*q Enable/disable the emulation of the third (middle) mouse button for mice diff --git a/src/Makefile.am b/src/Makefile.am index d1efe53..7cb4bae 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -37,5 +37,6 @@ AM_CPPFLAGS =-I$(top_srcdir)/include emuMB.c \ emuThird.c \ emuWheel.c \ + autorelease.c \ draglock.c diff --git a/src/autorelease.c b/src/autorelease.c new file mode 100644 index 0000000..d70d1fd --- /dev/null +++ b/src/autorelease.c @@ -0,0 +1,206 @@ +/* + * Copyright 2010 Darren Salt + * Structure taken from draglock.c + * 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 + * 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 button auto-release code. + * This is for the likes of the Cyborg R.A.T. mice. + * One button found on these mice acts differently: + * first press = button 13 down + * first release = nothing + * Then it repeats as follows: + * press = button 13 up, button 14 down + * press = button 14 up, button 15 down + * press = button 13 down, button 15 up + * with no action on releasing the button. + * + * This confuses X: it thinks that the button is still pressed when the user + * has actually released it. + * + * What this code does is to synthesise a button-up event when a + * button-down event is received (for specified buttons). + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "evdev.h" + +#include +#include +#include +#include + +#include + +#ifdef HAVE_PROPERTIES +static Atom prop_autorelease = 0; +#endif + + +/* Setup and configuration code */ +void +EvdevAutoReleasePreInit(InputInfoPtr pInfo) +{ + EvdevPtr pEvdev = (EvdevPtr)pInfo->private; + char *option_string = NULL; + CARD32 release = 0; + char *next_num = NULL; + char *end_str = NULL; + + option_string = xf86CheckStrOption(pInfo->options, "AutoReleaseButtons",NULL); + + if (!option_string) + return; + + next_num = option_string; + + /* Loop until we hit the end of our option string */ + while (next_num != NULL) { + release = strtol(next_num, &end_str, 10); + + /* check to see if we found anything */ + if (next_num != end_str) + /* setup for the next number */ + next_num = end_str; + else + /* we have nothing more to parse, drop out of the loop */ + next_num = NULL; + + /* Ok, let the user know what we found on this look */ + if (release > 0 && release <= EVDEV_MAXBUTTONS) + pEvdev->releaseButtons |= 1U << (release - 1); + else { + xf86Msg(X_ERROR, "%s: Found AutoReleaseButtons " + "with invalid button string : '%s'\n", + pInfo->name, option_string); + + /* This should be the case anyhow; just make sure */ + next_num = NULL; + } + + /* Check for end of string (to avoid annoying error) */ + if (next_num != NULL && *next_num == '\0') + next_num = NULL; + } + + free(option_string); +} + +/* Filter button presses looking for either a meta button or the + * control of a button pair. + * + * @param button button number (1 for left, 3 for right) + * @param value TRUE if button press, FALSE if release + * + * @return TRUE if the event was swallowed here, FALSE otherwise. + */ +BOOL +EvdevAutoReleaseFilterEvent(InputInfoPtr pInfo, unsigned int button, int value) +{ + EvdevPtr pEvdev = (EvdevPtr)pInfo->private; + + if (button == 0) + return FALSE; + + if (pEvdev->releaseButtons & (1U << (button - 1))) { + /* Instant release if the button is marked such + and this is a press event*/ + if (value) + EvdevQueueButtonClicks(pInfo, button, 1); + + /* Eat the release event */ + return TRUE; + } + + return FALSE; +} + +#ifdef HAVE_PROPERTIES +/** + * Set the auto-release property. + * This is a bitmap, with bit N for button (N+1). + */ +static int +EvdevAutoReleaseSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, + BOOL checkonly) +{ + InputInfoPtr pInfo = dev->public.devicePrivate; + EvdevPtr pEvdev = pInfo->private; + + if (atom == prop_autorelease) + { + CARD32 release; + + if (val->format != 32 || val->type != XA_INTEGER) + return BadMatch; + + if (val->size != 1) + return BadMatch; + + release = *((CARD32*)val->data); + + if (release & ~((1UL << EVDEV_MAXBUTTONS) - 1)) + return BadValue; + + if (!checkonly) + pEvdev->releaseButtons = release; + } + + return Success; +} + +/** + * Initialise property for drag lock buttons setting. + */ +void +EvdevAutoReleaseInitProperty(DeviceIntPtr dev) +{ + InputInfoPtr pInfo = dev->public.devicePrivate; + EvdevPtr pEvdev = pInfo->private; + + if (!dev->button) /* don't init prop for keyboards */ + return; + + prop_autorelease = MakeAtom(EVDEV_PROP_AUTORELEASE, + strlen(EVDEV_PROP_AUTORELEASE), TRUE); + + XIChangeDeviceProperty(dev, prop_autorelease, XA_INTEGER, 32, + PropModeReplace, 1, &pEvdev->releaseButtons, + FALSE); + + XISetDevicePropertyDeletable(dev, prop_autorelease, FALSE); + + XIRegisterPropertyHandler(dev, EvdevAutoReleaseSetProperty, NULL, NULL); +} + +#endif diff --git a/src/evdev.c b/src/evdev.c index ab46277..e67ce52 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -553,6 +553,9 @@ EvdevProcessButtonEvent(InputInfoPtr pInfo, struct input_event *ev) if (EvdevDragLockFilterEvent(pInfo, button, value)) return; + if (EvdevAutoReleaseFilterEvent(pInfo, button, value)) + return; + if (EvdevWheelEmuFilterButton(pInfo, button, value)) return; @@ -1349,6 +1352,7 @@ EvdevInit(DeviceIntPtr device) Evdev3BEmuInitProperty(device); EvdevWheelEmuInitProperty(device); EvdevDragLockInitProperty(device); + EvdevAutoReleaseInitProperty(device); return Success; } @@ -1897,6 +1901,7 @@ EvdevPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags) Evdev3BEmuPreInit(pInfo); EvdevWheelEmuPreInit(pInfo); EvdevDragLockPreInit(pInfo); + EvdevAutoReleasePreInit(pInfo); } return Success; diff --git a/src/evdev.h b/src/evdev.h index c16ccb2..99db1c7 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -172,6 +172,7 @@ typedef struct { int min_y; int max_y; } calibration; + uint32_t releaseButtons; unsigned char btnmap[32]; /* config-file specified button mapping */ @@ -236,8 +237,13 @@ BOOL EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv); void EvdevDragLockPreInit(InputInfoPtr pInfo); BOOL EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value); +/* Auto-release code */ +void EvdevAutoReleasePreInit(InputInfoPtr pInfo); +BOOL EvdevAutoReleaseFilterEvent(InputInfoPtr pInfo, unsigned int button, int value); + void EvdevMBEmuInitProperty(DeviceIntPtr); void Evdev3BEmuInitProperty(DeviceIntPtr); void EvdevWheelEmuInitProperty(DeviceIntPtr); void EvdevDragLockInitProperty(DeviceIntPtr); +void EvdevAutoReleaseInitProperty(DeviceIntPtr); #endif