summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2014-04-15 14:27:59 +0200
committerHans de Goede <hdegoede@redhat.com>2014-05-22 14:39:00 +0200
commitcba4560566b6b998027de716bfd15693a83cbe3e (patch)
treee1a7708ecc8f5be8af26f5d1d2b0288a2e8f95c3
parent4b089fbd67951d33c1031316813d768316262b5c (diff)
touchpad: after a click, lock the finger to its current position
On clickpads, clicking the pad usually causes some motion events. To avoid erroneous movements, lock all fingers into position on the click and don't allow for motion events until a finger moves past a given threshold (currently 2% of the touchpad diagonal). Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Jonas Ã…dahl <jadahl@gmail.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--src/evdev-mt-touchpad.c80
-rw-r--r--src/evdev-mt-touchpad.h12
2 files changed, 50 insertions, 42 deletions
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index b4a89e3..54a95ef 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -32,6 +32,7 @@
#define DEFAULT_MIN_ACCEL_FACTOR 0.16
#define DEFAULT_MAX_ACCEL_FACTOR 1.0
#define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
+#define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* 2% of size */
static inline int
tp_hysteresis(int in, int center, int margin)
@@ -158,6 +159,7 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
tp_motion_history_reset(t);
t->dirty = true;
t->state = TOUCH_BEGIN;
+ t->pinned.is_pinned = false;
tp->nfingers_down++;
assert(tp->nfingers_down >= 1);
tp->queued |= TOUCHPAD_EVENT_MOTION;
@@ -182,6 +184,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
t->dirty = true;
t->is_pointer = false;
t->state = TOUCH_END;
+ t->pinned.is_pinned = false;
assert(tp->nfingers_down >= 1);
tp->nfingers_down--;
tp->queued |= TOUCHPAD_EVENT_MOTION;
@@ -346,50 +349,43 @@ tp_process_key(struct tp_dispatch *tp,
}
static void
-tp_unpin_finger(struct tp_dispatch *tp)
+tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
{
- struct tp_touch *t;
- tp_for_each_touch(tp, t) {
- if (t->is_pinned) {
- t->is_pinned = false;
+ unsigned int xdist, ydist;
+ struct tp_touch *tmp = NULL;
+
+ if (!t->pinned.is_pinned)
+ return;
+
+ xdist = abs(t->x - t->pinned.center_x);
+ ydist = abs(t->y - t->pinned.center_y);
- if (t->state != TOUCH_END &&
- tp->nfingers_down == 1)
- t->is_pointer = true;
+ if (xdist * xdist + ydist * ydist <
+ tp->buttons.motion_dist * tp->buttons.motion_dist)
+ return;
+
+ t->pinned.is_pinned = false;
+
+ tp_for_each_touch(tp, tmp) {
+ if (tmp->is_pointer)
break;
- }
}
+
+ if (t->state != TOUCH_END && !tmp->is_pointer)
+ t->is_pointer = true;
}
static void
-tp_pin_finger(struct tp_dispatch *tp)
+tp_pin_fingers(struct tp_dispatch *tp)
{
- struct tp_touch *t,
- *pinned = NULL;
+ struct tp_touch *t;
tp_for_each_touch(tp, t) {
- if (t->is_pinned) {
- pinned = t;
- break;
- }
- }
-
- assert(!pinned);
-
- pinned = tp_current_touch(tp);
-
- if (tp->nfingers_down != 1) {
- tp_for_each_touch(tp, t) {
- if (t == pinned)
- continue;
-
- if (t->y > pinned->y)
- pinned = t;
- }
+ t->is_pointer = false;
+ t->pinned.is_pinned = true;
+ t->pinned.center_x = t->x;
+ t->pinned.center_y = t->y;
}
-
- pinned->is_pinned = true;
- pinned->is_pointer = false;
}
static void
@@ -409,16 +405,19 @@ tp_process_state(struct tp_dispatch *tp, uint32_t time)
tp_motion_hysteresis(tp, t);
tp_motion_history_push(t);
+
+ tp_unpin_finger(tp, t);
}
- /* We have a physical button down event on a clickpad. For drag and
- drop, this means we try to identify which finger pressed the
- physical button and "pin" it, i.e. remove pointer-moving
- capabilities from it.
+ /*
+ * We have a physical button down event on a clickpad. To avoid
+ * spurious pointer moves by the clicking finger we pin all fingers.
+ * We unpin fingers when they move more then a certain threshold to
+ * to allow drag and drop.
*/
if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
!tp->buttons.has_buttons)
- tp_pin_finger(tp);
+ tp_pin_fingers(tp);
}
static void
@@ -441,9 +440,6 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time)
tp->buttons.old_state = tp->buttons.state;
- if (tp->queued & TOUCHPAD_EVENT_BUTTON_RELEASE)
- tp_unpin_finger(tp);
-
tp->queued = TOUCHPAD_EVENT_NONE;
}
@@ -798,6 +794,8 @@ tp_init(struct tp_dispatch *tp,
tp->hysteresis.margin_y =
diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
+ tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD;
+
if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) ||
libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT))
tp->buttons.has_buttons = true;
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 2bdb329..e5fbd7a 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -77,7 +77,6 @@ struct tp_touch {
bool dirty;
bool fake; /* a fake touch */
bool is_pointer; /* the pointer-controlling touch */
- bool is_pinned; /* holds the phys. button */
int32_t x;
int32_t y;
uint32_t millis;
@@ -92,6 +91,16 @@ struct tp_touch {
int32_t center_x;
int32_t center_y;
} hysteresis;
+
+ /* A pinned touchpoint is the one that pressed the physical button
+ * on a clickpad. After the release, it won't move until the center
+ * moves more than a threshold away from the original coordinates
+ */
+ struct {
+ bool is_pinned;
+ int32_t center_x;
+ int32_t center_y;
+ } pinned;
};
struct tp_dispatch {
@@ -122,6 +131,7 @@ struct tp_dispatch {
bool has_buttons; /* true for physical LMR buttons */
uint32_t state;
uint32_t old_state;
+ uint32_t motion_dist; /* for pinned touches */
} buttons; /* physical buttons */
struct {