From d07c43f9f19dc0ee38aaf44947cfc396f437490e Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Tue, 3 Aug 2010 15:01:50 +0200 Subject: Introduce zoom, rotate and combo gestures Introduce grail_mask bit functions, and add new gestures as separate functions, referring to the same move model. Signed-off-by: Henrik Rydberg --- src/Makefile.am | 7 ++ src/gebuf.h | 3 + src/gestures-combo.c | 82 ++++++++++++++++ src/gestures-rotate.c | 71 ++++++++++++++ src/gestures-scroll.c | 74 +++++++++++++++ src/gestures-zoom.c | 71 ++++++++++++++ src/grail-api.c | 22 ++--- src/grail-bits.c | 94 +++++++++++++++++++ src/grail-gestures.c | 150 ++++++++++++++++++++++++++++++ src/grail-gestures.h | 85 +++++++++++++++++ src/grail-inserter.c | 248 ++++++++++++++++++++++++++++++------------------- src/grail-inserter.h | 46 +++++---- src/grail-recognizer.c | 76 ++++++--------- src/grail-recognizer.h | 13 ++- src/mtdev-details.h | 19 ++++ src/mtdev-plumbing.h | 105 --------------------- src/touch-dev.c | 45 ++++++--- src/touch-engine.c | 42 ++++----- 18 files changed, 935 insertions(+), 318 deletions(-) create mode 100644 src/gestures-combo.c create mode 100644 src/gestures-rotate.c create mode 100644 src/gestures-scroll.c create mode 100644 src/gestures-zoom.c create mode 100644 src/grail-bits.c create mode 100644 src/grail-gestures.c create mode 100644 src/grail-gestures.h create mode 100644 src/mtdev-details.h delete mode 100644 src/mtdev-plumbing.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 5835897..d0a7d26 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,13 @@ libgrail_la_LDFLAGS = \ libgrail_la_SOURCES = \ touch-dev.c \ touch-engine.c \ + grail-bits.c \ grail-inserter.c \ + grail-gestures.c \ + gestures-scroll.c \ + gestures-zoom.c \ + gestures-rotate.c \ + gestures-combo.c \ grail-recognizer.c \ grail-api.c @@ -17,5 +23,6 @@ INCLUDES = -I$(top_srcdir)/include/ libgrailincludedir = $(includedir) libgrailinclude_HEADERS = \ + $(top_srcdir)/include/grail-bits.h \ $(top_srcdir)/include/grail-touch.h \ $(top_srcdir)/include/grail.h diff --git a/src/gebuf.h b/src/gebuf.h index 37e4a5c..3f71ab5 100644 --- a/src/gebuf.h +++ b/src/gebuf.h @@ -30,7 +30,10 @@ #define DIM_GESTURE_EVENTS 512 struct gesture_event { + int ntouch; + int nprop; touch_time_t time; + struct grail_coord pos; grail_prop_t prop[DIM_GRAIL_PROP]; }; diff --git a/src/gestures-combo.c b/src/gestures-combo.c new file mode 100644 index 0000000..4ecd1e4 --- /dev/null +++ b/src/gestures-combo.c @@ -0,0 +1,82 @@ +/***************************************************************************** + * + * grail - Gesture Recognition And Instantiation Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Henrik Rydberg + * + ****************************************************************************/ + +#include "grail-recognizer.h" +#include +#include + +void gru_reset_combo(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_recognizer *gru = ge->gru; + struct combo_model *state = &gru->combo; + struct move_model *move = &gru->move; + gin_gesture_discard_type(gin, GRAIL_TYPE_SZRCOMBO); + state->r = move->r; + state->active = 0; + state->running = 0; +} + +int gru_combo(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_recognizer *gru = ge->gru; + struct combo_model *state = &gru->combo; + struct move_model *move = &gru->move; + grail_prop_t prop[DIM_GRAIL_PROP]; + float dx, dy, dr, da; + int i; + dx = move->x - state->x; + dy = move->y - state->y; + dr = move->r - state->r; + da = move->a - state->a; + if (fabs(dx) < 1 && fabs(dy) < 1 && fabs(da) < 1 && fabs(dr) < 1) + return 0; + if (!state->active) { + i = gin_gesture_begin(ge, + GRAIL_TYPE_SZRCOMBO, 2, + frame->touches, sizeof(frame->touches)); + state->geslot = i; + state->active = 1; + } + if (!state->running && + fabs(dx) < move->xbar && fabs(dy) < move->ybar && + fabs(da) < move->abar && fabs(dr) < move->rbar) + return 0; + state->running = 1; + prop[0] = dx; + prop[1] = dy; + prop[2] = dr; + prop[3] = da; + gin_gesture_event(gin, state->geslot, + move->x, move->y, move->ntouch, + prop, 4); + state->x = move->x; + state->y = move->y; + state->r = move->r; + state->a = move->a; + return 1; +} diff --git a/src/gestures-rotate.c b/src/gestures-rotate.c new file mode 100644 index 0000000..6097347 --- /dev/null +++ b/src/gestures-rotate.c @@ -0,0 +1,71 @@ +/***************************************************************************** + * + * grail - Gesture Recognition And Instantiation Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Henrik Rydberg + * + ****************************************************************************/ + +#include "grail-recognizer.h" +#include +#include + +void gru_reset_rotate(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_recognizer *gru = ge->gru; + struct rotate_model *state = &gru->rotate; + struct move_model *move = &gru->move; + gin_gesture_discard_type(gin, GRAIL_TYPE_ROTATE); + state->a = move->a; + state->active = 0; + state->rotating = 0; +} + +int gru_rotate(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_recognizer *gru = ge->gru; + struct rotate_model *state = &gru->rotate; + struct move_model *move = &gru->move; + grail_prop_t prop[DIM_GRAIL_PROP]; + float da; + int i; + da = move->a - state->a; + if (fabs(da) < 1) + return 0; + if (!state->active) { + i = gin_gesture_begin(ge, + GRAIL_TYPE_ROTATE, 1, + frame->touches, sizeof(frame->touches)); + state->geslot = i; + state->active = 1; + } + if (!state->rotating && fabs(da) < move->abar) + return 0; + state->rotating = 1; + prop[0] = da; + gin_gesture_event(gin, state->geslot, + move->x, move->y, move->ntouch, + prop, 1); + state->a = move->a; + return 1; +} diff --git a/src/gestures-scroll.c b/src/gestures-scroll.c new file mode 100644 index 0000000..96e153b --- /dev/null +++ b/src/gestures-scroll.c @@ -0,0 +1,74 @@ +/***************************************************************************** + * + * grail - Gesture Recognition And Instantiation Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Henrik Rydberg + * + ****************************************************************************/ + +#include "grail-recognizer.h" +#include + +void gru_reset_scroll(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_recognizer *gru = ge->gru; + struct scroll_model *state = &gru->scroll; + struct move_model *move = &gru->move; + gin_gesture_discard_type(gin, GRAIL_TYPE_SCROLL); + state->x = move->x; + state->y = move->y; + state->active = 0; + state->moving = 0; +} + +int gru_scroll(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_recognizer *gru = ge->gru; + struct scroll_model *state = &gru->scroll; + struct move_model *move = &gru->move; + grail_prop_t prop[DIM_GRAIL_PROP]; + float dx, dy; + int i; + dx = move->x - state->x; + dy = move->y - state->y; + if (fabs(dx) < 1 && fabs(dy) < 1) + return 0; + if (!state->active) { + i = gin_gesture_begin(ge, GRAIL_TYPE_SCROLL, 1, + frame->touches, sizeof(frame->touches)); + state->geslot = i; + state->active = 1; + } + if (!state->moving && fabs(dx) < move->xbar && fabs(dy) < move->ybar) + return 0; + state->moving = 1; + prop[0] = dx; + prop[1] = dy; + gin_gesture_event(gin, state->geslot, + move->x, move->y, move->ntouch, + prop, 2); + state->x = move->x; + state->y = move->y; + return 1; +} + diff --git a/src/gestures-zoom.c b/src/gestures-zoom.c new file mode 100644 index 0000000..9e05b8b --- /dev/null +++ b/src/gestures-zoom.c @@ -0,0 +1,71 @@ +/***************************************************************************** + * + * grail - Gesture Recognition And Instantiation Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Henrik Rydberg + * + ****************************************************************************/ + +#include "grail-recognizer.h" +#include +#include + +void gru_reset_zoom(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_recognizer *gru = ge->gru; + struct zoom_model *state = &gru->zoom; + struct move_model *move = &gru->move; + gin_gesture_discard_type(gin, GRAIL_TYPE_ZOOM); + state->r = move->r; + state->active = 0; + state->zooming = 0; +} + +int gru_zoom(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_recognizer *gru = ge->gru; + struct zoom_model *state = &gru->zoom; + struct move_model *move = &gru->move; + grail_prop_t prop[DIM_GRAIL_PROP]; + float dr; + int i; + dr = move->r - state->r; + if (fabs(dr) < 1) + return 0; + if (!state->active) { + i = gin_gesture_begin(ge, + GRAIL_TYPE_ZOOM, 1, + frame->touches, sizeof(frame->touches)); + state->geslot = i; + state->active = 1; + } + if (!state->zooming && fabs(dr) < move->rbar) + return 0; + state->zooming = 1; + prop[0] = dr; + gin_gesture_event(gin, state->geslot, + move->x, move->y, move->ntouch, + prop, 1); + state->r = move->r; + return 1; +} diff --git a/src/grail-api.c b/src/grail-api.c index e3b8125..cbd2da4 100644 --- a/src/grail-api.c +++ b/src/grail-api.c @@ -70,16 +70,16 @@ static void tp_sync(struct touch_engine *engine, struct touch_frame *frame = &engine->frame; grail_mask_t filtered[DIM_EV_TYPE_BYTES]; int nevent = 0; - gin_frame_begin(ge, frame->time); + gin_frame_begin(ge, frame); gru_recognize(ge, frame); - gin_frame_end(ge, filtered); + gin_frame_end(ge, filtered, sizeof(filtered), frame); if (!ge->event) { evbuf_clear(&x->evbuf); return; } while (!evbuf_empty(&x->evbuf)) { evbuf_get(&x->evbuf, &ev); - if (grail_get_mask(filtered, ev.type)) + if (grail_mask_get(filtered, ev.type)) continue; ge->event(ge, &ev); nevent++; @@ -98,27 +98,27 @@ int grail_open(struct grail *ge, int fd) ret = gin_init(ge); if (ret) goto freemem; - ret = gru_init(ge); - if (ret) - goto freedev; ret = touch_dev_open(&x->dev, fd); if (ret) - goto freegru; + goto freegin; + ret = gru_init(ge, &x->dev.caps); + if (ret) + goto freedev; x->fd = fd; x->mutex = c_mutex; x->wait = c_wait; ret = pthread_create(&x->thread, NULL, grail_thread, x); if (ret) - goto freetouch; + goto freegru; ge->impl = x; touch_engine_init(&x->engine, tp_event, tp_sync, ge); touch_engine_attach(&x->engine, &x->dev); return 0; - freetouch: - touch_dev_close(&x->dev, fd); freegru: gru_destroy(ge); freedev: + touch_dev_close(&x->dev, fd); + freegin: gin_destroy(ge); freemem: free(x); @@ -134,8 +134,8 @@ void grail_close(struct grail *ge, int fd) pthread_cond_signal (&x->wait); pthread_mutex_unlock(&x->mutex); touch_engine_detach(&x->engine, &x->dev); - touch_dev_close(&x->dev, fd); gru_destroy(ge); + touch_dev_close(&x->dev, fd); gin_destroy(ge); free(ge->impl); ge->impl = 0; diff --git a/src/grail-bits.c b/src/grail-bits.c new file mode 100644 index 0000000..1b38d58 --- /dev/null +++ b/src/grail-bits.c @@ -0,0 +1,94 @@ +/***************************************************************************** + * + * grail - Gesture Recognition And Instantiation Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Henrik Rydberg + * + ****************************************************************************/ + +#include "grail-bits.h" + +static const int grail_bits_in_byte[256] = +{ + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, +}; + +static const int grail_first_set_bit[256] = +{ + -1,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +}; + +void grail_mask_set_mask(grail_mask_t *a, const grail_mask_t *b, int bytes) +{ + while (bytes--) + *a++ |= *b++; +} + +void grail_mask_clear_mask(grail_mask_t *a, const grail_mask_t *b, int bytes) +{ + while (bytes--) + *a++ &= ~*b++; +} + +int grail_mask_count(const grail_mask_t *mask, int bytes) +{ + int count = 0; + while (bytes--) + count += grail_bits_in_byte[*mask++]; + return count; +} + +int grail_mask_get_first(const grail_mask_t *mask, int bytes) +{ + int k; + for (k = 0; k < bytes; k++) + if (mask[k]) + return (k << 3) | grail_first_set_bit[mask[k]]; + return -1; +} + +int grail_mask_get_next(int i, const grail_mask_t *mask, int bytes) +{ + int k = ++i >> 3; + if (k < bytes) { + i = grail_first_set_bit[mask[k] & (~0 << (i & 7))]; + if (i >= 0) + return (k << 3) | i; + while (++k < bytes) { + i = grail_first_set_bit[mask[k]]; + if (i >= 0) + return (k << 3) | i; + } + } + return -1; +} diff --git a/src/grail-gestures.c b/src/grail-gestures.c new file mode 100644 index 0000000..d79da96 --- /dev/null +++ b/src/grail-gestures.c @@ -0,0 +1,150 @@ +/***************************************************************************** + * + * grail - Gesture Recognition And Instantiation Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Henrik Rydberg + * + ****************************************************************************/ + +#include "grail-recognizer.h" +#include + +static const float SN_MOVE = 50; +static const float SN_ZOOM = 50; +static const float SN_ROTATE = 200; +static const float BAR_MOVE = 1; +static const float BAR_ZOOM = 2; +static const float BAR_ROTATE = 4; + +static void compute_position(float *x, float *y, + const struct touch_frame *frame) +{ + int i, n = frame->nactive; + *x = 0; + *y = 0; + if (n < 1) + return; + for (i = 0; i < n; i++) { + const struct touch *t = frame->active[i]; + *x += t->prop[TP_POS_X]; + *y += t->prop[TP_POS_Y]; + } + *x /= n; + *y /= n; +} + +static float compute_radius(float x, float y, + const struct touch_frame *frame) +{ + int i, n = frame->nactive; + float r = 0, r2 = 0; + if (n < 2) + return r; + for (i = 0; i < n; i++) { + const struct touch *t = frame->active[i]; + float dx = t->prop[TP_POS_X] - x; + float dy = t->prop[TP_POS_Y] - y; + r2 += dx * dx + dy * dy; + } + r2 /= n; + r = sqrt(r2); + return r; +} + +static float compute_rotation(float x, float y, float r, + const struct touch_frame *prev, + const struct touch_frame *frame) +{ + int i, n = frame->nactive; + float da = 0, da2 = 0; + if (n < 2) + return da; + for (i = 0; i < n; i++) { + const struct touch *t = frame->active[i]; + const struct touch *ot = &prev->touch[t->slot]; + float dx = t->prop[TP_POS_X] - x; + float dy = t->prop[TP_POS_Y] - y; + float mx = t->prop[TP_POS_X] - ot->prop[TP_POS_X]; + float my = t->prop[TP_POS_Y] - ot->prop[TP_POS_Y]; + da2 += dx * my - dy * mx; + } + da2 /= n; + da = da2 / r; + return da; +} + +static float move_filter(float x, float x0, float fuzz) +{ + if (x > x0 - fuzz / 2 && x < x0 + fuzz / 2) + return x0; + if (x > x0 - fuzz && x < x0 + fuzz) + return (x0 * 3 + x) / 4; + if (x > x0 - fuzz * 2 && x < x0 + fuzz * 2) + return (x0 + x) / 2; + return x; +} + +void gru_init_motion(struct grail *ge, const struct touch_dev_caps *caps) +{ + struct gesture_recognizer *gru = ge->gru; + struct move_model *state = &gru->move; + float x = caps->info[TP_POS_X].maximum - caps->info[TP_POS_X].minimum; + float y = caps->info[TP_POS_Y].maximum - caps->info[TP_POS_Y].minimum; + float r = sqrt(x * x + y * y); + state->xfuzz = x / SN_MOVE; + state->yfuzz = y / SN_MOVE; + state->rfuzz = r / SN_ZOOM; + state->afuzz = r / SN_ROTATE; + state->xbar = BAR_MOVE * state->xfuzz; + state->ybar = BAR_MOVE * state->yfuzz; + state->rbar = BAR_ZOOM * state->rfuzz; + state->abar = BAR_ROTATE * state->afuzz; +} + +void gru_reset_motion(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_recognizer *gru = ge->gru; + struct move_model *state = &gru->move; + compute_position(&state->x, &state->y, frame); + state->r = compute_radius(state->x, state->y, frame); + state->a = 0; + state->ntouch = frame->nactive; +} + +void gru_compute_motion(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_recognizer *gru = ge->gru; + struct move_model *state = &gru->move; + float x, y, r, a; + compute_position(&x, &y, frame); + x = move_filter(x, state->x, state->xfuzz); + y = move_filter(y, state->y, state->yfuzz); + r = compute_radius(x, y, frame); + r = move_filter(r, state->r, state->rfuzz); + a = state->a + compute_rotation(x, y, r, &gru->frame, frame); + a = move_filter(a, state->a, state->afuzz); + state->x = x; + state->y = y; + state->r = r; + state->a = a; + state->ntouch = frame->nactive; +} diff --git a/src/grail-gestures.h b/src/grail-gestures.h new file mode 100644 index 0000000..70a5a98 --- /dev/null +++ b/src/grail-gestures.h @@ -0,0 +1,85 @@ +/***************************************************************************** + * + * grail - Gesture Recognition And Instantiation Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Henrik Rydberg + * + ****************************************************************************/ + +#ifndef _GRAIL_GESTURES_H +#define _GRAIL_GESTURES_H + +#include "grail-inserter.h" + +struct move_model { + float xfuzz, yfuzz, rfuzz, afuzz; + float xbar, ybar, rbar, abar; + float x, y, r, a; + int ntouch; +}; + +void gru_init_motion(struct grail *ge, + const struct touch_dev_caps *caps); +void gru_reset_motion(struct grail *ge, + const struct touch_frame *frame); +void gru_compute_motion(struct grail *ge, + const struct touch_frame *frame); + +struct scroll_model { + float x, y; + int active, moving, geslot; +}; + +void gru_reset_scroll(struct grail *ge, + const struct touch_frame *frame); +int gru_scroll(struct grail *ge, + const struct touch_frame *frame); + +struct zoom_model { + float r; + int active, zooming, geslot; +}; + +void gru_reset_zoom(struct grail *ge, + const struct touch_frame *frame); +int gru_zoom(struct grail *ge, + const struct touch_frame *frame); + +struct rotate_model { + float a; + int active, rotating, geslot; +}; + +void gru_reset_rotate(struct grail *ge, + const struct touch_frame *frame); +int gru_rotate(struct grail *ge, + const struct touch_frame *frame); + +struct combo_model { + float x, y, r, a; + int active, running, geslot; +}; + +void gru_reset_combo(struct grail *ge, + const struct touch_frame *frame); +int gru_combo(struct grail *ge, + const struct touch_frame *frame); + +#endif + diff --git a/src/grail-inserter.c b/src/grail-inserter.c index b357e29..3927875 100644 --- a/src/grail-inserter.c +++ b/src/grail-inserter.c @@ -29,28 +29,6 @@ static const int MAX_GESTURE_ID = 0xfff; -int gin_init(struct grail *ge) -{ - struct gesture_inserter *x; - x = calloc(1, sizeof(*x)); - if (!x) - return -ENOMEM; - ge->gin = x; - return 0; -} - -void gin_destroy(struct grail *ge) -{ - free(ge->gin); - ge->gin = NULL; -} - -void gin_frame_begin(struct grail *ge, grail_time_t time) -{ - struct gesture_inserter *gin = ge->gin; - gin->time = time; -} - static void send_event(struct grail *ge, struct slot_state *s, const struct gesture_event *ev) { @@ -61,124 +39,200 @@ static void send_event(struct grail *ge, struct slot_state *s, gev.type = s->type; gev.id = s->id; gev.status = s->status; - gev.pos.x = s->x; - gev.pos.y = s->x; + gev.ntouch = ev->ntouch; + gev.nprop = ev->nprop; gev.time = ev->time; - memcpy(gev.prop, ev->prop, DIM_GRAIL_PROP * sizeof(gev.prop[0])); + gev.pos = ev->pos; + memcpy(gev.prop, ev->prop, ev->nprop * sizeof(grail_prop_t)); for (i = 0; i < s->nclient; i++) { gev.client_id = s->client_id[i]; ge->gesture(ge, &gev); } } -void gin_frame_end(struct grail *ge, grail_mask_t *filtered) +// todo: spanning tree for multi-user case +static void setup_new_gestures(struct grail *ge, + const struct touch_frame *frame) { struct gesture_inserter *gin = ge->gin; - struct gesture_event ev; - grail_mask_t span[DIM_SLOT_BYTES]; - int i, slot, spanned = 0; - memset(filtered, 0, DIM_EV_TYPE_BYTES); + grail_mask_t types[DIM_GRAIL_TYPE_BYTES]; + grail_mask_t span[DIM_TOUCH_BYTES]; + struct grail_client_info info[DIM_CLIENT]; + int i, j, nclient = 0; + int nfresh = grail_mask_count(gin->fresh, sizeof(gin->fresh)); + if (!nfresh) + return; + + memset(types, 0, sizeof(types)); memset(span, 0, sizeof(span)); - for (slot = 0; slot < DIM_SLOT; slot++) { - struct slot_state *s = &gin->state[slot]; - if (!grail_get_mask(gin->used, slot)) - continue; + + grail_mask_foreach(i, gin->fresh, sizeof(gin->fresh)) { + struct slot_state *s = &gin->state[i]; + grail_mask_set(types, s->type); + grail_mask_set_mask(span, s->span, sizeof(span)); + } + + if (ge->get_clients) { + struct grail_coord coord[DIM_CLIENT]; + int ncoord = 0; + grail_mask_foreach(i, span, sizeof(span)) { + const struct touch *t = &frame->touch[i]; + coord[ncoord].x = t->prop[TP_POS_X]; + coord[ncoord].y = t->prop[TP_POS_Y]; + ncoord++; + } + nclient = ge->get_clients(ge, info, DIM_CLIENT, + coord, ncoord, types, sizeof(types)); + } + + grail_mask_foreach(i, gin->fresh, sizeof(gin->fresh)) { + struct slot_state *s = &gin->state[i]; + s->nclient = 0; + for (j = 0; j < nclient; j++) { + if (!grail_mask_get(info[j].mask, s->type)) + continue; + s->client_id[s->nclient++] = info[j].id; + } + } + + memset(gin->fresh, 0, sizeof(gin->fresh)); +} + +int gin_init(struct grail *ge) +{ + struct gesture_inserter *gin; + int i; + gin = calloc(1, sizeof(*gin)); + if (!gin) + return -ENOMEM; + for (i = 0; i < DIM_INSTANCE; i++) + grail_mask_set(gin->unused, i); + ge->gin = gin; + return 0; +} + +void gin_destroy(struct grail *ge) +{ + free(ge->gin); + ge->gin = NULL; +} + +void gin_frame_begin(struct grail *ge, const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + gin->time = frame->time; +} + +void gin_frame_end(struct grail *ge, + grail_mask_t *filtered, int max_filtered, + const struct touch_frame *frame) +{ + struct gesture_inserter *gin = ge->gin; + grail_mask_t span[DIM_INSTANCE_BYTES]; + int i, hold = 0, discard = 0; + + memset(filtered, 0, max_filtered); + memset(span, 0, sizeof(span)); + + setup_new_gestures(ge, frame); + + grail_mask_foreach(i, gin->used, sizeof(gin->used)) { + struct slot_state *s = &gin->state[i]; if (!s->nclient) - gin_gesture_discard(gin, slot); + continue; + if (s->priority > hold) + hold = s->priority; + if (s->status == GRAIL_STATUS_BEGIN) + continue; + if (s->priority > discard) + discard = s->priority; } - for (slot = 0; slot < DIM_SLOT; slot++) { - struct slot_state *s = &gin->state[slot]; - if (!grail_get_mask(gin->used, slot)) + + grail_mask_foreach(i, gin->used, sizeof(gin->used)) { + struct slot_state *s = &gin->state[i]; + if (!s->nclient || s->priority < discard) + gin_gesture_discard(gin, i); + } + + grail_mask_foreach(i, gin->used, sizeof(gin->used)) { + struct slot_state *s = &gin->state[i]; + struct gesture_event ev; + grail_mask_set_mask(span, s->span, sizeof(span)); + if (s->priority < hold) continue; - for (i = 0; i < DIM_SLOT_BYTES; i++) { - span[i] |= s->span[i]; - spanned += !!span[i]; - } while (!gebuf_empty(&s->buf)) { gebuf_get(&s->buf, &ev); send_event(ge, s, &ev); } - if (s->status == GRAIL_STATUS_BEGIN) - s->status = GRAIL_STATUS_UPDATE; } - if (spanned) - grail_set_mask(filtered, EV_ABS); + + grail_mask_foreach(i, gin->used, sizeof(gin->used)) { + struct slot_state *s = &gin->state[i]; + if (s->status == GRAIL_STATUS_END) + gin_gesture_discard(gin, i); + } + + if (grail_mask_count(span, sizeof(span))) + grail_mask_set(filtered, EV_ABS); } -int gin_gesture_begin(struct grail *ge, const struct touch_frame *frame, - int type, int x, int y, const grail_mask_t *span) +int gin_gesture_begin(struct grail *ge, int type, int priority, + const grail_mask_t *span, int nspan) { - struct grail_client_info info[DIM_CLIENT]; - struct grail_coord coord[DIM_CLIENT]; struct gesture_inserter *gin = ge->gin; struct slot_state *s; - int i, slot, nc, ncoord = 0; - for (slot = 0; slot < DIM_SLOT; slot++) - if (!grail_get_mask(gin->used, slot)) - break; - if (slot >= DIM_SLOT) + int geslot = grail_mask_get_first(gin->unused, sizeof(gin->unused)); + if (geslot < 0) return -1; - s = &gin->state[slot]; + s = &gin->state[geslot]; s->type = type; + s->priority = priority; s->id = gin->gestureid++ & MAX_GESTURE_ID; s->status = GRAIL_STATUS_BEGIN; - s->x = x; - s->y = y; s->nclient = 0; - if (ge->get_clients) { - grail_mask_t tps[DIM_GRAIL_TYPE_BYTES]; - memset(tps, 0, sizeof(tps)); - grail_set_mask(tps, type); - for (i = 0; i < DIM_SLOT; i++) { - const struct touch *t = &frame->touch[i]; - if (!grail_get_mask(span, i)) - continue; - coord[ncoord].x = t->prop[TP_POS_X]; - coord[ncoord].y = t->prop[TP_POS_Y]; - ncoord++; - } - nc = ge->get_clients(ge, info, DIM_CLIENT, coord, ncoord, tps); - for (i = 0; i < nc; i++) { - if (!grail_get_mask(info[i].mask, type)) - continue; - s->client_id[s->nclient] = info[i].id; - s->nclient++; - } - } - memcpy(s->span, span, sizeof(s->span)); + memcpy(s->span, span, nspan); gebuf_clear(&s->buf); - grail_set_mask(gin->used, slot); - return slot; + grail_mask_clear(gin->unused, geslot); + grail_mask_set(gin->fresh, geslot); + grail_mask_set(gin->used, geslot); + return geslot; } -void gin_gesture_end(struct gesture_inserter *gin, int slot) +void gin_gesture_end(struct gesture_inserter *gin, int geslot) { - struct slot_state *s = &gin->state[slot]; - s->status = GRAIL_STATUS_END; - grail_clear_mask(gin->used, slot); + gin->state[geslot].status = GRAIL_STATUS_END; } -void gin_gesture_discard(struct gesture_inserter *gin, int slot) +void gin_gesture_discard(struct gesture_inserter *gin, int geslot) { - struct slot_state *s = &gin->state[slot]; - gebuf_clear(&s->buf); - gin_gesture_end(gin, slot); + gebuf_clear(&gin->state[geslot].buf); + gin_gesture_end(gin, geslot); + grail_mask_clear(gin->used, geslot); + grail_mask_set(gin->unused, geslot); } -void gin_gesture_end_all(struct gesture_inserter *gin) +void gin_gesture_discard_type(struct gesture_inserter *gin, int type) { - int slot; - for (slot = 0; slot < DIM_SLOT; slot++) - gin_gesture_end(gin, slot); + int i; + grail_mask_foreach(i, gin->used, sizeof(gin->used)) + if (gin->state[i].type == type) + gin_gesture_discard(gin, i); } -void gin_gesture_event(struct gesture_inserter *gin, int slot, - const grail_prop_t *prop) +void gin_gesture_event(struct gesture_inserter *gin, int geslot, + float x, float y, int ntouch, + const grail_prop_t *prop, int nprop) { - struct slot_state *s = &gin->state[slot]; + struct slot_state *s = &gin->state[geslot]; struct gesture_event ev; + ev.ntouch = ntouch; + ev.nprop = nprop; ev.time = gin->time; - memcpy(ev.prop, prop, sizeof(ev.prop)); + ev.pos.x = x; + ev.pos.y = y; + memcpy(ev.prop, prop, nprop * sizeof(grail_prop_t)); + if (s->status == GRAIL_STATUS_BEGIN) + s->status = GRAIL_STATUS_UPDATE; gebuf_put(&s->buf, &ev); } diff --git a/src/grail-inserter.h b/src/grail-inserter.h index 1e02d5f..cca71d2 100644 --- a/src/grail-inserter.h +++ b/src/grail-inserter.h @@ -22,31 +22,37 @@ * ****************************************************************************/ -#ifndef _GRAIL_GESTURE_H -#define _GRAIL_GESTURE_H +#ifndef _GRAIL_INSERTER_H +#define _GRAIL_INSERTER_H #include #include #include "gebuf.h" #define DIM_EV_TYPE EV_CNT -#define DIM_EV_TYPE_BYTES (DIM_EV_TYPE >> 3) +#define DIM_EV_TYPE_BYTES ((DIM_EV_TYPE + 7) >> 3) -#define DIM_SLOT 32 -#define DIM_SLOT_BYTES (DIM_SLOT >> 3) +#define DIM_INSTANCE 32 +#define DIM_INSTANCE_BYTES ((DIM_INSTANCE + 7) >> 3) -#define DIM_CLIENT 32 +#define DIM_CLIENT 32 struct slot_state { - int type, id, status, x, y, nclient; + int type; + int priority; + int id; + int status; + int nclient; struct grail_client_id client_id[DIM_CLIENT]; - grail_mask_t span[DIM_SLOT_BYTES]; + grail_mask_t span[DIM_TOUCH_BYTES]; struct gebuf buf; }; struct gesture_inserter { - struct slot_state state[DIM_SLOT]; - grail_mask_t used[DIM_SLOT_BYTES]; + struct slot_state state[DIM_INSTANCE]; + grail_mask_t unused[DIM_INSTANCE_BYTES]; + grail_mask_t fresh[DIM_INSTANCE_BYTES]; + grail_mask_t used[DIM_INSTANCE_BYTES]; grail_time_t time; int gestureid; }; @@ -54,16 +60,18 @@ struct gesture_inserter { int gin_init(struct grail *ge); void gin_destroy(struct grail *ge); -void gin_frame_begin(struct grail *ge, grail_time_t time); -void gin_frame_end(struct grail *ge, grail_mask_t *filtered); +void gin_frame_begin(struct grail *ge, const struct touch_frame *frame); +void gin_frame_end(struct grail *ge, grail_mask_t *filtered, int max_filtered, + const struct touch_frame *frame); -int gin_gesture_begin(struct grail *ge, const struct touch_frame *frame, - int type, int x, int y, const grail_mask_t *span); -void gin_gesture_discard(struct gesture_inserter *gin, int slot); -void gin_gesture_end(struct gesture_inserter *gin, int slot); -void gin_gesture_end_all(struct gesture_inserter *gin); +int gin_gesture_begin(struct grail *ge, int type, int priority, + const grail_mask_t *span, int nspan); +void gin_gesture_end(struct gesture_inserter *gin, int geslot); +void gin_gesture_discard(struct gesture_inserter *gin, int geslot); +void gin_gesture_discard_type(struct gesture_inserter *gin, int type); -void gin_gesture_event(struct gesture_inserter *gin, int slot, - const grail_prop_t *prop); +void gin_gesture_event(struct gesture_inserter *gin, int geslot, + float x, float y, int ntouch, + const grail_prop_t *prop, int nprop); #endif diff --git a/src/grail-recognizer.c b/src/grail-recognizer.c index 9ede059..1e7a8bf 100644 --- a/src/grail-recognizer.c +++ b/src/grail-recognizer.c @@ -22,24 +22,21 @@ * ****************************************************************************/ -#include "grail-inserter.h" +#include "grail-recognizer.h" #include #include #include -struct gesture_recognizer { - struct touch_frame frame; - touch_time_t scroll_time; - int scroll_active; - int scroll_gslot; - int scroll_slots[2]; -}; +static const touch_time_t DROP_TIMEOUT_MS = 100; -int gru_init(struct grail *ge) +int gru_init(struct grail *ge, const struct touch_dev_caps *caps) { - ge->gru = calloc(1, sizeof(struct gesture_recognizer)); - if (!ge->gru) + struct gesture_recognizer *gru; + gru = calloc(1, sizeof(struct gesture_recognizer)); + if (!gru) return -ENOMEM; + ge->gru = gru; + gru_init_motion(ge, caps); return 0; } @@ -49,49 +46,32 @@ void gru_destroy(struct grail *ge) ge->gru = NULL; } +static void reset_gru_state(struct grail *ge, const struct touch_frame *frame) +{ + gru_reset_combo(ge, frame); + gru_reset_rotate(ge, frame); + gru_reset_zoom(ge, frame); + gru_reset_scroll(ge, frame); + gru_reset_motion(ge, frame); +} + void gru_recognize(struct grail *ge, const struct touch_frame *frame) { - struct gesture_inserter *gin = ge->gin; struct gesture_recognizer *gru = ge->gru; - grail_prop_t prop[DIM_GRAIL_PROP]; - grail_mask_t span[16]; - int slot, nslot, x, y, dx, dy; - if (!gru) - return; - if (frame->ncreate || frame->ndestroy) { - gin_gesture_end_all(gin); - gru->scroll_active = 0; + struct move_model *move = &gru->move; + if (!ge->gin || !ge->gru) return; - } - if (frame->ntouch != 2) + if (frame->nactive < move->ntouch && + frame->time < gru->frame.time + DROP_TIMEOUT_MS) return; - memset(span, 0, sizeof(span)); - nslot = 0; - x = y = dx = dy = 0; - for (slot = frame->slot; slot >= 0; slot = next_slot(frame, slot)) { - struct touch *ot = &gru->frame.touch[slot]; - const struct touch *t = &frame->touch[slot]; - gru->scroll_slots[nslot] = slot; - grail_set_mask(span, slot); - x += t->prop[TP_POS_X]; - y += t->prop[TP_POS_Y]; - dx += t->prop[TP_POS_X] - ot->prop[TP_POS_X]; - dy += t->prop[TP_POS_Y] - ot->prop[TP_POS_Y]; - nslot++; - } - x /= nslot; - y /= nslot; - dx /= nslot; - dy /= nslot; - if (!dy) + if (frame->nactive < 2 || frame->ncreate || frame->ndestroy) { + reset_gru_state(ge, frame); return; - if (!gru->scroll_active) { - gru->scroll_gslot = gin_gesture_begin(ge, frame, - GRAIL_TYPE_VSCROLL, - x, y, span); - gru->scroll_active = 1; } - prop[0] = dy; - gin_gesture_event(gin, gru->scroll_gslot, prop); + gru_compute_motion(ge, frame); + gru_scroll(ge, frame); + gru_zoom(ge, frame); + gru_rotate(ge, frame); + gru_combo(ge, frame); gru->frame = *frame; } diff --git a/src/grail-recognizer.h b/src/grail-recognizer.h index 8c47162..247687d 100644 --- a/src/grail-recognizer.h +++ b/src/grail-recognizer.h @@ -25,9 +25,18 @@ #ifndef _GRAIL_RECOGNIZER_H #define _GRAIL_RECOGNIZER_H -#include "grail-inserter.h" +#include "grail-gestures.h" -int gru_init(struct grail *ge); +struct gesture_recognizer { + struct touch_frame frame; + struct move_model move; + struct scroll_model scroll; + struct zoom_model zoom; + struct rotate_model rotate; + struct combo_model combo; +}; + +int gru_init(struct grail *ge, const struct touch_dev_caps *caps); void gru_recognize(struct grail *ge, const struct touch_frame *frame); void gru_destroy(struct grail *ge); diff --git a/src/mtdev-details.h b/src/mtdev-details.h new file mode 100644 index 0000000..873528d --- /dev/null +++ b/src/mtdev-details.h @@ -0,0 +1,19 @@ +#ifndef _MTDEV_DETAILS_H +#define _MTDEV_DETAILS_H + +#define MTDEV_TRACKING_ID 9 +#define MTDEV_POSITION_X 5 +#define MTDEV_POSITION_Y 6 +#define MTDEV_TOUCH_MAJOR 0 +#define MTDEV_TOUCH_MINOR 1 +#define MTDEV_WIDTH_MAJOR 2 +#define MTDEV_WIDTH_MINOR 3 +#define MTDEV_ORIENTATION 4 +#define MTDEV_PRESSURE 10 + +int mtdev_fetch_event(struct mtdev *dev, int fd, struct input_event *ev); +void mtdev_put_event(struct mtdev *dev, const struct input_event *ev); +int mtdev_empty(struct mtdev *dev); +void mtdev_get_event(struct mtdev *dev, struct input_event* ev); + +#endif diff --git a/src/mtdev-plumbing.h b/src/mtdev-plumbing.h deleted file mode 100644 index c1d141e..0000000 --- a/src/mtdev-plumbing.h +++ /dev/null @@ -1,105 +0,0 @@ -/***************************************************************************** - * - * mtdev - Multitouch Protocol Translation Library (MIT license) - * - * Copyright (C) 2010 Henrik Rydberg - * Copyright (C) 2010 Canonical Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - ****************************************************************************/ - -#ifndef _MTDEV_PLUMBING_H -#define _MTDEV_PLUMBING_H - -#include - -/** - * mtdev_init - initialize mtdev converter - * @dev: the mtdev to initialize - * - * Sets up the internal data structures. - * - * Returns zero on success, negative error number otherwise. - */ -int mtdev_init(struct mtdev *dev); - -/** - * mtdev_configure - configure the mtdev converter - * @dev: the mtdev to configure - * @fd: file descriptor of the kernel device - * - * Reads the device properties to set up the protocol capabilities. - * If preferred, this can be done by hand, omitting this call. - * - * Returns zero on success, negative error number otherwise. - */ -int mtdev_configure(struct mtdev *dev, int fd); - -/** - * mtdev_fetch_event - fetch an event from the kernel device - * @dev: the mtdev in use - * @fd: file descriptor of the kernel device - * @ev: the kernel input event to fill - * - * Fetch a kernel event from the kernel device. The read operation - * behaves as dictated by the file descriptor; if O_NONBLOCK is not - * set, the read will block until an event is available. - * - * On success, returns the number of events read (0 or 1). Otherwise, - * a standard negative error number is returned. - */ -int mtdev_fetch_event(struct mtdev *dev, int fd, struct input_event *ev); - -/** - * mtdev_put_event - put an event into the converter - * @dev: the mtdev in use - * @ev: the kernel input event to put - * - * Put a kernel event into the mtdev converter. The event should - * come straight from the device. - * - * This call does not block; if the buffer becomes full, older events - * are dropped. The buffer is guaranteed to handle several complete MT - * packets. - */ -void mtdev_put_event(struct mtdev *dev, const struct input_event *ev); - -/** - * mtdev_empty - check if there are events to get - * @dev: the mtdev in use - * - * Returns true if the processed event queue is empty, false otherwise. - */ -int mtdev_empty(struct mtdev *dev); - -/** - * mtdev_get_event - get processed events from mtdev - * @dev: the mtdev in use - * @ev: the input event to fill - * - * Get a processed event from mtdev. The events appear as if they came - * from a type B device emitting MT slot events. - * - * The queue must be non-empty before calling this function. - */ -void mtdev_get_event(struct mtdev *dev, struct input_event* ev); - -#endif diff --git a/src/touch-dev.c b/src/touch-dev.c index b7efb35..3c3036c 100644 --- a/src/touch-dev.c +++ b/src/touch-dev.c @@ -27,20 +27,46 @@ #include #include #include "evbuf.h" -#include "mtdev-plumbing.h" - -#define DIM_TOUCH 32 +#include "mtdev-details.h" struct touch_dev_impl { int id[DIM_TOUCH]; int slot; int status; - touch_prop_mask_t mask[1]; + grail_mask_t mask[DIM_TOUCH_BYTES]; touch_prop_t prop[DIM_TOUCH_PROP]; struct evbuf evbuf; struct mtdev mtdev; }; +static inline void set_info(struct touch_dev_caps *caps, int code, + const struct input_absinfo *info) +{ + grail_mask_set(caps->mask, code); + caps->info[code] = *info; +} + +static void set_caps(struct touch_dev_caps *caps, + const struct mtdev_caps *mtcaps) +{ + if (mtcaps->has_abs[MTDEV_POSITION_X]) + set_info(caps, TP_POS_X, &mtcaps->abs[MTDEV_POSITION_X]); + if (mtcaps->has_abs[MTDEV_POSITION_Y]) + set_info(caps, TP_POS_Y, &mtcaps->abs[MTDEV_POSITION_Y]); + if (mtcaps->has_abs[MTDEV_TOUCH_MAJOR]) + set_info(caps, TP_TOUCH_MAJOR, &mtcaps->abs[MTDEV_TOUCH_MAJOR]); + if (mtcaps->has_abs[MTDEV_TOUCH_MINOR]) + set_info(caps, TP_TOUCH_MINOR, &mtcaps->abs[MTDEV_TOUCH_MINOR]); + if (mtcaps->has_abs[MTDEV_WIDTH_MAJOR]) + set_info(caps, TP_WIDTH_MAJOR, &mtcaps->abs[MTDEV_WIDTH_MAJOR]); + if (mtcaps->has_abs[MTDEV_WIDTH_MINOR]) + set_info(caps, TP_WIDTH_MINOR, &mtcaps->abs[MTDEV_WIDTH_MINOR]); + if (mtcaps->has_abs[MTDEV_ORIENTATION]) + set_info(caps, TP_ORIENTATION, &mtcaps->abs[MTDEV_ORIENTATION]); + if (mtcaps->has_abs[MTDEV_PRESSURE]) + set_info(caps, TP_PRESSURE, &mtcaps->abs[MTDEV_PRESSURE]); +} + static int touch_get_fetched(struct touch_dev_impl *x, struct input_event* ev, int ev_max) { @@ -58,14 +84,9 @@ static int touch_get_fetched(struct touch_dev_impl *x, return count; } -static inline int has_any_prop(const touch_prop_mask_t *mask) -{ - return mask[0] != 0; -} - static inline void set_prop(struct touch_dev_impl *x, int code, int value) { - x->mask[code >> 5] |= 1U << (code & 31); + grail_mask_set(x->mask, code); x->prop[code] = value; } @@ -76,7 +97,8 @@ static void finish_touch(struct touch_dev *dev, dev->destroy(dev, x->slot); if (x->status > 0 && dev->create) dev->create(dev, x->slot, x->mask, x->prop); - if (x->status == 0 && has_any_prop(x->mask) && dev->modify) + if (x->status == 0 && dev->modify && + grail_mask_count(x->mask, sizeof(x->mask))) dev->modify(dev, x->slot, x->mask, x->prop); x->status = 0; memset(x->mask, 0, sizeof(x->mask)); @@ -157,6 +179,7 @@ int touch_dev_open(struct touch_dev *dev, int fd) goto error; for (i = 0; i < DIM_TOUCH; i++) x->id[i] = MT_ID_NULL; + set_caps(&dev->caps, &x->mtdev.caps); dev->impl = x; return 0; error: diff --git a/src/touch-engine.c b/src/touch-engine.c index 28b68da..3e6870e 100644 --- a/src/touch-engine.c +++ b/src/touch-engine.c @@ -34,40 +34,29 @@ static void tp_event(struct touch_dev *dev, const struct input_event *ev) static void update_frame(struct touch_frame *frame, int slot, int active, - const touch_prop_mask_t *mask, + const grail_mask_t *mask, const touch_prop_t *prop) { - struct touch *touch = &frame->touch[slot]; - touch->active = active; - if (mask && prop) { - int i; - for (i = 0; i < DIM_TOUCH_PROP; i++) - if (has_prop(mask, i)) - touch->prop[i] = prop[i]; - } + struct touch *t = &frame->touch[slot]; + int i; + t->active = active; + grail_mask_modify(frame->touches, slot, active); + if (mask && prop) + grail_mask_foreach(i, mask, DIM_TOUCH_PROP_BYTES) + t->prop[i] = prop[i]; } static void finalize_frame(struct touch_frame *frame, touch_time_t time) { - int i, last = -1; - frame->ntouch = 0; - frame->slot = -1; - for (i = 0; i < DIM_TOUCH_PROP; i++) { - frame->touch[i].next = -1; - if (frame->touch[i].active) { - if (last < 0) - frame->slot = i; - else - frame->touch[last].next = i; - last = i; - frame->ntouch++; - } - } + int i, nslot = 0; + grail_mask_foreach(i, frame->touches, DIM_TOUCH_BYTES) + frame->active[nslot++] = &frame->touch[i]; + frame->nactive = nslot; frame->time = time; } static void tp_create(struct touch_dev *dev, int slot, - const touch_prop_mask_t *mask, const touch_prop_t *prop) + const grail_mask_t *mask, const touch_prop_t *prop) { struct touch_engine *engine = dev->priv; if (engine) { @@ -77,7 +66,7 @@ static void tp_create(struct touch_dev *dev, int slot, } static void tp_modify(struct touch_dev *dev, int slot, - const touch_prop_mask_t *mask, const touch_prop_t *prop) + const grail_mask_t *mask, const touch_prop_t *prop) { struct touch_engine *engine = dev->priv; if (engine) { @@ -117,7 +106,10 @@ void touch_engine_init(struct touch_engine *engine, const struct input_event *ev), void *priv) { + int i; memset(engine, 0, sizeof(*engine)); + for (i = 0; i < DIM_TOUCH; i++) + engine->frame.touch[i].slot = i; engine->event = event; engine->sync = sync; engine->priv = priv; -- cgit v1.2.3