diff --git a/src/evdev.c b/src/evdev.c index 46f89c3..a1081ff 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -32,6 +32,10 @@ #endif #include +#include +#ifndef XInput_2_0 +#include +#endif #include #include @@ -92,6 +96,7 @@ #define EVDEV_TABLET (1 << 8) /* device looks like a tablet? */ #define EVDEV_UNIGNORE_ABSOLUTE (1 << 9) /* explicitly unignore abs axes */ #define EVDEV_UNIGNORE_RELATIVE (1 << 10) /* explicitly unignore rel axes */ +#define EVDEV_RELATIVE_MODE (1 << 11) /* Force absplute events, if device suporrt it */ #define MIN_KEYCODE 8 #define GLYPHS_PER_KEY 2 @@ -117,6 +122,7 @@ static const char *evdevDefaults[] = { static int EvdevOn(DeviceIntPtr); static int EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare); static void EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl); +static int EvdevSwitchMode(ClientPtr client, DeviceIntPtr device, int mode); #ifdef HAVE_PROPERTIES static void EvdevInitAxesLabels(EvdevPtr pEvdev, int natoms, Atom *atoms); @@ -136,6 +142,35 @@ static Atom prop_btn_label = 0; * cannot be used by evdev, leaving us with a space of 2 at the end. */ static EvdevPtr evdev_devices[MAXDEVICES] = {NULL}; +static int EvdevSwitchMode(ClientPtr client, DeviceIntPtr device, int mode) +{ + InputInfoPtr pInfo; + EvdevPtr pEvdev; + + pInfo = device->public.devicePrivate; + pEvdev = pInfo->private; + + if (!pEvdev->abs) + return BadMatch; + + switch ( mode ) + { + case Absolute: + xf86Msg(X_INFO, "%s: force absolute mode\n", pInfo->name); + pEvdev->flags &= ~EVDEV_RELATIVE_MODE; + break; + case Relative: + xf86Msg(X_INFO, "%s: force relative mode\n", pInfo->name); + pEvdev->flags |= EVDEV_RELATIVE_MODE; + break; + default: + xf86Msg(X_WARNING, "%s: unknown mode (%d)\n", pInfo->name, mode); + return BadValue; + } + + return Success; +} + static size_t CountBits(unsigned long *array, size_t nlongs) { unsigned int i; @@ -341,7 +376,7 @@ EvdevProcessValuators(InputInfoPtr pInfo, int v[MAX_VALUATORS], int *num_v, *num_v = *first_v = 0; /* convert to relative motion for touchpads */ - if (pEvdev->abs && (pEvdev->flags & EVDEV_TOUCHPAD)) { + if (pEvdev->abs && (pEvdev->flags & EVDEV_RELATIVE_MODE)) { if (pEvdev->tool) { /* meaning, touch is active */ if (pEvdev->old_vals[0] != -1) pEvdev->delta[REL_X] = pEvdev->vals[0] - pEvdev->old_vals[0]; @@ -1128,6 +1163,7 @@ EvdevAddAbsClass(DeviceIntPtr device) EvdevPtr pEvdev; int num_axes, axis, i = 0; Atom *atoms; + const char *mode; pInfo = device->public.devicePrivate; pEvdev = pInfo->private; @@ -1199,6 +1235,36 @@ EvdevAddAbsClass(DeviceIntPtr device) TestBit(ABS_TILT_Y, pEvdev->abs_bitmask))) pInfo->flags |= XI86_POINTER_CAPABLE; + mode = xf86SetStrOption(pInfo->options, "Mode", "auto"); + if ( !strcmp("absolute", mode) ) + { + xf86Msg(X_INFO, "%s: force absolute mode\n", pInfo->name); + pEvdev->flags &= ~EVDEV_RELATIVE_MODE; + } + else if ( !strcmp("relative", mode) ) + { + xf86Msg(X_INFO, "%s: force relative mode\n", pInfo->name); + pEvdev->flags |= EVDEV_RELATIVE_MODE; + } + else + { + if ( strcmp("auto", mode) ) + xf86Msg(X_WARNING, "%s: unknown mode '%s', use default\n", + pInfo->name, mode); + + if ( pEvdev->flags & EVDEV_TOUCHPAD ) + { + xf86Msg(X_INFO, "%s: use relative mode\n", pInfo->name); + pEvdev->flags |= EVDEV_RELATIVE_MODE; + } + else + { + xf86Msg(X_INFO, "%s: use absolute mode\n", pInfo->name); + pEvdev->flags &= ~EVDEV_RELATIVE_MODE; + } + } + + return Success; } @@ -1965,7 +2031,7 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags) pInfo->history_size = 0; pInfo->control_proc = NULL; pInfo->close_proc = NULL; - pInfo->switch_mode = NULL; + pInfo->switch_mode = EvdevSwitchMode; pInfo->conversion_proc = NULL; pInfo->reverse_conversion_proc = NULL; pInfo->dev = NULL;