From 78737a96969e98afa495cdb78a4037dff1669ddc Mon Sep 17 00:00:00 2001 From: Moritz Bitsch Date: Fri, 6 Jun 2014 11:40:33 -0400 Subject: [PATCH] ecore-drm: implement multitouch support Summary: Support for type B touch devices, tested with egalax_ts compatible touchscreen. Reviewers: devilhorns Reviewed By: devilhorns CC: cedric Differential Revision: https://phab.enlightenment.org/D933 --- src/lib/ecore_drm/Ecore_Drm.h | 1 + src/lib/ecore_drm/ecore_drm_evdev.c | 185 ++++++++++++++++++++++++++-------- src/lib/ecore_drm/ecore_drm_private.h | 14 ++- 3 files changed, 155 insertions(+), 45 deletions(-) diff --git a/src/lib/ecore_drm/Ecore_Drm.h b/src/lib/ecore_drm/Ecore_Drm.h index a8f0a64..2fffaa8 100644 --- a/src/lib/ecore_drm/Ecore_Drm.h +++ b/src/lib/ecore_drm/Ecore_Drm.h @@ -163,6 +163,7 @@ EAPI Eina_Bool ecore_drm_inputs_create(Ecore_Drm_Device *dev); EAPI void ecore_drm_inputs_destroy(Ecore_Drm_Device *dev); EAPI Eina_Bool ecore_drm_inputs_enable(Ecore_Drm_Input *input); EAPI void ecore_drm_inputs_disable(Ecore_Drm_Input *input); +EAPI void ecore_drm_inputs_device_axis_size_set(Ecore_Drm_Evdev *dev, int w, int h); EAPI Eina_Bool ecore_drm_sprites_create(Ecore_Drm_Device *dev); EAPI void ecore_drm_sprites_destroy(Ecore_Drm_Device *dev); diff --git a/src/lib/ecore_drm/ecore_drm_evdev.c b/src/lib/ecore_drm/ecore_drm_evdev.c index e5fb531..53dfa82 100644 --- a/src/lib/ecore_drm/ecore_drm_evdev.c +++ b/src/lib/ecore_drm/ecore_drm_evdev.c @@ -97,6 +97,21 @@ _device_configure(Ecore_Drm_Evdev *edev) return ret; } +static void +_device_axis_update(Ecore_Drm_Evdev *dev) +{ + int w, h; + + if (!dev) return; + + if (dev->abs.rel_w < 0 || dev->abs.rel_h < 0) + { + ecore_drm_output_size_get(dev->seat->input->dev, dev->seat->input->dev->window, &w, &h); + if (w && h) + ecore_drm_inputs_device_axis_size_set(dev, w, h); + } +} + static Eina_Bool _device_handle(Ecore_Drm_Evdev *edev) { @@ -131,7 +146,7 @@ _device_handle(Ecore_Drm_Evdev *edev) ioctl(edev->fd, EVIOCGABS(ABS_X), &absinfo); edev->abs.min_x = absinfo.minimum; edev->abs.max_x = absinfo.maximum; - edev->abs.x[0] = edev->abs.x[1] = edev->abs.min_x - 1; + edev->abs.rel_w = -1; edev->mouse.x = -1; edev->caps |= EVDEV_MOTION_ABS; } @@ -141,7 +156,7 @@ _device_handle(Ecore_Drm_Evdev *edev) ioctl(edev->fd, EVIOCGABS(ABS_Y), &absinfo); edev->abs.min_y = absinfo.minimum; edev->abs.max_y = absinfo.maximum; - edev->abs.y[0] = edev->abs.y[1] = edev->abs.min_y - 1; + edev->abs.rel_h = -1; edev->mouse.y = -1; edev->caps |= EVDEV_MOTION_ABS; } @@ -409,6 +424,17 @@ _device_notify_motion(Ecore_Drm_Evdev *dev, unsigned int timestamp) ev->root.x = ev->x; ev->root.y = ev->y; + ev->multi.device = dev->mt_slot; + ev->multi.radius = 1; + ev->multi.radius_x = 1; + ev->multi.radius_y = 1; + ev->multi.pressure = 1.0; + ev->multi.angle = 0.0; + ev->multi.x = ev->x; + ev->multi.y = ev->y; + ev->multi.root.x = ev->x; + ev->multi.root.y = ev->y; + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL); } @@ -468,6 +494,17 @@ _device_notify_button(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned ev->root.x = ev->x; ev->root.y = ev->y; + ev->multi.device = dev->mt_slot; + ev->multi.radius = 1; + ev->multi.radius_x = 1; + ev->multi.radius_y = 1; + ev->multi.pressure = 1.0; + ev->multi.angle = 0.0; + ev->multi.x = ev->x; + ev->multi.y = ev->y; + ev->multi.root.x = ev->x; + ev->multi.root.y = ev->y; + button = ((event->code & 0x00F) + 1); /* swap buttons 2 & 3 so behaviour is like X */ @@ -537,28 +574,27 @@ _device_process_flush(Ecore_Drm_Evdev *dev, unsigned int timestamp) goto out; break; case EVDEV_ABSOLUTE_TOUCH_DOWN: - goto out; - break; + case EVDEV_ABSOLUTE_TOUCH_UP: + { + struct input_event event; + + event.code = 0; + event.value = dev->abs.pt[dev->mt_slot].down; + + dev->mouse.x = dev->abs.pt[dev->mt_slot].x[0]; + dev->mouse.y = dev->abs.pt[dev->mt_slot].y[0]; + + _device_notify_motion(dev, timestamp); + _device_notify_button(dev, &event, timestamp); + + break; + } case EVDEV_ABSOLUTE_MOTION: - /* FIXME what the actual fuck */ - if ((dev->mouse.x == -1) && (dev->mouse.y == -1)) - { - /* start first motion as centered I guess? */ - dev->mouse.x = (dev->abs.min_x + dev->abs.max_x) / 2; - dev->mouse.y = (dev->abs.min_y + dev->abs.max_y) / 2; - } + dev->mouse.x = dev->abs.pt[dev->mt_slot].x[0]; + dev->mouse.y = dev->abs.pt[dev->mt_slot].y[0]; - dev->mouse.x += (dev->abs.x[0] - dev->abs.x[1]); - dev->mouse.y += (dev->abs.y[0] - dev->abs.y[1]); - dev->mouse.x = MAX(dev->abs.min_x, dev->mouse.x); - dev->mouse.y = MAX(dev->abs.min_y, dev->mouse.y); - dev->mouse.x = MIN(dev->abs.max_x, dev->mouse.x); - dev->mouse.y = MIN(dev->abs.max_y, dev->mouse.y); _device_notify_motion(dev, timestamp); break; - case EVDEV_ABSOLUTE_TOUCH_UP: - goto out; - break; } out: @@ -578,38 +614,60 @@ _device_process_key(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned in else if ((event->code >= KEY_ESC) && (event->code <= KEY_MICMUTE)) _device_notify_key(dev, event, timestamp); else if ((event->code == BTN_TOUCH) && (dev->caps & EVDEV_MOTION_ABS)) - { - dev->abs.down = event->value; - if (!dev->abs.down) - { - dev->abs.x[0] = dev->abs.x[1] = dev->abs.min_x - 1; - dev->abs.y[0] = dev->abs.y[1] = dev->abs.min_y - 1; - } - } + dev->abs.pt[dev->mt_slot].down = event->value; } static void -_device_process_absolute(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp) +_device_process_absolute(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp EINA_UNUSED) { + int tmp; + + _device_axis_update(dev); + switch (event->code) { case ABS_X: - if (dev->pending_event != EVDEV_ABSOLUTE_MOTION) - _device_process_flush(dev, timestamp); - dev->abs.x[1] = dev->abs.x[0]; - dev->abs.x[0] = event->value; - if (dev->abs.x[1] == dev->abs.min_x - 1) - dev->abs.x[1] = dev->abs.x[0]; - dev->pending_event = EVDEV_ABSOLUTE_MOTION; + if (dev->abs.pt[dev->mt_slot].down == 0) + return; + case ABS_MT_POSITION_X: + tmp = (int)((double)(event->value - dev->abs.min_x) / dev->abs.rel_w); + + dev->abs.pt[dev->mt_slot].x[0] = tmp; + + if (dev->pending_event != EVDEV_ABSOLUTE_TOUCH_DOWN) + if (dev->pending_event != EVDEV_ABSOLUTE_TOUCH_UP) + dev->pending_event = EVDEV_ABSOLUTE_MOTION; + break; case ABS_Y: - if (dev->pending_event != EVDEV_ABSOLUTE_MOTION) - _device_process_flush(dev, timestamp); - dev->abs.y[1] = dev->abs.y[0]; - dev->abs.y[0] = event->value; - if (dev->abs.y[1] == dev->abs.min_y - 1) - dev->abs.y[1] = dev->abs.y[0]; - dev->pending_event = EVDEV_ABSOLUTE_MOTION; + if (dev->abs.pt[dev->mt_slot].down == 0) + return; + case ABS_MT_POSITION_Y: + tmp = (int)((double)(event->value - dev->abs.min_y) / dev->abs.rel_h); + + dev->abs.pt[dev->mt_slot].y[0] = tmp; + + if (dev->pending_event != EVDEV_ABSOLUTE_TOUCH_DOWN) + if (dev->pending_event != EVDEV_ABSOLUTE_TOUCH_UP) + dev->pending_event = EVDEV_ABSOLUTE_MOTION; + + break; + case ABS_MT_SLOT: + if (event->value >= 0 && event->value < EVDEV_MAX_SLOTS) + dev->mt_slot = event->value; + + break; + case ABS_MT_TRACKING_ID: + if (event->value < 0) + { + dev->abs.pt[dev->mt_slot].down = 0; + dev->pending_event = EVDEV_ABSOLUTE_TOUCH_UP; + } + else + { + dev->abs.pt[dev->mt_slot].down = 1; + dev->pending_event = EVDEV_ABSOLUTE_TOUCH_DOWN; + } break; } } @@ -714,6 +772,7 @@ _ecore_drm_evdev_device_create(Ecore_Drm_Seat *seat, const char *path, int fd) edev->seat = seat; edev->path = eina_stringshare_add(path); edev->fd = fd; + edev->mt_slot = 0; if (ioctl(edev->fd, EVIOCGNAME(sizeof(name)), name) < 0) DBG("Error getting device name: %m"); @@ -763,3 +822,43 @@ _ecore_drm_evdev_device_destroy(Ecore_Drm_Evdev *dev) free(dev); } + + +/** + * @brief Set the axis size of the given device. + * + * @param dev The device to set the axis size to. + * @param w The width of the axis. + * @param h The height of the axis. + * + * This function sets set the width @p w and height @p h of the axis + * of device @p dev. If @p dev is a relative input device, a width and + * height must set for it. If its absolute set the ioctl correctly, if + * not, unsupported device. + */ +EAPI void +ecore_drm_inputs_device_axis_size_set(Ecore_Drm_Evdev *dev, int w, int h) +{ + if (!dev) return; + if ((w < 0) || (h < 0)) return; + + if (dev->caps & EVDEV_MOTION_ABS) + { + /* FIXME looks like some kernels dont include this struct */ + struct input_absinfo abs_features; + + ioctl(dev->fd, EVIOCGABS(ABS_X), &abs_features); + dev->abs.rel_w = (double)(abs_features.maximum - abs_features.minimum)/(double)(w); + dev->abs.min_x = abs_features.minimum; + + ioctl(dev->fd, EVIOCGABS(ABS_Y), &abs_features); + dev->abs.rel_h = (double)(abs_features.maximum - abs_features.minimum)/(double)(h); + dev->abs.min_y = abs_features.minimum; + } + else if (!(dev->caps & EVDEV_MOTION_REL)) + return; + + /* update the local values */ + if (dev->mouse.x > w - 1) dev->mouse.x = w -1; + if (dev->mouse.y > h - 1) dev->mouse.y = h -1; +} diff --git a/src/lib/ecore_drm/ecore_drm_private.h b/src/lib/ecore_drm/ecore_drm_private.h index d2de2b0..2456d15 100644 --- a/src/lib/ecore_drm/ecore_drm_private.h +++ b/src/lib/ecore_drm/ecore_drm_private.h @@ -69,6 +69,9 @@ extern int _ecore_drm_log_dom; +/* FIXME: Get slots from evdev device */ +#define EVDEV_MAX_SLOTS 32 + /* undef this for non-testing builds */ //# define LOG_TO_FILE @@ -178,12 +181,19 @@ struct _Ecore_Drm_Evdev const char *name, *path; int fd; + int mt_slot; + struct { int min_x, min_y; int max_x, max_y; - int x[2], y[2]; - Eina_Bool down : 1; + double rel_w, rel_h; + struct + { + int x[2]; + int y[2]; + Eina_Bool down : 1; + } pt[EVDEV_MAX_SLOTS]; } abs; struct -- 2.7.4