[PATCH evdev v2] Add third button emulation.

Benjamin Tissoires tissoire at cena.fr
Wed Feb 2 02:28:10 PST 2011


Hi Peter,

well, I still have troubles (again, based on the backport to 2.6.0). ;)

On 02/02/2011 07:35 AM, Peter Hutterer wrote:
> New properties:
> "Evdev Third Button Emulation" → switch on/off
> "Evdev Third Button Emulation Timeout" → timeout until event is delivered
> "Evdev Third Button Emulation Button" → phys button to be emulated
> "Evdev Third Button Emulation Threshold" → move threshold before emulation
> is cancelled
>
> Signed-off-by: Peter Hutterer<peter.hutterer at who-t.net>
> ---
> Changes since v1:
> - filter button event before it is posted, not before it is queued to avoid
>    race with coordinate updates

I did not manage to make it work (see comments below)

> - reset timer to NULL to avoid double-free

great, the freezes stopped.

> - when cancelling, post the abs button event for the start position.

I did not manage to make it work too (in relative mode). This may be 
introduce by the backport, so please just tell if you have trouble when 
setting the 3rd emulation with a generic mouse.

>
> Benjamin, the first two were the two issues you pointed out, should be fixed
> now. The last one I came up with all by myself :)
>
> again, applies to my people.fdo master branch
>
> Cheers,
>    Peter
>
>   include/evdev-properties.h |    9 +
>   man/evdev.man              |   25 +++
>   src/Makefile.am            |    1 +
>   src/emuThird.c             |  387 ++++++++++++++++++++++++++++++++++++++++++++
>   src/evdev.c                |   19 +++
>   src/evdev.h                |   23 +++
>   6 files changed, 464 insertions(+), 0 deletions(-)
>   create mode 100644 src/emuThird.c
>
> diff --git a/include/evdev-properties.h b/include/evdev-properties.h
> index 7df2876..16f2af7 100644
> --- a/include/evdev-properties.h
> +++ b/include/evdev-properties.h
> @@ -66,4 +66,13 @@
>   /* BOOL */
>   #define EVDEV_PROP_SWAP_AXES "Evdev Axes Swap"
>
> +/* BOOL */
> +#define EVDEV_PROP_THIRDBUTTON "Evdev Third Button Emulation"
> +/* CARD32 */
> +#define EVDEV_PROP_THIRDBUTTON_TIMEOUT "Evdev Third Button Emulation Timeout"
> +/* CARD8 */
> +#define EVDEV_PROP_THIRDBUTTON_BUTTON "Evdev Third Button Emulation Button"
> +/* CARD32 */
> +#define EVDEV_PROP_THIRDBUTTON_THRESHOLD "Evdev Third Button Emulation Threshold"
> +
>   #endif
> diff --git a/man/evdev.man b/man/evdev.man
> index a202ae8..2709d7a 100644
> --- a/man/evdev.man
> +++ b/man/evdev.man
> @@ -134,6 +134,31 @@ must be pressed before wheel emulation is started. If the
>   is released before this timeout, the original button press/release event
>   is sent.  Default: 200. Property: "Evdev Wheel Emulation Timeout".
>   .TP 7
> +.BI "Option \*qEmulateThirdButton\*q \*q" boolean \*q
> +Enable third button emulation. Third button emulation emits a right button
> +event (by default) by pressing and holding the first button. The first
> +button must be held down for the configured timeout and must not move more
> +than the configured threshold for the emulation to activate. Otherwise, the
> +first button event is posted as normal. Default: off.  Property: "Evdev
> +Third Button Emulation".
> +.TP 7
> +.BI "Option \*qEmulateThirdButtonTimeout\*q \*q" integer \*q
> +Specifies the timeout in milliseconds between the initial button press and
> +the generation of the emulated button event.
> +Default: 1000. Property: "Evdev Third Button Emulation Timeout".
> +.TP 7
> +.BI "Option \*qEmulateThirdButtonButton\*q \*q" integer \*q
> +Specifies the physical button number to be emitted if third button emulation
> +is triggered.
> +Default: 3.  Property: "Evdev Third Button Button".
> +.TP 7
> +.BI "Option \*qEmulateThirdButtonMoveThreshold\*q \*q" integer \*q
> +Specifies the maximum move fuzz in device coordinates for third button
> +emulation. If the device moves by more than this threshold before the third
> +button emulation is triggered, the emulation is cancelled and a first button
> +event is generated as normal.
> +Default: 20. Property: "Evdev Third Button Emulation Threshold".
> +.TP 7
>   .BI "Option \*qGrabDevice\*q \*q" boolean \*q
>   Force a grab on the event device. Doing so will ensure that no other driver
>   can initialise the same device and it will also stop the device from sending
> diff --git a/src/Makefile.am b/src/Makefile.am
> index a5c89ac..d1efe53 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -35,6 +35,7 @@ AM_CPPFLAGS =-I$(top_srcdir)/include
>   @DRIVER_NAME at _drv_la_SOURCES = @DRIVER_NAME at .c \
>                                  @DRIVER_NAME at .h \
>                                  emuMB.c \
> +                               emuThird.c \
>                                  emuWheel.c \
>                                  draglock.c
>
> diff --git a/src/emuThird.c b/src/emuThird.c
> new file mode 100644
> index 0000000..139b7df
> --- /dev/null
> +++ b/src/emuThird.c
> @@ -0,0 +1,387 @@
> +/*
> + * Copyright © 2011 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.
> + *
> + */
> +
> +/* Right mouse button emulation code.
> + * Emulates a right button event if the first button is held down for a
> + * timeout. If the device moves more than a certain amount before the
> + * timeout is over, the emulation is cancelled and a normal button event is
> + * generated.
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include "config.h"
> +#endif
> +
> +#include "evdev.h"
> +
> +#include<X11/Xatom.h>
> +#include<xf86.h>
> +#include<xf86Xinput.h>
> +#include<exevents.h>
> +
> +#include<evdev-properties.h>
> +
> +/* Threshold (in device coordinates) for devices to cancel emulation */
> +#define DEFAULT_MOVE_THRESHOLD 20
> +
> +static Atom prop_3bemu;         /* Right button emulation on/off property   */
> +static Atom prop_3btimeout;     /* Right button timeout property            */
> +static Atom prop_3bbutton;      /* Right button target physical button      */
> +static Atom prop_3bthreshold;   /* Right button move cancellation threshold */
> +
> +/* State machine for 3rd button emulation */
> +enum EmulationState {
> +    EM3B_OFF,             /* no event      */
> +    EM3B_PENDING,         /* timer pending */
> +    EM3B_EMULATING        /* in emulation  */
> +};
> +
> +
> +/**
> + * Timer function. Post a button down event to the server.
> + *
> + * @param arg The InputInfoPtr for this device.
> + */
> +CARD32
> +Evdev3BEmuTimer(OsTimerPtr timer, CARD32 time, pointer arg)
> +{
> +    InputInfoPtr pInfo = arg;
> +    EvdevPtr pEvdev = pInfo->private;
> +    int	sigstate;
> +
> +    sigstate = xf86BlockSIGIO ();
> +    pEvdev->emulate3B.state = EM3B_EMULATING;
> +    EvdevPostButtonEvent(pInfo, pEvdev->emulate3B.button, 1);
> +    xf86UnblockSIGIO (sigstate);
> +    return 0;
> +}
> +
> +
> +/**
> + * Cancel all emulation, reset the timer and reset deltas.
> + */
> +static void
> +Evdev3BCancel(InputInfoPtr pInfo)
> +{
> +    EvdevPtr pEvdev = pInfo->private;
> +
> +    if (pEvdev->emulate3B.state != EM3B_OFF)
> +    {
> +        TimerCancel(pEvdev->emulate3B.timer);
> +        pEvdev->emulate3B.state = EM3B_OFF;
> +        memset(pEvdev->emulate3B.delta, 0, sizeof(pEvdev->emulate3B.delta));
> +    }
> +}
> +
> +/**
> + * Emulate a third button on button press. Note that emulation only triggers
> + * on button 1.
> + *
> + * Return TRUE if event was swallowed by middle mouse button emulation,
> + * FALSE otherwise.
> + */
> +BOOL
> +Evdev3BEmuFilterEvent(InputInfoPtr pInfo, int button, BOOL press)
> +{
> +    EvdevPtr pEvdev = pInfo->private;
> +    int ret = FALSE;
> +
> +    if (!pEvdev->emulate3B.enabled)
> +        goto out;
> +
> +    if (press)
> +        pEvdev->emulate3B.buttonstate |= button;
> +    else
> +        pEvdev->emulate3B.buttonstate&= ~button;
> +
> +    /* Any other button pressed? Cancel timer */
> +    if (button != 1)
> +    {
> +        switch (pEvdev->emulate3B.state)
> +        {
> +            case EM3B_PENDING:
> +                Evdev3BCancel(pInfo);
> +                EvdevQueueButtonEvent(pInfo, 1, 1);
> +                break;
> +            case EM3B_EMULATING:
> +                /* We're emulating and now the user pressed a different
> +                 * button. Just release the emulating one, tell the user to
> +                 * not do that and get on with life */
> +                Evdev3BCancel(pInfo);
> +                EvdevQueueButtonEvent(pInfo, pEvdev->emulate3B.button, 0);

This function is called in EvdevPostQueuedEvents. Shouldn't we use 
xf86PostButtonEventP or xf86PostButtonEvent instead?

(I did not get the release event of the right button on an absolute device)

> +                break;
> +            default:
> +                break;
> +        }
> +        goto out;
> +    }
> +
> +    /* Don't emulate if any other button is down */
> +    if ((pEvdev->emulate3B.buttonstate&  ~0x1) != 0)
> +        goto out;
> +
> +    /* Release event → cancel, send press and release now. */
> +    if (!press)
> +    {
> +        switch(pEvdev->emulate3B.state)
> +        {
> +            case EM3B_PENDING:
> +                Evdev3BCancel(pInfo);
> +                EvdevQueueButtonEvent(pInfo, 1, 1);

same above

> +                break;
> +            case EM3B_EMULATING:
> +                Evdev3BCancel(pInfo);
> +                EvdevQueueButtonEvent(pInfo, pEvdev->emulate3B.button, 0);

;)

> +                ret = TRUE;
> +                break;
> +            default:
> +                break;
> +        }
> +
> +        goto out;
> +    }
> +
> +    if (press&&  pEvdev->emulate3B.state == EM3B_OFF)
> +    {
> +        pEvdev->emulate3B.state = EM3B_PENDING;
> +        pEvdev->emulate3B.timer = TimerSet(pEvdev->emulate3B.timer,
> +                                           0, pEvdev->emulate3B.timeout,
> +                                           Evdev3BEmuTimer, pInfo);
> +        ret = TRUE;
> +        goto out;
> +    }
> +
> +out:
> +    return ret;
> +}
> +
> +/**
> + * Handle absolute x/y motion. If the motion is above the threshold, cancel
> + * emulation.
> + */
> +void
> +Evdev3BEmuProcessAbsMotion(InputInfoPtr pInfo, ValuatorMask *vals)
> +{
> +    EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
> +    int cancel = FALSE;
> +
> +    if (pEvdev->emulate3B.state != EM3B_PENDING)
> +    {
> +        if (valuator_mask_isset(vals, 0))
> +            pEvdev->emulate3B.startpos[0] = valuator_mask_get(vals, 0);
> +        if (valuator_mask_isset(vals, 1))
> +            pEvdev->emulate3B.startpos[1] = valuator_mask_get(vals, 1);
> +        return;
> +    }
> +
> +    if (!cancel&&  valuator_mask_isset(vals, 0))
> +    {
> +        int dx = valuator_mask_get(vals, 0) - pEvdev->emulate3B.startpos[0];
> +        if (abs(dx)>  pEvdev->emulate3B.threshold)
> +            cancel = TRUE;
> +    }
> +
> +    if (!cancel&&  valuator_mask_isset(vals, 1))
> +    {
> +        int dy = valuator_mask_get(vals, 1) - pEvdev->emulate3B.startpos[1];
> +        if (abs(dy)>  pEvdev->emulate3B.threshold)
> +            cancel = TRUE;
> +    }
> +
> +    if (cancel)
> +    {
> +        Evdev3BCancel(pInfo);
> +        /* if we cancel, emit the button down event at our start position,
> +         * not at the current position. */
> +        xf86PostButtonEventP(pInfo->dev, 1, 1, 1, 0, 2,
> +                             pEvdev->emulate3B.startpos);
> +    }
> +}
> +
> +/**
> + * Handle relative x/y motion. If the motion is above the threshold, cancel
> + * emulation.
> + */
> +void
> +Evdev3BEmuProcessRelMotion(InputInfoPtr pInfo, int dx, int dy)
> +{
> +    EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
> +
> +    if (pEvdev->emulate3B.state != EM3B_PENDING)
> +
> +        return;
> +
> +    pEvdev->emulate3B.delta[0] += dx;
> +    pEvdev->emulate3B.delta[1] += dy;
> +
> +    if (abs(pEvdev->emulate3B.delta[0])>  pEvdev->emulate3B.threshold ||
> +        abs(pEvdev->emulate3B.delta[1])>  pEvdev->emulate3B.threshold)
> +    {
> +        Evdev3BCancel(pInfo);
> +        EvdevPostButtonEvent(pInfo, 1, 1);
> +    }
> +}
> +
> +void
> +Evdev3BEmuPreInit(InputInfoPtr pInfo)
> +{
> +    EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
> +
> +    pEvdev->emulate3B.enabled = xf86SetBoolOption(pInfo->options,
> +                                                  "EmulateThirdButton",
> +                                                  FALSE);
> +    pEvdev->emulate3B.timeout = xf86SetIntOption(pInfo->options,
> +                                                 "EmulateThirdButtonTimeout",
> +                                                 1000);
> +    pEvdev->emulate3B.button = xf86SetBoolOption(pInfo->options,
> +                                                 "EmulateThirdButtonButton",
> +                                                 3);
> +    /* FIXME: this should be auto-configured based on axis ranges */
> +    pEvdev->emulate3B.threshold = xf86SetBoolOption(pInfo->options,
> +                                                    "EmulateThirdButtonMoveThreshold",
> +                                                    DEFAULT_MOVE_THRESHOLD);
> +    /* allocate now so we don't allocate in the signal handler */
> +    pEvdev->emulate3B.timer = TimerSet(NULL, 0, 0, NULL, NULL);
> +}
> +
> +void
> +Evdev3BEmuOn(InputInfoPtr pInfo)
> +{
> +    /* This function just exists for symmetry in evdev.c */
> +}
> +
> +void
> +Evdev3BEmuFinalize(InputInfoPtr pInfo)
> +{
> +    EvdevPtr     pEvdev = pInfo->private;
> +
> +    TimerFree(pEvdev->emulate3B.timer);
> +    pEvdev->emulate3B.timer = NULL;
> +}
> +
> +static int
> +Evdev3BEmuSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
> +                      BOOL checkonly)
> +{
> +    InputInfoPtr pInfo  = dev->public.devicePrivate;
> +    EvdevPtr     pEvdev = pInfo->private;
> +
> +    if (atom == prop_3bemu)
> +    {
> +        if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
> +            return BadMatch;
> +
> +        if (!checkonly)
> +            pEvdev->emulate3B.enabled = *((BOOL*)val->data);
> +
> +    } else if (atom == prop_3btimeout)
> +    {
> +        if (val->format != 32 || val->size != 1 || val->type != XA_INTEGER)
> +            return BadMatch;
> +
> +        if (!checkonly)
> +            pEvdev->emulate3B.timeout = *((CARD32*)val->data);
> +
> +    } else if (atom == prop_3bbutton)
> +    {
> +        if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
> +            return BadMatch;
> +
> +        if (!checkonly)
> +            pEvdev->emulate3B.button = *((CARD8*)val->data);
> +    } else if (atom == prop_3bthreshold)
> +    {
> +        if (val->format != 32 || val->size != 1 || val->type != XA_INTEGER)
> +            return BadMatch;
> +
> +        if (!checkonly)
> +            pEvdev->emulate3B.threshold = *((CARD32*)val->data);
> +    }
> +
> +
> +    return Success;
> +}
> +
> +/**
> + * Initialise properties for third button emulation
> + */
> +void
> +Evdev3BEmuInitProperty(DeviceIntPtr dev)
> +{
> +    InputInfoPtr pInfo  = dev->public.devicePrivate;
> +    EvdevPtr     pEvdev = pInfo->private;
> +    int          rc;
> +
> +    if (!dev->button) /* don't init prop for keyboards */
> +        return;
> +
> +    /* third button emulation on/off */
> +    prop_3bemu = MakeAtom(EVDEV_PROP_THIRDBUTTON, strlen(EVDEV_PROP_THIRDBUTTON), TRUE);
> +    rc = XIChangeDeviceProperty(dev, prop_3bemu, XA_INTEGER, 8,
> +                                PropModeReplace, 1,
> +&pEvdev->emulate3B.enabled,
> +                                FALSE);
> +    if (rc != Success)
> +        return;
> +
> +    XISetDevicePropertyDeletable(dev, prop_3bemu, FALSE);
> +
> +    /* third button emulation timeout */
> +    prop_3btimeout = MakeAtom(EVDEV_PROP_THIRDBUTTON_TIMEOUT,
> +                              strlen(EVDEV_PROP_THIRDBUTTON_TIMEOUT),
> +                              TRUE);
> +    rc = XIChangeDeviceProperty(dev, prop_3btimeout, XA_INTEGER, 32, PropModeReplace, 1,
> +&pEvdev->emulate3B.timeout, FALSE);
> +
> +    if (rc != Success)
> +        return;
> +
> +    XISetDevicePropertyDeletable(dev, prop_3btimeout, FALSE);
> +
> +    /* third button emulation button to be triggered  */
> +    prop_3bbutton = MakeAtom(EVDEV_PROP_THIRDBUTTON_BUTTON,
> +                             strlen(EVDEV_PROP_THIRDBUTTON_BUTTON),
> +                             TRUE);
> +    rc = XIChangeDeviceProperty(dev, prop_3bbutton, XA_INTEGER, 8, PropModeReplace, 1,
> +&pEvdev->emulate3B.button, FALSE);
> +
> +    if (rc != Success)
> +        return;
> +
> +    XISetDevicePropertyDeletable(dev, prop_3bbutton, FALSE);
> +
> +    /* third button emulation movement threshold */
> +    prop_3bthreshold = MakeAtom(EVDEV_PROP_THIRDBUTTON_THRESHOLD,
> +                                strlen(EVDEV_PROP_THIRDBUTTON_THRESHOLD),
> +                                TRUE);
> +    rc = XIChangeDeviceProperty(dev, prop_3bthreshold, XA_INTEGER, 32, PropModeReplace, 1,
> +&pEvdev->emulate3B.threshold, FALSE);
> +
> +    if (rc != Success)
> +        return;
> +
> +    XISetDevicePropertyDeletable(dev, prop_3bthreshold, FALSE);
> +
> +    XIRegisterPropertyHandler(dev, Evdev3BEmuSetProperty, NULL, NULL);
> +}
> diff --git a/src/evdev.c b/src/evdev.c
> index 9f8e003..768ab70 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -397,6 +397,11 @@ EvdevProcessValuators(InputInfoPtr pInfo)
>           if (pEvdev->invert_y)
>               pEvdev->delta[REL_Y] *= -1;
>
> +
> +        Evdev3BEmuProcessRelMotion(pInfo,
> +                                   pEvdev->delta[REL_X],
> +                                   pEvdev->delta[REL_Y]);
> +
>           for (i = 0; i<  REL_CNT; i++)
>           {
>               int map = pEvdev->axis_map[i];
> @@ -454,6 +459,7 @@ EvdevProcessValuators(InputInfoPtr pInfo)
>
>               valuator_mask_set(pEvdev->vals, i, val);
>           }
> +        Evdev3BEmuProcessAbsMotion(pInfo, pEvdev->vals);
>       }
>   }
>
> @@ -755,6 +761,12 @@ static void EvdevPostQueuedEvents(InputInfoPtr pInfo, int num_v, int first_v,
>               break;
>           case EV_QUEUE_BTN:
>               if (pEvdev->abs_queued&&  pEvdev->in_proximity) {

does that means that this is just available for absolute devices?

> +
> +                if (Evdev3BEmuFilterEvent(pInfo,
> +                                          pEvdev->queue[i].key,
> +                                          pEvdev->queue[i].val))
> +                    break;
> +
>                   xf86PostButtonEventP(pInfo->dev, 1, pEvdev->queue[i].key,
>                                        pEvdev->queue[i].val, first_v, num_v,
>                                        v + first_v);
> @@ -845,6 +857,7 @@ EvdevReadInput(InputInfoPtr pInfo)
>               if (errno == ENODEV) /* May happen after resume */
>               {
>                   EvdevMBEmuFinalize(pInfo);
> +                Evdev3BEmuFinalize(pInfo);
>                   xf86RemoveEnabledDevice(pInfo);
>                   close(pInfo->fd);
>                   pInfo->fd = -1;
> @@ -1335,6 +1348,7 @@ EvdevInit(DeviceIntPtr device)
>       EvdevInitProperty(device);
>       XIRegisterPropertyHandler(device, EvdevSetProperty, NULL, NULL);
>       EvdevMBEmuInitProperty(device);
> +    Evdev3BEmuInitProperty(device);
>       EvdevWheelEmuInitProperty(device);
>       EvdevDragLockInitProperty(device);
>
> @@ -1363,6 +1377,7 @@ EvdevOn(DeviceIntPtr device)
>       xf86FlushInput(pInfo->fd);
>       xf86AddEnabledDevice(pInfo);
>       EvdevMBEmuOn(pInfo);
> +    Evdev3BEmuOn(pInfo);
>       pEvdev->flags |= EVDEV_INITIALIZED;
>       device->public.on = TRUE;
>
> @@ -1389,7 +1404,10 @@ EvdevProc(DeviceIntPtr device, int what)
>
>       case DEVICE_OFF:
>           if (pEvdev->flags&  EVDEV_INITIALIZED)
> +        {
>               EvdevMBEmuFinalize(pInfo);
> +            Evdev3BEmuFinalize(pInfo);
> +        }
>           if (pInfo->fd != -1)
>           {
>               EvdevGrabDevice(pInfo, 0, 1);
> @@ -1863,6 +1881,7 @@ EvdevPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
>       if (pEvdev->flags&  EVDEV_BUTTON_EVENTS)
>       {
>           EvdevMBEmuPreInit(pInfo);
> +        Evdev3BEmuPreInit(pInfo);
>           EvdevWheelEmuPreInit(pInfo);
>           EvdevDragLockPreInit(pInfo);
>       }
> diff --git a/src/evdev.h b/src/evdev.h
> index 73c9acb..9db4b83 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -140,6 +140,18 @@ typedef struct {
>           Time                expires;     /* time of expiry */
>           Time                timeout;
>       } emulateMB;
> +    /* Third mouse button emulation */
> +    struct {
> +        BOOL                enabled;
> +        BOOL                state;       /* current state */
> +        Time                timeout;     /* timeout until third button press */
> +        int                 buttonstate; /* phys. button state */
> +        int                 button;      /* phys button to emit */
> +        int                 threshold;   /* move threshold in dev coords */
> +        OsTimerPtr          timer;
> +        int                 delta[2];    /* delta x/y, accumulating */
> +        int                 startpos[2]; /* starting pos for abs devices */
> +    } emulate3B;
>       struct {
>   	int                 meta;           /* meta key to lock any button */
>   	BOOL                meta_state;     /* meta_button state */
> @@ -208,6 +220,16 @@ void EvdevMBEmuPreInit(InputInfoPtr);
>   void EvdevMBEmuOn(InputInfoPtr);
>   void EvdevMBEmuFinalize(InputInfoPtr);
>
> +/* Third button emulation */
> +CARD32 Evdev3BEmuTimer(OsTimerPtr timer, CARD32 time, pointer arg);
> +BOOL Evdev3BEmuFilterEvent(InputInfoPtr, int, BOOL);
> +void Evdev3BEmuPreInit(InputInfoPtr pInfo);
> +void Evdev3BEmuPreInit(InputInfoPtr);
> +void Evdev3BEmuOn(InputInfoPtr);
> +void Evdev3BEmuFinalize(InputInfoPtr);
> +void Evdev3BEmuProcessRelMotion(InputInfoPtr pInfo, int dx, int dy);
> +void Evdev3BEmuProcessAbsMotion(InputInfoPtr pInfo, ValuatorMask *vals);
> +
>   /* Mouse Wheel emulation */
>   void EvdevWheelEmuPreInit(InputInfoPtr pInfo);
>   BOOL EvdevWheelEmuFilterButton(InputInfoPtr pInfo, unsigned int button, int value);
> @@ -218,6 +240,7 @@ void EvdevDragLockPreInit(InputInfoPtr pInfo);
>   BOOL EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value);
>
>   void EvdevMBEmuInitProperty(DeviceIntPtr);
> +void Evdev3BEmuInitProperty(DeviceIntPtr);
>   void EvdevWheelEmuInitProperty(DeviceIntPtr);
>   void EvdevDragLockInitProperty(DeviceIntPtr);
>   #endif


That's all. Thanks for the work Peter.

Cheers,
Benjamin


More information about the xorg-devel mailing list