/***************************************************************************** * * 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 /* from mtdev-mapping.h */ #define MT_TOUCH_MAJOR 0 #define MT_TOUCH_MINOR 1 #define MT_WIDTH_MAJOR 2 #define MT_WIDTH_MINOR 3 #define MT_ORIENTATION 4 #define MT_POSITION_X 5 #define MT_POSITION_Y 6 #define MT_TRACKING_ID 9 #define MT_PRESSURE 10 int mtdev_fetch_event(struct mtdev *dev, int fd, struct input_event *ev); void mtdev_put_event(struct mtdev *dev, const struct input_event *ev); int mtdev_empty(struct mtdev *dev); void mtdev_get_event(struct mtdev *dev, struct input_event* ev); struct touch_dev_impl { int id[DIM_TOUCH]; int slot; int status; grail_mask_t mask[DIM_TOUCH_BYTES]; touch_prop_t prop[DIM_TOUCH_PROP]; struct mtdev mtdev; }; static inline void set_info(struct touch_dev_caps *caps, int code, const struct input_absinfo *info) { grail_mask_set(caps->mask, code); caps->info[code] = *info; } static void set_caps(struct touch_dev_caps *caps, const struct mtdev_caps *mtcaps) { if (mtcaps->has_abs[MT_POSITION_X]) set_info(caps, TP_POS_X, &mtcaps->abs[MT_POSITION_X]); if (mtcaps->has_abs[MT_POSITION_Y]) set_info(caps, TP_POS_Y, &mtcaps->abs[MT_POSITION_Y]); if (mtcaps->has_abs[MT_TOUCH_MAJOR]) set_info(caps, TP_TOUCH_MAJOR, &mtcaps->abs[MT_TOUCH_MAJOR]); if (mtcaps->has_abs[MT_TOUCH_MINOR]) set_info(caps, TP_TOUCH_MINOR, &mtcaps->abs[MT_TOUCH_MINOR]); if (mtcaps->has_abs[MT_WIDTH_MAJOR]) set_info(caps, TP_WIDTH_MAJOR, &mtcaps->abs[MT_WIDTH_MAJOR]); if (mtcaps->has_abs[MT_WIDTH_MINOR]) set_info(caps, TP_WIDTH_MINOR, &mtcaps->abs[MT_WIDTH_MINOR]); if (mtcaps->has_abs[MT_ORIENTATION]) set_info(caps, TP_ORIENTATION, &mtcaps->abs[MT_ORIENTATION]); if (mtcaps->has_abs[MT_PRESSURE]) set_info(caps, TP_PRESSURE, &mtcaps->abs[MT_PRESSURE]); } static inline void set_prop(struct touch_dev_impl *x, int code, int value) { grail_mask_set(x->mask, code); 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 && dev->modify && grail_mask_count(x->mask, sizeof(x->mask))) 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) { finish_touch(dev, dev->impl); if (dev->sync) dev->sync(dev, syn); } 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 && !x->mtdev.caps.has_mtdata) ret = -ENODEV; if (ret) goto error; for (i = 0; i < DIM_TOUCH; i++) x->id[i] = MT_ID_NULL; set_caps(&dev->caps, &x->mtdev.caps); 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)); }