From 94b8e3b80f3771bfe7ea799aed5895f729b06271 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Mon, 18 Oct 2010 18:12:07 +0200 Subject: [PATCH 2/2] Use a unified pointer emulation model The existing kernel MT devices together use a handful of different pointer emulation strategies, each with its own subtlety. This creates a problem for grail, which needs to rebuild pointer emulation during gesture recognition; relying on the correct pointer information to be available at the right time becomes almost impossible. This patch implements a common pointer emulation model for grail, following a strategy recently discussed on LKML. This resolves the problems stemming from different emulation strategies, and results in a common pointer emulation experience for all devices. Signed-off-by: Henrik Rydberg --- src/grail-api.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/grail-impl.h | 1 + 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/grail-api.c b/src/grail-api.c index 9cc94df..f013aa3 100644 --- a/src/grail-api.c +++ b/src/grail-api.c @@ -36,10 +36,6 @@ static void tp_event(struct touch_dev *dev, struct grail *ge = dev->priv; struct grail_impl *x = ge->impl; if (ev->type == EV_ABS) { - if (ev->code == ABS_X) - x->pointer_x = ev->value; - if (ev->code == ABS_Y) - x->pointer_y = ev->value; return; } if (ev->type == EV_KEY) { @@ -80,6 +76,60 @@ static void report_up(struct grail_impl *impl, const struct input_event *syn) 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; @@ -95,6 +145,7 @@ static void handle_abs_events(struct grail *ge, const struct input_event *syn) 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; @@ -175,6 +226,7 @@ int grail_open(struct grail *ge, int fd) 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; diff --git a/src/grail-impl.h b/src/grail-impl.h index 6093a0f..dc3b425 100644 --- a/src/grail-impl.h +++ b/src/grail-impl.h @@ -28,6 +28,7 @@ struct grail_impl { struct touch_dev dev; + struct touch_caps emu; struct evbuf evbuf; int filter_abs; int pointer_status; -- 1.7.1