dix: use average of pointer accel profile
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
25882af6d3
commit
18e9fd69fe
138
dix/ptrveloc.c
138
dix/ptrveloc.c
|
@ -73,7 +73,8 @@ InitFilterChain(DeviceVelocityPtr s, float rdecay, float degression,
|
||||||
void
|
void
|
||||||
CleanupFilterChain(DeviceVelocityPtr s);
|
CleanupFilterChain(DeviceVelocityPtr s);
|
||||||
static float
|
static float
|
||||||
SimpleSmoothProfile(DeviceVelocityPtr pVel, float threshold, float acc);
|
SimpleSmoothProfile(DeviceVelocityPtr pVel, float velocity,
|
||||||
|
float threshold, float acc);
|
||||||
|
|
||||||
|
|
||||||
/********************************
|
/********************************
|
||||||
|
@ -88,6 +89,7 @@ InitVelocityData(DeviceVelocityPtr s)
|
||||||
{
|
{
|
||||||
s->lrm_time = 0;
|
s->lrm_time = 0;
|
||||||
s->velocity = 0;
|
s->velocity = 0;
|
||||||
|
s->last_velocity = 0;
|
||||||
s->corr_mul = 10.0; /* dots per 10 milisecond should be usable */
|
s->corr_mul = 10.0; /* dots per 10 milisecond should be usable */
|
||||||
s->const_acceleration = 1.0; /* no acceleration/deceleration */
|
s->const_acceleration = 1.0; /* no acceleration/deceleration */
|
||||||
s->reset_time = 300;
|
s->reset_time = 300;
|
||||||
|
@ -97,6 +99,7 @@ InitVelocityData(DeviceVelocityPtr s)
|
||||||
s->use_softening = 1;
|
s->use_softening = 1;
|
||||||
s->min_acceleration = 1.0; /* don't decelerate */
|
s->min_acceleration = 1.0; /* don't decelerate */
|
||||||
s->coupling = 0.25;
|
s->coupling = 0.25;
|
||||||
|
s->average_accel = TRUE;
|
||||||
s->profile_private = NULL;
|
s->profile_private = NULL;
|
||||||
memset(&s->statistics, 0, sizeof(s->statistics));
|
memset(&s->statistics, 0, sizeof(s->statistics));
|
||||||
memset(&s->filters, 0, sizeof(s->filters));
|
memset(&s->filters, 0, sizeof(s->filters));
|
||||||
|
@ -163,7 +166,7 @@ InitFilterChain(DeviceVelocityPtr s, float rdecay, float progression, int stages
|
||||||
rdecay /= progression;
|
rdecay /= progression;
|
||||||
}
|
}
|
||||||
/* release again. Should the input loop be threaded, we also need
|
/* release again. Should the input loop be threaded, we also need
|
||||||
* memory release here (in princliple).
|
* memory release here (in principle).
|
||||||
*/
|
*/
|
||||||
OsReleaseSignals();
|
OsReleaseSignals();
|
||||||
}
|
}
|
||||||
|
@ -330,10 +333,14 @@ ProcessVelocityData(
|
||||||
float cvelocity;
|
float cvelocity;
|
||||||
|
|
||||||
int diff = time - s->lrm_time;
|
int diff = time - s->lrm_time;
|
||||||
int cur_ax = GetAxis(dx, dy);
|
int cur_ax, last_ax;
|
||||||
int last_ax = GetAxis(s->last_dx, s->last_dy);
|
|
||||||
short reset = (diff >= s->reset_time);
|
short reset = (diff >= s->reset_time);
|
||||||
|
|
||||||
|
/* remember last round's result */
|
||||||
|
s->last_velocity = s->velocity;
|
||||||
|
cur_ax = GetAxis(dx, dy);
|
||||||
|
last_ax = GetAxis(s->last_dx, s->last_dy);
|
||||||
|
|
||||||
if(cur_ax != last_ax && cur_ax != -1 && last_ax != -1 && !reset){
|
if(cur_ax != last_ax && cur_ax != -1 && last_ax != -1 && !reset){
|
||||||
/* correct for the error induced when diagonal movements are
|
/* correct for the error induced when diagonal movements are
|
||||||
reported as alternating axis mickeys */
|
reported as alternating axis mickeys */
|
||||||
|
@ -368,15 +375,22 @@ ProcessVelocityData(
|
||||||
if (diff == 0)
|
if (diff == 0)
|
||||||
diff = 1; /* prevent div-by-zero, though it shouldn't happen anyway*/
|
diff = 1; /* prevent div-by-zero, though it shouldn't happen anyway*/
|
||||||
|
|
||||||
/* translate velocity to dots/ms (somewhat untractable in integers,
|
/* translate velocity to dots/ms (somewhat intractable in integers,
|
||||||
so we multiply by some per-device adjustable factor) */
|
so we multiply by some per-device adjustable factor) */
|
||||||
cvelocity = cvelocity * s->corr_mul / (float)diff;
|
cvelocity = cvelocity * s->corr_mul / (float)diff;
|
||||||
|
|
||||||
/* short-circuit: when nv-reset the rest can be skipped */
|
/* short-circuit: when nv-reset the rest can be skipped */
|
||||||
if(reset == TRUE){
|
if(reset == TRUE){
|
||||||
|
/*
|
||||||
|
* we don't really have a velocity here, since diff includes inactive
|
||||||
|
* time. This is dealt with in ComputeAcceleration.
|
||||||
|
*/
|
||||||
StuffFilterChain(s, cvelocity);
|
StuffFilterChain(s, cvelocity);
|
||||||
s->velocity = cvelocity;
|
s->velocity = s->last_velocity = cvelocity;
|
||||||
s->last_reset = TRUE;
|
s->last_reset = TRUE;
|
||||||
|
#ifdef PTRACCEL_DEBUGGING
|
||||||
|
ErrorF("(dix ptracc) non-visible state reset\n");
|
||||||
|
#endif
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,6 +402,9 @@ ProcessVelocityData(
|
||||||
* stuff that into the filter chain.
|
* stuff that into the filter chain.
|
||||||
*/
|
*/
|
||||||
s->last_reset = FALSE;
|
s->last_reset = FALSE;
|
||||||
|
#ifdef PTRACCEL_DEBUGGING
|
||||||
|
ErrorF("(dix ptracc) after-reset vel:%.3f\n", cvelocity);
|
||||||
|
#endif
|
||||||
StuffFilterChain(s, cvelocity);
|
StuffFilterChain(s, cvelocity);
|
||||||
s->velocity = cvelocity;
|
s->velocity = cvelocity;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -448,6 +465,72 @@ ApplySofteningAndConstantDeceleration(
|
||||||
*fdy *= s->const_acceleration;
|
*fdy *= s->const_acceleration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* compute the acceleration for given velocity and enforce min_acceleartion
|
||||||
|
*/
|
||||||
|
static float
|
||||||
|
BasicComputeAcceleration(
|
||||||
|
DeviceVelocityPtr pVel,
|
||||||
|
float velocity,
|
||||||
|
float threshold,
|
||||||
|
float acc){
|
||||||
|
|
||||||
|
float result;
|
||||||
|
result = pVel->Profile(pVel, velocity, threshold, acc);
|
||||||
|
|
||||||
|
/* enforce min_acceleration */
|
||||||
|
if (result < pVel->min_acceleration)
|
||||||
|
result = pVel->min_acceleration;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute acceleration. Takes into account averaging, nv-reset, etc.
|
||||||
|
*/
|
||||||
|
static float
|
||||||
|
ComputeAcceleration(
|
||||||
|
DeviceVelocityPtr vel,
|
||||||
|
float threshold,
|
||||||
|
float acc){
|
||||||
|
float res;
|
||||||
|
|
||||||
|
if(vel->last_reset){
|
||||||
|
#ifdef PTRACCEL_DEBUGGING
|
||||||
|
ErrorF("(dix ptracc) profile skipped\n");
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* This is intended to override the first estimate of a stroke,
|
||||||
|
* which is too low (see ProcessVelocityData). 1 should make sure
|
||||||
|
* the mickey is seen on screen.
|
||||||
|
*/
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(vel->average_accel && vel->velocity != vel->last_velocity){
|
||||||
|
/* use simpson's rule to average acceleration between
|
||||||
|
* current and previous velocity.
|
||||||
|
* Though being the more natural choice, it causes a minor delay
|
||||||
|
* in comparison, so it can be disabled. */
|
||||||
|
res = BasicComputeAcceleration(vel, vel->velocity, threshold, acc);
|
||||||
|
res += BasicComputeAcceleration(vel, vel->last_velocity, threshold, acc);
|
||||||
|
res += 4.0f * BasicComputeAcceleration(vel,
|
||||||
|
(vel->last_velocity + vel->velocity) / 2,
|
||||||
|
threshold, acc);
|
||||||
|
res /= 6.0f;
|
||||||
|
#ifdef PTRACCEL_DEBUGGING
|
||||||
|
ErrorF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n",
|
||||||
|
vel->velocity, vel->last_velocity, res);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}else{
|
||||||
|
res = BasicComputeAcceleration(vel, vel->velocity, threshold, acc);
|
||||||
|
#ifdef PTRACCEL_DEBUGGING
|
||||||
|
ErrorF("(dix ptracc) profile sample [%.2f] is %.3f\n",
|
||||||
|
vel->velocity, res);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************
|
/*****************************************
|
||||||
|
@ -460,10 +543,11 @@ ApplySofteningAndConstantDeceleration(
|
||||||
static float
|
static float
|
||||||
PolynomialAccelerationProfile(
|
PolynomialAccelerationProfile(
|
||||||
DeviceVelocityPtr pVel,
|
DeviceVelocityPtr pVel,
|
||||||
|
float velocity,
|
||||||
float ignored,
|
float ignored,
|
||||||
float acc)
|
float acc)
|
||||||
{
|
{
|
||||||
return pow(pVel->velocity, (acc - 1.0) * 0.5);
|
return pow(velocity, (acc - 1.0) * 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -474,15 +558,18 @@ PolynomialAccelerationProfile(
|
||||||
static float
|
static float
|
||||||
ClassicProfile(
|
ClassicProfile(
|
||||||
DeviceVelocityPtr pVel,
|
DeviceVelocityPtr pVel,
|
||||||
|
float velocity,
|
||||||
float threshold,
|
float threshold,
|
||||||
float acc)
|
float acc)
|
||||||
{
|
{
|
||||||
if (threshold) {
|
if (threshold) {
|
||||||
return SimpleSmoothProfile (pVel,
|
return SimpleSmoothProfile (pVel,
|
||||||
|
velocity,
|
||||||
threshold,
|
threshold,
|
||||||
acc);
|
acc);
|
||||||
} else {
|
} else {
|
||||||
return PolynomialAccelerationProfile (pVel,
|
return PolynomialAccelerationProfile (pVel,
|
||||||
|
velocity,
|
||||||
0,
|
0,
|
||||||
acc);
|
acc);
|
||||||
}
|
}
|
||||||
|
@ -500,6 +587,7 @@ ClassicProfile(
|
||||||
static float
|
static float
|
||||||
PowerProfile(
|
PowerProfile(
|
||||||
DeviceVelocityPtr pVel,
|
DeviceVelocityPtr pVel,
|
||||||
|
float velocity,
|
||||||
float threshold,
|
float threshold,
|
||||||
float acc)
|
float acc)
|
||||||
{
|
{
|
||||||
|
@ -507,9 +595,9 @@ PowerProfile(
|
||||||
|
|
||||||
acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */
|
acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */
|
||||||
|
|
||||||
if (pVel->velocity <= threshold)
|
if (velocity <= threshold)
|
||||||
return pVel->min_acceleration;
|
return pVel->min_acceleration;
|
||||||
vel_dist = pVel->velocity - threshold;
|
vel_dist = velocity - threshold;
|
||||||
return (pow(acc, vel_dist)) * pVel->min_acceleration;
|
return (pow(acc, vel_dist)) * pVel->min_acceleration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,10 +624,10 @@ CalcPenumbralGradient(float x){
|
||||||
static float
|
static float
|
||||||
SimpleSmoothProfile(
|
SimpleSmoothProfile(
|
||||||
DeviceVelocityPtr pVel,
|
DeviceVelocityPtr pVel,
|
||||||
|
float velocity,
|
||||||
float threshold,
|
float threshold,
|
||||||
float acc)
|
float acc)
|
||||||
{
|
{
|
||||||
float velocity = pVel->velocity;
|
|
||||||
if(velocity < 1.0f)
|
if(velocity < 1.0f)
|
||||||
return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f;
|
return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f;
|
||||||
if(threshold < 1.0f)
|
if(threshold < 1.0f)
|
||||||
|
@ -561,6 +649,7 @@ SimpleSmoothProfile(
|
||||||
static float
|
static float
|
||||||
SmoothLinearProfile(
|
SmoothLinearProfile(
|
||||||
DeviceVelocityPtr pVel,
|
DeviceVelocityPtr pVel,
|
||||||
|
float velocity,
|
||||||
float threshold,
|
float threshold,
|
||||||
float acc)
|
float acc)
|
||||||
{
|
{
|
||||||
|
@ -571,7 +660,7 @@ SmoothLinearProfile(
|
||||||
else
|
else
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
|
|
||||||
nv = (pVel->velocity - threshold) * acc * 0.5f;
|
nv = (velocity - threshold) * acc * 0.5f;
|
||||||
|
|
||||||
if(nv < 0){
|
if(nv < 0){
|
||||||
res = 0;
|
res = 0;
|
||||||
|
@ -590,10 +679,11 @@ SmoothLinearProfile(
|
||||||
static float
|
static float
|
||||||
LinearProfile(
|
LinearProfile(
|
||||||
DeviceVelocityPtr pVel,
|
DeviceVelocityPtr pVel,
|
||||||
|
float velocity,
|
||||||
float threshold,
|
float threshold,
|
||||||
float acc)
|
float acc)
|
||||||
{
|
{
|
||||||
return acc * pVel->velocity;
|
return acc * velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -730,7 +820,9 @@ acceleratePointerPredictable(
|
||||||
if (dx || dy){
|
if (dx || dy){
|
||||||
/* reset nonvisible state? */
|
/* reset nonvisible state? */
|
||||||
if (ProcessVelocityData(velocitydata, dx , dy, evtime)) {
|
if (ProcessVelocityData(velocitydata, dx , dy, evtime)) {
|
||||||
/* set to center of pixel */
|
/* set to center of pixel. makes sense as long as there are no
|
||||||
|
* means of passing on sub-pixel values.
|
||||||
|
*/
|
||||||
pDev->last.remainder[0] = pDev->last.remainder[1] = 0.5f;
|
pDev->last.remainder[0] = pDev->last.remainder[1] = 0.5f;
|
||||||
/* prevent softening (somewhat quirky solution,
|
/* prevent softening (somewhat quirky solution,
|
||||||
as it depends on the algorithm) */
|
as it depends on the algorithm) */
|
||||||
|
@ -740,22 +832,10 @@ acceleratePointerPredictable(
|
||||||
|
|
||||||
if (pDev->ptrfeed && pDev->ptrfeed->ctrl.num) {
|
if (pDev->ptrfeed && pDev->ptrfeed->ctrl.num) {
|
||||||
/* invoke acceleration profile to determine acceleration */
|
/* invoke acceleration profile to determine acceleration */
|
||||||
mult = velocitydata->Profile(velocitydata,
|
mult = ComputeAcceleration (velocitydata,
|
||||||
pDev->ptrfeed->ctrl.threshold,
|
pDev->ptrfeed->ctrl.threshold,
|
||||||
(float)pDev->ptrfeed->ctrl.num /
|
(float)pDev->ptrfeed->ctrl.num /
|
||||||
(float)pDev->ptrfeed->ctrl.den);
|
(float)pDev->ptrfeed->ctrl.den);
|
||||||
|
|
||||||
#ifdef PTRACCEL_DEBUGGING
|
|
||||||
ErrorF("(dix ptracc) resulting speed multiplier : %.3f\n", mult);
|
|
||||||
#endif
|
|
||||||
/* enforce min_acceleration */
|
|
||||||
if (mult < velocitydata->min_acceleration) {
|
|
||||||
#ifdef PTRACCEL_DEBUGGING
|
|
||||||
ErrorF("(dix ptracc) enforced min multiplier : %.3f\n",
|
|
||||||
velocitydata->min_acceleration);
|
|
||||||
#endif
|
|
||||||
mult = velocitydata->min_acceleration;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mult != 1.0 || velocitydata->const_acceleration != 1.0) {
|
if(mult != 1.0 || velocitydata->const_acceleration != 1.0) {
|
||||||
ApplySofteningAndConstantDeceleration( velocitydata,
|
ApplySofteningAndConstantDeceleration( velocitydata,
|
||||||
|
|
|
@ -150,6 +150,8 @@ ProcessVelocityConfiguration(char* devname, pointer list, DeviceVelocityPtr s){
|
||||||
s->use_softening = xf86SetBoolOption(list, "Softening",
|
s->use_softening = xf86SetBoolOption(list, "Softening",
|
||||||
s->const_acceleration == 1.0);
|
s->const_acceleration == 1.0);
|
||||||
|
|
||||||
|
s->average_accel = xf86SetBoolOption(list, "AccelerationProfileAveraging", TRUE);
|
||||||
|
|
||||||
s->reset_time = xf86SetIntOption(list, "VelocityReset", 300);
|
s->reset_time = xf86SetIntOption(list, "VelocityReset", 300);
|
||||||
|
|
||||||
tempf = xf86SetRealOption(list, "ExpectedRate", 0);
|
tempf = xf86SetRealOption(list, "ExpectedRate", 0);
|
||||||
|
@ -214,7 +216,7 @@ ApplyAccelerationSettings(DeviceIntPtr dev){
|
||||||
/* process special configuration */
|
/* process special configuration */
|
||||||
switch(scheme){
|
switch(scheme){
|
||||||
case PtrAccelPredictable:
|
case PtrAccelPredictable:
|
||||||
pVel = (DeviceVelocityPtr) dev->valuator->accelScheme.accelData;
|
pVel = GetDevicePredictableAccelData(dev);
|
||||||
ProcessVelocityConfiguration (local->name, local->options,
|
ProcessVelocityConfiguration (local->name, local->options,
|
||||||
pVel);
|
pVel);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -53,7 +53,7 @@ struct _DeviceVelocityRec;
|
||||||
*/
|
*/
|
||||||
typedef float (*PointerAccelerationProfileFunc)
|
typedef float (*PointerAccelerationProfileFunc)
|
||||||
(struct _DeviceVelocityRec* /*pVel*/,
|
(struct _DeviceVelocityRec* /*pVel*/,
|
||||||
float /*threshold*/, float /*acc*/);
|
float /*velocity*/, float /*threshold*/, float /*acc*/);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a filter stage contains the data for adaptive IIR filtering.
|
* a filter stage contains the data for adaptive IIR filtering.
|
||||||
|
@ -78,6 +78,7 @@ typedef struct _FilterStage {
|
||||||
typedef struct _DeviceVelocityRec {
|
typedef struct _DeviceVelocityRec {
|
||||||
FilterStage filters[MAX_VELOCITY_FILTERS];
|
FilterStage filters[MAX_VELOCITY_FILTERS];
|
||||||
float velocity; /* velocity as guessed by algorithm */
|
float velocity; /* velocity as guessed by algorithm */
|
||||||
|
float last_velocity; /* previous velocity estimate */
|
||||||
int lrm_time; /* time the last motion event was processed */
|
int lrm_time; /* time the last motion event was processed */
|
||||||
int last_dx, last_dy; /* last motion delta */
|
int last_dx, last_dy; /* last motion delta */
|
||||||
int last_diff; /* last time-difference */
|
int last_diff; /* last time-difference */
|
||||||
|
@ -88,6 +89,7 @@ typedef struct _DeviceVelocityRec {
|
||||||
short reset_time; /* config: reset non-visible state after # ms */
|
short reset_time; /* config: reset non-visible state after # ms */
|
||||||
short use_softening; /* config: use softening of mouse values */
|
short use_softening; /* config: use softening of mouse values */
|
||||||
float coupling; /* config: max. divergence before coupling */
|
float coupling; /* config: max. divergence before coupling */
|
||||||
|
Bool average_accel; /* config: average acceleration over velocity */
|
||||||
PointerAccelerationProfileFunc Profile;
|
PointerAccelerationProfileFunc Profile;
|
||||||
PointerAccelerationProfileFunc deviceSpecificProfile;
|
PointerAccelerationProfileFunc deviceSpecificProfile;
|
||||||
void* profile_private;/* extended data, see SetAccelerationProfile() */
|
void* profile_private;/* extended data, see SetAccelerationProfile() */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user