/***************************************************************************** * * grail - Gesture Recognition And Instantiation Library * * Copyright (C) 2010 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Henrik Rydberg * ****************************************************************************/ #include #include #include #include #define DIM_TOUCH 32 struct touch_dev_impl { int id[DIM_TOUCH]; int slot; int status; touch_prop_mask_t mask[1]; touch_prop_t prop[DIM_TOUCH_PROP]; struct mtdev mtdev; }; static inline int has_any_prop(const touch_prop_mask_t *mask) { return mask[0] != 0; } static inline void set_prop(struct touch_dev_impl *x, int code, int value) { x->mask[code >> 5] |= 1U << (code & 31); x->prop[code] = value; } static void finish_touch(struct touch_dev *dev, struct touch_dev_impl *x) { if (x->status < 0 && dev->destroy) dev->destroy(dev, x->slot); if (x->status > 0 && dev->create) dev->create(dev, x->slot, x->mask, x->prop); if (x->status == 0 && has_any_prop(x->mask) && dev->modify) dev->modify(dev, x->slot, x->mask, x->prop); x->status = 0; memset(x->mask, 0, sizeof(x->mask)); } static void finish_packet(struct touch_dev *dev, const struct input_event *syn) { static const touch_time_t ms = 1000; touch_time_t time = syn->time.tv_usec / ms + syn->time.tv_sec * ms; finish_touch(dev, dev->impl); if (dev->sync) dev->sync(dev, time); } static int handle_abs_event(struct touch_dev *dev, const struct input_event *ev) { struct touch_dev_impl *x = dev->impl; switch (ev->code) { case ABS_MT_SLOT: if (ev->value >= 0 && ev->value < DIM_TOUCH) { if (x->slot != ev->value) finish_touch(dev, x); x->slot = ev->value; } return 1; case ABS_MT_POSITION_X: set_prop(x, TP_POS_X, ev->value); return 1; case ABS_MT_POSITION_Y: set_prop(x, TP_POS_Y, ev->value); return 1; case ABS_MT_TOUCH_MAJOR: set_prop(x, TP_TOUCH_MAJOR, ev->value); return 1; case ABS_MT_TOUCH_MINOR: set_prop(x, TP_TOUCH_MINOR, ev->value); return 1; case ABS_MT_WIDTH_MAJOR: set_prop(x, TP_WIDTH_MAJOR, ev->value); return 1; case ABS_MT_WIDTH_MINOR: set_prop(x, TP_WIDTH_MINOR, ev->value); return 1; case ABS_MT_ORIENTATION: set_prop(x, TP_ORIENTATION, ev->value); return 1; case ABS_MT_PRESSURE: set_prop(x, TP_PRESSURE, ev->value); return 1; case ABS_MT_TRACKING_ID: if (x->id[x->slot] != ev->value) { if (x->id[x->slot] != MT_ID_NULL) { x->status = -1; finish_touch(dev, x); } if (ev->value != MT_ID_NULL) x->status = 1; } x->id[x->slot] = ev->value; return 1; default: return 0; } } int touch_dev_open(struct touch_dev *dev, int fd) { struct touch_dev_impl *x; int ret, i; memset(dev, 0, sizeof(*dev)); x = calloc(1, sizeof(*x)); if (!x) return -ENOMEM; ret = mtdev_open(&x->mtdev, fd); if (ret) goto error; for (i = 0; i < DIM_TOUCH; i++) x->id[i] = MT_ID_NULL; dev->impl = x; return 0; error: free(x); return ret; } int touch_dev_idle(struct touch_dev *dev, int fd, int ms) { return mtdev_idle(&dev->impl->mtdev, fd, ms); } int touch_dev_pull(struct touch_dev *dev, int fd) { struct touch_dev_impl *x = dev->impl; struct input_event ev; int ret, count = 0, consumed; while ((ret = mtdev_get(&x->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); } if (!consumed && dev->event) dev->event(dev, &ev); count++; } return count > 0 ? count : ret; } void touch_dev_close(struct touch_dev *dev, int fd) { struct touch_dev_impl *x = dev->impl; mtdev_close(&x->mtdev); free(x); memset(dev, 0, sizeof(*dev)); }