From 7db9d8d76ff61c4802ac15559dcea6fa54ff567a Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Fri, 6 Aug 2010 21:11:17 +0200 Subject: initial bzr repo at rev 27 --- src/grail-inserter.c | 282 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 src/grail-inserter.c (limited to 'src/grail-inserter.c') diff --git a/src/grail-inserter.c b/src/grail-inserter.c new file mode 100644 index 0000000..724052c --- /dev/null +++ b/src/grail-inserter.c @@ -0,0 +1,282 @@ +/***************************************************************************** + * + * 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-inserter.h" +#include +#include +#include + +static const int MAX_GESTURE_ID = 0xfff; + +struct gesture_inserter { + 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; +}; + +static int find_gslot(const struct gesture_inserter *gin, int gid) +{ + int i; + grail_mask_foreach(i, gin->used, sizeof(gin->used)) + if (gin->state[i].id == gid) + return i; + return -1; +} + +static void send_event(struct grail *ge, struct slot_state *s, + const struct gesture_event *ev) +{ + struct grail_event gev; + int i; + if (!ge->gesture) + return; + gev.type = s->type; + gev.id = s->id; + gev.status = s->status; + gev.ntouch = ev->ntouch; + gev.nprop = ev->nprop; + gev.time = ev->time; + 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); + } +} + +// 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; + 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)); + + 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) + continue; + if (s->priority > hold) + hold = s->priority; + if (s->status == GRAIL_STATUS_BEGIN) + continue; + if (s->priority > discard) + discard = s->priority; + } + + grail_mask_foreach(i, gin->used, sizeof(gin->used)) { + struct slot_state *s = &gin->state[i]; + if (!s->nclient || s->priority < discard) + gin_gid_discard(ge, s->id); + } + + 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; + while (!gebuf_empty(&s->buf)) { + gebuf_get(&s->buf, &ev); + send_event(ge, s, &ev); + } + } + + grail_mask_foreach(i, gin->used, sizeof(gin->used)) { + struct slot_state *s = &gin->state[i]; + if (s->status == GRAIL_STATUS_END) + gin_gid_discard(ge, s->id); + } + + if (grail_mask_count(span, sizeof(span))) + grail_mask_set(filtered, EV_ABS); +} + +int gin_gid_begin_select(struct grail *ge, int type, int priority, + const grail_mask_t *span, int nspan) +{ + struct gesture_inserter *gin = ge->gin; + struct slot_state *s; + int i = grail_mask_get_first(gin->unused, sizeof(gin->unused)); + if (i < 0) + return -1; + s = &gin->state[i]; + s->type = type; + s->priority = priority; + s->id = gin->gestureid++ & MAX_GESTURE_ID; + s->status = GRAIL_STATUS_BEGIN; + s->nclient = 0; + memcpy(s->span, span, nspan); + gebuf_clear(&s->buf); + grail_mask_clear(gin->unused, i); + grail_mask_set(gin->fresh, i); + grail_mask_set(gin->used, i); + return s->id; +} + +int gin_gid_begin(struct grail *ge, int type, int priority, + const struct touch_frame *frame) +{ + return gin_gid_begin_select(ge, type, priority, + frame->touches, sizeof(frame->touches)); +} + +void gin_gid_discard(struct grail *ge, int gid) +{ + struct gesture_inserter *gin = ge->gin; + struct slot_state *s; + int i = find_gslot(gin, gid); + if (i < 0) + return; + s = &gin->state[i]; + gebuf_clear(&s->buf); + s->status = GRAIL_STATUS_END; + grail_mask_clear(gin->used, i); + grail_mask_set(gin->unused, i); +} + +void gin_gid_event(struct grail *ge, int gid, + float x, float y, int ntouch, + const grail_prop_t *prop, int nprop, + int status) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_event ev; + struct slot_state *s; + int i = find_gslot(gin, gid); + if (i < 0) + return; + s = &gin->state[i]; + ev.ntouch = ntouch; + ev.nprop = nprop; + ev.time = gin->time; + ev.pos.x = x; + ev.pos.y = y; + memcpy(ev.prop, prop, nprop * sizeof(grail_prop_t)); + gebuf_put(&s->buf, &ev); + if (s->status == GRAIL_STATUS_BEGIN) + s->status = status; +} + +void gin_gid_end(struct grail *ge, int gid, + float x, float y, int ntouch) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_event ev; + struct slot_state *s; + int i = find_gslot(gin, gid); + if (i < 0) + return; + s = &gin->state[i]; + if (s->status != GRAIL_STATUS_BEGIN) { + ev.ntouch = ntouch; + ev.nprop = 0; + ev.time = gin->time; + ev.pos.x = x; + ev.pos.y = y; + gebuf_put(&s->buf, &ev); + } + s->status = GRAIL_STATUS_END; +} -- cgit v1.2.3