diff options
| -rw-r--r-- | include/grail-bits.h | 65 | ||||
| -rw-r--r-- | include/grail-touch.h | 35 | ||||
| -rw-r--r-- | include/grail.h | 52 | ||||
| -rw-r--r-- | src/Makefile.am | 7 | ||||
| -rw-r--r-- | src/gebuf.h | 3 | ||||
| -rw-r--r-- | src/gestures-combo.c | 82 | ||||
| -rw-r--r-- | src/gestures-rotate.c | 71 | ||||
| -rw-r--r-- | src/gestures-scroll.c | 74 | ||||
| -rw-r--r-- | src/gestures-zoom.c | 71 | ||||
| -rw-r--r-- | src/grail-api.c | 22 | ||||
| -rw-r--r-- | src/grail-bits.c | 94 | ||||
| -rw-r--r-- | src/grail-gestures.c | 150 | ||||
| -rw-r--r-- | src/grail-gestures.h | 85 | ||||
| -rw-r--r-- | src/grail-inserter.c | 248 | ||||
| -rw-r--r-- | src/grail-inserter.h | 46 | ||||
| -rw-r--r-- | src/grail-recognizer.c | 76 | ||||
| -rw-r--r-- | src/grail-recognizer.h | 13 | ||||
| -rw-r--r-- | src/mtdev-details.h | 19 | ||||
| -rw-r--r-- | src/mtdev-plumbing.h | 105 | ||||
| -rw-r--r-- | src/touch-dev.c | 45 | ||||
| -rw-r--r-- | src/touch-engine.c | 42 | ||||
| -rw-r--r-- | test/Makefile.am | 4 | ||||
| -rw-r--r-- | test/grail.c | 13 | ||||
| -rw-r--r-- | test/touch.c | 16 |
24 files changed, 1052 insertions, 386 deletions
diff --git a/include/grail-bits.h b/include/grail-bits.h new file mode 100644 index 0000000..ca04c3f --- /dev/null +++ b/include/grail-bits.h | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * grail - Gesture Recognition And Instantiation Library | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Canonical Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the | ||
| 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along | ||
| 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | * Authors: | ||
| 21 | * Henrik Rydberg <rydberg@bitmath.org> | ||
| 22 | * | ||
| 23 | ****************************************************************************/ | ||
| 24 | |||
| 25 | #ifndef _GRAIL_BITS_H | ||
| 26 | #define _GRAIL_BITS_H | ||
| 27 | |||
| 28 | typedef unsigned char grail_mask_t; | ||
| 29 | |||
| 30 | static inline void grail_mask_set(grail_mask_t *mask, int i) | ||
| 31 | { | ||
| 32 | mask[i >> 3] |= (1 << (i & 7)); | ||
| 33 | } | ||
| 34 | |||
| 35 | static inline void grail_mask_clear(grail_mask_t *mask, int i) | ||
| 36 | { | ||
| 37 | mask[i >> 3] &= ~(1 << (i & 7)); | ||
| 38 | } | ||
| 39 | |||
| 40 | static inline void grail_mask_modify(grail_mask_t *mask, int i, int v) | ||
| 41 | { | ||
| 42 | if (v) | ||
| 43 | grail_mask_set(mask, i); | ||
| 44 | else | ||
| 45 | grail_mask_clear(mask, i); | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline int grail_mask_get(const grail_mask_t *mask, int i) | ||
| 49 | { | ||
| 50 | return (mask[i >> 3] >> (i & 7)) & 1; | ||
| 51 | } | ||
| 52 | |||
| 53 | void grail_mask_set_mask(grail_mask_t *a, const grail_mask_t *b, int bytes); | ||
| 54 | void grail_mask_clear_mask(grail_mask_t *a, const grail_mask_t *b, int bytes); | ||
| 55 | |||
| 56 | int grail_mask_count(const grail_mask_t *mask, int bytes); | ||
| 57 | int grail_mask_get_first(const grail_mask_t *mask, int bytes); | ||
| 58 | int grail_mask_get_next(int i, const grail_mask_t *mask, int bytes); | ||
| 59 | |||
| 60 | #define grail_mask_foreach(i, mask, bytes) \ | ||
| 61 | for (i = grail_mask_get_first(mask, bytes); \ | ||
| 62 | i >= 0; \ | ||
| 63 | i = grail_mask_get_next(i, mask, bytes)) | ||
| 64 | |||
| 65 | #endif | ||
diff --git a/include/grail-touch.h b/include/grail-touch.h index e07ffca..5bf0034 100644 --- a/include/grail-touch.h +++ b/include/grail-touch.h | |||
| @@ -25,12 +25,13 @@ | |||
| 25 | #ifndef _GRAIL_TOUCH_H | 25 | #ifndef _GRAIL_TOUCH_H |
| 26 | #define _GRAIL_TOUCH_H | 26 | #define _GRAIL_TOUCH_H |
| 27 | 27 | ||
| 28 | #include <grail-bits.h> | ||
| 28 | #include <mtdev.h> | 29 | #include <mtdev.h> |
| 29 | 30 | ||
| 30 | #define DIM_TOUCHES 32 | 31 | #define DIM_TOUCH 32 |
| 32 | #define DIM_TOUCH_BYTES ((DIM_TOUCH + 7) >> 3) | ||
| 31 | 33 | ||
| 32 | typedef int touch_prop_t; | 34 | typedef int touch_prop_t; |
| 33 | typedef unsigned touch_prop_mask_t; | ||
| 34 | typedef __u64 touch_time_t; | 35 | typedef __u64 touch_time_t; |
| 35 | 36 | ||
| 36 | enum touch_prop_list { | 37 | enum touch_prop_list { |
| @@ -45,29 +46,37 @@ enum touch_prop_list { | |||
| 45 | DIM_TOUCH_PROP | 46 | DIM_TOUCH_PROP |
| 46 | }; | 47 | }; |
| 47 | 48 | ||
| 49 | #define DIM_TOUCH_PROP_BYTES ((DIM_TOUCH_PROP + 7) >> 3) | ||
| 50 | |||
| 48 | struct touch { | 51 | struct touch { |
| 49 | int active; | 52 | int active; |
| 50 | int slot; | 53 | int slot; |
| 51 | int next; | ||
| 52 | touch_prop_t prop[DIM_TOUCH_PROP]; | 54 | touch_prop_t prop[DIM_TOUCH_PROP]; |
| 53 | }; | 55 | }; |
| 54 | 56 | ||
| 55 | struct touch_frame { | 57 | struct touch_frame { |
| 56 | int ntouch; | 58 | int nactive; |
| 57 | int slot; | ||
| 58 | int ncreate, nmodify, ndestroy; | 59 | int ncreate, nmodify, ndestroy; |
| 59 | touch_time_t time; | 60 | touch_time_t time; |
| 60 | struct touch touch[DIM_TOUCHES]; | 61 | grail_mask_t touches[DIM_TOUCH_BYTES]; |
| 62 | struct touch *active[DIM_TOUCH]; | ||
| 63 | struct touch touch[DIM_TOUCH]; | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct touch_dev_caps { | ||
| 67 | grail_mask_t mask[DIM_TOUCH_PROP_BYTES]; | ||
| 68 | struct input_absinfo info[DIM_TOUCH_PROP]; | ||
| 61 | }; | 69 | }; |
| 62 | 70 | ||
| 63 | struct touch_dev { | 71 | struct touch_dev { |
| 64 | void (*event)(struct touch_dev *dev, const struct input_event *ev); | 72 | void (*event)(struct touch_dev *dev, const struct input_event *ev); |
| 65 | void (*create)(struct touch_dev *dev, int slot, | 73 | void (*create)(struct touch_dev *dev, int slot, |
| 66 | const touch_prop_mask_t *mask, const touch_prop_t *prop); | 74 | const grail_mask_t *mask, const touch_prop_t *prop); |
| 67 | void (*modify)(struct touch_dev *dev, int slot, | 75 | void (*modify)(struct touch_dev *dev, int slot, |
| 68 | const touch_prop_mask_t *mask, const touch_prop_t *prop); | 76 | const grail_mask_t *mask, const touch_prop_t *prop); |
| 69 | void (*destroy)(struct touch_dev *dev, int slot); | 77 | void (*destroy)(struct touch_dev *dev, int slot); |
| 70 | void (*sync)(struct touch_dev *dev, const struct input_event *syn); | 78 | void (*sync)(struct touch_dev *dev, const struct input_event *syn); |
| 79 | struct touch_dev_caps caps; | ||
| 71 | struct touch_dev_impl *impl; | 80 | struct touch_dev_impl *impl; |
| 72 | void *priv; | 81 | void *priv; |
| 73 | }; | 82 | }; |
| @@ -81,16 +90,6 @@ struct touch_engine { | |||
| 81 | void *priv; | 90 | void *priv; |
| 82 | }; | 91 | }; |
| 83 | 92 | ||
| 84 | static inline int has_prop(const touch_prop_mask_t *mask, int code) | ||
| 85 | { | ||
| 86 | return (mask[code >> 5] >> (code & 31)) & 1; | ||
| 87 | } | ||
| 88 | |||
| 89 | static inline int next_slot(const struct touch_frame *frame, int slot) | ||
| 90 | { | ||
| 91 | return frame->touch[slot].next; | ||
| 92 | } | ||
| 93 | |||
| 94 | int touch_dev_open(struct touch_dev *dev, int fd); | 93 | int touch_dev_open(struct touch_dev *dev, int fd); |
| 95 | int touch_dev_idle(struct touch_dev *dev, int fd, int ms); | 94 | int touch_dev_idle(struct touch_dev *dev, int fd, int ms); |
| 96 | int touch_dev_fetch(struct touch_dev *dev, int fd); | 95 | int touch_dev_fetch(struct touch_dev *dev, int fd); |
diff --git a/include/grail.h b/include/grail.h index de202b5..0570101 100644 --- a/include/grail.h +++ b/include/grail.h | |||
| @@ -25,50 +25,30 @@ | |||
| 25 | #ifndef _GRAIL_H | 25 | #ifndef _GRAIL_H |
| 26 | #define _GRAIL_H | 26 | #define _GRAIL_H |
| 27 | 27 | ||
| 28 | #include <grail-bits.h> | ||
| 28 | #include <linux/input.h> | 29 | #include <linux/input.h> |
| 29 | 30 | ||
| 30 | #define GRAIL_STATUS_BEGIN 0 | ||
| 31 | #define GRAIL_STATUS_UPDATE 1 | ||
| 32 | #define GRAIL_STATUS_END 2 | ||
| 33 | |||
| 34 | #define DIM_GRAIL_TYPE 64 | 31 | #define DIM_GRAIL_TYPE 64 |
| 35 | #define DIM_GRAIL_TYPE_BYTES (DIM_GRAIL_TYPE >> 3) | 32 | #define DIM_GRAIL_TYPE_BYTES ((DIM_GRAIL_TYPE + 7) >> 3) |
| 36 | 33 | ||
| 37 | #define GRAIL_TYPE_MOVE 0 | 34 | #define DIM_GRAIL_PROP 16 |
| 38 | #define GRAIL_TYPE_VSCROLL 1 | 35 | #define DIM_GRAIL_PROP_BYTES ((DIM_GRAIL_PROP + 7) >> 3) |
| 39 | #define GRAIL_TYPE_HSCROLL 2 | ||
| 40 | #define GRAIL_TYPE_SCROLL 3 | ||
| 41 | 36 | ||
| 42 | #define DIM_GRAIL_PROP 8 | 37 | #define GRAIL_TYPE_MOVE 0 |
| 38 | #define GRAIL_TYPE_SCROLL 1 | ||
| 39 | #define GRAIL_TYPE_ZOOM 2 | ||
| 40 | #define GRAIL_TYPE_ROTATE 3 | ||
| 41 | #define GRAIL_TYPE_SZRCOMBO 4 | ||
| 43 | 42 | ||
| 44 | static const int GRAIL_NPROP[] = { | 43 | #define GRAIL_STATUS_BEGIN 0 |
| 45 | 2, /* MOVE */ | 44 | #define GRAIL_STATUS_UPDATE 1 |
| 46 | 1, /* VSCROLL */ | 45 | #define GRAIL_STATUS_END 2 |
| 47 | 1, /* HSCROLL */ | ||
| 48 | 2, /* SCROLL */ | ||
| 49 | }; | ||
| 50 | 46 | ||
| 51 | typedef unsigned char grail_mask_t; | 47 | typedef float grail_prop_t; |
| 52 | typedef int grail_prop_t; | ||
| 53 | typedef __u64 grail_time_t; | 48 | typedef __u64 grail_time_t; |
| 54 | 49 | ||
| 55 | static inline void grail_set_mask(grail_mask_t *mask, int i) | ||
| 56 | { | ||
| 57 | mask[i >> 3] |= (1 << (i & 7)); | ||
| 58 | } | ||
| 59 | |||
| 60 | static inline void grail_clear_mask(grail_mask_t *mask, int i) | ||
| 61 | { | ||
| 62 | mask[i >> 3] &= ~(1 << (i & 7)); | ||
| 63 | } | ||
| 64 | |||
| 65 | static inline int grail_get_mask(const grail_mask_t *mask, int i) | ||
| 66 | { | ||
| 67 | return (mask[i >> 3] >> (i & 7)) & 1; | ||
| 68 | } | ||
| 69 | |||
| 70 | struct grail_coord { | 50 | struct grail_coord { |
| 71 | int x, y; | 51 | float x, y; |
| 72 | }; | 52 | }; |
| 73 | 53 | ||
| 74 | struct grail_client_id { | 54 | struct grail_client_id { |
| @@ -85,6 +65,8 @@ struct grail_event { | |||
| 85 | int type; | 65 | int type; |
| 86 | int id; | 66 | int id; |
| 87 | int status; | 67 | int status; |
| 68 | int ntouch; | ||
| 69 | int nprop; | ||
| 88 | struct grail_coord pos; | 70 | struct grail_coord pos; |
| 89 | struct grail_client_id client_id; | 71 | struct grail_client_id client_id; |
| 90 | grail_time_t time; | 72 | grail_time_t time; |
| @@ -95,7 +77,7 @@ struct grail { | |||
| 95 | int (*get_clients)(struct grail *ge, | 77 | int (*get_clients)(struct grail *ge, |
| 96 | struct grail_client_info *client, int max_clients, | 78 | struct grail_client_info *client, int max_clients, |
| 97 | const struct grail_coord *coords, int num_coords, | 79 | const struct grail_coord *coords, int num_coords, |
| 98 | const grail_mask_t *types); | 80 | const grail_mask_t *types, int num_types); |
| 99 | void (*event)(struct grail *ge, | 81 | void (*event)(struct grail *ge, |
| 100 | const struct input_event *ev); | 82 | const struct input_event *ev); |
| 101 | void (*gesture)(struct grail *ge, | 83 | void (*gesture)(struct grail *ge, |
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 = \ | |||
| 7 | libgrail_la_SOURCES = \ | 7 | libgrail_la_SOURCES = \ |
| 8 | touch-dev.c \ | 8 | touch-dev.c \ |
| 9 | touch-engine.c \ | 9 | touch-engine.c \ |
| 10 | grail-bits.c \ | ||
| 10 | grail-inserter.c \ | 11 | grail-inserter.c \ |
| 12 | grail-gestures.c \ | ||
| 13 | gestures-scroll.c \ | ||
| 14 | gestures-zoom.c \ | ||
| 15 | gestures-rotate.c \ | ||
| 16 | gestures-combo.c \ | ||
| 11 | grail-recognizer.c \ | 17 | grail-recognizer.c \ |
| 12 | grail-api.c | 18 | grail-api.c |
| 13 | 19 | ||
| @@ -17,5 +23,6 @@ INCLUDES = -I$(top_srcdir)/include/ | |||
| 17 | 23 | ||
| 18 | libgrailincludedir = $(includedir) | 24 | libgrailincludedir = $(includedir) |
| 19 | libgrailinclude_HEADERS = \ | 25 | libgrailinclude_HEADERS = \ |
| 26 | $(top_srcdir)/include/grail-bits.h \ | ||
| 20 | $(top_srcdir)/include/grail-touch.h \ | 27 | $(top_srcdir)/include/grail-touch.h \ |
| 21 | $(top_srcdir)/include/grail.h | 28 | $(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 @@ | |||
| 30 | #define DIM_GESTURE_EVENTS 512 | 30 | #define DIM_GESTURE_EVENTS 512 |
| 31 | 31 | ||
| 32 | struct gesture_event { | 32 | struct gesture_event { |
| 33 | int ntouch; | ||
| 34 | int nprop; | ||
| 33 | touch_time_t time; | 35 | touch_time_t time; |
| 36 | struct grail_coord pos; | ||
| 34 | grail_prop_t prop[DIM_GRAIL_PROP]; | 37 | grail_prop_t prop[DIM_GRAIL_PROP]; |
| 35 | }; | 38 | }; |
| 36 | 39 | ||
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 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * grail - Gesture Recognition And Instantiation Library | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Canonical Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the | ||
| 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along | ||
| 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | * Authors: | ||
| 21 | * Henrik Rydberg <rydberg@bitmath.org> | ||
| 22 | * | ||
| 23 | ****************************************************************************/ | ||
| 24 | |||
| 25 | #include "grail-recognizer.h" | ||
| 26 | #include <math.h> | ||
| 27 | #include <stdio.h> | ||
| 28 | |||
| 29 | void gru_reset_combo(struct grail *ge, | ||
| 30 | const struct touch_frame *frame) | ||
| 31 | { | ||
| 32 | struct gesture_inserter *gin = ge->gin; | ||
| 33 | struct gesture_recognizer *gru = ge->gru; | ||
| 34 | struct combo_model *state = &gru->combo; | ||
| 35 | struct move_model *move = &gru->move; | ||
| 36 | gin_gesture_discard_type(gin, GRAIL_TYPE_SZRCOMBO); | ||
| 37 | state->r = move->r; | ||
| 38 | state->active = 0; | ||
| 39 | state->running = 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | int gru_combo(struct grail *ge, | ||
| 43 | const struct touch_frame *frame) | ||
| 44 | { | ||
| 45 | struct gesture_inserter *gin = ge->gin; | ||
| 46 | struct gesture_recognizer *gru = ge->gru; | ||
| 47 | struct combo_model *state = &gru->combo; | ||
| 48 | struct move_model *move = &gru->move; | ||
| 49 | grail_prop_t prop[DIM_GRAIL_PROP]; | ||
| 50 | float dx, dy, dr, da; | ||
| 51 | int i; | ||
| 52 | dx = move->x - state->x; | ||
| 53 | dy = move->y - state->y; | ||
| 54 | dr = move->r - state->r; | ||
| 55 | da = move->a - state->a; | ||
| 56 | if (fabs(dx) < 1 && fabs(dy) < 1 && fabs(da) < 1 && fabs(dr) < 1) | ||
| 57 | return 0; | ||
| 58 | if (!state->active) { | ||
| 59 | i = gin_gesture_begin(ge, | ||
| 60 | GRAIL_TYPE_SZRCOMBO, 2, | ||
| 61 | frame->touches, sizeof(frame->touches)); | ||
| 62 | state->geslot = i; | ||
| 63 | state->active = 1; | ||
| 64 | } | ||
| 65 | if (!state->running && | ||
| 66 | fabs(dx) < move->xbar && fabs(dy) < move->ybar && | ||
| 67 | fabs(da) < move->abar && fabs(dr) < move->rbar) | ||
| 68 | return 0; | ||
| 69 | state->running = 1; | ||
| 70 | prop[0] = dx; | ||
| 71 | prop[1] = dy; | ||
| 72 | prop[2] = dr; | ||
| 73 | prop[3] = da; | ||
| 74 | gin_gesture_event(gin, state->geslot, | ||
| 75 | move->x, move->y, move->ntouch, | ||
| 76 | prop, 4); | ||
| 77 | state->x = move->x; | ||
| 78 | state->y = move->y; | ||
| 79 | state->r = move->r; | ||
| 80 | state->a = move->a; | ||
| 81 | return 1; | ||
| 82 | } | ||
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 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * grail - Gesture Recognition And Instantiation Library | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Canonical Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the | ||
| 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along | ||
| 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | * Authors: | ||
| 21 | * Henrik Rydberg <rydberg@bitmath.org> | ||
| 22 | * | ||
| 23 | ****************************************************************************/ | ||
| 24 | |||
| 25 | #include "grail-recognizer.h" | ||
| 26 | #include <math.h> | ||
| 27 | #include <stdio.h> | ||
| 28 | |||
| 29 | void gru_reset_rotate(struct grail *ge, | ||
| 30 | const struct touch_frame *frame) | ||
| 31 | { | ||
| 32 | struct gesture_inserter *gin = ge->gin; | ||
| 33 | struct gesture_recognizer *gru = ge->gru; | ||
| 34 | struct rotate_model *state = &gru->rotate; | ||
| 35 | struct move_model *move = &gru->move; | ||
| 36 | gin_gesture_discard_type(gin, GRAIL_TYPE_ROTATE); | ||
| 37 | state->a = move->a; | ||
| 38 | state->active = 0; | ||
| 39 | state->rotating = 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | int gru_rotate(struct grail *ge, | ||
| 43 | const struct touch_frame *frame) | ||
| 44 | { | ||
| 45 | struct gesture_inserter *gin = ge->gin; | ||
| 46 | struct gesture_recognizer *gru = ge->gru; | ||
| 47 | struct rotate_model *state = &gru->rotate; | ||
| 48 | struct move_model *move = &gru->move; | ||
| 49 | grail_prop_t prop[DIM_GRAIL_PROP]; | ||
| 50 | float da; | ||
| 51 | int i; | ||
| 52 | da = move->a - state->a; | ||
| 53 | if (fabs(da) < 1) | ||
| 54 | return 0; | ||
| 55 | if (!state->active) { | ||
| 56 | i = gin_gesture_begin(ge, | ||
| 57 | GRAIL_TYPE_ROTATE, 1, | ||
| 58 | frame->touches, sizeof(frame->touches)); | ||
| 59 | state->geslot = i; | ||
| 60 | state->active = 1; | ||
| 61 | } | ||
| 62 | if (!state->rotating && fabs(da) < move->abar) | ||
| 63 | return 0; | ||
| 64 | state->rotating = 1; | ||
| 65 | prop[0] = da; | ||
| 66 | gin_gesture_event(gin, state->geslot, | ||
| 67 | move->x, move->y, move->ntouch, | ||
| 68 | prop, 1); | ||
| 69 | state->a = move->a; | ||
| 70 | return 1; | ||
| 71 | } | ||
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 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * grail - Gesture Recognition And Instantiation Library | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Canonical Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the | ||
| 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along | ||
| 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | * Authors: | ||
| 21 | * Henrik Rydberg <rydberg@bitmath.org> | ||
| 22 | * | ||
| 23 | ****************************************************************************/ | ||
| 24 | |||
| 25 | #include "grail-recognizer.h" | ||
| 26 | #include <math.h> | ||
| 27 | |||
| 28 | void gru_reset_scroll(struct grail *ge, | ||
| 29 | const struct touch_frame *frame) | ||
| 30 | { | ||
| 31 | struct gesture_inserter *gin = ge->gin; | ||
| 32 | struct gesture_recognizer *gru = ge->gru; | ||
| 33 | struct scroll_model *state = &gru->scroll; | ||
| 34 | struct move_model *move = &gru->move; | ||
| 35 | gin_gesture_discard_type(gin, GRAIL_TYPE_SCROLL); | ||
| 36 | state->x = move->x; | ||
| 37 | state->y = move->y; | ||
| 38 | state->active = 0; | ||
| 39 | state->moving = 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | int gru_scroll(struct grail *ge, | ||
| 43 | const struct touch_frame *frame) | ||
| 44 | { | ||
| 45 | struct gesture_inserter *gin = ge->gin; | ||
| 46 | struct gesture_recognizer *gru = ge->gru; | ||
| 47 | struct scroll_model *state = &gru->scroll; | ||
| 48 | struct move_model *move = &gru->move; | ||
| 49 | grail_prop_t prop[DIM_GRAIL_PROP]; | ||
| 50 | float dx, dy; | ||
| 51 | int i; | ||
| 52 | dx = move->x - state->x; | ||
| 53 | dy = move->y - state->y; | ||
| 54 | if (fabs(dx) < 1 && fabs(dy) < 1) | ||
| 55 | return 0; | ||
| 56 | if (!state->active) { | ||
| 57 | i = gin_gesture_begin(ge, GRAIL_TYPE_SCROLL, 1, | ||
| 58 | frame->touches, sizeof(frame->touches)); | ||
| 59 | state->geslot = i; | ||
| 60 | state->active = 1; | ||
| 61 | } | ||
| 62 | if (!state->moving && fabs(dx) < move->xbar && fabs(dy) < move->ybar) | ||
| 63 | return 0; | ||
| 64 | state->moving = 1; | ||
| 65 | prop[0] = dx; | ||
| 66 | prop[1] = dy; | ||
| 67 | gin_gesture_event(gin, state->geslot, | ||
| 68 | move->x, move->y, move->ntouch, | ||
| 69 | prop, 2); | ||
| 70 | state->x = move->x; | ||
| 71 | state->y = move->y; | ||
| 72 | return 1; | ||
| 73 | } | ||
| 74 | |||
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 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * grail - Gesture Recognition And Instantiation Library | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Canonical Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the | ||
| 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along | ||
| 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | * Authors: | ||
| 21 | * Henrik Rydberg <rydberg@bitmath.org> | ||
| 22 | * | ||
| 23 | ****************************************************************************/ | ||
| 24 | |||
| 25 | #include "grail-recognizer.h" | ||
| 26 | #include <math.h> | ||
| 27 | #include <stdio.h> | ||
| 28 | |||
| 29 | void gru_reset_zoom(struct grail *ge, | ||
| 30 | const struct touch_frame *frame) | ||
| 31 | { | ||
| 32 | struct gesture_inserter *gin = ge->gin; | ||
| 33 | struct gesture_recognizer *gru = ge->gru; | ||
| 34 | struct zoom_model *state = &gru->zoom; | ||
| 35 | struct move_model *move = &gru->move; | ||
| 36 | gin_gesture_discard_type(gin, GRAIL_TYPE_ZOOM); | ||
| 37 | state->r = move->r; | ||
| 38 | state->active = 0; | ||
| 39 | state->zooming = 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | int gru_zoom(struct grail *ge, | ||
| 43 | const struct touch_frame *frame) | ||
| 44 | { | ||
| 45 | struct gesture_inserter *gin = ge->gin; | ||
| 46 | struct gesture_recognizer *gru = ge->gru; | ||
| 47 | struct zoom_model *state = &gru->zoom; | ||
| 48 | struct move_model *move = &gru->move; | ||
| 49 | grail_prop_t prop[DIM_GRAIL_PROP]; | ||
| 50 | float dr; | ||
| 51 | int i; | ||
| 52 | dr = move->r - state->r; | ||
| 53 | if (fabs(dr) < 1) | ||
| 54 | return 0; | ||
| 55 | if (!state->active) { | ||
| 56 | i = gin_gesture_begin(ge, | ||
| 57 | GRAIL_TYPE_ZOOM, 1, | ||
| 58 | frame->touches, sizeof(frame->touches)); | ||
| 59 | state->geslot = i; | ||
| 60 | state->active = 1; | ||
| 61 | } | ||
| 62 | if (!state->zooming && fabs(dr) < move->rbar) | ||
| 63 | return 0; | ||
| 64 | state->zooming = 1; | ||
| 65 | prop[0] = dr; | ||
| 66 | gin_gesture_event(gin, state->geslot, | ||
| 67 | move->x, move->y, move->ntouch, | ||
| 68 | prop, 1); | ||
| 69 | state->r = move->r; | ||
| 70 | return 1; | ||
| 71 | } | ||
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, | |||
| 70 | struct touch_frame *frame = &engine->frame; | 70 | struct touch_frame *frame = &engine->frame; |
| 71 | grail_mask_t filtered[DIM_EV_TYPE_BYTES]; | 71 | grail_mask_t filtered[DIM_EV_TYPE_BYTES]; |
| 72 | int nevent = 0; | 72 | int nevent = 0; |
| 73 | gin_frame_begin(ge, frame->time); | 73 | gin_frame_begin(ge, frame); |
| 74 | gru_recognize(ge, frame); | 74 | gru_recognize(ge, frame); |
| 75 | gin_frame_end(ge, filtered); | 75 | gin_frame_end(ge, filtered, sizeof(filtered), frame); |
| 76 | if (!ge->event) { | 76 | if (!ge->event) { |
| 77 | evbuf_clear(&x->evbuf); | 77 | evbuf_clear(&x->evbuf); |
| 78 | return; | 78 | return; |
| 79 | } | 79 | } |
| 80 | while (!evbuf_empty(&x->evbuf)) { | 80 | while (!evbuf_empty(&x->evbuf)) { |
| 81 | evbuf_get(&x->evbuf, &ev); | 81 | evbuf_get(&x->evbuf, &ev); |
| 82 | if (grail_get_mask(filtered, ev.type)) | 82 | if (grail_mask_get(filtered, ev.type)) |
| 83 | continue; | 83 | continue; |
| 84 | ge->event(ge, &ev); | 84 | ge->event(ge, &ev); |
| 85 | nevent++; | 85 | nevent++; |
| @@ -98,27 +98,27 @@ int grail_open(struct grail *ge, int fd) | |||
| 98 | ret = gin_init(ge); | 98 | ret = gin_init(ge); |
| 99 | if (ret) | 99 | if (ret) |
| 100 | goto freemem; | 100 | goto freemem; |
| 101 | ret = gru_init(ge); | ||
| 102 | if (ret) | ||
| 103 | goto freedev; | ||
| 104 | ret = touch_dev_open(&x->dev, fd); | 101 | ret = touch_dev_open(&x->dev, fd); |
| 105 | if (ret) | 102 | if (ret) |
| 106 | goto freegru; | 103 | goto freegin; |
| 104 | ret = gru_init(ge, &x->dev.caps); | ||
| 105 | if (ret) | ||
| 106 | goto freedev; | ||
| 107 | x->fd = fd; | 107 | x->fd = fd; |
| 108 | x->mutex = c_mutex; | 108 | x->mutex = c_mutex; |
| 109 | x->wait = c_wait; | 109 | x->wait = c_wait; |
| 110 | ret = pthread_create(&x->thread, NULL, grail_thread, x); | 110 | ret = pthread_create(&x->thread, NULL, grail_thread, x); |
| 111 | if (ret) | 111 | if (ret) |
| 112 | goto freetouch; | 112 | goto freegru; |
| 113 | ge->impl = x; | 113 | ge->impl = x; |
| 114 | touch_engine_init(&x->engine, tp_event, tp_sync, ge); | 114 | touch_engine_init(&x->engine, tp_event, tp_sync, ge); |
| 115 | touch_engine_attach(&x->engine, &x->dev); | 115 | touch_engine_attach(&x->engine, &x->dev); |
| 116 | return 0; | 116 | return 0; |
| 117 | freetouch: | ||
| 118 | touch_dev_close(&x->dev, fd); | ||
| 119 | freegru: | 117 | freegru: |
| 120 | gru_destroy(ge); | 118 | gru_destroy(ge); |
| 121 | freedev: | 119 | freedev: |
| 120 | touch_dev_close(&x->dev, fd); | ||
| 121 | freegin: | ||
| 122 | gin_destroy(ge); | 122 | gin_destroy(ge); |
| 123 | freemem: | 123 | freemem: |
| 124 | free(x); | 124 | free(x); |
| @@ -134,8 +134,8 @@ void grail_close(struct grail *ge, int fd) | |||
| 134 | pthread_cond_signal (&x->wait); | 134 | pthread_cond_signal (&x->wait); |
| 135 | pthread_mutex_unlock(&x->mutex); | 135 | pthread_mutex_unlock(&x->mutex); |
| 136 | touch_engine_detach(&x->engine, &x->dev); | 136 | touch_engine_detach(&x->engine, &x->dev); |
| 137 | touch_dev_close(&x->dev, fd); | ||
| 138 | gru_destroy(ge); | 137 | gru_destroy(ge); |
| 138 | touch_dev_close(&x->dev, fd); | ||
| 139 | gin_destroy(ge); | 139 | gin_destroy(ge); |
| 140 | free(ge->impl); | 140 | free(ge->impl); |
| 141 | ge->impl = 0; | 141 | 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 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * grail - Gesture Recognition And Instantiation Library | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Canonical Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the | ||
| 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along | ||
| 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | * Authors: | ||
| 21 | * Henrik Rydberg <rydberg@bitmath.org> | ||
| 22 | * | ||
| 23 | ****************************************************************************/ | ||
| 24 | |||
| 25 | #include "grail-bits.h" | ||
| 26 | |||
| 27 | static const int grail_bits_in_byte[256] = | ||
| 28 | { | ||
| 29 | 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, | ||
| 30 | 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, | ||
| 31 | 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, | ||
| 32 | 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, | ||
| 33 | 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, | ||
| 34 | 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, | ||
| 35 | 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, | ||
| 36 | 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, | ||
| 37 | }; | ||
| 38 | |||
| 39 | static const int grail_first_set_bit[256] = | ||
| 40 | { | ||
| 41 | -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, | ||
| 42 | 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, | ||
| 43 | 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, | ||
| 44 | 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, | ||
| 45 | 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, | ||
| 46 | 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, | ||
| 47 | 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, | ||
| 48 | 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, | ||
| 49 | }; | ||
| 50 | |||
| 51 | void grail_mask_set_mask(grail_mask_t *a, const grail_mask_t *b, int bytes) | ||
| 52 | { | ||
| 53 | while (bytes--) | ||
| 54 | *a++ |= *b++; | ||
| 55 | } | ||
| 56 | |||
| 57 | void grail_mask_clear_mask(grail_mask_t *a, const grail_mask_t *b, int bytes) | ||
| 58 | { | ||
| 59 | while (bytes--) | ||
| 60 | *a++ &= ~*b++; | ||
| 61 | } | ||
| 62 | |||
| 63 | int grail_mask_count(const grail_mask_t *mask, int bytes) | ||
| 64 | { | ||
| 65 | int count = 0; | ||
| 66 | while (bytes--) | ||
| 67 | count += grail_bits_in_byte[*mask++]; | ||
| 68 | return count; | ||
| 69 | } | ||
| 70 | |||
| 71 | int grail_mask_get_first(const grail_mask_t *mask, int bytes) | ||
| 72 | { | ||
| 73 | int k; | ||
| 74 | for (k = 0; k < bytes; k++) | ||
| 75 | if (mask[k]) | ||
| 76 | return (k << 3) | grail_first_set_bit[mask[k]]; | ||
| 77 | return -1; | ||
| 78 | } | ||
| 79 | |||
| 80 | int grail_mask_get_next(int i, const grail_mask_t *mask, int bytes) | ||
| 81 | { | ||
| 82 | int k = ++i >> 3; | ||
| 83 | if (k < bytes) { | ||
| 84 | i = grail_first_set_bit[mask[k] & (~0 << (i & 7))]; | ||
| 85 | if (i >= 0) | ||
| 86 | return (k << 3) | i; | ||
| 87 | while (++k < bytes) { | ||
| 88 | i = grail_first_set_bit[mask[k]]; | ||
| 89 | if (i >= 0) | ||
| 90 | return (k << 3) | i; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | return -1; | ||
| 94 | } | ||
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 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * grail - Gesture Recognition And Instantiation Library | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Canonical Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the | ||
| 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along | ||
| 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | * Authors: | ||
| 21 | * Henrik Rydberg <rydberg@bitmath.org> | ||
| 22 | * | ||
| 23 | ****************************************************************************/ | ||
| 24 | |||
| 25 | #include "grail-recognizer.h" | ||
| 26 | #include <math.h> | ||
| 27 | |||
| 28 | static const float SN_MOVE = 50; | ||
| 29 | static const float SN_ZOOM = 50; | ||
| 30 | static const float SN_ROTATE = 200; | ||
| 31 | static const float BAR_MOVE = 1; | ||
| 32 | static const float BAR_ZOOM = 2; | ||
| 33 | static const float BAR_ROTATE = 4; | ||
| 34 | |||
| 35 | static void compute_position(float *x, float *y, | ||
| 36 | const struct touch_frame *frame) | ||
| 37 | { | ||
| 38 | int i, n = frame->nactive; | ||
| 39 | *x = 0; | ||
| 40 | *y = 0; | ||
| 41 | if (n < 1) | ||
| 42 | return; | ||
| 43 | for (i = 0; i < n; i++) { | ||
| 44 | const struct touch *t = frame->active[i]; | ||
| 45 | *x += t->prop[TP_POS_X]; | ||
| 46 | *y += t->prop[TP_POS_Y]; | ||
| 47 | } | ||
| 48 | *x /= n; | ||
| 49 | *y /= n; | ||
| 50 | } | ||
| 51 | |||
| 52 | static float compute_radius(float x, float y, | ||
| 53 | const struct touch_frame *frame) | ||
| 54 | { | ||
| 55 | int i, n = frame->nactive; | ||
| 56 | float r = 0, r2 = 0; | ||
| 57 | if (n < 2) | ||
| 58 | return r; | ||
| 59 | for (i = 0; i < n; i++) { | ||
| 60 | const struct touch *t = frame->active[i]; | ||
| 61 | float dx = t->prop[TP_POS_X] - x; | ||
| 62 | float dy = t->prop[TP_POS_Y] - y; | ||
| 63 | r2 += dx * dx + dy * dy; | ||
| 64 | } | ||
| 65 | r2 /= n; | ||
| 66 | r = sqrt(r2); | ||
| 67 | return r; | ||
| 68 | } | ||
| 69 | |||
| 70 | static float compute_rotation(float x, float y, float r, | ||
| 71 | const struct touch_frame *prev, | ||
| 72 | const struct touch_frame *frame) | ||
| 73 | { | ||
| 74 | int i, n = frame->nactive; | ||
| 75 | float da = 0, da2 = 0; | ||
| 76 | if (n < 2) | ||
| 77 | return da; | ||
| 78 | for (i = 0; i < n; i++) { | ||
| 79 | const struct touch *t = frame->active[i]; | ||
| 80 | const struct touch *ot = &prev->touch[t->slot]; | ||
| 81 | float dx = t->prop[TP_POS_X] - x; | ||
| 82 | float dy = t->prop[TP_POS_Y] - y; | ||
| 83 | float mx = t->prop[TP_POS_X] - ot->prop[TP_POS_X]; | ||
| 84 | float my = t->prop[TP_POS_Y] - ot->prop[TP_POS_Y]; | ||
| 85 | da2 += dx * my - dy * mx; | ||
| 86 | } | ||
| 87 | da2 /= n; | ||
| 88 | da = da2 / r; | ||
| 89 | return da; | ||
| 90 | } | ||
| 91 | |||
| 92 | static float move_filter(float x, float x0, float fuzz) | ||
| 93 | { | ||
| 94 | if (x > x0 - fuzz / 2 && x < x0 + fuzz / 2) | ||
| 95 | return x0; | ||
| 96 | if (x > x0 - fuzz && x < x0 + fuzz) | ||
| 97 | return (x0 * 3 + x) / 4; | ||
| 98 | if (x > x0 - fuzz * 2 && x < x0 + fuzz * 2) | ||
| 99 | return (x0 + x) / 2; | ||
| 100 | return x; | ||
| 101 | } | ||
| 102 | |||
| 103 | void gru_init_motion(struct grail *ge, const struct touch_dev_caps *caps) | ||
| 104 | { | ||
| 105 | struct gesture_recognizer *gru = ge->gru; | ||
| 106 | struct move_model *state = &gru->move; | ||
| 107 | float x = caps->info[TP_POS_X].maximum - caps->info[TP_POS_X].minimum; | ||
| 108 | float y = caps->info[TP_POS_Y].maximum - caps->info[TP_POS_Y].minimum; | ||
| 109 | float r = sqrt(x * x + y * y); | ||
| 110 | state->xfuzz = x / SN_MOVE; | ||
| 111 | state->yfuzz = y / SN_MOVE; | ||
| 112 | state->rfuzz = r / SN_ZOOM; | ||
| 113 | state->afuzz = r / SN_ROTATE; | ||
| 114 | state->xbar = BAR_MOVE * state->xfuzz; | ||
| 115 | state->ybar = BAR_MOVE * state->yfuzz; | ||
| 116 | state->rbar = BAR_ZOOM * state->rfuzz; | ||
| 117 | state->abar = BAR_ROTATE * state->afuzz; | ||
| 118 | } | ||
| 119 | |||
| 120 | void gru_reset_motion(struct grail *ge, | ||
| 121 | const struct touch_frame *frame) | ||
| 122 | { | ||
| 123 | struct gesture_recognizer *gru = ge->gru; | ||
| 124 | struct move_model *state = &gru->move; | ||
| 125 | compute_position(&state->x, &state->y, frame); | ||
| 126 | state->r = compute_radius(state->x, state->y, frame); | ||
| 127 | state->a = 0; | ||
| 128 | state->ntouch = frame->nactive; | ||
| 129 | } | ||
| 130 | |||
| 131 | void gru_compute_motion(struct grail *ge, | ||
| 132 | const struct touch_frame *frame) | ||
| 133 | { | ||
| 134 | struct gesture_inserter *gin = ge->gin; | ||
| 135 | struct gesture_recognizer *gru = ge->gru; | ||
| 136 | struct move_model *state = &gru->move; | ||
| 137 | float x, y, r, a; | ||
| 138 | compute_position(&x, &y, frame); | ||
| 139 | x = move_filter(x, state->x, state->xfuzz); | ||
| 140 | y = move_filter(y, state->y, state->yfuzz); | ||
| 141 | r = compute_radius(x, y, frame); | ||
| 142 | r = move_filter(r, state->r, state->rfuzz); | ||
| 143 | a = state->a + compute_rotation(x, y, r, &gru->frame, frame); | ||
| 144 | a = move_filter(a, state->a, state->afuzz); | ||
| 145 | state->x = x; | ||
| 146 | state->y = y; | ||
| 147 | state->r = r; | ||
| 148 | state->a = a; | ||
| 149 | state->ntouch = frame->nactive; | ||
| 150 | } | ||
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 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * grail - Gesture Recognition And Instantiation Library | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Canonical Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the | ||
| 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along | ||
| 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | * Authors: | ||
| 21 | * Henrik Rydberg <rydberg@bitmath.org> | ||
| 22 | * | ||
| 23 | ****************************************************************************/ | ||
| 24 | |||
| 25 | #ifndef _GRAIL_GESTURES_H | ||
| 26 | #define _GRAIL_GESTURES_H | ||
| 27 | |||
| 28 | #include "grail-inserter.h" | ||
| 29 | |||
| 30 | struct move_model { | ||
| 31 | float xfuzz, yfuzz, rfuzz, afuzz; | ||
| 32 | float xbar, ybar, rbar, abar; | ||
| 33 | float x, y, r, a; | ||
| 34 | int ntouch; | ||
| 35 | }; | ||
| 36 | |||
| 37 | void gru_init_motion(struct grail *ge, | ||
| 38 | const struct touch_dev_caps *caps); | ||
| 39 | void gru_reset_motion(struct grail *ge, | ||
| 40 | const struct touch_frame *frame); | ||
| 41 | void gru_compute_motion(struct grail *ge, | ||
| 42 | const struct touch_frame *frame); | ||
| 43 | |||
| 44 | struct scroll_model { | ||
| 45 | float x, y; | ||
| 46 | int active, moving, geslot; | ||
| 47 | }; | ||
| 48 | |||
| 49 | void gru_reset_scroll(struct grail *ge, | ||
| 50 | const struct touch_frame *frame); | ||
| 51 | int gru_scroll(struct grail *ge, | ||
| 52 | const struct touch_frame *frame); | ||
| 53 | |||
| 54 | struct zoom_model { | ||
| 55 | float r; | ||
| 56 | int active, zooming, geslot; | ||
| 57 | }; | ||
| 58 | |||
| 59 | void gru_reset_zoom(struct grail *ge, | ||
| 60 | const struct touch_frame *frame); | ||
| 61 | int gru_zoom(struct grail *ge, | ||
| 62 | const struct touch_frame *frame); | ||
| 63 | |||
| 64 | struct rotate_model { | ||
| 65 | float a; | ||
| 66 | int active, rotating, geslot; | ||
| 67 | }; | ||
| 68 | |||
| 69 | void gru_reset_rotate(struct grail *ge, | ||
| 70 | const struct touch_frame *frame); | ||
| 71 | int gru_rotate(struct grail *ge, | ||
| 72 | const struct touch_frame *frame); | ||
| 73 | |||
| 74 | struct combo_model { | ||
| 75 | float x, y, r, a; | ||
| 76 | int active, running, geslot; | ||
| 77 | }; | ||
| 78 | |||
| 79 | void gru_reset_combo(struct grail *ge, | ||
| 80 | const struct touch_frame *frame); | ||
| 81 | int gru_combo(struct grail *ge, | ||
| 82 | const struct touch_frame *frame); | ||
| 83 | |||
| 84 | #endif | ||
| 85 | |||
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 @@ | |||
| 29 | 29 | ||
| 30 | static const int MAX_GESTURE_ID = 0xfff; | 30 | static const int MAX_GESTURE_ID = 0xfff; |
| 31 | 31 | ||
| 32 | int gin_init(struct grail *ge) | ||
| 33 | { | ||
| 34 | struct gesture_inserter *x; | ||
| 35 | x = calloc(1, sizeof(*x)); | ||
| 36 | if (!x) | ||
| 37 | return -ENOMEM; | ||
| 38 | ge->gin = x; | ||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | void gin_destroy(struct grail *ge) | ||
| 43 | { | ||
| 44 | free(ge->gin); | ||
| 45 | ge->gin = NULL; | ||
| 46 | } | ||
| 47 | |||
| 48 | void gin_frame_begin(struct grail *ge, grail_time_t time) | ||
| 49 | { | ||
| 50 | struct gesture_inserter *gin = ge->gin; | ||
| 51 | gin->time = time; | ||
| 52 | } | ||
| 53 | |||
| 54 | static void send_event(struct grail *ge, struct slot_state *s, | 32 | static void send_event(struct grail *ge, struct slot_state *s, |
| 55 | const struct gesture_event *ev) | 33 | const struct gesture_event *ev) |
| 56 | { | 34 | { |
| @@ -61,124 +39,200 @@ static void send_event(struct grail *ge, struct slot_state *s, | |||
| 61 | gev.type = s->type; | 39 | gev.type = s->type; |
| 62 | gev.id = s->id; | 40 | gev.id = s->id; |
| 63 | gev.status = s->status; | 41 | gev.status = s->status; |
| 64 | gev.pos.x = s->x; | 42 | gev.ntouch = ev->ntouch; |
| 65 | gev.pos.y = s->x; | 43 | gev.nprop = ev->nprop; |
| 66 | gev.time = ev->time; | 44 | gev.time = ev->time; |
| 67 | memcpy(gev.prop, ev->prop, DIM_GRAIL_PROP * sizeof(gev.prop[0])); | 45 | gev.pos = ev->pos; |
| 46 | memcpy(gev.prop, ev->prop, ev->nprop * sizeof(grail_prop_t)); | ||
| 68 | for (i = 0; i < s->nclient; i++) { | 47 | for (i = 0; i < s->nclient; i++) { |
| 69 | gev.client_id = s->client_id[i]; | 48 | gev.client_id = s->client_id[i]; |
| 70 | ge->gesture(ge, &gev); | 49 | ge->gesture(ge, &gev); |
| 71 | } | 50 | } |
| 72 | } | 51 | } |
| 73 | 52 | ||
| 74 | void gin_frame_end(struct grail *ge, grail_mask_t *filtered) | 53 | // todo: spanning tree for multi-user case |
| 54 | static void setup_new_gestures(struct grail *ge, | ||
| 55 | const struct touch_frame *frame) | ||
| 75 | { | 56 | { |
| 76 | struct gesture_inserter *gin = ge->gin; | 57 | struct gesture_inserter *gin = ge->gin; |
| 77 | struct gesture_event ev; | 58 | grail_mask_t types[DIM_GRAIL_TYPE_BYTES]; |
| 78 | grail_mask_t span[DIM_SLOT_BYTES]; | 59 | grail_mask_t span[DIM_TOUCH_BYTES]; |
| 79 | int i, slot, spanned = 0; | 60 | struct grail_client_info info[DIM_CLIENT]; |
| 80 | memset(filtered, 0, DIM_EV_TYPE_BYTES); | 61 | int i, j, nclient = 0; |
| 62 | int nfresh = grail_mask_count(gin->fresh, sizeof(gin->fresh)); | ||
| 63 | if (!nfresh) | ||
| 64 | return; | ||
| 65 | |||
| 66 | memset(types, 0, sizeof(types)); | ||
| 81 | memset(span, 0, sizeof(span)); | 67 | memset(span, 0, sizeof(span)); |
| 82 | for (slot = 0; slot < DIM_SLOT; slot++) { | 68 | |
| 83 | struct slot_state *s = &gin->state[slot]; | 69 | grail_mask_foreach(i, gin->fresh, sizeof(gin->fresh)) { |
| 84 | if (!grail_get_mask(gin->used, slot)) | 70 | struct slot_state *s = &gin->state[i]; |
| 85 | continue; | 71 | grail_mask_set(types, s->type); |
| 72 | grail_mask_set_mask(span, s->span, sizeof(span)); | ||
| 73 | } | ||
| 74 | |||
| 75 | if (ge->get_clients) { | ||
| 76 | struct grail_coord coord[DIM_CLIENT]; | ||
| 77 | int ncoord = 0; | ||
| 78 | grail_mask_foreach(i, span, sizeof(span)) { | ||
| 79 | const struct touch *t = &frame->touch[i]; | ||
| 80 | coord[ncoord].x = t->prop[TP_POS_X]; | ||
| 81 | coord[ncoord].y = t->prop[TP_POS_Y]; | ||
| 82 | ncoord++; | ||
| 83 | } | ||
| 84 | nclient = ge->get_clients(ge, info, DIM_CLIENT, | ||
| 85 | coord, ncoord, types, sizeof(types)); | ||
| 86 | } | ||
| 87 | |||
| 88 | grail_mask_foreach(i, gin->fresh, sizeof(gin->fresh)) { | ||
| 89 | struct slot_state *s = &gin->state[i]; | ||
| 90 | s->nclient = 0; | ||
| 91 | for (j = 0; j < nclient; j++) { | ||
| 92 | if (!grail_mask_get(info[j].mask, s->type)) | ||
| 93 | continue; | ||
| 94 | s->client_id[s->nclient++] = info[j].id; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | memset(gin->fresh, 0, sizeof(gin->fresh)); | ||
| 99 | } | ||
| 100 | |||
| 101 | int gin_init(struct grail *ge) | ||
| 102 | { | ||
| 103 | struct gesture_inserter *gin; | ||
| 104 | int i; | ||
| 105 | gin = calloc(1, sizeof(*gin)); | ||
| 106 | if (!gin) | ||
| 107 | return -ENOMEM; | ||
| 108 | for (i = 0; i < DIM_INSTANCE; i++) | ||
| 109 | grail_mask_set(gin->unused, i); | ||
| 110 | ge->gin = gin; | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | void gin_destroy(struct grail *ge) | ||
| 115 | { | ||
| 116 | free(ge->gin); | ||
| 117 | ge->gin = NULL; | ||
| 118 | } | ||
| 119 | |||
| 120 | void gin_frame_begin(struct grail *ge, const struct touch_frame *frame) | ||
| 121 | { | ||
| 122 | struct gesture_inserter *gin = ge->gin; | ||
| 123 | gin->time = frame->time; | ||
| 124 | } | ||
| 125 | |||
| 126 | void gin_frame_end(struct grail *ge, | ||
| 127 | grail_mask_t *filtered, int max_filtered, | ||
| 128 | const struct touch_frame *frame) | ||
| 129 | { | ||
| 130 | struct gesture_inserter *gin = ge->gin; | ||
| 131 | grail_mask_t span[DIM_INSTANCE_BYTES]; | ||
| 132 | int i, hold = 0, discard = 0; | ||
| 133 | |||
| 134 | memset(filtered, 0, max_filtered); | ||
| 135 | memset(span, 0, sizeof(span)); | ||
| 136 | |||
| 137 | setup_new_gestures(ge, frame); | ||
| 138 | |||
| 139 | grail_mask_foreach(i, gin->used, sizeof(gin->used)) { | ||
| 140 | struct slot_state *s = &gin->state[i]; | ||
| 86 | if (!s->nclient) | 141 | if (!s->nclient) |
| 87 | gin_gesture_discard(gin, slot); | 142 | continue; |
| 143 | if (s->priority > hold) | ||
| 144 | hold = s->priority; | ||
| 145 | if (s->status == GRAIL_STATUS_BEGIN) | ||
| 146 | continue; | ||
| 147 | if (s->priority > discard) | ||
| 148 | discard = s->priority; | ||
| 88 | } | 149 | } |
| 89 | for (slot = 0; slot < DIM_SLOT; slot++) { | 150 | |
| 90 | struct slot_state *s = &gin->state[slot]; | 151 | grail_mask_foreach(i, gin->used, sizeof(gin->used)) { |
| 91 | if (!grail_get_mask(gin->used, slot)) | 152 | struct slot_state *s = &gin->state[i]; |
| 153 | if (!s->nclient || s->priority < discard) | ||
| 154 | gin_gesture_discard(gin, i); | ||
| 155 | } | ||
| 156 | |||
| 157 | grail_mask_foreach(i, gin->used, sizeof(gin->used)) { | ||
| 158 | struct slot_state *s = &gin->state[i]; | ||
| 159 | struct gesture_event ev; | ||
| 160 | grail_mask_set_mask(span, s->span, sizeof(span)); | ||
| 161 | if (s->priority < hold) | ||
| 92 | continue; | 162 | continue; |
| 93 | for (i = 0; i < DIM_SLOT_BYTES; i++) { | ||
| 94 | span[i] |= s->span[i]; | ||
| 95 | spanned += !!span[i]; | ||
| 96 | } | ||
| 97 | while (!gebuf_empty(&s->buf)) { | 163 | while (!gebuf_empty(&s->buf)) { |
| 98 | gebuf_get(&s->buf, &ev); | 164 | gebuf_get(&s->buf, &ev); |
| 99 | send_event(ge, s, &ev); | 165 | send_event(ge, s, &ev); |
| 100 | } | 166 | } |
| 101 | if (s->status == GRAIL_STATUS_BEGIN) | ||
| 102 | s->status = GRAIL_STATUS_UPDATE; | ||
| 103 | } | 167 | } |
| 104 | if (spanned) | 168 | |
| 105 | grail_set_mask(filtered, EV_ABS); | 169 | grail_mask_foreach(i, gin->used, sizeof(gin->used)) { |
| 170 | struct slot_state *s = &gin->state[i]; | ||
| 171 | if (s->status == GRAIL_STATUS_END) | ||
| 172 | gin_gesture_discard(gin, i); | ||
| 173 | } | ||
| 174 | |||
| 175 | if (grail_mask_count(span, sizeof(span))) | ||
| 176 | grail_mask_set(filtered, EV_ABS); | ||
| 106 | } | 177 | } |
| 107 | 178 | ||
| 108 | int gin_gesture_begin(struct grail *ge, const struct touch_frame *frame, | 179 | int gin_gesture_begin(struct grail *ge, int type, int priority, |
| 109 | int type, int x, int y, const grail_mask_t *span) | 180 | const grail_mask_t *span, int nspan) |
| 110 | { | 181 | { |
| 111 | struct grail_client_info info[DIM_CLIENT]; | ||
| 112 | struct grail_coord coord[DIM_CLIENT]; | ||
| 113 | struct gesture_inserter *gin = ge->gin; | 182 | struct gesture_inserter *gin = ge->gin; |
| 114 | struct slot_state *s; | 183 | struct slot_state *s; |
| 115 | int i, slot, nc, ncoord = 0; | 184 | int geslot = grail_mask_get_first(gin->unused, sizeof(gin->unused)); |
| 116 | for (slot = 0; slot < DIM_SLOT; slot++) | 185 | if (geslot < 0) |
| 117 | if (!grail_get_mask(gin->used, slot)) | ||
| 118 | break; | ||
| 119 | if (slot >= DIM_SLOT) | ||
| 120 | return -1; | 186 | return -1; |
| 121 | s = &gin->state[slot]; | 187 | s = &gin->state[geslot]; |
| 122 | s->type = type; | 188 | s->type = type; |
| 189 | s->priority = priority; | ||
| 123 | s->id = gin->gestureid++ & MAX_GESTURE_ID; | 190 | s->id = gin->gestureid++ & MAX_GESTURE_ID; |
| 124 | s->status = GRAIL_STATUS_BEGIN; | 191 | s->status = GRAIL_STATUS_BEGIN; |
| 125 | s->x = x; | ||
| 126 | s->y = y; | ||
| 127 | s->nclient = 0; | 192 | s->nclient = 0; |
| 128 | if (ge->get_clients) { | 193 | memcpy(s->span, span, nspan); |
| 129 | grail_mask_t tps[DIM_GRAIL_TYPE_BYTES]; | ||
| 130 | memset(tps, 0, sizeof(tps)); | ||
| 131 | grail_set_mask(tps, type); | ||
| 132 | for (i = 0; i < DIM_SLOT; i++) { | ||
| 133 | const struct touch *t = &frame->touch[i]; | ||
| 134 | if (!grail_get_mask(span, i)) | ||
| 135 | continue; | ||
| 136 | coord[ncoord].x = t->prop[TP_POS_X]; | ||
| 137 | coord[ncoord].y = t->prop[TP_POS_Y]; | ||
| 138 | ncoord++; | ||
| 139 | } | ||
| 140 | nc = ge->get_clients(ge, info, DIM_CLIENT, coord, ncoord, tps); | ||
| 141 | for (i = 0; i < nc; i++) { | ||
| 142 | if (!grail_get_mask(info[i].mask, type)) | ||
| 143 | continue; | ||
| 144 | s->client_id[s->nclient] = info[i].id; | ||
| 145 | s->nclient++; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | memcpy(s->span, span, sizeof(s->span)); | ||
| 149 | gebuf_clear(&s->buf); | 194 | gebuf_clear(&s->buf); |
| 150 | grail_set_mask(gin->used, slot); | 195 | grail_mask_clear(gin->unused, geslot); |
| 151 | return slot; | 196 | grail_mask_set(gin->fresh, geslot); |
| 197 | grail_mask_set(gin->used, geslot); | ||
| 198 | return geslot; | ||
| 152 | } | 199 | } |
| 153 | 200 | ||
| 154 | void gin_gesture_end(struct gesture_inserter *gin, int slot) | 201 | void gin_gesture_end(struct gesture_inserter *gin, int geslot) |
| 155 | { | 202 | { |
| 156 | struct slot_state *s = &gin->state[slot]; | 203 | gin->state[geslot].status = GRAIL_STATUS_END; |
| 157 | s->status = GRAIL_STATUS_END; | ||
| 158 | grail_clear_mask(gin->used, slot); | ||
| 159 | } | 204 | } |
| 160 | 205 | ||
| 161 | void gin_gesture_discard(struct gesture_inserter *gin, int slot) | 206 | void gin_gesture_discard(struct gesture_inserter *gin, int geslot) |
| 162 | { | 207 | { |
| 163 | struct slot_state *s = &gin->state[slot]; | 208 | gebuf_clear(&gin->state[geslot].buf); |
| 164 | gebuf_clear(&s->buf); | 209 | gin_gesture_end(gin, geslot); |
| 165 | gin_gesture_end(gin, slot); | 210 | grail_mask_clear(gin->used, geslot); |
| 211 | grail_mask_set(gin->unused, geslot); | ||
| 166 | } | 212 | } |
| 167 | 213 | ||
| 168 | void gin_gesture_end_all(struct gesture_inserter *gin) | 214 | void gin_gesture_discard_type(struct gesture_inserter *gin, int type) |
| 169 | { | 215 | { |
| 170 | int slot; | 216 | int i; |
| 171 | for (slot = 0; slot < DIM_SLOT; slot++) | 217 | grail_mask_foreach(i, gin->used, sizeof(gin->used)) |
| 172 | gin_gesture_end(gin, slot); | 218 | if (gin->state[i].type == type) |
| 219 | gin_gesture_discard(gin, i); | ||
| 173 | } | 220 | } |
| 174 | 221 | ||
| 175 | void gin_gesture_event(struct gesture_inserter *gin, int slot, | 222 | void gin_gesture_event(struct gesture_inserter *gin, int geslot, |
| 176 | const grail_prop_t *prop) | 223 | float x, float y, int ntouch, |
| 224 | const grail_prop_t *prop, int nprop) | ||
| 177 | { | 225 | { |
| 178 | struct slot_state *s = &gin->state[slot]; | 226 | struct slot_state *s = &gin->state[geslot]; |
| 179 | struct gesture_event ev; | 227 | struct gesture_event ev; |
| 228 | ev.ntouch = ntouch; | ||
| 229 | ev.nprop = nprop; | ||
| 180 | ev.time = gin->time; | 230 | ev.time = gin->time; |
| 181 | memcpy(ev.prop, prop, sizeof(ev.prop)); | 231 | ev.pos.x = x; |
| 232 | ev.pos.y = y; | ||
| 233 | memcpy(ev.prop, prop, nprop * sizeof(grail_prop_t)); | ||
| 234 | if (s->status == GRAIL_STATUS_BEGIN) | ||
| 235 | s->status = GRAIL_STATUS_UPDATE; | ||
| 182 | gebuf_put(&s->buf, &ev); | 236 | gebuf_put(&s->buf, &ev); |
| 183 | } | 237 | } |
| 184 | 238 | ||
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 @@ | |||
| 22 | * | 22 | * |
| 23 | ****************************************************************************/ | 23 | ****************************************************************************/ |
| 24 | 24 | ||
| 25 | #ifndef _GRAIL_GESTURE_H | 25 | #ifndef _GRAIL_INSERTER_H |
| 26 | #define _GRAIL_GESTURE_H | 26 | #define _GRAIL_INSERTER_H |
| 27 | 27 | ||
| 28 | #include <grail-touch.h> | 28 | #include <grail-touch.h> |
| 29 | #include <grail.h> | 29 | #include <grail.h> |
| 30 | #include "gebuf.h" | 30 | #include "gebuf.h" |
| 31 | 31 | ||
| 32 | #define DIM_EV_TYPE EV_CNT | 32 | #define DIM_EV_TYPE EV_CNT |
| 33 | #define DIM_EV_TYPE_BYTES (DIM_EV_TYPE >> 3) | 33 | #define DIM_EV_TYPE_BYTES ((DIM_EV_TYPE + 7) >> 3) |
| 34 | 34 | ||
| 35 | #define DIM_SLOT 32 | 35 | #define DIM_INSTANCE 32 |
| 36 | #define DIM_SLOT_BYTES (DIM_SLOT >> 3) | 36 | #define DIM_INSTANCE_BYTES ((DIM_INSTANCE + 7) >> 3) |
| 37 | 37 | ||
| 38 | #define DIM_CLIENT 32 | 38 | #define DIM_CLIENT 32 |
| 39 | 39 | ||
| 40 | struct slot_state { | 40 | struct slot_state { |
| 41 | int type, id, status, x, y, nclient; | 41 | int type; |
| 42 | int priority; | ||
| 43 | int id; | ||
| 44 | int status; | ||
| 45 | int nclient; | ||
| 42 | struct grail_client_id client_id[DIM_CLIENT]; | 46 | struct grail_client_id client_id[DIM_CLIENT]; |
| 43 | grail_mask_t span[DIM_SLOT_BYTES]; | 47 | grail_mask_t span[DIM_TOUCH_BYTES]; |
| 44 | struct gebuf buf; | 48 | struct gebuf buf; |
| 45 | }; | 49 | }; |
| 46 | 50 | ||
| 47 | struct gesture_inserter { | 51 | struct gesture_inserter { |
| 48 | struct slot_state state[DIM_SLOT]; | 52 | struct slot_state state[DIM_INSTANCE]; |
| 49 | grail_mask_t used[DIM_SLOT_BYTES]; | 53 | grail_mask_t unused[DIM_INSTANCE_BYTES]; |
| 54 | grail_mask_t fresh[DIM_INSTANCE_BYTES]; | ||
| 55 | grail_mask_t used[DIM_INSTANCE_BYTES]; | ||
| 50 | grail_time_t time; | 56 | grail_time_t time; |
| 51 | int gestureid; | 57 | int gestureid; |
| 52 | }; | 58 | }; |
| @@ -54,16 +60,18 @@ struct gesture_inserter { | |||
| 54 | int gin_init(struct grail *ge); | 60 | int gin_init(struct grail *ge); |
| 55 | void gin_destroy(struct grail *ge); | 61 | void gin_destroy(struct grail *ge); |
| 56 | 62 | ||
| 57 | void gin_frame_begin(struct grail *ge, grail_time_t time); | 63 | void gin_frame_begin(struct grail *ge, const struct touch_frame *frame); |
| 58 | void gin_frame_end(struct grail *ge, grail_mask_t *filtered); | 64 | void gin_frame_end(struct grail *ge, grail_mask_t *filtered, int max_filtered, |
| 65 | const struct touch_frame *frame); | ||
| 59 | 66 | ||
| 60 | int gin_gesture_begin(struct grail *ge, const struct touch_frame *frame, | 67 | int gin_gesture_begin(struct grail *ge, int type, int priority, |
| 61 | int type, int x, int y, const grail_mask_t *span); | 68 | const grail_mask_t *span, int nspan); |
| 62 | void gin_gesture_discard(struct gesture_inserter *gin, int slot); | 69 | void gin_gesture_end(struct gesture_inserter *gin, int geslot); |
| 63 | void gin_gesture_end(struct gesture_inserter *gin, int slot); | 70 | void gin_gesture_discard(struct gesture_inserter *gin, int geslot); |
| 64 | void gin_gesture_end_all(struct gesture_inserter *gin); | 71 | void gin_gesture_discard_type(struct gesture_inserter *gin, int type); |
| 65 | 72 | ||
| 66 | void gin_gesture_event(struct gesture_inserter *gin, int slot, | 73 | void gin_gesture_event(struct gesture_inserter *gin, int geslot, |
| 67 | const grail_prop_t *prop); | 74 | float x, float y, int ntouch, |
| 75 | const grail_prop_t *prop, int nprop); | ||
| 68 | 76 | ||
| 69 | #endif | 77 | #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 @@ | |||
| 22 | * | 22 | * |
| 23 | ****************************************************************************/ | 23 | ****************************************************************************/ |
| 24 | 24 | ||
| 25 | #include "grail-inserter.h" | 25 | #include "grail-recognizer.h" |
| 26 | #include <string.h> | 26 | #include <string.h> |
| 27 | #include <malloc.h> | 27 | #include <malloc.h> |
| 28 | #include <errno.h> | 28 | #include <errno.h> |
| 29 | 29 | ||
| 30 | struct gesture_recognizer { | 30 | static const touch_time_t DROP_TIMEOUT_MS = 100; |
| 31 | struct touch_frame frame; | ||
| 32 | touch_time_t scroll_time; | ||
| 33 | int scroll_active; | ||
| 34 | int scroll_gslot; | ||
| 35 | int scroll_slots[2]; | ||
| 36 | }; | ||
| 37 | 31 | ||
| 38 | int gru_init(struct grail *ge) | 32 | int gru_init(struct grail *ge, const struct touch_dev_caps *caps) |
| 39 | { | 33 | { |
| 40 | ge->gru = calloc(1, sizeof(struct gesture_recognizer)); | 34 | struct gesture_recognizer *gru; |
| 41 | if (!ge->gru) | 35 | gru = calloc(1, sizeof(struct gesture_recognizer)); |
| 36 | if (!gru) | ||
| 42 | return -ENOMEM; | 37 | return -ENOMEM; |
| 38 | ge->gru = gru; | ||
| 39 | gru_init_motion(ge, caps); | ||
| 43 | return 0; | 40 | return 0; |
| 44 | } | 41 | } |
| 45 | 42 | ||
| @@ -49,49 +46,32 @@ void gru_destroy(struct grail *ge) | |||
| 49 | ge->gru = NULL; | 46 | ge->gru = NULL; |
| 50 | } | 47 | } |
| 51 | 48 | ||
| 49 | static void reset_gru_state(struct grail *ge, const struct touch_frame *frame) | ||
| 50 | { | ||
| 51 | gru_reset_combo(ge, frame); | ||
| 52 | gru_reset_rotate(ge, frame); | ||
| 53 | gru_reset_zoom(ge, frame); | ||
| 54 | gru_reset_scroll(ge, frame); | ||
| 55 | gru_reset_motion(ge, frame); | ||
| 56 | } | ||
| 57 | |||
| 52 | void gru_recognize(struct grail *ge, const struct touch_frame *frame) | 58 | void gru_recognize(struct grail *ge, const struct touch_frame *frame) |
| 53 | { | 59 | { |
| 54 | struct gesture_inserter *gin = ge->gin; | ||
| 55 | struct gesture_recognizer *gru = ge->gru; | 60 | struct gesture_recognizer *gru = ge->gru; |
| 56 | grail_prop_t prop[DIM_GRAIL_PROP]; | 61 | struct move_model *move = &gru->move; |
| 57 | grail_mask_t span[16]; | 62 | if (!ge->gin || !ge->gru) |
| 58 | int slot, nslot, x, y, dx, dy; | ||
| 59 | if (!gru) | ||
| 60 | return; | ||
| 61 | if (frame->ncreate || frame->ndestroy) { | ||
| 62 | gin_gesture_end_all(gin); | ||
| 63 | gru->scroll_active = 0; | ||
| 64 | return; | 63 | return; |
| 65 | } | 64 | if (frame->nactive < move->ntouch && |
| 66 | if (frame->ntouch != 2) | 65 | frame->time < gru->frame.time + DROP_TIMEOUT_MS) |
| 67 | return; | 66 | return; |
| 68 | memset(span, 0, sizeof(span)); | 67 | if (frame->nactive < 2 || frame->ncreate || frame->ndestroy) { |
| 69 | nslot = 0; | 68 | reset_gru_state(ge, frame); |
| 70 | x = y = dx = dy = 0; | ||
| 71 | for (slot = frame->slot; slot >= 0; slot = next_slot(frame, slot)) { | ||
| 72 | struct touch *ot = &gru->frame.touch[slot]; | ||
| 73 | const struct touch *t = &frame->touch[slot]; | ||
| 74 | gru->scroll_slots[nslot] = slot; | ||
| 75 | grail_set_mask(span, slot); | ||
| 76 | x += t->prop[TP_POS_X]; | ||
| 77 | y += t->prop[TP_POS_Y]; | ||
| 78 | dx += t->prop[TP_POS_X] - ot->prop[TP_POS_X]; | ||
| 79 | dy += t->prop[TP_POS_Y] - ot->prop[TP_POS_Y]; | ||
| 80 | nslot++; | ||
| 81 | } | ||
| 82 | x /= nslot; | ||
| 83 | y /= nslot; | ||
| 84 | dx /= nslot; | ||
| 85 | dy /= nslot; | ||
| 86 | if (!dy) | ||
| 87 | return; | 69 | return; |
| 88 | if (!gru->scroll_active) { | ||
| 89 | gru->scroll_gslot = gin_gesture_begin(ge, frame, | ||
| 90 | GRAIL_TYPE_VSCROLL, | ||
| 91 | x, y, span); | ||
| 92 | gru->scroll_active = 1; | ||
| 93 | } | 70 | } |
| 94 | prop[0] = dy; | 71 | gru_compute_motion(ge, frame); |
| 95 | gin_gesture_event(gin, gru->scroll_gslot, prop); | 72 | gru_scroll(ge, frame); |
| 73 | gru_zoom(ge, frame); | ||
| 74 | gru_rotate(ge, frame); | ||
| 75 | gru_combo(ge, frame); | ||
| 96 | gru->frame = *frame; | 76 | gru->frame = *frame; |
| 97 | } | 77 | } |
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 @@ | |||
| 25 | #ifndef _GRAIL_RECOGNIZER_H | 25 | #ifndef _GRAIL_RECOGNIZER_H |
| 26 | #define _GRAIL_RECOGNIZER_H | 26 | #define _GRAIL_RECOGNIZER_H |
| 27 | 27 | ||
| 28 | #include "grail-inserter.h" | 28 | #include "grail-gestures.h" |
| 29 | 29 | ||
| 30 | int gru_init(struct grail *ge); | 30 | struct gesture_recognizer { |
| 31 | struct touch_frame frame; | ||
| 32 | struct move_model move; | ||
| 33 | struct scroll_model scroll; | ||
| 34 | struct zoom_model zoom; | ||
| 35 | struct rotate_model rotate; | ||
| 36 | struct combo_model combo; | ||
| 37 | }; | ||
| 38 | |||
| 39 | int gru_init(struct grail *ge, const struct touch_dev_caps *caps); | ||
| 31 | void gru_recognize(struct grail *ge, const struct touch_frame *frame); | 40 | void gru_recognize(struct grail *ge, const struct touch_frame *frame); |
| 32 | void gru_destroy(struct grail *ge); | 41 | void gru_destroy(struct grail *ge); |
| 33 | 42 | ||
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 @@ | |||
| 1 | #ifndef _MTDEV_DETAILS_H | ||
| 2 | #define _MTDEV_DETAILS_H | ||
| 3 | |||
| 4 | #define MTDEV_TRACKING_ID 9 | ||
| 5 | #define MTDEV_POSITION_X 5 | ||
| 6 | #define MTDEV_POSITION_Y 6 | ||
| 7 | #define MTDEV_TOUCH_MAJOR 0 | ||
| 8 | #define MTDEV_TOUCH_MINOR 1 | ||
| 9 | #define MTDEV_WIDTH_MAJOR 2 | ||
| 10 | #define MTDEV_WIDTH_MINOR 3 | ||
| 11 | #define MTDEV_ORIENTATION 4 | ||
| 12 | #define MTDEV_PRESSURE 10 | ||
| 13 | |||
| 14 | int mtdev_fetch_event(struct mtdev *dev, int fd, struct input_event *ev); | ||
| 15 | void mtdev_put_event(struct mtdev *dev, const struct input_event *ev); | ||
| 16 | int mtdev_empty(struct mtdev *dev); | ||
| 17 | void mtdev_get_event(struct mtdev *dev, struct input_event* ev); | ||
| 18 | |||
| 19 | #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 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * mtdev - Multitouch Protocol Translation Library (MIT license) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> | ||
| 6 | * Copyright (C) 2010 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice (including the next | ||
| 16 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 17 | * Software. | ||
| 18 | * | ||
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 25 | * DEALINGS IN THE SOFTWARE. | ||
| 26 | * | ||
| 27 | ****************************************************************************/ | ||
| 28 | |||
| 29 | #ifndef _MTDEV_PLUMBING_H | ||
| 30 | #define _MTDEV_PLUMBING_H | ||
| 31 | |||
| 32 | #include <mtdev.h> | ||
| 33 | |||
| 34 | /** | ||
| 35 | * mtdev_init - initialize mtdev converter | ||
| 36 | * @dev: the mtdev to initialize | ||
| 37 | * | ||
| 38 | * Sets up the internal data structures. | ||
| 39 | * | ||
| 40 | * Returns zero on success, negative error number otherwise. | ||
| 41 | */ | ||
| 42 | int mtdev_init(struct mtdev *dev); | ||
| 43 | |||
| 44 | /** | ||
| 45 | * mtdev_configure - configure the mtdev converter | ||
| 46 | * @dev: the mtdev to configure | ||
| 47 | * @fd: file descriptor of the kernel device | ||
| 48 | * | ||
| 49 | * Reads the device properties to set up the protocol capabilities. | ||
| 50 | * If preferred, this can be done by hand, omitting this call. | ||
| 51 | * | ||
| 52 | * Returns zero on success, negative error number otherwise. | ||
| 53 | */ | ||
| 54 | int mtdev_configure(struct mtdev *dev, int fd); | ||
| 55 | |||
| 56 | /** | ||
| 57 | * mtdev_fetch_event - fetch an event from the kernel device | ||
| 58 | * @dev: the mtdev in use | ||
| 59 | * @fd: file descriptor of the kernel device | ||
| 60 | * @ev: the kernel input event to fill | ||
| 61 | * | ||
| 62 | * Fetch a kernel event from the kernel device. The read operation | ||
| 63 | * behaves as dictated by the file descriptor; if O_NONBLOCK is not | ||
| 64 | * set, the read will block until an event is available. | ||
| 65 | * | ||
| 66 | * On success, returns the number of events read (0 or 1). Otherwise, | ||
| 67 | * a standard negative error number is returned. | ||
| 68 | */ | ||
| 69 | int mtdev_fetch_event(struct mtdev *dev, int fd, struct input_event *ev); | ||
| 70 | |||
| 71 | /** | ||
| 72 | * mtdev_put_event - put an event into the converter | ||
| 73 | * @dev: the mtdev in use | ||
| 74 | * @ev: the kernel input event to put | ||
| 75 | * | ||
| 76 | * Put a kernel event into the mtdev converter. The event should | ||
| 77 | * come straight from the device. | ||
| 78 | * | ||
| 79 | * This call does not block; if the buffer becomes full, older events | ||
| 80 | * are dropped. The buffer is guaranteed to handle several complete MT | ||
| 81 | * packets. | ||
| 82 | */ | ||
| 83 | void mtdev_put_event(struct mtdev *dev, const struct input_event *ev); | ||
| 84 | |||
| 85 | /** | ||
| 86 | * mtdev_empty - check if there are events to get | ||
| 87 | * @dev: the mtdev in use | ||
| 88 | * | ||
| 89 | * Returns true if the processed event queue is empty, false otherwise. | ||
| 90 | */ | ||
| 91 | int mtdev_empty(struct mtdev *dev); | ||
| 92 | |||
| 93 | /** | ||
| 94 | * mtdev_get_event - get processed events from mtdev | ||
| 95 | * @dev: the mtdev in use | ||
| 96 | * @ev: the input event to fill | ||
| 97 | * | ||
| 98 | * Get a processed event from mtdev. The events appear as if they came | ||
| 99 | * from a type B device emitting MT slot events. | ||
| 100 | * | ||
| 101 | * The queue must be non-empty before calling this function. | ||
| 102 | */ | ||
| 103 | void mtdev_get_event(struct mtdev *dev, struct input_event* ev); | ||
| 104 | |||
| 105 | #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 @@ | |||
| 27 | #include <string.h> | 27 | #include <string.h> |
| 28 | #include <errno.h> | 28 | #include <errno.h> |
| 29 | #include "evbuf.h" | 29 | #include "evbuf.h" |
| 30 | #include "mtdev-plumbing.h" | 30 | #include "mtdev-details.h" |
| 31 | |||
| 32 | #define DIM_TOUCH 32 | ||
| 33 | 31 | ||
| 34 | struct touch_dev_impl { | 32 | struct touch_dev_impl { |
| 35 | int id[DIM_TOUCH]; | 33 | int id[DIM_TOUCH]; |
| 36 | int slot; | 34 | int slot; |
| 37 | int status; | 35 | int status; |
| 38 | touch_prop_mask_t mask[1]; | 36 | grail_mask_t mask[DIM_TOUCH_BYTES]; |
| 39 | touch_prop_t prop[DIM_TOUCH_PROP]; | 37 | touch_prop_t prop[DIM_TOUCH_PROP]; |
| 40 | struct evbuf evbuf; | 38 | struct evbuf evbuf; |
| 41 | struct mtdev mtdev; | 39 | struct mtdev mtdev; |
| 42 | }; | 40 | }; |
| 43 | 41 | ||
| 42 | static inline void set_info(struct touch_dev_caps *caps, int code, | ||
| 43 | const struct input_absinfo *info) | ||
| 44 | { | ||
| 45 | grail_mask_set(caps->mask, code); | ||
| 46 | caps->info[code] = *info; | ||
| 47 | } | ||
| 48 | |||
| 49 | static void set_caps(struct touch_dev_caps *caps, | ||
| 50 | const struct mtdev_caps *mtcaps) | ||
| 51 | { | ||
| 52 | if (mtcaps->has_abs[MTDEV_POSITION_X]) | ||
| 53 | set_info(caps, TP_POS_X, &mtcaps->abs[MTDEV_POSITION_X]); | ||
| 54 | if (mtcaps->has_abs[MTDEV_POSITION_Y]) | ||
| 55 | set_info(caps, TP_POS_Y, &mtcaps->abs[MTDEV_POSITION_Y]); | ||
| 56 | if (mtcaps->has_abs[MTDEV_TOUCH_MAJOR]) | ||
| 57 | set_info(caps, TP_TOUCH_MAJOR, &mtcaps->abs[MTDEV_TOUCH_MAJOR]); | ||
| 58 | if (mtcaps->has_abs[MTDEV_TOUCH_MINOR]) | ||
| 59 | set_info(caps, TP_TOUCH_MINOR, &mtcaps->abs[MTDEV_TOUCH_MINOR]); | ||
| 60 | if (mtcaps->has_abs[MTDEV_WIDTH_MAJOR]) | ||
| 61 | set_info(caps, TP_WIDTH_MAJOR, &mtcaps->abs[MTDEV_WIDTH_MAJOR]); | ||
| 62 | if (mtcaps->has_abs[MTDEV_WIDTH_MINOR]) | ||
| 63 | set_info(caps, TP_WIDTH_MINOR, &mtcaps->abs[MTDEV_WIDTH_MINOR]); | ||
| 64 | if (mtcaps->has_abs[MTDEV_ORIENTATION]) | ||
| 65 | set_info(caps, TP_ORIENTATION, &mtcaps->abs[MTDEV_ORIENTATION]); | ||
| 66 | if (mtcaps->has_abs[MTDEV_PRESSURE]) | ||
| 67 | set_info(caps, TP_PRESSURE, &mtcaps->abs[MTDEV_PRESSURE]); | ||
| 68 | } | ||
| 69 | |||
| 44 | static int touch_get_fetched(struct touch_dev_impl *x, | 70 | static int touch_get_fetched(struct touch_dev_impl *x, |
| 45 | struct input_event* ev, int ev_max) | 71 | struct input_event* ev, int ev_max) |
| 46 | { | 72 | { |
| @@ -58,14 +84,9 @@ static int touch_get_fetched(struct touch_dev_impl *x, | |||
| 58 | return count; | 84 | return count; |
| 59 | } | 85 | } |
| 60 | 86 | ||
| 61 | static inline int has_any_prop(const touch_prop_mask_t *mask) | ||
| 62 | { | ||
| 63 | return mask[0] != 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | static inline void set_prop(struct touch_dev_impl *x, int code, int value) | 87 | static inline void set_prop(struct touch_dev_impl *x, int code, int value) |
| 67 | { | 88 | { |
| 68 | x->mask[code >> 5] |= 1U << (code & 31); | 89 | grail_mask_set(x->mask, code); |
| 69 | x->prop[code] = value; | 90 | x->prop[code] = value; |
| 70 | } | 91 | } |
| 71 | 92 | ||
| @@ -76,7 +97,8 @@ static void finish_touch(struct touch_dev *dev, | |||
| 76 | dev->destroy(dev, x->slot); | 97 | dev->destroy(dev, x->slot); |
| 77 | if (x->status > 0 && dev->create) | 98 | if (x->status > 0 && dev->create) |
| 78 | dev->create(dev, x->slot, x->mask, x->prop); | 99 | dev->create(dev, x->slot, x->mask, x->prop); |
| 79 | if (x->status == 0 && has_any_prop(x->mask) && dev->modify) | 100 | if (x->status == 0 && dev->modify && |
| 101 | grail_mask_count(x->mask, sizeof(x->mask))) | ||
| 80 | dev->modify(dev, x->slot, x->mask, x->prop); | 102 | dev->modify(dev, x->slot, x->mask, x->prop); |
| 81 | x->status = 0; | 103 | x->status = 0; |
| 82 | memset(x->mask, 0, sizeof(x->mask)); | 104 | memset(x->mask, 0, sizeof(x->mask)); |
| @@ -157,6 +179,7 @@ int touch_dev_open(struct touch_dev *dev, int fd) | |||
| 157 | goto error; | 179 | goto error; |
| 158 | for (i = 0; i < DIM_TOUCH; i++) | 180 | for (i = 0; i < DIM_TOUCH; i++) |
| 159 | x->id[i] = MT_ID_NULL; | 181 | x->id[i] = MT_ID_NULL; |
| 182 | set_caps(&dev->caps, &x->mtdev.caps); | ||
| 160 | dev->impl = x; | 183 | dev->impl = x; |
| 161 | return 0; | 184 | return 0; |
| 162 | error: | 185 | 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) | |||
| 34 | 34 | ||
| 35 | static void update_frame(struct touch_frame *frame, | 35 | static void update_frame(struct touch_frame *frame, |
| 36 | int slot, int active, | 36 | int slot, int active, |
| 37 | const touch_prop_mask_t *mask, | 37 | const grail_mask_t *mask, |
| 38 | const touch_prop_t *prop) | 38 | const touch_prop_t *prop) |
| 39 | { | 39 | { |
| 40 | struct touch *touch = &frame->touch[slot]; | 40 | struct touch *t = &frame->touch[slot]; |
| 41 | touch->active = active; | 41 | int i; |
| 42 | if (mask && prop) { | 42 | t->active = active; |
| 43 | int i; | 43 | grail_mask_modify(frame->touches, slot, active); |
| 44 | for (i = 0; i < DIM_TOUCH_PROP; i++) | 44 | if (mask && prop) |
| 45 | if (has_prop(mask, i)) | 45 | grail_mask_foreach(i, mask, DIM_TOUCH_PROP_BYTES) |
| 46 | touch->prop[i] = prop[i]; | 46 | t->prop[i] = prop[i]; |
| 47 | } | ||
| 48 | } | 47 | } |
| 49 | 48 | ||
| 50 | static void finalize_frame(struct touch_frame *frame, touch_time_t time) | 49 | static void finalize_frame(struct touch_frame *frame, touch_time_t time) |
| 51 | { | 50 | { |
| 52 | int i, last = -1; | 51 | int i, nslot = 0; |
| 53 | frame->ntouch = 0; | 52 | grail_mask_foreach(i, frame->touches, DIM_TOUCH_BYTES) |
| 54 | frame->slot = -1; | 53 | frame->active[nslot++] = &frame->touch[i]; |
| 55 | for (i = 0; i < DIM_TOUCH_PROP; i++) { | 54 | frame->nactive = nslot; |
| 56 | frame->touch[i].next = -1; | ||
| 57 | if (frame->touch[i].active) { | ||
| 58 | if (last < 0) | ||
| 59 | frame->slot = i; | ||
| 60 | else | ||
| 61 | frame->touch[last].next = i; | ||
| 62 | last = i; | ||
| 63 | frame->ntouch++; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | frame->time = time; | 55 | frame->time = time; |
| 67 | } | 56 | } |
| 68 | 57 | ||
| 69 | static void tp_create(struct touch_dev *dev, int slot, | 58 | static void tp_create(struct touch_dev *dev, int slot, |
| 70 | const touch_prop_mask_t *mask, const touch_prop_t *prop) | 59 | const grail_mask_t *mask, const touch_prop_t *prop) |
| 71 | { | 60 | { |
| 72 | struct touch_engine *engine = dev->priv; | 61 | struct touch_engine *engine = dev->priv; |
| 73 | if (engine) { | 62 | if (engine) { |
| @@ -77,7 +66,7 @@ static void tp_create(struct touch_dev *dev, int slot, | |||
| 77 | } | 66 | } |
| 78 | 67 | ||
| 79 | static void tp_modify(struct touch_dev *dev, int slot, | 68 | static void tp_modify(struct touch_dev *dev, int slot, |
| 80 | const touch_prop_mask_t *mask, const touch_prop_t *prop) | 69 | const grail_mask_t *mask, const touch_prop_t *prop) |
| 81 | { | 70 | { |
| 82 | struct touch_engine *engine = dev->priv; | 71 | struct touch_engine *engine = dev->priv; |
| 83 | if (engine) { | 72 | if (engine) { |
| @@ -117,7 +106,10 @@ void touch_engine_init(struct touch_engine *engine, | |||
| 117 | const struct input_event *ev), | 106 | const struct input_event *ev), |
| 118 | void *priv) | 107 | void *priv) |
| 119 | { | 108 | { |
| 109 | int i; | ||
| 120 | memset(engine, 0, sizeof(*engine)); | 110 | memset(engine, 0, sizeof(*engine)); |
| 111 | for (i = 0; i < DIM_TOUCH; i++) | ||
| 112 | engine->frame.touch[i].slot = i; | ||
| 121 | engine->event = event; | 113 | engine->event = event; |
| 122 | engine->sync = sync; | 114 | engine->sync = sync; |
| 123 | engine->priv = priv; | 115 | engine->priv = priv; |
diff --git a/test/Makefile.am b/test/Makefile.am index c8404f8..e0498ba 100644 --- a/test/Makefile.am +++ b/test/Makefile.am | |||
| @@ -3,7 +3,7 @@ noinst_PROGRAMS = touch grail | |||
| 3 | INCLUDES=-I$(top_srcdir)/include/ | 3 | INCLUDES=-I$(top_srcdir)/include/ |
| 4 | 4 | ||
| 5 | touch_SOURCES = touch.c | 5 | touch_SOURCES = touch.c |
| 6 | touch_LDFLAGS = -L$(top_builddir)/src/.libs/ -lgrail -lmtdev | 6 | touch_LDFLAGS = -L$(top_builddir)/src/.libs/ -lgrail -lmtdev -lm |
| 7 | 7 | ||
| 8 | grail_SOURCES = grail.c | 8 | grail_SOURCES = grail.c |
| 9 | grail_LDFLAGS = -L$(top_builddir)/src/.libs/ -lgrail -lmtdev | 9 | grail_LDFLAGS = -L$(top_builddir)/src/.libs/ -lgrail -lmtdev -lm |
diff --git a/test/grail.c b/test/grail.c index 361fd22..795e88f 100644 --- a/test/grail.c +++ b/test/grail.c | |||
| @@ -31,28 +31,31 @@ | |||
| 31 | static int tp_get_clients(struct grail *ge, | 31 | static int tp_get_clients(struct grail *ge, |
| 32 | struct grail_client_info *clients, int max_clients, | 32 | struct grail_client_info *clients, int max_clients, |
| 33 | const struct grail_coord *coords, int num_coords, | 33 | const struct grail_coord *coords, int num_coords, |
| 34 | const grail_mask_t *types) | 34 | const grail_mask_t *types, int ntypes) |
| 35 | { | 35 | { |
| 36 | memset(&clients[0], 0, sizeof(clients[0])); | 36 | memset(&clients[0], 0, sizeof(clients[0])); |
| 37 | clients[0].id.client = 345; | 37 | clients[0].id.client = 345; |
| 38 | clients[0].id.root = 1; | 38 | clients[0].id.root = 1; |
| 39 | clients[0].id.event = 2; | 39 | clients[0].id.event = 2; |
| 40 | clients[0].id.child = 3; | 40 | clients[0].id.child = 3; |
| 41 | clients[0].mask[0] = 3; | 41 | clients[0].mask[0] = 0xff; |
| 42 | return 1; | 42 | return 1; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static void tp_event(struct grail *ge, const struct input_event *ev) | 45 | static void tp_event(struct grail *ge, const struct input_event *ev) |
| 46 | { | 46 | { |
| 47 | fprintf(stderr, "event %d %d %d\n", ev->type, ev->code, ev->value); | 47 | fprintf(stderr, "event %d 0x%x %d\n", ev->type, ev->code, ev->value); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static void tp_gesture(struct grail *ge, const struct grail_event *ev) | 50 | static void tp_gesture(struct grail *ge, const struct grail_event *ev) |
| 51 | { | 51 | { |
| 52 | fprintf(stderr, "gesture %d %d %d %d: %d %d\n", | 52 | int i; |
| 53 | fprintf(stderr, "gesture %d %d %d %d %f %f %d:\n", | ||
| 53 | ev->type, ev->id, | 54 | ev->type, ev->id, |
| 54 | ev->client_id.client, ev->client_id.event, | 55 | ev->client_id.client, ev->client_id.event, |
| 55 | ev->prop[0], ev->prop[1]); | 56 | ev->pos.x, ev->pos.y, ev->ntouch); |
| 57 | for (i = 0; i < ev->nprop; i++) | ||
| 58 | fprintf(stderr, "\t%d: %f\n", i, ev->prop[i]); | ||
| 56 | } | 59 | } |
| 57 | 60 | ||
| 58 | static void loop_device(struct grail *ge, int fd) | 61 | static void loop_device(struct grail *ge, int fd) |
diff --git a/test/touch.c b/test/touch.c index 1dd9cd4..9b2d38a 100644 --- a/test/touch.c +++ b/test/touch.c | |||
| @@ -31,20 +31,20 @@ | |||
| 31 | static void tp_event(struct touch_engine *engine, | 31 | static void tp_event(struct touch_engine *engine, |
| 32 | const struct input_event *ev) | 32 | const struct input_event *ev) |
| 33 | { | 33 | { |
| 34 | fprintf(stderr, "event %d %d %d\n", ev->type, ev->code, ev->value); | 34 | fprintf(stderr, "event %d 0x%x %d\n", ev->type, ev->code, ev->value); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | static void tp_sync(struct touch_engine *engine, | 37 | static void tp_sync(struct touch_engine *engine, |
| 38 | const struct input_event *syn) | 38 | const struct input_event *syn) |
| 39 | { | 39 | { |
| 40 | struct touch_frame *frame = &engine->frame; | 40 | struct touch_frame *frame = &engine->frame; |
| 41 | int slot, i; | 41 | int i, j; |
| 42 | fprintf(stderr, "sync %d %lld\n", frame->ntouch, frame->time); | 42 | fprintf(stderr, "sync %d %lld\n", frame->nactive, frame->time); |
| 43 | for (slot = frame->slot; slot >= 0; slot = next_slot(frame, slot)) { | 43 | for (i = 0; i < frame->nactive; i++) { |
| 44 | struct touch *touch = &frame->touch[slot]; | 44 | struct touch *t = frame->active[i]; |
| 45 | fprintf(stderr, "touch %d\n", slot); | 45 | fprintf(stderr, "touch %d %d\n", i, t->slot); |
| 46 | for (i = 0; i < DIM_TOUCH_PROP; i++) | 46 | for (j = 0; j < DIM_TOUCH_PROP; j++) |
| 47 | fprintf(stderr, " %d\n", touch->prop[i]); | 47 | fprintf(stderr, " %d\n", t->prop[j]); |
| 48 | } | 48 | } |
| 49 | } | 49 | } |
| 50 | 50 | ||
