From 9bdd12a8046f33a6d190bb33371eb30d3ee59062 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Thu, 9 Sep 2010 10:17:09 +0200 Subject: Support legacy devices Simulate MT touch events for legacy devices that support the DOUBLETAP, TRIPLETAP and QUADTAP events. This allows multi-finger tap and drag gestures to be emitted, providing a basic level of MT functionality for legacy devices. Signed-off-by: Henrik Rydberg --- include/grail-touch.h | 1 + src/touch-caps.c | 37 ++++++++++++++++++++++ src/touch-dev.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 123 insertions(+), 2 deletions(-) diff --git a/include/grail-touch.h b/include/grail-touch.h index acfc779..9c63c80 100644 --- a/include/grail-touch.h +++ b/include/grail-touch.h @@ -72,6 +72,7 @@ struct touch_dev { int state; }; +int touch_caps_is_supported(struct touch_dev *dev, int fd); void touch_caps_init(struct touch_dev *dev); float touch_angle(const struct touch_dev *dev, int orientation); float touch_pressure(const struct touch_dev *dev, int pressure); diff --git a/src/touch-caps.c b/src/touch-caps.c index 7f243c5..a51912c 100644 --- a/src/touch-caps.c +++ b/src/touch-caps.c @@ -21,6 +21,7 @@ ****************************************************************************/ #include +#include #include /* see mtdev-mapping.h */ @@ -29,6 +30,42 @@ #define MTDEV_ORIENTATION 4 #define MTDEV_PRESSURE 10 +#define SYSCALL(call) while (((call) == -1) && (errno == EINTR)) + +static const int bits_per_long = 8 * sizeof(long); + +static inline int nlongs(int nbit) +{ + return (nbit + bits_per_long - 1) / bits_per_long; +} + +static inline int getbit(const unsigned long *map, int key) +{ + return (map[key / bits_per_long] >> (key % bits_per_long)) & 0x01; +} + +int touch_caps_is_supported(struct touch_dev *dev, int fd) +{ + unsigned long keybits[nlongs(KEY_MAX)]; + unsigned long absbits[nlongs(ABS_MAX)]; + int rc; + + if (dev->mtdev.caps.has_mtdata) + return 1; + + SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits)); + if (rc < 0) + return 0; + SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits)); + if (rc < 0) + return 0; + + return getbit(absbits, ABS_X) && + getbit(absbits, ABS_Y) && + getbit(keybits, BTN_TOUCH) && + getbit(keybits, BTN_TOOL_DOUBLETAP); +} + void touch_caps_init(struct touch_dev *dev) { const struct mtdev_caps *mt = &dev->mtdev.caps; diff --git a/src/touch-dev.c b/src/touch-dev.c index 17082ed..d8e192e 100644 --- a/src/touch-dev.c +++ b/src/touch-dev.c @@ -53,13 +53,45 @@ static void finish_touch(struct touch_dev *dev, struct touch_frame *frame) dev->state = 0; } +static void finish_legacy(struct touch_dev *dev, struct touch_frame *frame) +{ + static int trkid; + int i; + for (i = 0; i < frame->nactive; i++) { + struct touch *t = &frame->touch[i]; + t->active = 1; + if (t->id < 0) { + t->id = trkid++ & 0xffff; + frame->ncreate++; + } + if (i > 0) { + SET_PROP(x, frame->touch[0].x); + SET_PROP(y, frame->touch[0].y); + SET_PROP(pressure, frame->touch[0].pressure); + } + grail_mask_set(frame->touches, i); + } + for (i = frame->nactive; i < DIM_TOUCH; i++) { + struct touch *t = &frame->touch[i]; + t->active = 0; + if (t->id >= 0) { + t->id = -1; + frame->ndestroy++; + } + grail_mask_clear(frame->touches, i); + } +} + static void finish_packet(struct touch_dev *dev, const struct input_event *syn) { static const touch_time_t ms = 1000; struct touch_frame *frame = &dev->frame; int i, nslot = 0; - finish_touch(dev, frame); + if (dev->mtdev.caps.has_mtdata) + finish_touch(dev, frame); + else + finish_legacy(dev, frame); grail_mask_foreach(i, frame->touches, DIM_TOUCH_BYTES) frame->active[nslot++] = &frame->touch[i]; frame->nactive = nslot; @@ -77,6 +109,21 @@ static int handle_abs_event(struct touch_dev *dev, struct touch_frame *frame = &dev->frame; struct touch *t = &frame->touch[dev->slot]; switch (ev->code) { + case ABS_X: + if (dev->mtdev.caps.has_mtdata) + return 0; + SET_PROP(x, ev->value); + return 0; + case ABS_Y: + if (dev->mtdev.caps.has_mtdata) + return 0; + SET_PROP(y, ev->value); + return 0; + case ABS_PRESSURE: + if (dev->mtdev.caps.has_mtdata) + return 0; + SET_PROP(pressure, ev->value); + return 0; case ABS_MT_SLOT: if (ev->value >= 0 && ev->value < DIM_TOUCH) { if (dev->slot != ev->value) @@ -128,6 +175,40 @@ static int handle_abs_event(struct touch_dev *dev, } } +static int handle_key_event(struct touch_dev *dev, + const struct input_event *ev) +{ + struct touch_frame *frame = &dev->frame; + if (dev->mtdev.caps.has_mtdata) + return 0; + switch (ev->code) { + case BTN_TOUCH: + if (ev->value && !frame->nactive) + frame->nactive = 1; + else if (!ev->value && frame->nactive) + frame->nactive = 0; + return 0; + case BTN_TOOL_FINGER: + if (ev->value) + frame->nactive = 1; + return 0; + case BTN_TOOL_DOUBLETAP: + if (ev->value) + frame->nactive = 2; + return 0; + case BTN_TOOL_TRIPLETAP: + if (ev->value) + frame->nactive = 3; + return 0; + case BTN_TOOL_QUADTAP: + if (ev->value) + frame->nactive = 4; + return 0; + default: + return 0; + } +} + int touch_dev_open(struct touch_dev *dev, int fd) { struct touch_frame *frame = &dev->frame; @@ -139,7 +220,7 @@ int touch_dev_open(struct touch_dev *dev, int fd) t->id = MT_ID_NULL; } ret = mtdev_open(&dev->mtdev, fd); - if (!ret && !dev->mtdev.caps.has_mtdata) + if (!ret && !touch_caps_is_supported(dev, fd)) ret = -ENODEV; if (ret) goto error; @@ -166,6 +247,8 @@ int touch_dev_pull(struct touch_dev *dev, int fd) consumed++; } else if (ev.type == EV_ABS) { consumed += handle_abs_event(dev, &ev); + } else if (ev.type == EV_KEY) { + consumed += handle_key_event(dev, &ev); } if (!consumed && dev->event) dev->event(dev, &ev); -- cgit v1.2.3