/***************************************************************************** * * 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 "grail-inserter.h" #include "grail-recognizer.h" #include "grail-impl.h" #include #include #include #include #include #include static void tp_event(struct touch_dev *dev, const struct input_event *ev) { struct grail *ge = dev->priv; struct grail_impl *x = ge->impl; if (ev->type == EV_ABS) { return; } if (ev->type == EV_KEY) { switch (ev->code) { case BTN_TOUCH: case BTN_TOOL_FINGER: case BTN_TOOL_DOUBLETAP: case BTN_TOOL_TRIPLETAP: case BTN_TOOL_QUADTAP: return; } } evbuf_put(&x->evbuf, ev); } static void evput(struct grail_impl *x, struct timeval time, unsigned type, unsigned code, int value) { struct input_event ev = { time, type, code, value }; evbuf_put(&x->evbuf, &ev); } static void report_down(struct grail_impl *impl) { if (impl->report_status) return; evput(impl, impl->report_time, EV_KEY, BTN_TOUCH, 1); evput(impl, impl->report_time, EV_ABS, ABS_X, impl->report_x); evput(impl, impl->report_time, EV_ABS, ABS_Y, impl->report_y); impl->report_status = 1; } static void report_up(struct grail_impl *impl, const struct input_event *syn) { if (!impl->report_status) return; evput(impl, syn->time, EV_KEY, BTN_TOUCH, 0); impl->report_status = 0; } #define SYSCALL(call) while (((call) == -1) && (errno == EINTR)) static int getabs(struct input_absinfo *abs, int key, int fd) { int rc; SYSCALL(rc = ioctl(fd, EVIOCGABS(key), abs)); return rc >= 0; } static void set_emulation_caps(struct grail_impl *impl, int fd) { struct touch_caps *emu = &impl->emu; struct input_absinfo info; memset(emu, 0, sizeof(*emu)); if (getabs(&info, ABS_X, fd)) { emu->min_x = info.minimum; emu->max_x = info.maximum; } if (getabs(&info, ABS_Y, fd)) { emu->min_y = info.minimum; emu->max_y = info.maximum; } } static void set_pointer(struct grail_impl *impl) { struct touch_dev *dev = &impl->dev; struct touch_caps *caps = &dev->caps; struct touch_caps *emu = &impl->emu; struct touch_frame *frame = &dev->frame; int best_x, best_y, best_d = -1; int i; for (i = 0; i < frame->nactive; i++) { struct touch *t = frame->active[i]; float u = (t->x - caps->min_x) / (caps->max_x - caps->min_x); float v = (t->y - caps->min_y) / (caps->max_y - caps->min_y); int x = emu->min_x + u * (emu->max_x - emu->min_x); int y = emu->min_y + v * (emu->max_y - emu->min_y); int d = abs(x - impl->pointer_x) + abs(y - impl->pointer_y); if (best_d < 0 || d < best_d) { best_x = x; best_y = y; best_d = d; } } if (best_d >= 0) { impl->pointer_x = best_x; impl->pointer_y = best_y; } } static void handle_abs_events(struct grail *ge, const struct input_event *syn) { static const int fm_mask = 0x03; struct grail_impl *impl = ge->impl; struct gesture_inserter *gin = ge->gin; struct gesture_recognizer *gru = ge->gru; struct move_model *move = &gru->move; struct tapping_model *tap = &gru->tapping; int used_move = grail_mask_count(gin->types, sizeof(gin->types)); int used_tap = grail_mask_get(gin->types, GRAIL_TYPE_TAP1); int pointer = move->ntouch == 1; int ismove = pointer && (move->active & fm_mask) && !used_move; int ishold = pointer && tap->active && !used_move; int istap = gru->tapping.tap == 1 && !used_tap; set_pointer(impl); if (!impl->pointer_status && pointer) { impl->report_x = impl->pointer_x; impl->report_y = impl->pointer_y; impl->report_time = syn->time; impl->pointer_status = 1; if (!used_move) report_down(impl); return; } if (ishold) return; if (istap) { report_down(impl); evput(impl, impl->report_time, EV_KEY, BTN_LEFT, 1); evput(impl, impl->report_time, EV_SYN, SYN_REPORT, 0); evput(impl, syn->time, EV_KEY, BTN_LEFT, 0); } else if (ismove) { report_down(impl); if (impl->report_x != impl->pointer_x) { evput(impl, syn->time, EV_ABS, ABS_X, impl->pointer_x); impl->report_x = impl->pointer_x; } if (impl->report_y != impl->pointer_y) { evput(impl, syn->time, EV_ABS, ABS_Y, impl->pointer_y); impl->report_y = impl->pointer_y; } } if (impl->pointer_status && !pointer) { impl->pointer_status = 0; report_up(impl, syn); } } static void tp_sync(struct touch_dev *dev, const struct input_event *syn) { struct input_event ev; struct grail *ge = dev->priv; struct grail_impl *impl = ge->impl; struct touch_frame *frame = &dev->frame; int nevent = 0; gin_frame_begin(ge, frame); gru_recognize(ge, frame); gin_frame_end(ge, frame); if (!ge->event) { evbuf_clear(&impl->evbuf); return; } if (!impl->filter_abs) handle_abs_events(ge, syn); while (!evbuf_empty(&impl->evbuf)) { evbuf_get(&impl->evbuf, &ev); ge->event(ge, &ev); nevent++; } if (nevent) ge->event(ge, syn); } void grail_filter_abs_events(struct grail *ge, int usage) { struct grail_impl *x = ge->impl; x->filter_abs = usage; } int grail_open(struct grail *ge, int fd) { struct grail_impl *x; int ret; x = calloc(1, sizeof(*x)); if (!x) return -ENOMEM; ge->impl = x; ret = touch_dev_open(&x->dev, fd); if (ret) goto freemem; set_emulation_caps(x, fd); x->dev.event = tp_event; x->dev.sync = tp_sync; x->dev.priv = ge; ret = gin_init(ge); if (ret) goto freedev; ret = gru_init(ge); if (ret) goto freegin; return 0; freegin: gin_destroy(ge); freedev: touch_dev_close(&x->dev, fd); freemem: free(x); ge->impl = 0; return ret; } void grail_close(struct grail *ge, int fd) { struct grail_impl *x = ge->impl; void *status; gru_destroy(ge); gin_destroy(ge); touch_dev_close(&x->dev, fd); free(ge->impl); ge->impl = 0; } int grail_idle(struct grail *ge, int fd, int ms) { struct grail_impl *x = ge->impl; return touch_dev_idle(&x->dev, fd, ms); } int grail_pull(struct grail *ge, int fd) { struct grail_impl *x = ge->impl; return touch_dev_pull(&x->dev, fd); } void grail_get_units(const struct grail *ge, struct grail_coord *min, struct grail_coord *max) { const struct touch_caps *caps = &ge->impl->dev.caps; min->x = caps->min_x; min->y = caps->min_y; max->x = caps->max_x; max->y = caps->max_y; }