mirror of
https://github.com/X11Libre/xf86-input-synaptics.git
synced 2026-03-24 01:34:04 +00:00
Add configurable x/y resolution to fix sensitivity on wide touchpads.
Synaptics uses anisotropic coordinate system. On some wide touchpads vertical resolution can be twice as high as horizontal which causes unequal sensitivity on x/y directions. VertResolution and HorizResolution can be used to set the resolution. The ratio of the values is used to compensate x/y sensitivity. The properties are configured automatically if touchpad reports resolution and if running on linux 2.6.31 or newer. Fixes xorg bug #18351. Signed-off-by: Tero Saarni <tero.saarni@gmail.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
committed by
Peter Hutterer
parent
afb60a0b24
commit
0c3fbceb1b
@@ -149,4 +149,7 @@
|
||||
* has_double, has_triple */
|
||||
#define SYNAPTICS_PROP_CAPABILITIES "Synaptics Capabilities"
|
||||
|
||||
/* 32 bit unsigned, 2 values, vertical, horizontal in units/millimeter */
|
||||
#define SYNAPTICS_PROP_RESOLUTION "Synaptics Pad Resolution"
|
||||
|
||||
#endif /* _SYNAPTICS_PROPERTIES_H_ */
|
||||
|
||||
@@ -425,6 +425,23 @@ touching again and moving the finger on the touchpad.
|
||||
The gesture is enabled by default and can be disabled by setting the
|
||||
TapAndDragGesture option to false. Property: "Synaptics Gestures"
|
||||
.
|
||||
.TP
|
||||
.BI "Option \*qVertResolution\*q \*q" integer \*q
|
||||
Resolution of X coordinates in units/millimeter. The value is used
|
||||
together with HorizResolution to compensate unequal vertical and
|
||||
horizontal sensitivity. Setting VertResolution and HorizResolution
|
||||
equal values means no compensation. Default value is read from
|
||||
the touchpad or set to 1 if value could not be read.
|
||||
Property: "Synaptics Pad Resolution"
|
||||
.
|
||||
.TP
|
||||
.BI "Option \*qHorizResolution\*q \*q" integer \*q
|
||||
Resolution of Y coordinates in units/millimeter. The value is used
|
||||
together with VertResolution to compensate unequal vertical and
|
||||
horizontal sensitivity. Setting VertResolution and HorizResolution
|
||||
equal values means no compensation. Default value is read from
|
||||
the touchpad or set to 1 if value could not be read.
|
||||
Property: "Synaptics Pad Resolution"
|
||||
.LP
|
||||
The LeftEdge, RightEdge, TopEdge and BottomEdge parameters are used to
|
||||
define the edge and corner areas of the touchpad.
|
||||
@@ -812,6 +829,10 @@ scrolling.
|
||||
8 bit (BOOL), 5 values (read-only), has left button, has middle button, has
|
||||
right button, two-finger detection, three-finger detection.
|
||||
|
||||
.TP 7
|
||||
.BI "Synaptics Pad Resolution"
|
||||
32 bit unsigned, 2 values (read-only), vertical, horizontal in units/millimeter.
|
||||
|
||||
.SH "NOTES"
|
||||
There is an example hal policy file in
|
||||
.I ${sourcecode}/fdi/11-x11-synaptics.fdi
|
||||
@@ -827,8 +848,8 @@ If either of
|
||||
(default) or
|
||||
.BI "Protocol \*q" event \*q
|
||||
is used, the driver initializes defaults based on the capabilities reported by
|
||||
the kernel driver. Acceleration and edges are based on the dimensions reported
|
||||
by the kernel. If the kernel reports multi-finger detection, two-finger
|
||||
the kernel driver. Acceleration, edges and resolution are based on the dimensions
|
||||
reported by the kernel. If the kernel reports multi-finger detection, two-finger
|
||||
vertical scrolling is enabled, horizontal two-finger scrolling is disabled and
|
||||
edge scrolling is disabled. If no multi-finger capabilities are reported,
|
||||
edge scrolling is enabled for both horizontal and vertical scrolling.
|
||||
|
||||
@@ -171,7 +171,7 @@ static void
|
||||
event_query_axis_ranges(LocalDevicePtr local)
|
||||
{
|
||||
SynapticsPrivate *priv = (SynapticsPrivate *)local->private;
|
||||
struct input_absinfo abs;
|
||||
struct input_absinfo abs = {0};
|
||||
unsigned long absbits[NBITS(ABS_MAX)] = {0};
|
||||
unsigned long keybits[NBITS(KEY_MAX)] = {0};
|
||||
char buf[256];
|
||||
@@ -184,6 +184,9 @@ event_query_axis_ranges(LocalDevicePtr local)
|
||||
abs.minimum, abs.maximum);
|
||||
priv->minx = abs.minimum;
|
||||
priv->maxx = abs.maximum;
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
|
||||
priv->resx = abs.resolution;
|
||||
#endif
|
||||
} else
|
||||
xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", local->name,
|
||||
strerror(errno));
|
||||
@@ -195,6 +198,9 @@ event_query_axis_ranges(LocalDevicePtr local)
|
||||
abs.minimum, abs.maximum);
|
||||
priv->miny = abs.minimum;
|
||||
priv->maxy = abs.maximum;
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
|
||||
priv->resy = abs.resolution;
|
||||
#endif
|
||||
} else
|
||||
xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", local->name,
|
||||
strerror(errno));
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define _EVENTCOMM_H_
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
/* for auto-dev: */
|
||||
#define DEV_INPUT_EVENT "/dev/input"
|
||||
|
||||
@@ -82,6 +82,7 @@ Atom prop_pressuremotion_factor = 0;
|
||||
Atom prop_grab = 0;
|
||||
Atom prop_gestures = 0;
|
||||
Atom prop_capabilities = 0;
|
||||
Atom prop_resolution = 0;
|
||||
|
||||
static Atom
|
||||
InitAtom(DeviceIntPtr dev, char *name, int format, int nvalues, int *values)
|
||||
@@ -262,6 +263,11 @@ InitDeviceProperties(LocalDevicePtr local)
|
||||
values[3] = priv->has_double;
|
||||
values[4] = priv->has_triple;
|
||||
prop_capabilities = InitAtom(local->dev, SYNAPTICS_PROP_CAPABILITIES, 8, 5, values);
|
||||
|
||||
values[0] = para->resolution_vert;
|
||||
values[1] = para->resolution_horiz;
|
||||
prop_resolution = InitAtom(local->dev, SYNAPTICS_PROP_RESOLUTION, 32, 2, values);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
@@ -609,6 +615,10 @@ SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
|
||||
|
||||
para->grab_event_device = *(BOOL*)prop->data;
|
||||
} else if (property == prop_capabilities)
|
||||
{
|
||||
/* read-only */
|
||||
return BadValue;
|
||||
} else if (property == prop_resolution)
|
||||
{
|
||||
/* read-only */
|
||||
return BadValue;
|
||||
|
||||
@@ -118,6 +118,8 @@ static Bool DeviceOff(DeviceIntPtr);
|
||||
static Bool DeviceClose(DeviceIntPtr);
|
||||
static Bool QueryHardware(LocalDevicePtr);
|
||||
static void ReadDevDimensions(LocalDevicePtr);
|
||||
static void ScaleCoordinates(SynapticsPrivate *priv, struct SynapticsHwState *hw);
|
||||
static void CalculateScalingCoeffs(SynapticsPrivate *priv);
|
||||
|
||||
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 3
|
||||
void InitDeviceProperties(LocalDevicePtr local);
|
||||
@@ -338,6 +340,8 @@ static void set_default_parameters(LocalDevicePtr local)
|
||||
int clickFinger1, clickFinger2, clickFinger3;
|
||||
Bool vertEdgeScroll, horizEdgeScroll;
|
||||
Bool vertTwoFingerScroll, horizTwoFingerScroll;
|
||||
int horizResolution = 1;
|
||||
int vertResolution = 1;
|
||||
|
||||
/* read the parameters */
|
||||
if (priv->synshm)
|
||||
@@ -439,6 +443,12 @@ static void set_default_parameters(LocalDevicePtr local)
|
||||
vertTwoFingerScroll = priv->has_double ? TRUE : FALSE;
|
||||
horizTwoFingerScroll = FALSE;
|
||||
|
||||
/* Use resolution reported by hardware if available */
|
||||
if ((priv->resx > 0) && (priv->resy > 0)) {
|
||||
horizResolution = priv->resx;
|
||||
vertResolution = priv->resy;
|
||||
}
|
||||
|
||||
/* set the parameters */
|
||||
priv->edges_forced = 0;
|
||||
if (xf86CheckIfOptionUsedByName(opts, "LeftEdge"))
|
||||
@@ -517,6 +527,8 @@ static void set_default_parameters(LocalDevicePtr local)
|
||||
pars->press_motion_max_factor = xf86SetRealOption(opts, "PressureMotionMaxFactor", 1.0);
|
||||
pars->grab_event_device = xf86SetBoolOption(opts, "GrabEventDevice", TRUE);
|
||||
pars->tap_and_drag_gesture = xf86SetBoolOption(opts, "TapAndDragGesture", TRUE);
|
||||
pars->resolution_horiz = xf86SetIntOption(opts, "HorizResolution", horizResolution);
|
||||
pars->resolution_vert = xf86SetIntOption(opts, "VertResolution", vertResolution);
|
||||
|
||||
/* Warn about (and fix) incorrectly configured TopEdge/BottomEdge parameters */
|
||||
if (pars->top_edge > pars->bottom_edge) {
|
||||
@@ -619,6 +631,8 @@ SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
|
||||
|
||||
set_default_parameters(local);
|
||||
|
||||
CalculateScalingCoeffs(priv);
|
||||
|
||||
if (!alloc_param_data(local))
|
||||
goto SetupProc_fail;
|
||||
|
||||
@@ -905,7 +919,7 @@ DeviceInit(DeviceIntPtr dev)
|
||||
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
|
||||
axes_labels[0],
|
||||
#endif
|
||||
min, max, 1, 0, 1);
|
||||
min, max, priv->resx * 1000, 0, priv->resx * 1000);
|
||||
xf86InitValuatorDefaults(dev, 0);
|
||||
|
||||
/* Y valuator */
|
||||
@@ -923,7 +937,7 @@ DeviceInit(DeviceIntPtr dev)
|
||||
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
|
||||
axes_labels[1],
|
||||
#endif
|
||||
min, max, 1, 0, 1);
|
||||
min, max, priv->resy * 1000, 0, priv->resy * 1000);
|
||||
xf86InitValuatorDefaults(dev, 1);
|
||||
|
||||
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
|
||||
@@ -2229,6 +2243,13 @@ HandleState(LocalDevicePtr local, struct SynapticsHwState *hw)
|
||||
if (timeleft > 0)
|
||||
delay = MIN(delay, timeleft);
|
||||
|
||||
/*
|
||||
* Compensate for unequal x/y resolution. This needs to be done after
|
||||
* calculations that require unadjusted coordinates, for example edge
|
||||
* detection.
|
||||
*/
|
||||
ScaleCoordinates(priv, hw);
|
||||
|
||||
timeleft = ComputeDeltas(priv, hw, edge, &dx, &dy);
|
||||
delay = MIN(delay, timeleft);
|
||||
|
||||
@@ -2414,3 +2435,30 @@ QueryHardware(LocalDevicePtr local)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ScaleCoordinates(SynapticsPrivate *priv, struct SynapticsHwState *hw)
|
||||
{
|
||||
int xCenter = (priv->synpara.left_edge + priv->synpara.right_edge) / 2;
|
||||
int yCenter = (priv->synpara.top_edge + priv->synpara.bottom_edge) / 2;
|
||||
|
||||
hw->x = (hw->x - xCenter) * priv->horiz_coeff + xCenter;
|
||||
hw->y = (hw->y - yCenter) * priv->vert_coeff + yCenter;
|
||||
}
|
||||
|
||||
void
|
||||
CalculateScalingCoeffs(SynapticsPrivate *priv)
|
||||
{
|
||||
int vertRes = priv->synpara.resolution_vert;
|
||||
int horizRes = priv->synpara.resolution_horiz;
|
||||
|
||||
if ((horizRes > vertRes) && (horizRes > 0)) {
|
||||
priv->horiz_coeff = vertRes / (double)horizRes;
|
||||
priv->vert_coeff = 1;
|
||||
} else if ((horizRes < vertRes) && (vertRes > 0)) {
|
||||
priv->horiz_coeff = 1;
|
||||
priv->vert_coeff = horizRes / (double)vertRes;
|
||||
} else {
|
||||
priv->horiz_coeff = 1;
|
||||
priv->vert_coeff = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +164,8 @@ typedef struct _SynapticsParameters
|
||||
double press_motion_max_factor; /* factor applied on speed when finger pressure is at minimum */
|
||||
Bool grab_event_device; /* grab event device for exclusive use? */
|
||||
Bool tap_and_drag_gesture; /* Switches the tap-and-drag gesture on/off */
|
||||
unsigned int resolution_horiz; /* horizontal resolution of touchpad in units/mm */
|
||||
unsigned int resolution_vert; /* vertical resolution of touchpad in units/mm */
|
||||
} SynapticsParameters;
|
||||
|
||||
|
||||
@@ -224,9 +226,12 @@ typedef struct _SynapticsPrivateRec
|
||||
palm/finger contact disappears */
|
||||
int prev_z; /* previous z value, for palm detection */
|
||||
int avg_width; /* weighted average of previous fingerWidth values */
|
||||
double horiz_coeff; /* normalization factor for x coordintes */
|
||||
double vert_coeff; /* normalization factor for y coordintes */
|
||||
|
||||
int minx, maxx, miny, maxy; /* min/max dimensions as detected */
|
||||
int minp, maxp, minw, maxw; /* min/max pressure and finger width as detected */
|
||||
int resx, resy; /* resolution of coordinates as detected in units/mm */
|
||||
Bool has_left; /* left button detected for this device */
|
||||
Bool has_right; /* right button detected for this device */
|
||||
Bool has_middle; /* middle button detected for this device */
|
||||
|
||||
Reference in New Issue
Block a user