diff options
| author | Henrik Rydberg <rydberg@euromail.se> | 2010-06-16 18:48:53 +0200 |
|---|---|---|
| committer | Henrik Rydberg <rydberg@euromail.se> | 2010-06-16 18:54:52 +0200 |
| commit | 21a363a2486a713434e890fc1f6b86a180755230 (patch) | |
| tree | ca788ccf7c8269c5cbd41350463fa478aa499903 /src | |
| parent | 523d193b089111849873d9de0ec1bf29f4176fbc (diff) | |
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 <rydberg@euromail.se>
Diffstat (limited to 'src')
| -rw-r--r-- | src/gestures.c | 43 | ||||
| -rw-r--r-- | src/memory.c | 84 | ||||
| -rw-r--r-- | src/mtouch.c | 8 | ||||
| -rw-r--r-- | src/test.c | 4 |
4 files changed, 139 insertions, 0 deletions
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 @@ | |||
| 27 | 27 | ||
| 28 | static const int FINGER_THUMB_MS = 600; | 28 | static const int FINGER_THUMB_MS = 600; |
| 29 | static const int BUTTON_HOLD_MS = 200; | 29 | static const int BUTTON_HOLD_MS = 200; |
| 30 | #define use_tapping 0 | ||
| 30 | 31 | ||
| 31 | /** | 32 | /** |
| 32 | * extract_buttons | 33 | * extract_buttons |
| @@ -50,6 +51,12 @@ static void extract_buttons(struct Gestures *gs, struct MTouch* mt) | |||
| 50 | gs->btmask = (btdata ^ mt->mem.btdata) & BITONES(DIM_BUTTON); | 51 | gs->btmask = (btdata ^ mt->mem.btdata) & BITONES(DIM_BUTTON); |
| 51 | gs->btdata = btdata; | 52 | gs->btdata = btdata; |
| 52 | mt->mem.btdata = btdata; | 53 | mt->mem.btdata = btdata; |
| 54 | } else if (btdata == 0 && mt->mem.ntap) { | ||
| 55 | if (npoint == 1 && mt->mem.maxtap == 1) | ||
| 56 | btdata = BITMASK(MT_BUTTON_LEFT); | ||
| 57 | gs->btmask = (btdata ^ mt->mem.btdata) & BITONES(DIM_BUTTON); | ||
| 58 | gs->btdata = btdata; | ||
| 59 | mt->mem.btdata = btdata; | ||
| 53 | } | 60 | } |
| 54 | if (gs->btmask) { | 61 | if (gs->btmask) { |
| 55 | mt_delay_movement(mt, BUTTON_HOLD_MS); | 62 | mt_delay_movement(mt, BUTTON_HOLD_MS); |
| @@ -178,6 +185,40 @@ void extract_gestures(struct Gestures *gs, struct MTouch* mt) | |||
| 178 | mt->prev_state = mt->state; | 185 | mt->prev_state = mt->state; |
| 179 | } | 186 | } |
| 180 | 187 | ||
| 188 | /** | ||
| 189 | * extract_delayed_gestures | ||
| 190 | * | ||
| 191 | * Extract delayed gestures, such as tapping | ||
| 192 | * | ||
| 193 | * Reset memory after use. | ||
| 194 | * | ||
| 195 | */ | ||
| 196 | void extract_delayed_gestures(struct Gestures *gs, struct MTouch* mt) | ||
| 197 | { | ||
| 198 | mt->mem.wait = 0; | ||
| 199 | |||
| 200 | if (!use_tapping && mt->caps.has_left) | ||
| 201 | return; | ||
| 202 | |||
| 203 | if (mt->mem.tpdown < mt->mem.tpup) { | ||
| 204 | switch (mt->mem.maxtap) { | ||
| 205 | case 1: | ||
| 206 | gs->tapmask = BITMASK(MT_BUTTON_LEFT); | ||
| 207 | break; | ||
| 208 | case 2: | ||
| 209 | gs->tapmask = BITMASK(MT_BUTTON_RIGHT); | ||
| 210 | break; | ||
| 211 | case 3: | ||
| 212 | gs->tapmask = BITMASK(MT_BUTTON_MIDDLE); | ||
| 213 | break; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | if (gs->tapmask) | ||
| 218 | SETBIT(gs->type, GS_TAP); | ||
| 219 | |||
| 220 | gs->ntap = mt->mem.ntap; | ||
| 221 | } | ||
| 181 | 222 | ||
| 182 | void output_gesture(const struct Gestures *gs) | 223 | void output_gesture(const struct Gestures *gs) |
| 183 | { | 224 | { |
| @@ -199,4 +240,6 @@ void output_gesture(const struct Gestures *gs) | |||
| 199 | xf86Msg(X_INFO, "scale: %d\n", gs->scale); | 240 | xf86Msg(X_INFO, "scale: %d\n", gs->scale); |
| 200 | if (GETBIT(gs->type, GS_ROTATE)) | 241 | if (GETBIT(gs->type, GS_ROTATE)) |
| 201 | xf86Msg(X_INFO, "rotate: %d\n", gs->rot); | 242 | xf86Msg(X_INFO, "rotate: %d\n", gs->rot); |
| 243 | foreach_bit(i, gs->tapmask) | ||
| 244 | xf86Msg(X_INFO, "tap: %d %d\n", i, gs->ntap); | ||
| 202 | } | 245 | } |
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 @@ | |||
| 27 | /* fraction of max movement threshold */ | 27 | /* fraction of max movement threshold */ |
| 28 | #define DELTA_CUT(x) (0.5 * (x)) | 28 | #define DELTA_CUT(x) (0.5 * (x)) |
| 29 | 29 | ||
| 30 | /* fraction of tap movement threshold */ | ||
| 31 | #define TAP_XMOVE(c) (0.05 * get_cap_xsize(c)) | ||
| 32 | #define TAP_YMOVE(c) (0.05 * get_cap_ysize(c)) | ||
| 33 | |||
| 30 | /* timer for cursor stability on finger touch/release */ | 34 | /* timer for cursor stability on finger touch/release */ |
| 31 | static const int FINGER_ATTACK_MS = 40; | 35 | static const int FINGER_ATTACK_MS = 40; |
| 32 | static const int FINGER_DECAY_MS = 120; | 36 | static const int FINGER_DECAY_MS = 120; |
| 33 | static const int FINGER_CORNER_MS = 300; | 37 | static const int FINGER_CORNER_MS = 300; |
| 34 | 38 | ||
| 39 | /* tapping timings */ | ||
| 40 | static const int TAP_SETTLE_MS = 400; | ||
| 41 | static const int TAP_TOUCH_MS = 120; | ||
| 42 | static const int TAP_GAP_MS = 200; | ||
| 43 | |||
| 35 | static inline int dxval(const struct FingerState *a, | 44 | static inline int dxval(const struct FingerState *a, |
| 36 | const struct FingerState *b) | 45 | const struct FingerState *b) |
| 37 | { | 46 | { |
| @@ -43,6 +52,23 @@ static inline int dyval(const struct FingerState *a, | |||
| 43 | return a->position_y - b->position_y; | 52 | return a->position_y - b->position_y; |
| 44 | } | 53 | } |
| 45 | 54 | ||
| 55 | static inline void relax_tapping(struct Memory *m, const struct MTState *state) | ||
| 56 | { | ||
| 57 | m->tprelax = state->evtime + TAP_SETTLE_MS; | ||
| 58 | m->wait = 0; | ||
| 59 | m->ntap = 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | static inline int unrelated_taps(const struct Memory *m, | ||
| 63 | const struct Capabilities *caps) | ||
| 64 | { | ||
| 65 | return abs(m->xdown - m->xup) > TAP_XMOVE(caps) || | ||
| 66 | abs(m->ydown - m->yup) > TAP_YMOVE(caps); | ||
| 67 | } | ||
| 68 | |||
| 69 | /** | ||
| 70 | * init_memory | ||
| 71 | */ | ||
| 46 | void init_memory(struct Memory *mem) | 72 | void init_memory(struct Memory *mem) |
| 47 | { | 73 | { |
| 48 | memset(mem, 0, sizeof(struct Memory)); | 74 | memset(mem, 0, sizeof(struct Memory)); |
| @@ -188,6 +214,63 @@ static void update_movement(struct Memory *m, | |||
| 188 | m->moving = m->pending; | 214 | m->moving = m->pending; |
| 189 | } | 215 | } |
| 190 | 216 | ||
| 217 | /** | ||
| 218 | * update_tapping | ||
| 219 | * | ||
| 220 | * Update tpdown, tpup, tprelax, wait, maxtap, ntap. | ||
| 221 | * | ||
| 222 | * Precondition: pointing and thumb are set | ||
| 223 | * | ||
| 224 | * Postcondition: tpdown, tpup, tprelax, wait, maxtap, ntap set | ||
| 225 | * | ||
| 226 | */ | ||
| 227 | static void update_tapping(struct Memory *m, | ||
| 228 | const struct MTState *prev_state, | ||
| 229 | const struct MTState *state, | ||
| 230 | const struct Capabilities *caps) | ||
| 231 | { | ||
| 232 | int x, y, i, npoint = bitcount(m->pointing); | ||
| 233 | |||
| 234 | /* use a position independent on the number of fingers */ | ||
| 235 | if (state->nfinger) { | ||
| 236 | x = state->finger[0].position_x; | ||
| 237 | y = state->finger[0].position_y; | ||
| 238 | for (i = 1; i < state->nfinger; i++) { | ||
| 239 | x = minval(x, state->finger[i].position_x); | ||
| 240 | y = minval(y, state->finger[i].position_y); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | if (m->thumb || state->evtime < m->mvforget) { | ||
| 245 | relax_tapping(m, state); | ||
| 246 | } else if (state->nfinger && !prev_state->nfinger) { | ||
| 247 | m->tpdown = state->evtime; | ||
| 248 | m->xdown = x; | ||
| 249 | m->ydown = y; | ||
| 250 | m->wait = 0; | ||
| 251 | m->maxtap = npoint; | ||
| 252 | if (m->tpdown > m->tpup + TAP_GAP_MS) | ||
| 253 | m->ntap = 0; | ||
| 254 | else if (unrelated_taps(m, caps)) | ||
| 255 | relax_tapping(m, state); | ||
| 256 | m->xup = x; | ||
| 257 | m->yup = y; | ||
| 258 | } else if (!state->nfinger && prev_state->nfinger) { | ||
| 259 | m->tpup = state->evtime; | ||
| 260 | if (m->tpup > m->tprelax && | ||
| 261 | m->tpup <= m->tpdown + TAP_TOUCH_MS) { | ||
| 262 | m->wait = TAP_GAP_MS; | ||
| 263 | m->ntap++; | ||
| 264 | if (unrelated_taps(m, caps)) | ||
| 265 | relax_tapping(m, state); | ||
| 266 | } | ||
| 267 | } else if (state->nfinger) { | ||
| 268 | m->xup = minval(m->xup, x); | ||
| 269 | m->yup = minval(m->yup, y); | ||
| 270 | m->maxtap = maxval(m->maxtap, npoint); | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 191 | void refresh_memory(struct Memory *m, | 274 | void refresh_memory(struct Memory *m, |
| 192 | const struct MTState *prev_state, | 275 | const struct MTState *prev_state, |
| 193 | const struct MTState *state, | 276 | const struct MTState *state, |
| @@ -196,6 +279,7 @@ void refresh_memory(struct Memory *m, | |||
| 196 | update_configuration(m, prev_state, state); | 279 | update_configuration(m, prev_state, state); |
| 197 | update_pointers(m, state, caps); | 280 | update_pointers(m, state, caps); |
| 198 | update_movement(m, prev_state, state, caps); | 281 | update_movement(m, prev_state, state, caps); |
| 282 | update_tapping(m, prev_state, state, caps); | ||
| 199 | } | 283 | } |
| 200 | 284 | ||
| 201 | void output_memory(const struct Memory *m) | 285 | 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) | |||
| 73 | #endif | 73 | #endif |
| 74 | return 1; | 74 | return 1; |
| 75 | } | 75 | } |
| 76 | |||
| 77 | int mt_is_idle(struct MTouch *mt, int fd) | ||
| 78 | { | ||
| 79 | return mt->mem.wait && | ||
| 80 | evbuf_empty(&mt->dev.outbuf) && | ||
| 81 | evbuf_empty(&mt->dev.inbuf) && | ||
| 82 | poll_iobuf(&mt->buf, fd, mt->mem.wait) == 0; | ||
| 83 | } | ||
| @@ -42,6 +42,10 @@ static void loop_device(int fd) | |||
| 42 | extract_gestures(&gs, &mt); | 42 | extract_gestures(&gs, &mt); |
| 43 | output_gesture(&gs); | 43 | output_gesture(&gs); |
| 44 | } | 44 | } |
| 45 | if (mt_is_idle(&mt, fd)) { | ||
| 46 | extract_delayed_gestures(&gs, &mt); | ||
| 47 | output_gesture(&gs); | ||
| 48 | } | ||
| 45 | } | 49 | } |
| 46 | close_mtouch(&mt, fd); | 50 | close_mtouch(&mt, fd); |
| 47 | } | 51 | } |
