This enables two-finger scrolling and two- and three-finger tapping on a
single-touch touchpad if BTN_TOOL_DOUBLETAP and BTN_TOOL_TRIPLETAP is set.

These require a bit of special processing:
BTN_TOUCH is set with the first finger down, but somewhat randomly unset and
re-set when switching between the various BTN_TOOL_*TAP values.
BTN_TOOL_<N>TAP is only set for N fingers down, thus a double->triple move
will see a release for DOUBLETAP and a press for TRIPLETAP. This may happen in
the same event, or across two consecutive events.

This patch adds a fake_touches mask to the touchpad struct. The mask is set
for each matching BTN_* event and used to count the number of expected
fake touchpoints. From that we begin/end the number of actual touchpoints
required. Fake touchpoints take their x/y coordinates from the first
touchpoint, which reads ABS_X/ABS_Y.

Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
---
 src/evdev-mt-touchpad.c | 78 ++++++++++++++++++++++++++++++++++++++++++-------
 src/evdev-mt-touchpad.h |  1 +
 2 files changed, 68 insertions(+), 11 deletions(-)

diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index f8edb8c..d0864fe 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -142,6 +142,13 @@ tp_current_touch(struct tp_dispatch *tp)
        return &tp->touches[min(tp->slot, tp->ntouches)];
 }
 
+static inline struct tp_touch *
+tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
+{
+       assert(slot < tp->ntouches);
+       return &tp->touches[slot];
+}
+
 static inline void
 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
 {
@@ -248,6 +255,54 @@ tp_process_absolute_st(struct tp_dispatch *tp,
 }
 
 static void
+tp_process_fake_touch(struct tp_dispatch *tp,
+                     const struct input_event *e,
+                     uint32_t time)
+{
+       struct tp_touch *t;
+       unsigned int fake_touches;
+       unsigned int nfake_touches;
+       unsigned int i;
+       unsigned int shift;
+
+       if (e->code != BTN_TOUCH &&
+           (e->code < BTN_TOOL_DOUBLETAP || e->code > BTN_TOOL_QUADTAP))
+               return;
+
+       shift = e->code == BTN_TOUCH ? 0 : (e->code - BTN_TOOL_DOUBLETAP + 1);
+
+       if (e->value)
+               tp->fake_touches |= 1 << shift;
+       else
+               tp->fake_touches &= ~(0x1 << shift);
+
+       fake_touches = tp->fake_touches;
+       nfake_touches = 0;
+       while (fake_touches) {
+               nfake_touches++;
+               fake_touches >>= 1;
+       }
+
+       for (i = 0; i < tp->ntouches; i++) {
+               t = tp_get_touch(tp, i);
+               if (i >= nfake_touches) {
+                       if (t->state != TOUCH_NONE) {
+                               tp_end_touch(tp, t);
+                               t->millis = time;
+                       }
+               } else if (t->state != TOUCH_UPDATE &&
+                          t->state != TOUCH_BEGIN) {
+                       t->state = TOUCH_NONE;
+                       tp_begin_touch(tp, t);
+                       t->millis = time;
+                       t->fake =true;
+               }
+       }
+
+       assert(tp->nfingers_down == nfake_touches);
+}
+
+static void
 tp_process_key(struct tp_dispatch *tp,
               const struct input_event *e,
               uint32_t time)
@@ -268,16 +323,11 @@ tp_process_key(struct tp_dispatch *tp,
                        }
                        break;
                case BTN_TOUCH:
-                       if (!tp->has_mt) {
-                               struct tp_touch *t = tp_current_touch(tp);
-                               if (e->value) {
-                                       tp_begin_touch(tp, t);
-                                       t->fake = true;
-                               } else {
-                                       tp_end_touch(tp, t);
-                               }
-                               t->millis = time;
-                       }
+               case BTN_TOOL_DOUBLETAP:
+               case BTN_TOOL_TRIPLETAP:
+               case BTN_TOOL_QUADTAP:
+                       if (!tp->has_mt)
+                               tp_process_fake_touch(tp, e, time);
                        break;
        }
 }
@@ -286,9 +336,15 @@ static void
 tp_process_state(struct tp_dispatch *tp, uint32_t time)
 {
        struct tp_touch *t;
+       struct tp_touch *first = tp_get_touch(tp, 0);
 
        tp_for_each_touch(tp, t) {
-               if (!t->dirty)
+               if (!tp->has_mt && t != first && first->fake) {
+                       t->x = first->x;
+                       t->y = first->y;
+                       if (!t->dirty)
+                               t->dirty = first->dirty;
+               } else if (!t->dirty)
                        continue;
 
                tp_motion_hysteresis(tp, t);
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 1e09497..84d8cec 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -101,6 +101,7 @@ struct tp_dispatch {
 
        unsigned int ntouches;                  /* number of slots */
        struct tp_touch *touches;               /* len == ntouches */
+       unsigned int fake_touches;              /* fake touch mask */
 
        struct {
                int32_t margin_x;
-- 
1.8.4.2

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to