# On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: dix/Makefile.am # modified: dix/devices.c # modified: dix/getevents.c # modified: hw/xfree86/common/xf86Xinput.c # modified: include/Makefile.am # modified: include/input.h # modified: include/inputstr.h # # Untracked files: # (use "git add ..." to include in what will be committed) # # dix/devices.c.orig # dix/ptrveloc.c # hw/xfree86/common/xf86Xinput.c.orig # include/ptrveloc.h diff --git a/dix/Makefile.am b/dix/Makefile.am index 9320a2d..c8718e4 100644 --- a/dix/Makefile.am +++ b/dix/Makefile.am @@ -28,6 +28,7 @@ libdix_la_SOURCES = \ pixmap.c \ privates.c \ property.c \ + ptrveloc.c \ registry.c \ resource.c \ selection.c \ diff --git a/dix/devices.c b/dix/devices.c index 0a68c0e..87de229 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -62,6 +62,7 @@ SOFTWARE. #include "scrnintstr.h" #include "cursorstr.h" #include "dixstruct.h" +#include "ptrveloc.h" #include "site.h" #ifndef XKB_IN_SERVER #define XKB_IN_SERVER @@ -171,6 +172,7 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart) /* last valuators */ memset(dev->last.valuators, 0, sizeof(dev->last.valuators)); + memset(dev->last.remainder, 0, sizeof(dev->last.remainder)); dev->last.numValuators = 0; /* security creation/labeling check @@ -776,6 +778,10 @@ CloseDevice(DeviceIntPtr dev) /* free sprite memory */ if (dev->isMaster && dev->spriteInfo->sprite) screen->DeviceCursorCleanup(dev, screen); + + /* free acceleration info */ + if(dev->valuator && dev->valuator->accelScheme.AccelCleanupProc) + dev->valuator->accelScheme.AccelCleanupProc(dev); xfree(dev->name); @@ -1188,8 +1194,6 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, valc->mode = mode; valc->axes = (AxisInfoPtr)(valc + 1); valc->axisVal = (int *)(valc->axes + numAxes); - valc->dxremaind = 0; - valc->dyremaind = 0; dev->valuator = valc; AllocateMotionHistory(dev); @@ -1201,9 +1205,63 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, } dev->last.numValuators = numAxes; + if(!dev->isMaster) /* master devs do not accelerate */ + InitPointerAccelerationScheme(dev, PtrAccelDefault); return TRUE; } +/* global list of acceleration schemes */ +ValuatorAccelerationRec pointerAccelerationScheme[] = { + {PtrAccelNoOp, NULL, NULL, NULL}, + {PtrAccelPredictable, acceleratePointerPredictable, NULL, AccelerationDefaultCleanup}, + {PtrAccelClassic, acceleratePointerClassic, NULL, NULL}, + {-1, NULL, NULL, NULL} /* terminator */ +}; + +_X_EXPORT Bool +InitPointerAccelerationScheme(DeviceIntPtr dev, + int scheme) +{ + int x, i = -1; + + if(dev->isMaster) /* bail out if called for master devs */ + return FALSE; + + for(x = 0; pointerAccelerationScheme[x].number >= 0; x++) { + if(pointerAccelerationScheme[x].number == scheme){ + i = x; + break; + } + } + + if(-1 == i) + return FALSE; + + void* data = NULL; + + /* init scheme-specific data */ + switch(scheme){ + case PtrAccelPredictable: + { + DeviceVelocityPtr s; + s = (DeviceVelocityPtr)xalloc(sizeof(DeviceVelocityRec)); + InitVelocityData(s); + data = s; + break; + } + + default: + break; + } + + ValuatorClassPtr val = dev->valuator; + val->accelScheme = pointerAccelerationScheme[i]; + val->accelScheme.accelData = data; + + return TRUE; +} + + _X_EXPORT Bool InitAbsoluteClassDeviceStruct(DeviceIntPtr dev) { diff --git a/dix/getevents.c b/dix/getevents.c index 3713f4b..4c2afaa 100644 --- a/dix/getevents.c +++ b/dix/getevents.c @@ -487,80 +487,6 @@ GetMaximumEventsNum(void) { } -/* Originally a part of xf86PostMotionEvent; modifies valuators - * in-place. */ -static void -acceleratePointer(DeviceIntPtr pDev, int first_valuator, int num_valuators, - int *valuators) -{ - float mult = 0.0; - int dx = 0, dy = 0; - int *px = NULL, *py = NULL; - - if (!num_valuators || !valuators) - return; - - if (first_valuator == 0) { - dx = valuators[0]; - px = &valuators[0]; - } - if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) { - dy = valuators[1 - first_valuator]; - py = &valuators[1 - first_valuator]; - } - - if (!dx && !dy) - return; - - if (pDev->ptrfeed && pDev->ptrfeed->ctrl.num) { - /* modeled from xf86Events.c */ - if (pDev->ptrfeed->ctrl.threshold) { - if ((abs(dx) + abs(dy)) >= pDev->ptrfeed->ctrl.threshold) { - pDev->valuator->dxremaind = ((float)dx * - (float)(pDev->ptrfeed->ctrl.num)) / - (float)(pDev->ptrfeed->ctrl.den) + - pDev->valuator->dxremaind; - if (px) { - *px = (int)pDev->valuator->dxremaind; - pDev->valuator->dxremaind = pDev->valuator->dxremaind - - (float)(*px); - } - - pDev->valuator->dyremaind = ((float)dy * - (float)(pDev->ptrfeed->ctrl.num)) / - (float)(pDev->ptrfeed->ctrl.den) + - pDev->valuator->dyremaind; - if (py) { - *py = (int)pDev->valuator->dyremaind; - pDev->valuator->dyremaind = pDev->valuator->dyremaind - - (float)(*py); - } - } - } - else { - mult = pow((float)dx * (float)dx + (float)dy * (float)dy, - ((float)(pDev->ptrfeed->ctrl.num) / - (float)(pDev->ptrfeed->ctrl.den) - 1.0) / - 2.0) / 2.0; - if (dx) { - pDev->valuator->dxremaind = mult * (float)dx + - pDev->valuator->dxremaind; - *px = (int)pDev->valuator->dxremaind; - pDev->valuator->dxremaind = pDev->valuator->dxremaind - - (float)(*px); - } - if (dy) { - pDev->valuator->dyremaind = mult * (float)dy + - pDev->valuator->dyremaind; - *py = (int)pDev->valuator->dyremaind; - pDev->valuator->dyremaind = pDev->valuator->dyremaind - - (float)(*py); - } - } - } -} - - /** * Clip an axis to its bounds, which are declared in the call to * InitValuatorAxisClassStruct. @@ -884,6 +810,9 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons, DeviceIntPtr master; int x, y, /* switches between device and screen coords */ cx, cy; /* only screen coordinates */ + + ms = GetTimeInMillis(); //before pointer update to help precision + ScreenPtr scr = miPointerGetScreen(pDev); int *v0 = NULL, *v1 = NULL; int i; @@ -900,8 +829,6 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons, if (type == MotionNotify && num_valuators <= 0) return 0; - ms = GetTimeInMillis(); - /* Do we need to send a DeviceValuator event? */ if (num_valuators) { if ((((num_valuators - 1) / 6) + 1) > MAX_VALUATOR_EVENTS) @@ -951,9 +878,11 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons, } } else { - if (flags & POINTER_ACCELERATE) - acceleratePointer(pDev, first_valuator, num_valuators, - valuators); + if (flags & POINTER_ACCELERATE && + pDev->valuator->accelScheme.AccelSchemeProc){ + pDev->valuator->accelScheme.AccelSchemeProc( + pDev, first_valuator, num_valuators, valuators, ms); + } if(v0) x += *v0; if(v1) y += *v1; diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index 498f797..891b763 100644 --- a/hw/xfree86/common/xf86Xinput.c +++ b/hw/xfree86/common/xf86Xinput.c @@ -82,12 +82,123 @@ #include "mi.h" +#include /* dix pointer acceleration */ + #ifdef XFreeXDGA #include "dgaproc.h" #endif EventListPtr xf86Events = NULL; +/** + * Eval config and modify DeviceVelocityRec accordingly + */ +static void +ProcessVelocityConfiguration(char* devname, pointer list, DeviceVelocityPtr s){ + int tempi, i; + float tempf, tempf2; + + if(!s) + return; + + tempf = xf86SetRealOption(list, "FilterHalflife", 20); + xf86Msg(X_CONFIG, "%s: (accel) filter halflife %.1f ms\n", devname, tempf); + if(tempf > 0) + tempf = 1.0 / tempf; /* set reciprocal if possible */ + else + tempf = 10000; /* else set fairly high */ + + tempf2 = xf86SetRealOption(list, "FilterChainProgression", 2.0); + xf86Msg(X_CONFIG, "%s: (accel) filter chain progression: %.2f\n", devname, tempf2); + if(tempf2 < 1) + tempf2 = 2; + + tempi = xf86SetIntOption(list, "FilterChainLength", 1); + if(tempi < 1 || tempi > MAX_VELOCITY_FILTERS) + tempi = 1; + + InitFilterChain(s, tempf, tempf2, tempi, 40); + for(i = 0; i < tempi; i++) + xf86Msg(X_CONFIG, "(accel) filter stage %i: %.2f ms", i, 1.0f / (s->filters[i].rdecay)); + + tempf = xf86SetIntOption(list, "ConstantDeceleration", 1); + if(tempf > 1.0){ + xf86Msg(X_CONFIG, "%s: (accel) constant deceleration by %.1f\n", devname, + tempf); + s->const_acceleration = 1.0 / tempf; /* set reciprocal deceleration + alias acceleration */ + } + + tempf = xf86SetIntOption(list, "AdaptiveDeceleration", 1); + if(tempf > 1.0){ + xf86Msg(X_CONFIG, "%s: (accel) adaptive deceleration by %.1f\n", devname, + tempf); + s->min_acceleration = 1.0 / tempf; /* set minimum acceleration */ + } + + tempf = xf86SetRealOption(list, "VelocityCoupling", 0.2); + xf86Msg(X_CONFIG, "%s: (accel) velocity coupling is %.1f%%\n", devname, + tempf*100.0); + s->coupling = tempf; + + /* Configure softening. If const deceleration is used, this is expected + * to provide better subpixel information so we enable + * softening by default only if ConstantDeceleration is not used + */ + s->use_softening = xf86SetBoolOption(list, "Softening", + s->const_acceleration == 1.0); + + s->reset_time = xf86SetIntOption(list, "VelocityReset", 300); + + tempf = xf86SetRealOption(list, "ExpectedRate", 0); + if(tempf > 0){ + s->corr_mul = 1000.0 / tempf; + }else{ + s->corr_mul = xf86SetRealOption(list, "VelocityScale", 10); + } + + /* select profile by number */ + tempi= xf86SetIntOption(list, "AccelerationProfile", 0); + if(SetAccelerationProfile(s, tempi)){ + xf86Msg(X_CONFIG, "%s: (accel) set acceleration profile %i\n", devname, tempi); + }else{ + xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i is unknown\n", + devname, tempi); + } +} + +static void +ApplyAccelerationSettings(DeviceIntPtr dev){ + int scheme; + DeviceVelocityPtr pVel; + LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate; + + if(dev->valuator){ + scheme = xf86SetIntOption(local->options, "AccelerationScheme", 1); + + /* reinit scheme if needed */ + if(dev->valuator->accelScheme.number != scheme){ + if(dev->valuator->accelScheme.AccelCleanupProc){ + dev->valuator->accelScheme.AccelCleanupProc(dev); + } + + xf86Msg(X_CONFIG, "%s: (accel) init acceleration scheme %i\n", local->name, scheme); + InitPointerAccelerationScheme(dev, scheme); + }else{ + xf86Msg(X_CONFIG, "%s: (accel) keeping acceleration scheme %i\n", local->name, scheme); + } + + /* process special configuration */ + switch(scheme){ + case 1: + pVel = (DeviceVelocityPtr) dev->valuator->accelScheme.accelData; + ProcessVelocityConfiguration (local->name, local->options, + pVel); + break; + } + } +} + static Bool xf86SendDragEvents(DeviceIntPtr device) { @@ -837,6 +948,9 @@ xf86InitValuatorDefaults(DeviceIntPtr dev, int axnum) dev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; dev->last.valuators[1] = dev->valuator->axisVal[1]; } + + if(axnum == 0) /* to prevent double invocation */ + ApplyAccelerationSettings(dev); } diff --git a/include/Makefile.am b/include/Makefile.am index 7d5fee7..49811c5 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -35,6 +35,7 @@ sdk_HEADERS = \ privates.h \ property.h \ propertyst.h \ + ptrveloc.h \ region.h \ regionstr.h \ registry.h \ diff --git a/include/input.h b/include/input.h index 59f4e7f..1ddeb83 100644 --- a/include/input.h +++ b/include/input.h @@ -63,6 +63,12 @@ SOFTWARE. #define POINTER_ABSOLUTE (1 << 2) #define POINTER_ACCELERATE (1 << 3) +/*int constants for pointer acceleration schemes*/ +#define PtrAccelNoOp 0 +#define PtrAccelPredictable 1 +#define PtrAccelClassic 2 +#define PtrAccelDefault PtrAccelPredictable + #define MAX_VALUATORS 36 /* XXX from comment in dix/getevents.c */ #define NO_AXIS_LIMITS -1 @@ -155,6 +161,17 @@ typedef void (*DeviceUnwrapProc)( void* /*data*/ ); +/* pointer acceleration handling */ +typedef void (*PointerAccelSchemeProc)( + DeviceIntPtr /*pDev*/, + int /*first_valuator*/, + int /*num_valuators*/, + int* /*valuators*/, + int /*evtime*/); + +typedef void (*DeviceCallbackProc)( + DeviceIntPtr /*pDev*/); + typedef struct _DeviceRec { pointer devicePrivate; ProcessInputProc processInputProc; /* current */ @@ -280,6 +297,10 @@ extern Bool InitValuatorClassDeviceStruct( int /*numMotionEvents*/, int /*mode*/); +extern Bool InitPointerAccelerationScheme( + DeviceIntPtr /*dev*/, + int /*scheme*/); + extern Bool InitAbsoluteClassDeviceStruct( DeviceIntPtr /*device*/); diff --git a/include/inputstr.h b/include/inputstr.h index e5de6fc..4334872 100644 --- a/include/inputstr.h +++ b/include/inputstr.h @@ -166,6 +166,13 @@ typedef struct _AxisInfo { int max_value; } AxisInfo, *AxisInfoPtr; +typedef struct _ValuatorAccelerationRec { + int number; + PointerAccelSchemeProc AccelSchemeProc; + void *accelData; /* at disposal of AccelScheme */ + DeviceCallbackProc AccelCleanupProc; +} ValuatorAccelerationRec, *ValuatorAccelerationPtr; + typedef struct _ValuatorClassRec { int numMotionEvents; int first_motion; @@ -177,8 +184,8 @@ typedef struct _ValuatorClassRec { AxisInfoPtr axes; unsigned short numAxes; int *axisVal; /* always absolute, but device-coord system */ - float dxremaind, dyremaind; /* for acceleration */ CARD8 mode; + ValuatorAccelerationRec accelScheme; } ValuatorClassRec, *ValuatorClassPtr; typedef struct _ButtonClassRec { @@ -426,9 +433,12 @@ typedef struct _DeviceIntRec { /* last valuator values recorded, not posted to client; * for slave devices, valuators is in device coordinates * for master devices, valuators is in screen coordinates - * see dix/getevents.c */ + * see dix/getevents.c + * remainder supports acceleration + */ struct { int valuators[MAX_VALUATORS]; + float remainder[MAX_VALUATORS]; int numValuators; } last; } DeviceIntRec;