/***************************************************************************** * * 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 #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 (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_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); 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_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; } } 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 && !dev->mtdev.caps.has_mtdata) 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); } 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)); }