From ee4a0c6821a1b79c3d18c6ef6d7ed6d37df74755 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 7 Aug 2010 18:28:29 +0200 Subject: gesture: Improved tickle/active logic Reorganize the mode model to use bitmasks for tickle and active, and refine the tickle logic for each gesture. --- src/gestures-combo.c | 17 ++++--- src/gestures-pan.c | 11 ++-- src/gestures-pinch.c | 11 ++-- src/gestures-rotate.c | 9 ++-- src/gestures-tapping.c | 6 ++- src/grail-gestures.c | 134 ++++++++++++++++++++++++------------------------- src/grail-gestures.h | 12 +++-- 7 files changed, 107 insertions(+), 93 deletions(-) diff --git a/src/gestures-combo.c b/src/gestures-combo.c index 0f4dd7e..6ce6197 100644 --- a/src/gestures-combo.c +++ b/src/gestures-combo.c @@ -33,6 +33,8 @@ static const int getype[DIM_TOUCH + 1] = { GRAIL_TYPE_COMBO5, }; +static const int fm_mask = 0x0f; + int gru_combo(struct grail *ge, const struct touch_frame *frame) { @@ -40,6 +42,7 @@ int gru_combo(struct grail *ge, struct combo_model *state = &gru->combo; struct move_model *move = &gru->move; grail_prop_t prop[DIM_GRAIL_PROP]; + int mask = state->active ? (move->active & fm_mask) : fm_mask; if (!move->multi) { if (state->active) { gru_end(ge, state->gid, move); @@ -47,8 +50,7 @@ int gru_combo(struct grail *ge, } return 0; } - if (!move->x.tickle && !move->y.tickle && - !move->r.tickle && !move->a.tickle) + if (!(move->tickle & mask)) return 0; if (!state->active) { int type = getype[move->ntouch]; @@ -57,13 +59,12 @@ int gru_combo(struct grail *ge, state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame); state->active = 1; } - if (!move->x.active && !move->y.active && - !move->r.active && !move->a.active) + if (!(move->active & fm_mask)) return 0; - prop[0] = move->x.active ? move->x.delta : 0; - prop[1] = move->y.active ? move->y.delta : 0; - prop[2] = move->r.active ? move->r.delta : 0; - prop[3] = move->a.active ? move->a.delta : 0; + prop[0] = move->fm[FM_X].delta; + prop[1] = move->fm[FM_Y].delta; + prop[2] = move->fm[FM_R].delta; + prop[3] = move->fm[FM_A].delta; gru_event(ge, state->gid, move, prop, 4); return 1; } diff --git a/src/gestures-pan.c b/src/gestures-pan.c index 320a987..a023122 100644 --- a/src/gestures-pan.c +++ b/src/gestures-pan.c @@ -33,6 +33,8 @@ static const int getype[DIM_TOUCH + 1] = { GRAIL_TYPE_HAND, }; +static const int fm_mask = 0x03; + int gru_pan(struct grail *ge, const struct touch_frame *frame) { @@ -40,6 +42,7 @@ int gru_pan(struct grail *ge, struct combo_model *state = &gru->pan; struct move_model *move = &gru->move; grail_prop_t prop[DIM_GRAIL_PROP]; + int mask = state->active ? (move->active & fm_mask) : fm_mask; if (!move->multi) { if (state->active) { gru_end(ge, state->gid, move); @@ -47,7 +50,7 @@ int gru_pan(struct grail *ge, } return 0; } - if (!move->x.tickle && !move->y.tickle) + if (!(move->tickle & mask)) return 0; if (!state->active) { int type = getype[move->ntouch]; @@ -56,10 +59,10 @@ int gru_pan(struct grail *ge, state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame); state->active = 1; } - if (!move->x.active && !move->y.active) + if (!(move->active & fm_mask)) return 0; - prop[0] = move->x.active ? move->x.delta : 0; - prop[1] = move->y.active ? move->y.delta : 0; + prop[0] = move->fm[FM_X].delta; + prop[1] = move->fm[FM_Y].delta; gru_event(ge, state->gid, move, prop, 2); return 1; } diff --git a/src/gestures-pinch.c b/src/gestures-pinch.c index c0d6a17..358718d 100644 --- a/src/gestures-pinch.c +++ b/src/gestures-pinch.c @@ -33,6 +33,8 @@ static const int getype[DIM_TOUCH + 1] = { GRAIL_TYPE_GRAB, }; +static const int fm_mask = 0x04; + int gru_pinch(struct grail *ge, const struct touch_frame *frame) { @@ -40,6 +42,7 @@ int gru_pinch(struct grail *ge, struct combo_model *state = &gru->pinch; struct move_model *move = &gru->move; grail_prop_t prop[DIM_GRAIL_PROP]; + int mask = state->active ? (move->active & fm_mask) : fm_mask; if (!move->multi) { if (state->active) { gru_end(ge, state->gid, move); @@ -47,9 +50,7 @@ int gru_pinch(struct grail *ge, } return 0; } - if (!move->a.tickle) - return 0; - if (!move->r.tickle) + if (!(move->tickle & mask)) return 0; if (!state->active) { int type = getype[move->ntouch]; @@ -58,9 +59,9 @@ int gru_pinch(struct grail *ge, state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame); state->active = 1; } - if (!move->r.active) + if (!(move->active & fm_mask)) return 0; - prop[0] = move->r.delta; + prop[0] = move->fm[FM_R].delta; gru_event(ge, state->gid, move, prop, 1); return 1; } diff --git a/src/gestures-rotate.c b/src/gestures-rotate.c index 105340b..5db4228 100644 --- a/src/gestures-rotate.c +++ b/src/gestures-rotate.c @@ -33,6 +33,8 @@ static const int getype[DIM_TOUCH + 1] = { GRAIL_TYPE_REVOLVE, }; +static const int fm_mask = 0x08; + int gru_rotate(struct grail *ge, const struct touch_frame *frame) { @@ -40,6 +42,7 @@ int gru_rotate(struct grail *ge, struct combo_model *state = &gru->rotate; struct move_model *move = &gru->move; grail_prop_t prop[DIM_GRAIL_PROP]; + int mask = state->active ? (move->active & fm_mask) : fm_mask; if (!move->multi) { if (state->active) { gru_end(ge, state->gid, move); @@ -47,7 +50,7 @@ int gru_rotate(struct grail *ge, } return 0; } - if (!move->a.tickle) + if (!(move->tickle & mask)) return 0; if (!state->active) { int type = getype[move->ntouch]; @@ -56,9 +59,9 @@ int gru_rotate(struct grail *ge, state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame); state->active = 1; } - if (!move->a.active) + if (!(move->active & fm_mask)) return 0; - prop[0] = move->a.delta; + prop[0] = move->fm[FM_A].delta; gru_event(ge, state->gid, move, prop, 1); return 1; } diff --git a/src/gestures-tapping.c b/src/gestures-tapping.c index a5357e4..1a02731 100644 --- a/src/gestures-tapping.c +++ b/src/gestures-tapping.c @@ -30,6 +30,8 @@ static const int TAP_CANCEL = 2; static const int TAP_MIN_GAP_MS = 25; static const int TAP_MAX_GAP_MS = 300; +static const int fm_mask = 0x03; + int gru_tapping(struct grail *ge, const struct touch_frame *frame) { @@ -69,7 +71,7 @@ int gru_tapping(struct grail *ge, if (state->status == TAP_END && move->time - state->start < TAP_MIN_GAP_MS) state->status = TAP_CANCEL; - if (move->x.active || move->y.active) + if (move->active & fm_mask) state->status = TAP_CANCEL; if (state->status == TAP_CANCEL) { if (state->active) { @@ -84,7 +86,7 @@ int gru_tapping(struct grail *ge, return 0; prop[0] = move->time - state->start; gin_gid_event(ge, state->gid, - move->x.val, move->y.val, state->ntouch, + move->fm[FM_X].val, move->fm[FM_Y].val, state->ntouch, prop, 1, GRAIL_STATUS_END); state->status = TAP_BEGIN; state->ntouch = 0; diff --git a/src/grail-gestures.c b/src/grail-gestures.c index 3c95d6f..67ceacf 100644 --- a/src/grail-gestures.c +++ b/src/grail-gestures.c @@ -23,12 +23,8 @@ #include "grail-recognizer.h" #include -static const float SN_MOVE = 200; -static const float SN_ZOOM = 200; -static const float SN_ROTATE = 200; -static const float BAR_MOVE = 4; -static const float BAR_ZOOM = 12; -static const float BAR_ROTATE = 12; +static const float FM_SN[DIM_FM] = { 200, 200, 200, 1000 }; +static const float FM_BAR[DIM_FM] = { 50, 50, 40, 50 }; static void compute_position(float *x, float *y, const struct touch_frame *frame) @@ -98,105 +94,107 @@ static float move_filter(const struct filter_model *m, float val) return val; } -static int move_reset(struct filter_model *m, float val) +static void move_reset(struct move_model *m, int i, float val) { - m->delta = 0; - m->tickle = 0; - m->active = 0; - m->val = val; - m->orig = val; + struct filter_model *fm = &m->fm[i]; + fm->delta = 0; + fm->val = val; + fm->orig = val; + m->tickle &= ~(1 << i); + m->active &= ~(1 << i); } -static int move_update(struct filter_model *m, float val) +static void move_update(struct move_model *m, int i, float val) { - float dval = val - m->orig; - m->delta = val - m->val; - m->tickle = fabs(m->delta) > 0.5; - m->val = val; - if (!m->active) { - if (fabs(dval) > m->bar) - m->active = 1; - else - m->delta = dval; - } - return m->active; + struct filter_model *fm = &m->fm[i]; + fm->delta = val - fm->val; + fm->val = val; + if (fabs(fm->delta) > 0.5) + m->tickle |= (1 << i); + else + m->tickle &= ~(1 << i); + if (m->active & (1 << i)) + return; + fm->delta = val - fm->orig; + if (fabs(fm->delta) > fm->bar) + m->active |= (1 << i); + else + fm->delta = 0; } void gru_init_motion(struct grail *ge) { struct gesture_recognizer *gru = ge->gru; - struct move_model *state = &gru->move; + struct move_model *m = &gru->move; struct grail_coord min, max; + float D[DIM_FM]; + int i; grail_get_units(&min, &max, ge); - float x = max.x - min.x; - float y = max.y - min.y; - float r = sqrt(x * x + y * y); - state->x.fuzz = x / SN_MOVE; - state->y.fuzz = y / SN_MOVE; - state->r.fuzz = r / SN_ZOOM; - state->a.fuzz = r / SN_ROTATE; - state->x.bar = BAR_MOVE * state->x.fuzz; - state->y.bar = BAR_MOVE * state->y.fuzz; - state->r.bar = BAR_ZOOM * state->r.fuzz; - state->a.bar = BAR_ROTATE * state->a.fuzz; - state->multi = 0; + D[FM_X] = max.x - min.x; + D[FM_Y] = max.y - min.y; + D[FM_R] = sqrt(D[FM_X] * D[FM_X] + D[FM_Y] * D[FM_Y]); + D[FM_A] = D[FM_R]; + for (i = 0; i < DIM_FM; i++) { + m->fm[i].fuzz = D[i] / FM_SN[i]; + m->fm[i].bar = D[i] / FM_BAR[i]; + } } void gru_motion(struct grail *ge, const struct touch_frame *frame) { struct gesture_recognizer *gru = ge->gru; - struct move_model *state = &gru->move; + struct move_model *m = &gru->move; float x, y, r, a; compute_position(&x, &y, frame); if (frame->ncreate || frame->ndestroy) { r = compute_radius(x, y, frame); a = 0; - move_reset(&state->x, x); - move_reset(&state->y, y); - move_reset(&state->r, r); - move_reset(&state->a, a); - state->single = 0; - state->multi = 0; + move_reset(m, FM_X, x); + move_reset(m, FM_Y, y); + move_reset(m, FM_R, r); + move_reset(m, FM_A, a); + m->single = 0; + m->multi = 0; } else if (frame->nactive < 2) { r = 0; a = 0; - move_update(&state->x, x); - move_update(&state->y, y); - move_reset(&state->r, r); - move_reset(&state->a, a); - state->single = 1; - state->multi = 0; + move_update(m, FM_X, x); + move_update(m, FM_Y, y); + move_reset(m, FM_R, r); + move_reset(m, FM_A, a); + m->single = 1; + m->multi = 0; } else { - x = move_filter(&state->x, x); - y = move_filter(&state->y, y); + x = move_filter(&m->fm[FM_X], x); + y = move_filter(&m->fm[FM_Y], y); r = compute_radius(x, y, frame); - r = move_filter(&state->r, r); - a = state->a.val + compute_rotation(x, y, r, &gru->frame, frame); - //a = move_filter(&state->a, a); - move_update(&state->x, x); - move_update(&state->y, y); - move_update(&state->r, r); - move_update(&state->a, a); - state->single = 0; - state->multi = 1; + r = move_filter(&m->fm[FM_R], r); + a = m->fm[FM_A].val; + a += compute_rotation(x, y, r, &gru->frame, frame); + a = move_filter(&m->fm[FM_A], a); + move_update(m, FM_X, x); + move_update(m, FM_Y, y); + move_update(m, FM_R, r); + move_update(m, FM_A, a); + m->single = 0; + m->multi = 1; } - state->ntouch = frame->nactive; - state->time = frame->time; + m->ntouch = frame->nactive; + m->time = frame->time; } void gru_event(struct grail *ge, int gid, - const struct move_model *move, + const struct move_model *m, const grail_prop_t *prop, int nprop) { - gin_gid_event(ge, gid, - move->x.val, move->y.val, move->ntouch, + gin_gid_event(ge, gid, m->fm[FM_X].val, m->fm[FM_Y].val, m->ntouch, prop, nprop, GRAIL_STATUS_UPDATE); } -void gru_end(struct grail *ge, int gid, const struct move_model *move) +void gru_end(struct grail *ge, int gid, const struct move_model *m) { - gin_gid_end(ge, gid, move->x.val, move->y.val, move->ntouch); + gin_gid_end(ge, gid, m->fm[FM_X].val, m->fm[FM_Y].val, m->ntouch); } diff --git a/src/grail-gestures.h b/src/grail-gestures.h index 6ba6cf7..3ace580 100644 --- a/src/grail-gestures.h +++ b/src/grail-gestures.h @@ -29,15 +29,21 @@ #define PRIO_GESTURE 2 #define PRIO_TAP 3 +#define DIM_FM 4 + +#define FM_X 0 +#define FM_Y 1 +#define FM_R 2 +#define FM_A 3 + struct filter_model { float delta, val, orig, fuzz, bar; - int tickle, active; }; struct move_model { - struct filter_model x, y, r, a; + struct filter_model fm[DIM_FM]; + int tickle, active; int single, multi, ntouch; - float dx, dy, dr, da; grail_time_t time; }; -- cgit v1.2.3