/***************************************************************************** * * grail - Gesture Recognition And Instantiation Library * * Copyright (C) 2010 Canonical Ltd. * Copyright (C) 2010 Henrik Rydberg * * 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 . * ****************************************************************************/ #include #include #include #include /* see mtdev-mapping.h */ #define MTDEV_TOUCH_MINOR 1 #define SET_PROP(name, value) \ if (t->name != value) { \ t->name = value; \ frame->nmodify++; \ } static void finish_touch(struct touch_dev *dev, struct touch_frame *frame) { struct touch *t = &frame->touch[dev->slot]; if (t->touch_major && !t->touch_minor || !dev->mtdev.caps.has_abs[MTDEV_TOUCH_MINOR]) SET_PROP(touch_minor, t->touch_major); if (dev->state > 0) { t->active = 1; grail_mask_set(frame->touches, dev->slot); frame->ncreate++; } if (dev->state < 0) { t->active = 0; grail_mask_clear(frame->touches, dev->slot); frame->ndestroy++; } 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; 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; frame->time = syn->time.tv_usec / ms + syn->time.tv_sec * ms; if (dev->sync) dev->sync(dev, syn); frame->ncreate = 0; frame->nmodify = 0; frame->ndestroy = 0; } static int handle_abs_event(struct touch_dev *dev, const struct input_event *ev) { 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) finish_touch(dev, frame); dev->slot = ev->value; t = &frame->touch[dev->slot]; } return 1; case ABS_MT_POSITION_X: SET_PROP(x, ev->value); return 1; case ABS_MT_POSITION_Y: SET_PROP(y, ev->value); return 1; case ABS_MT_TOUCH_MAJOR: SET_PROP(touch_major, ev->value); return 1; case ABS_MT_TOUCH_MINOR: SET_PROP(touch_minor, ev->value); return 1; case ABS_MT_WIDTH_MAJOR: SET_PROP(width_major, ev->value); return 1; case ABS_MT_WIDTH_MINOR: SET_PROP(width_minor, ev->value); return 1; case ABS_MT_ORIENTATION: SET_PROP(orientation, ev->value); return 1; case ABS_MT_PRESSURE: SET_PROP(pressure, ev->value); return 1; case ABS_MT_TOOL_TYPE: SET_PROP(tool_type, ev->value); return 1; case ABS_MT_TRACKING_ID: if (t->id != ev->value) { if (t->id != MT_ID_NULL) { dev->state = -1; finish_touch(dev, frame); } if (ev->value != MT_ID_NULL) dev->state = 1; t->id = ev->value; } return 1; default: return 0; } } 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; int ret, i; memset(dev, 0, sizeof(*dev)); for (i = 0; i < DIM_TOUCH; i++) { struct touch *t = &frame->touch[i]; t->slot = i; t->id = MT_ID_NULL; } ret = mtdev_open(&dev->mtdev, fd); if (!ret && !touch_caps_is_supported(dev, fd)) ret = -ENODEV; if (ret) goto error; touch_caps_init(dev); return 0; error: return ret; } int touch_dev_idle(struct touch_dev *dev, int fd, int ms) { return mtdev_idle(&dev->mtdev, fd, ms); } int touch_dev_pull(struct touch_dev *dev, int fd) { struct input_event ev; int ret, count = 0, consumed; while ((ret = mtdev_get(&dev->mtdev, fd, &ev, 1)) > 0) { consumed = 0; if (ev.type == EV_SYN) { if (ev.code == SYN_REPORT) finish_packet(dev, &ev); 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); count++; } return count > 0 ? count : ret; } void touch_dev_close(struct touch_dev *dev, int fd) { mtdev_close(&dev->mtdev); memset(dev, 0, sizeof(*dev)); }