diff -urN xf86-input-evdev-1.0.0.5/src/evdev.c xf86-input-evdev-1.0.0.5-emulatescroll/src/evdev.c --- xf86-input-evdev-1.0.0.5/src/evdev.c 2005-09-24 01:32:23.000000000 +0300 +++ xf86-input-evdev-1.0.0.5-emulatescroll/src/evdev.c 2006-07-05 01:55:38.000000000 +0300 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -81,18 +82,65 @@ typedef struct { int kernel24; + + /* wheel emulation */ + Bool isEmulatingWheel; + int wheelButtonTimeout;/* Timeout for the wheel button emulation */ + CARD32 wheelButtonExpires; + + Bool emulateWheel; + int wheelInertia; + int wheelButton; + int wheelYDistance; + int wheelXDistance; + + int negativeX; /* Button values. Unlike the Z and */ + int positiveX; /* W equivalents, these are button */ + int negativeY; /* values rather than button masks. */ + int positiveY; + int buttonMappings[BTN_TASK-BTN_LEFT+1]; } EvdevRec, *EvdevPtr; -static int wheel_up_button = 4; -static int wheel_down_button = 5; -static int wheel_left_button = 6; -static int wheel_right_button = 7; +typedef enum { + OPTION_EMULATE_WHEEL, + OPTION_EMU_WHEEL_BUTTON, + OPTION_EMU_WHEEL_INERTIA, + OPTION_EMU_WHEEL_TIMEOUT, + OPTION_X_AXIS_MAPPING, + OPTION_Y_AXIS_MAPPING, + OPTION_EXTRA_MAPPING, +} EvdevOpts; + +#ifdef XFree86LOADER +static const OptionInfoRec evdevOptions[] = { + { OPTION_EMULATE_WHEEL, "EmulateWheel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_EMU_WHEEL_BUTTON, "EmulateWheelButton", OPTV_INTEGER, {0}, FALSE }, + { OPTION_EMU_WHEEL_INERTIA, "EmulateWheelInertia", OPTV_INTEGER, {0}, FALSE }, + { OPTION_EMU_WHEEL_TIMEOUT, "EmulateWheelTimeout", OPTV_INTEGER, {0}, FALSE }, + { OPTION_EMU_WHEEL_TIMEOUT, "EmulateWheelTimeout", OPTV_INTEGER, {0}, FALSE }, + { OPTION_X_AXIS_MAPPING, "XAxisMapping", OPTV_STRING, {0}, FALSE }, + { OPTION_Y_AXIS_MAPPING, "YAxisMapping", OPTV_STRING, {0}, FALSE }, + { OPTION_EXTRA_MAPPING, "ExtraButtonMapping", OPTV_STRING, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; +#endif + +#ifdef XFree86LOADER +/*ARGSUSED*/ +static const OptionInfoRec * +EvdevAvailableOptions(void *unused) +{ + return (evdevOptions); +} +#endif static void PostButtonClicks(InputInfoPtr pInfo, int button, int count) { int i; + xf86Msg(X_INFO, "%s: %d button %d clicks\n", pInfo->name, count, button); + for (i = 0; i < count; i++) { xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0); xf86PostButtonEvent(pInfo->dev, 0, button, 0, 0, 0); @@ -116,11 +164,136 @@ } static void +EvdevHandleMovement(InputInfoPtr pInfo, int *dx, int *dy) +{ + EvdevPtr pEvdev; + int ms; + int emuWheelDelta, emuWheelButton, emuWheelButtonMask; + + if (*dx == 0 && *dy == 0) + return; + + pEvdev = pInfo->private; + + ms = pEvdev->wheelButtonExpires - GetTimeInMillis (); + + /* Intercept wheel emulation. */ + if (pEvdev->isEmulatingWheel) { + xf86Msg(X_INFO, "%s: handling wheel ms = %d\n", pInfo->name, ms); + if (ms <= 0) { + /* Y axis movement */ + if (pEvdev->negativeY != MSE_NOAXISMAP) { + pEvdev->wheelYDistance += *dy; + if (pEvdev->wheelYDistance < 0) { + emuWheelDelta = -pEvdev->wheelInertia; + emuWheelButton = pEvdev->negativeY; + } else { + emuWheelDelta = pEvdev->wheelInertia; + emuWheelButton = pEvdev->positiveY; + } + emuWheelButtonMask = 1 << (emuWheelButton - 1); + while (abs(pEvdev->wheelYDistance) > pEvdev->wheelInertia) { + pEvdev->wheelYDistance -= emuWheelDelta; + + /* + * Synthesize the press and release, but not when + * the button to be synthesized is already pressed + * "for real". + */ +// TODO if (!(emuWheelButtonMask & buttons) || +// (emuWheelButtonMask & wheelButtonMask)) { + + PostButtonClicks(pInfo, emuWheelButton, 1); +// } + } + } + + /* X axis movement */ + if (pEvdev->negativeX != MSE_NOAXISMAP) { + pEvdev->wheelXDistance += *dx; + if (pEvdev->wheelXDistance < 0) { + emuWheelDelta = -pEvdev->wheelInertia; + emuWheelButton = pEvdev->negativeX; + } else { + emuWheelDelta = pEvdev->wheelInertia; + emuWheelButton = pEvdev->positiveX; + } + emuWheelButtonMask = 1 << (emuWheelButton - 1); + while (abs(pEvdev->wheelXDistance) > pEvdev->wheelInertia) { + pEvdev->wheelXDistance -= emuWheelDelta; + + /* + * Synthesize the press and release, but not when + * the button to be synthesized is already pressed + * "for real". + */ +// TODO if (!(emuWheelButtonMask & buttons) || +// (emuWheelButtonMask & wheelButtonMask)) { + + PostButtonClicks(pInfo, emuWheelButton, 1); +// } + } + } + } + } else { + xf86PostMotionEvent(pInfo->dev, 0, 0, 2, *dx, *dy); + } + + /* + * Button events for the wheel button are only emitted through + * the timeout code. + */ + // TODO buttons &= ~wheelButtonMask; + // TODO change &= ~wheelButtonMask; +} + +static void +EvdevProcessButton(InputInfoPtr pInfo, int button, int value, int *dx, int *dy) +{ + EvdevPtr pEvdev; + int ms; + + pEvdev = pInfo->private; + + xf86Msg(X_INFO, "%s: Button %d %spressed\n", pInfo->name, button, value ? "" : "de"); + + if (pEvdev->emulateWheel) { + if (button == pEvdev->wheelButton) { + if (value) { + pEvdev->isEmulatingWheel = 1; + /* Start timeout handling */ + pEvdev->wheelButtonExpires = GetTimeInMillis () + pEvdev->wheelButtonTimeout; + } else { + pEvdev->isEmulatingWheel = 0; + ms = pEvdev->wheelButtonExpires - GetTimeInMillis (); + + if (0 < ms) { + /* + * If the button is released early enough emit the button + * press/release events + */ + PostButtonClicks(pInfo, pEvdev->wheelButton, 1); + } + } + + EvdevHandleMovement(pInfo, dx, dy); + } + } + + xf86PostButtonEvent(pInfo->dev, 0, button, value, 0, 0); +} + +static void EvdevReadInput(InputInfoPtr pInfo) { + EvdevPtr pEvdev; struct input_event ev; int len, value; int dx, dy; + int button; + int buttons; + + pEvdev = pInfo->private; dx = 0; dy = 0; @@ -150,16 +323,16 @@ case REL_WHEEL: if (value > 0) - PostButtonClicks(pInfo, wheel_up_button, value); + PostButtonClicks(pInfo, pEvdev->negativeY, value); if (value < 0) - PostButtonClicks(pInfo, wheel_down_button, -value); + PostButtonClicks(pInfo, pEvdev->positiveY, -value); break; case REL_HWHEEL: if (value > 0) - PostButtonClicks(pInfo, wheel_right_button, value); + PostButtonClicks(pInfo, pEvdev->positiveX, value); if (value < 0) - PostButtonClicks(pInfo, wheel_left_button, -value); + PostButtonClicks(pInfo, pEvdev->negativeX, -value); break; } break; @@ -168,24 +341,12 @@ break; case EV_KEY: - switch (ev.code) { - case BTN_LEFT: - case BTN_RIGHT: - case BTN_MIDDLE: - xf86PostButtonEvent(pInfo->dev, 0, ev.code - BTN_LEFT + 1, - 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; - - default: + if (ev.code >= BTN_LEFT && ev.code <= BTN_TASK) { + button = pEvdev->buttonMappings[ev.code - BTN_LEFT]; + if (button != MSE_NOAXISMAP) { + EvdevProcessButton(pInfo, button, value, &dx, &dy); + } + } else { PostKbdEvent(pInfo, &ev, value); } break; @@ -195,8 +356,7 @@ } } - if (dx != 0 || dy != 0) - xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy); + EvdevHandleMovement(pInfo, &dx, &dy); } #define TestBit(bit, array) (array[(bit) / 8] & (1 << ((bit) % 8))) @@ -640,6 +800,112 @@ return 0; } +static void +EvdevCommonOptions(InputInfoPtr pInfo) +{ + EvdevPtr pEvdev; + char *s; + int wheelButton; + + pEvdev = pInfo->private; + + if (xf86SetBoolOption(pInfo->options, "EmulateWheel", FALSE)) { + + pEvdev->emulateWheel = TRUE; + wheelButton = xf86SetIntOption(pInfo->options, + "EmulateWheelButton", 4); + if (wheelButton < 0 || wheelButton > MSE_MAXBUTTONS) { + xf86Msg(X_WARNING, "%s: Invalid EmulateWheelButton value: %d\n", + pInfo->name, wheelButton); + wheelButton = 4; + } + pEvdev->wheelButton = wheelButton; + + pEvdev->wheelInertia = xf86SetIntOption(pInfo->options, + "EmulateWheelInertia", 10); + if (pEvdev->wheelInertia <= 0) { + xf86Msg(X_WARNING, "%s: Invalid EmulateWheelInertia value: %d\n", + pInfo->name, pEvdev->wheelInertia); + pEvdev->wheelInertia = 10; + } + pEvdev->wheelButtonTimeout = xf86SetIntOption(pInfo->options, + "EmulateWheelTimeout", 200); + if (pEvdev->wheelButtonTimeout <= 0) { + xf86Msg(X_WARNING, "%s: Invalid EmulateWheelTimeout value: %d\n", + pInfo->name, pEvdev->wheelButtonTimeout); + pEvdev->wheelButtonTimeout = 200; + } + } + + pEvdev->buttonMappings[BTN_LEFT - BTN_LEFT] = 1; + pEvdev->buttonMappings[BTN_RIGHT - BTN_LEFT] = 2; + pEvdev->buttonMappings[BTN_MIDDLE - BTN_LEFT] = 3; + pEvdev->negativeY = 4; + pEvdev->positiveY = 5; + pEvdev->negativeX = 6; + pEvdev->positiveX = 7; + pEvdev->buttonMappings[BTN_SIDE - BTN_LEFT] = 8; + pEvdev->buttonMappings[BTN_EXTRA - BTN_LEFT] = 9; + pEvdev->buttonMappings[BTN_FORWARD - BTN_LEFT] = 10; + pEvdev->buttonMappings[BTN_BACK - BTN_LEFT] = 11; + pEvdev->buttonMappings[BTN_TASK - BTN_LEFT] = 12; + + s = xf86SetStrOption(pInfo->options, "XAxisMapping", NULL); + if (s) { + int b1 = 0, b2 = 0; + char *msg = NULL; + + if ((sscanf(s, "%d %d", &b1, &b2) == 2) && + b1 > 0 && b1 <= MSE_MAXBUTTONS && + b2 > 0 && b2 <= MSE_MAXBUTTONS) { + msg = xstrdup("buttons XX and YY"); + if (msg) + sprintf(msg, "buttons %d and %d", b1, b2); + pEvdev->negativeX = b1; + pEvdev->positiveX = b2; + } else { + xf86Msg(X_WARNING, "%s: Invalid XAxisMapping value: \"%s\"\n", + pInfo->name, s); + } + if (msg) { + xf86Msg(X_CONFIG, "%s: XAxisMapping: %s\n", pInfo->name, msg); + xfree(msg); + } + } + + s = xf86SetStrOption(pInfo->options, "YAxisMapping", NULL); + if (s) { + int b1 = 0, b2 = 0; + char *msg = NULL; + + if ((sscanf(s, "%d %d", &b1, &b2) == 2) && + b1 > 0 && b1 <= MSE_MAXBUTTONS && + b2 > 0 && b2 <= MSE_MAXBUTTONS) { + msg = xstrdup("buttons XX and YY"); + if (msg) + sprintf(msg, "buttons %d and %d", b1, b2); + pEvdev->negativeY = b1; + pEvdev->positiveY = b2; + } else { + xf86Msg(X_WARNING, "%s: Invalid YAxisMapping value: \"%s\"\n", + pInfo->name, s); + } + if (msg) { + xf86Msg(X_CONFIG, "%s: YAxisMapping: %s\n", pInfo->name, msg); + xfree(msg); + } + } + + //if (pEvdev->negativeY > pEvdev->buttons) pEvdev->buttons = pEvdev->negativeY; + //if (pEvdev->positiveY > pEvdev->buttons) pEvdev->buttons = pEvdev->positiveY; + + xf86Msg(X_CONFIG, "%s: EmulateWheel, EmulateWheelButton: %d, " + "EmulateWheelInertia: %d, " + "EmulateWheelTimeout: %d\n", + pInfo->name, wheelButton, pEvdev->wheelInertia, + pEvdev->wheelButtonTimeout); +} + static InputInfoPtr EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags) { @@ -698,6 +964,8 @@ if (EvdevProbe(pInfo)) xfree(pEvdev); + EvdevCommonOptions(pInfo); + return pInfo; } @@ -712,6 +980,13 @@ }; #ifdef XFree86LOADER +ModuleInfoRec EvdevInfo= { + 1, + "EVDEV", + NULL, + 0, + EvdevAvailableOptions, +}; static void EvdevUnplug(pointer p) @@ -724,6 +999,16 @@ int *errmaj, int *errmin) { + static Bool Initialised = FALSE; + + if (!Initialised) { + Initialised = TRUE; +#ifndef REMOVE_LOADER_CHECK_MODULE_INFO + if (xf86LoaderCheckSymbol("xf86AddModuleInfo")) +#endif + xf86AddModuleInfo(&EvdevInfo, module); + } + xf86AddInputDriver(&EVDEV, module, 0); return module; }