From 21a363a2486a713434e890fc1f6b86a180755230 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Wed, 16 Jun 2010 18:48:53 +0200 Subject: Add tapping logic This patch adds tap-to-click, tap-and-hold for dragging, two-finger and three-finger taps. Turned on by default for touch screens only; switch on in gestures.c. Signed-off-by: Henrik Rydberg --- src/gestures.c | 43 ++++++++++++++++++++++++++++++ src/memory.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/mtouch.c | 8 ++++++ src/test.c | 4 +++ 4 files changed, 139 insertions(+) (limited to 'src') diff --git a/src/gestures.c b/src/gestures.c index a5a17ca..3f59a1e 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -27,6 +27,7 @@ static const int FINGER_THUMB_MS = 600; static const int BUTTON_HOLD_MS = 200; +#define use_tapping 0 /** * extract_buttons @@ -50,6 +51,12 @@ static void extract_buttons(struct Gestures *gs, struct MTouch* mt) gs->btmask = (btdata ^ mt->mem.btdata) & BITONES(DIM_BUTTON); gs->btdata = btdata; mt->mem.btdata = btdata; + } else if (btdata == 0 && mt->mem.ntap) { + if (npoint == 1 && mt->mem.maxtap == 1) + btdata = BITMASK(MT_BUTTON_LEFT); + gs->btmask = (btdata ^ mt->mem.btdata) & BITONES(DIM_BUTTON); + gs->btdata = btdata; + mt->mem.btdata = btdata; } if (gs->btmask) { mt_delay_movement(mt, BUTTON_HOLD_MS); @@ -178,6 +185,40 @@ void extract_gestures(struct Gestures *gs, struct MTouch* mt) mt->prev_state = mt->state; } +/** + * extract_delayed_gestures + * + * Extract delayed gestures, such as tapping + * + * Reset memory after use. + * + */ +void extract_delayed_gestures(struct Gestures *gs, struct MTouch* mt) +{ + mt->mem.wait = 0; + + if (!use_tapping && mt->caps.has_left) + return; + + if (mt->mem.tpdown < mt->mem.tpup) { + switch (mt->mem.maxtap) { + case 1: + gs->tapmask = BITMASK(MT_BUTTON_LEFT); + break; + case 2: + gs->tapmask = BITMASK(MT_BUTTON_RIGHT); + break; + case 3: + gs->tapmask = BITMASK(MT_BUTTON_MIDDLE); + break; + } + } + + if (gs->tapmask) + SETBIT(gs->type, GS_TAP); + + gs->ntap = mt->mem.ntap; +} void output_gesture(const struct Gestures *gs) { @@ -199,4 +240,6 @@ void output_gesture(const struct Gestures *gs) xf86Msg(X_INFO, "scale: %d\n", gs->scale); if (GETBIT(gs->type, GS_ROTATE)) xf86Msg(X_INFO, "rotate: %d\n", gs->rot); + foreach_bit(i, gs->tapmask) + xf86Msg(X_INFO, "tap: %d %d\n", i, gs->ntap); } diff --git a/src/memory.c b/src/memory.c index cd88d7a..2bb4d95 100644 --- a/src/memory.c +++ b/src/memory.c @@ -27,11 +27,20 @@ /* fraction of max movement threshold */ #define DELTA_CUT(x) (0.5 * (x)) +/* fraction of tap movement threshold */ +#define TAP_XMOVE(c) (0.05 * get_cap_xsize(c)) +#define TAP_YMOVE(c) (0.05 * get_cap_ysize(c)) + /* timer for cursor stability on finger touch/release */ static const int FINGER_ATTACK_MS = 40; static const int FINGER_DECAY_MS = 120; static const int FINGER_CORNER_MS = 300; +/* tapping timings */ +static const int TAP_SETTLE_MS = 400; +static const int TAP_TOUCH_MS = 120; +static const int TAP_GAP_MS = 200; + static inline int dxval(const struct FingerState *a, const struct FingerState *b) { @@ -43,6 +52,23 @@ static inline int dyval(const struct FingerState *a, return a->position_y - b->position_y; } +static inline void relax_tapping(struct Memory *m, const struct MTState *state) +{ + m->tprelax = state->evtime + TAP_SETTLE_MS; + m->wait = 0; + m->ntap = 0; +} + +static inline int unrelated_taps(const struct Memory *m, + const struct Capabilities *caps) +{ + return abs(m->xdown - m->xup) > TAP_XMOVE(caps) || + abs(m->ydown - m->yup) > TAP_YMOVE(caps); +} + +/** + * init_memory + */ void init_memory(struct Memory *mem) { memset(mem, 0, sizeof(struct Memory)); @@ -188,6 +214,63 @@ static void update_movement(struct Memory *m, m->moving = m->pending; } +/** + * update_tapping + * + * Update tpdown, tpup, tprelax, wait, maxtap, ntap. + * + * Precondition: pointing and thumb are set + * + * Postcondition: tpdown, tpup, tprelax, wait, maxtap, ntap set + * + */ +static void update_tapping(struct Memory *m, + const struct MTState *prev_state, + const struct MTState *state, + const struct Capabilities *caps) +{ + int x, y, i, npoint = bitcount(m->pointing); + + /* use a position independent on the number of fingers */ + if (state->nfinger) { + x = state->finger[0].position_x; + y = state->finger[0].position_y; + for (i = 1; i < state->nfinger; i++) { + x = minval(x, state->finger[i].position_x); + y = minval(y, state->finger[i].position_y); + } + } + + if (m->thumb || state->evtime < m->mvforget) { + relax_tapping(m, state); + } else if (state->nfinger && !prev_state->nfinger) { + m->tpdown = state->evtime; + m->xdown = x; + m->ydown = y; + m->wait = 0; + m->maxtap = npoint; + if (m->tpdown > m->tpup + TAP_GAP_MS) + m->ntap = 0; + else if (unrelated_taps(m, caps)) + relax_tapping(m, state); + m->xup = x; + m->yup = y; + } else if (!state->nfinger && prev_state->nfinger) { + m->tpup = state->evtime; + if (m->tpup > m->tprelax && + m->tpup <= m->tpdown + TAP_TOUCH_MS) { + m->wait = TAP_GAP_MS; + m->ntap++; + if (unrelated_taps(m, caps)) + relax_tapping(m, state); + } + } else if (state->nfinger) { + m->xup = minval(m->xup, x); + m->yup = minval(m->yup, y); + m->maxtap = maxval(m->maxtap, npoint); + } +} + void refresh_memory(struct Memory *m, const struct MTState *prev_state, const struct MTState *state, @@ -196,6 +279,7 @@ void refresh_memory(struct Memory *m, update_configuration(m, prev_state, state); update_pointers(m, state, caps); update_movement(m, prev_state, state, caps); + update_tapping(m, prev_state, state, caps); } void output_memory(const struct Memory *m) diff --git a/src/mtouch.c b/src/mtouch.c index 7272edf..14c0fd9 100644 --- a/src/mtouch.c +++ b/src/mtouch.c @@ -73,3 +73,11 @@ int parse_event(struct MTouch *mt, const struct input_event *ev) #endif return 1; } + +int mt_is_idle(struct MTouch *mt, int fd) +{ + return mt->mem.wait && + evbuf_empty(&mt->dev.outbuf) && + evbuf_empty(&mt->dev.inbuf) && + poll_iobuf(&mt->buf, fd, mt->mem.wait) == 0; +} diff --git a/src/test.c b/src/test.c index 0088cdd..ce2fdf5 100644 --- a/src/test.c +++ b/src/test.c @@ -42,6 +42,10 @@ static void loop_device(int fd) extract_gestures(&gs, &mt); output_gesture(&gs); } + if (mt_is_idle(&mt, fd)) { + extract_delayed_gestures(&gs, &mt); + output_gesture(&gs); + } } close_mtouch(&mt, fd); } -- cgit v1.2.3