summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTero Saarni <tero.saarni@gmail.com>2009-07-12 19:24:40 +0300
committerPeter Hutterer <peter.hutterer@who-t.net>2009-07-16 14:54:15 +1000
commit0c3fbceb1b2a18f92166fe75c44b5aaada693c4b (patch)
treebb25e5b2285ad29da4ba293fcec9cca1271bef2e
parentafb60a0b2497c5d08cbd1739fa8ae6585c428881 (diff)
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>
-rw-r--r--include/synaptics-properties.h3
-rw-r--r--man/synaptics.man25
-rw-r--r--src/eventcomm.c8
-rw-r--r--src/eventcomm.h1
-rw-r--r--src/properties.c10
-rw-r--r--src/synaptics.c52
-rw-r--r--src/synapticsstr.h5
7 files changed, 99 insertions, 5 deletions
diff --git a/include/synaptics-properties.h b/include/synaptics-properties.h
index b944adb..3153d73 100644
--- a/include/synaptics-properties.h
+++ b/include/synaptics-properties.h
@@ -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_ */
diff --git a/man/synaptics.man b/man/synaptics.man
index 5b98082..a69c3c4 100644
--- a/man/synaptics.man
+++ b/man/synaptics.man
@@ -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.
diff --git a/src/eventcomm.c b/src/eventcomm.c
index 5ab34c0..ae853f2 100644
--- a/src/eventcomm.c
+++ b/src/eventcomm.c
@@ -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));
diff --git a/src/eventcomm.h b/src/eventcomm.h
index a4a9a44..8fd7bcb 100644
--- a/src/eventcomm.h
+++ b/src/eventcomm.h
@@ -28,6 +28,7 @@
#define _EVENTCOMM_H_
#include <linux/input.h>
+#include <linux/version.h>
/* for auto-dev: */
#define DEV_INPUT_EVENT "/dev/input"
diff --git a/src/properties.c b/src/properties.c
index 64dbc9e..43bcabb 100644
--- a/src/properties.c
+++ b/src/properties.c
@@ -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
@@ -612,6 +618,10 @@ SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
{
/* read-only */
return BadValue;
+ } else if (property == prop_resolution)
+ {
+ /* read-only */
+ return BadValue;
}
return Success;
diff --git a/src/synaptics.c b/src/synaptics.c
index 0a3a21a..d95aa30 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -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;
+ }
+}
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 87af600..8348e72 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -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 */