summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Osterlund <petero2@telia.com>2005-01-06 02:25:20 +0100
committerPeter Osterlund <petero2@telia.com>2006-04-09 04:03:03 +0200
commitd0754c4c39287af2c87aeb280d46f2325849b846 (patch)
treea71e5457276a52f006125b4f56b5b2c4b04ef583
parent7ad9b2ce77ed704b4a2537de85d81b1aaa82efaa (diff)
Implemented coasting, ie the ability to automatically
continue scrolling with the same speed in the same direction when the finger leaves the touchpad.
-rw-r--r--README11
-rw-r--r--synaptics.c85
-rw-r--r--synaptics.h6
-rw-r--r--synclient.c1
4 files changed, 100 insertions, 3 deletions
diff --git a/README b/README
index 797c884..91410b1 100644
--- a/README
+++ b/README
@@ -131,6 +131,7 @@ CircularPad Bool Instead of being a rectangle, the edge is the ellipse
PalmDetect Bool If palm detection should be enabled
PalmMinWidth Int Minimum width at which touch is considered a palm
PalmMinZ Int Minimum finger pressure at which touch is considered a palm
+CoastingSpeed Float Coasting threshold scrolling speed. 0 disables coasting.
The LeftEdge, RightEdge, TopEdge and BottomEdge parameters are used to
define the edge and corner areas of the touchpad. The parameters split
@@ -223,6 +224,16 @@ together with vertical scrolling, hitting the upper or lower right
corner will seamlessly switch over from vertical to circular
scrolling.
+Coasting is enabled by setting the CoastingSpeed parameter to a
+non-zero value. When coasting is enabled, horizontal/vertical
+scrolling can continue after the finger is released from the
+lower/right edge of the touchpad. The driver computes the scrolling
+speed corresponding to the finger speed immediately before the finger
+leaves the touchpad. If this scrolling speed is larger than the
+CoastingSpeed parameter (measured in scroll events per second), the
+scrolling will continue with the same speed in the same direction
+until the finger touches the touchpad again.
+
FAQ
---
diff --git a/synaptics.c b/synaptics.c
index c8ce0c1..fe6f5e1 100644
--- a/synaptics.c
+++ b/synaptics.c
@@ -394,6 +394,9 @@ SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
str_par = xf86FindOptionValue(local->options, "CircScrollDelta");
if ((!str_par) || (xf86sscanf(str_par, "%lf", &pars->scroll_dist_circ) != 1))
pars->scroll_dist_circ = 0.1;
+ str_par = xf86FindOptionValue(local->options, "CoastingSpeed");
+ if ((!str_par) || (xf86sscanf(str_par, "%lf", &pars->coasting_speed) != 1))
+ pars->coasting_speed = 0.0;
if (pars->circular_trigger < 0 || pars->circular_trigger > 8) {
xf86Msg(X_WARNING, "Unknown circular scrolling trigger, using 0 (edges)");
@@ -1274,15 +1277,51 @@ struct ScrollData {
};
static void
+start_coasting(SynapticsPrivate *priv, edge_type edge)
+{
+ SynapticsSHM *para = priv->synpara;
+
+ if ((priv->scroll_packet_count > 3) && (para->coasting_speed > 0.0)) {
+ double pkt_time = (HIST(0).millis - HIST(3).millis) / 1000.0;
+ if (priv->vert_scroll_on ||
+ (priv->circ_scroll_on && priv->circ_scroll_vert)) {
+ double dy = estimate_delta(HIST(0).y, HIST(1).y, HIST(2).y, HIST(3).y);
+ int sdelta = para->scroll_dist_vert;
+ if ((edge & RIGHT_EDGE) && pkt_time > 0 && sdelta > 0) {
+ double scrolls_per_sec = dy / pkt_time / sdelta;
+ if (fabs(scrolls_per_sec) >= para->coasting_speed)
+ priv->autoscroll_yspd = scrolls_per_sec;
+ }
+ } else {
+ double dx = estimate_delta(HIST(0).x, HIST(1).x, HIST(2).x, HIST(3).x);
+ int sdelta = para->scroll_dist_horiz;
+ if ((edge & BOTTOM_EDGE) && pkt_time > 0 && sdelta > 0) {
+ double scrolls_per_sec = dx / pkt_time / sdelta;
+ if (fabs(scrolls_per_sec) >= para->coasting_speed)
+ priv->autoscroll_xspd = scrolls_per_sec;
+ }
+ }
+ }
+ priv->scroll_packet_count = 0;
+ priv->autoscroll_y = 0.0;
+ priv->autoscroll_x = 0.0;
+}
+
+static int
HandleScrolling(SynapticsPrivate *priv, struct SynapticsHwState *hw,
edge_type edge, Bool finger, struct ScrollData *sd)
{
SynapticsSHM *para = priv->synpara;
+ Bool scroll_stop = FALSE;
+ int delay = 1000000000;
sd->left = sd->right = sd->up = sd->down = 0;
/* scroll detection */
if (finger && !priv->finger_flag) {
+ priv->autoscroll_xspd = 0;
+ priv->autoscroll_yspd = 0;
+ priv->scroll_packet_count = 0;
if (para->circular_scrolling) {
if ((para->circular_trigger == 0 && edge) ||
(para->circular_trigger == 1 && edge & TOP_EDGE) ||
@@ -1315,14 +1354,20 @@ HandleScrolling(SynapticsPrivate *priv, struct SynapticsHwState *hw,
if (priv->circ_scroll_on && !finger) {
/* circular scroll locks in until finger is raised */
DBG(7, ErrorF("cicular scroll off\n"));
- priv->circ_scroll_on = FALSE;
+ scroll_stop = TRUE;
}
if (priv->vert_scroll_on && (!(edge & RIGHT_EDGE) || !finger)) {
DBG(7, ErrorF("vert edge scroll off\n"));
- priv->vert_scroll_on = FALSE;
+ scroll_stop = TRUE;
}
if (priv->horiz_scroll_on && (!(edge & BOTTOM_EDGE) || !finger)) {
DBG(7, ErrorF("horiz edge scroll off\n"));
+ scroll_stop = TRUE;
+ }
+ if (scroll_stop) {
+ start_coasting(priv, edge);
+ priv->circ_scroll_on = FALSE;
+ priv->vert_scroll_on = FALSE;
priv->horiz_scroll_on = FALSE;
}
@@ -1348,6 +1393,9 @@ HandleScrolling(SynapticsPrivate *priv, struct SynapticsHwState *hw,
}
}
+ if (priv->vert_scroll_on || priv->horiz_scroll_on || priv->circ_scroll_on)
+ priv->scroll_packet_count++;
+
if (priv->vert_scroll_on) {
/* + = down, - = up */
int delta = para->scroll_dist_vert;
@@ -1400,6 +1448,35 @@ HandleScrolling(SynapticsPrivate *priv, struct SynapticsHwState *hw,
}
}
}
+
+ if (priv->autoscroll_yspd) {
+ double dtime = (hw->millis - HIST(0).millis) / 1000.0;
+ priv->autoscroll_y += priv->autoscroll_yspd * dtime;
+ delay = MIN(delay, 20);
+ while (priv->autoscroll_y > 1.0) {
+ sd->down++;
+ priv->autoscroll_y -= 1.0;
+ }
+ while (priv->autoscroll_y < -1.0) {
+ sd->up++;
+ priv->autoscroll_y += 1.0;
+ }
+ }
+ if (priv->autoscroll_xspd) {
+ double dtime = (hw->millis - HIST(0).millis) / 1000.0;
+ priv->autoscroll_x += priv->autoscroll_xspd * dtime;
+ delay = MIN(delay, 20);
+ while (priv->autoscroll_x > 1.0) {
+ sd->right++;
+ priv->autoscroll_x -= 1.0;
+ }
+ while (priv->autoscroll_x < -1.0) {
+ sd->left++;
+ priv->autoscroll_x += 1.0;
+ }
+ }
+
+ return delay;
}
/*
@@ -1497,7 +1574,9 @@ HandleState(LocalDevicePtr local, struct SynapticsHwState *hw)
if (timeleft > 0)
delay = MIN(delay, timeleft);
- HandleScrolling(priv, hw, edge, finger, &scroll);
+ timeleft = HandleScrolling(priv, hw, edge, finger, &scroll);
+ if (timeleft > 0)
+ delay = MIN(delay, timeleft);
timeleft = ComputeDeltas(priv, hw, edge, &dx, &dy);
delay = MIN(delay, timeleft);
diff --git a/synaptics.h b/synaptics.h
index 7369b1b..75b3f00 100644
--- a/synaptics.h
+++ b/synaptics.h
@@ -81,6 +81,7 @@ typedef struct _SynapticsSHM
Bool palm_detect; /* Enable Palm Detection */
int palm_min_width; /* Palm detection width */
int palm_min_z; /* Palm detection depth */
+ double coasting_speed; /* Coasting threshold scrolling speed */
} SynapticsSHM;
/*
@@ -181,6 +182,11 @@ typedef struct _SynapticsPrivateRec
Bool circ_scroll_on; /* scrolling flag */
Bool circ_scroll_vert; /* True: Generate vertical scroll events
False: Generate horizontal events */
+ double autoscroll_xspd; /* Horizontal coasting speed */
+ double autoscroll_yspd; /* Vertical coasting speed */
+ double autoscroll_x; /* Accumulated horizontal coasting scroll */
+ double autoscroll_y; /* Accumulated vertical coasting scroll */
+ int scroll_packet_count; /* Scroll duration */
double frac_x, frac_y; /* absolute -> relative fraction */
enum MidButtonEmulation mid_emu_state; /* emulated 3rd button */
int repeatButtons; /* buttons for repeat */
diff --git a/synclient.c b/synclient.c
index 11093eb..d443212 100644
--- a/synclient.c
+++ b/synclient.c
@@ -89,6 +89,7 @@ static struct Parameter params[] = {
DEFINE_PAR("PalmDetect", palm_detect, PT_BOOL, 0, 1),
DEFINE_PAR("PalmMinWidth", palm_min_width, PT_INT, 0, 15),
DEFINE_PAR("PalmMinZ", palm_min_z, PT_INT, 0, 255),
+ DEFINE_PAR("CoastingSpeed", coasting_speed, PT_DOUBLE, 0, 20),
{ 0, 0, 0, 0, 0 }
};