Skip to content

Instantly share code, notes, and snippets.

@galundin
Created January 31, 2015 05:21
Show Gist options
  • Save galundin/736d7331a626a0deda13 to your computer and use it in GitHub Desktop.
Save galundin/736d7331a626a0deda13 to your computer and use it in GitHub Desktop.
xf86-input-synaptics driver hack to implement relative circular scrolling
From 8dadbeab277773242e1869bd7c764bd0ddf28063 Mon Sep 17 00:00:00 2001
From: Andrew Lundin <galundin@yahoo.com>
Date: Fri, 30 Jan 2015 22:55:01 -0600
Subject: [PATCH] Change circular scrolling from absolute to relative.
---
src/synaptics.c | 41 ++++++++++++++++++++++++++++++++---------
src/synapticsstr.h | 5 ++++-
2 files changed, 36 insertions(+), 10 deletions(-)
diff --git a/src/synaptics.c b/src/synaptics.c
index e6a90f2..03db536 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -2627,17 +2627,40 @@ HandleScrolling(SynapticsPrivate * priv, struct SynapticsHwState *hw,
}
}
if (priv->circ_scroll_on) {
- /* + = counter clockwise, - = clockwise */
- double delta = para->scroll_dist_circ;
- double diff = diffa(priv->scroll.last_a, angle(priv, hw->x, hw->y));
-
- if (delta >= 0.005 && diff != 0.0) {
+ int dx = hw->x - priv->scroll.last_x;
+ int dy = hw->y - priv->scroll.last_y;
+ double d = sqrt(dx * dx + dy * dy);
+ double distance_factor = log(1 + fmin(d, priv->scroll.last_d) / 100);
+ double angle = atan2(-dy, dx);
+ double delta = diffa(priv->scroll.last_a, angle) * distance_factor;
+ double abs_delta = fabs(delta);
+ double filtered_delta = priv->scroll.filtered_delta;
+ double adaptive_delta = priv->scroll.adaptive_delta;
+ double divergence = fabs(adaptive_delta - filtered_delta);
+ double delta_error = delta - filtered_delta;
+ delta_error *= delta_error;
+
+ /* adaptive filter */
+ double weight = divergence * (1 + abs_delta) / (1 + delta_error * 100);
+ if (weight > 1)
+ weight = 1;
+ double decay = 1 + (hw->millis - priv->scroll.last_millis) / 50.0;
+ adaptive_delta = delta * weight + adaptive_delta * (1 - weight) / decay;
+
+ double delta_unit = para->scroll_dist_circ;
+ if (delta_unit >= 0.005 && adaptive_delta != 0.0) {
+ double output_delta = adaptive_delta;
if (priv->circ_scroll_vert)
- priv->scroll.delta_y -= diff / delta * para->scroll_dist_vert;
+ priv->scroll.delta_y -= output_delta / delta_unit * para->scroll_dist_vert;
else
- priv->scroll.delta_x -= diff / delta * para->scroll_dist_horiz;
- priv->scroll.last_a = angle(priv, hw->x, hw->y);
- }
+ priv->scroll.delta_x -= output_delta / delta_unit * para->scroll_dist_horiz;
+ }
+ priv->scroll.last_x = hw->x;
+ priv->scroll.last_y = hw->y;
+ priv->scroll.last_a = angle;
+ priv->scroll.last_d = d;
+ priv->scroll.filtered_delta = (delta + filtered_delta) / 2;
+ priv->scroll.adaptive_delta = adaptive_delta;
}
if (priv->scroll.coast_speed_y) {
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index a17e39b..3bb3d9a 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -255,7 +255,10 @@ struct _SynapticsPrivateRec {
int last_y; /* last y-scroll position */
double delta_x; /* accumulated horiz scroll delta */
double delta_y; /* accumulated vert scroll delta */
- double last_a; /* last angle-scroll position */
+ double last_a; /* angle of last segment of circular path */
+ double last_d; /* length of last segment of circular path */
+ double filtered_delta; /* naive filter for error estimation */
+ double adaptive_delta; /* adaptive filtered circular delta */
CARD32 last_millis; /* time last scroll event posted */
double coast_speed_x; /* Horizontal coasting speed in scrolls/s */
double coast_speed_y; /* Vertical coasting speed in scrolls/s */
--
1.7.10.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment