diff options
author | Hans de Goede <hdegoede@redhat.com> | 2014-06-04 14:04:08 +0200 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2014-06-17 15:46:48 +0200 |
commit | ff15ed82e3f416753f965831470057d2ab246304 (patch) | |
tree | 273ea23f35ea66b21c544dfa2145277874e0ee2b | |
parent | 81ed5950edc4910ada12d34b7ab26135fe35cef1 (diff) |
libgestures-wiplibgestures-integration
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/evdev-libgestures-timer.c | 107 | ||||
-rw-r--r-- | src/evdev-libgestures.c | 351 | ||||
-rw-r--r-- | src/evdev-libgestures.h | 32 | ||||
-rw-r--r-- | src/evdev.c | 2 | ||||
-rw-r--r-- | src/evdev.h | 3 |
6 files changed, 497 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index bf56184..7984de5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,6 +15,8 @@ libinput_la_SOURCES = \ evdev-mt-touchpad.h \ evdev-mt-touchpad-tap.c \ evdev-mt-touchpad-buttons.c \ + evdev-libgestures.c \ + evdev-libgestures-timer.c \ filter.c \ filter.h \ path.h \ @@ -28,6 +30,7 @@ libinput_la_SOURCES = \ libinput_la_LIBADD = $(MTDEV_LIBS) \ $(LIBUDEV_LIBS) \ $(LIBEVDEV_LIBS) \ + -lgestures \ -lm libinput_la_CFLAGS = -I$(top_srcdir)/include \ $(MTDEV_CFLAGS) \ diff --git a/src/evdev-libgestures-timer.c b/src/evdev-libgestures-timer.c new file mode 100644 index 0000000..672a4f6 --- /dev/null +++ b/src/evdev-libgestures-timer.c @@ -0,0 +1,107 @@ +/* + * Copyright © 2014 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <time.h> +#include <gestures/gestures.h> + +#include "timer.h" +#include "evdev.h" +#include "evdev-libgestures.h" + +struct GesturesTimer { + struct libinput_timer timer; + GesturesTimerCallback callback; + void *callback_data; +}; + +/* Note stime_t is an alias for double, it contains a time in seconds */ +static void +gestures_timer_set(void *provider_data, GesturesTimer *timer, stime_t delay, + GesturesTimerCallback callback, void *callback_data) +{ + struct timespec ts; + uint64_t now; + int r; + + r = clock_gettime(CLOCK_MONOTONIC, &ts); + if (r) { + log_error("clock_gettime error: %s\n", strerror(errno)); + return; + } + + now = ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000; + + timer->callback = callback; + timer->callback_data = callback_data; + + libinput_timer_set(&timer->timer, now + (uint64_t)(delay * 1000.0)); +} + +static void +gestures_timer_cancel(void *provider_data, GesturesTimer *timer) +{ + libinput_timer_cancel(&timer->timer); +} + +static void +gestures_timer_handle_timeout(uint64_t now, void *timer_func_data) +{ + GesturesTimer *timer = timer_func_data; + stime_t result; + + result = timer->callback(now / 1000.0, timer->callback_data); + if (result >= 0) + libinput_timer_set(&timer->timer, + now + (uint64_t)(result * 1000.0)); +} + +static GesturesTimer * +gestures_timer_create(void *provider_data) +{ + struct libinput *libinput = provider_data; + GesturesTimer *timer; + + timer = zalloc(sizeof *timer); + libinput_timer_init(&timer->timer, libinput, + gestures_timer_handle_timeout, timer); + + return timer; +} + +static void +gestures_timer_free(void *provider_data, GesturesTimer* timer) +{ + libinput_timer_cancel(&timer->timer); + free(timer); +} + +GesturesTimerProvider gestures_timer_provider = { + .create_fn = gestures_timer_create, + .free_fn = gestures_timer_free, + .set_fn = gestures_timer_set, + .cancel_fn = gestures_timer_cancel, +}; diff --git a/src/evdev-libgestures.c b/src/evdev-libgestures.c new file mode 100644 index 0000000..76ace04 --- /dev/null +++ b/src/evdev-libgestures.c @@ -0,0 +1,351 @@ +/* + * Copyright © 2014 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include <assert.h> +#include <stdio.h> /* FIXME only here for debug, remove me later */ +#include <gestures/gestures.h> + +#include "evdev.h" +#include "evdev-libgestures.h" + +struct gestures_dispatch { + struct evdev_dispatch base; + GestureInterpreter *interpreter; + struct FingerState *fingers; + struct FingerState *non_sparse_fingers; + int max_fingers; + int slot; + int buttons_down; + int touches_down; +}; + +static void +gestures_process_absolute(struct gestures_dispatch *gestures, + const struct input_event *e) +{ + int slot = gestures->slot; + + switch(e->code) { + case ABS_MT_TOUCH_MAJOR: + gestures->fingers[slot].touch_major = e->value; + break; + case ABS_MT_TOUCH_MINOR: + gestures->fingers[slot].touch_minor = e->value; + break; + case ABS_MT_WIDTH_MAJOR: + gestures->fingers[slot].width_major = e->value; + break; + case ABS_MT_WIDTH_MINOR: + gestures->fingers[slot].width_minor = e->value; + break; + case ABS_MT_PRESSURE: + gestures->fingers[slot].pressure = e->value; + break; + case ABS_MT_ORIENTATION: + gestures->fingers[slot].orientation = e->value; + break; + case ABS_MT_POSITION_X: + gestures->fingers[slot].position_x = e->value; + break; + case ABS_MT_POSITION_Y: + gestures->fingers[slot].position_y = e->value; + break; + case ABS_MT_TRACKING_ID: + gestures->fingers[slot].tracking_id = e->value; + break; + case ABS_MT_SLOT: + gestures->slot = e->value; + assert(slot >=0 && slot < gestures->max_fingers); + break; + /* FIXME deal with non MT abs events */ + } +} + +static void +gestures_process_key(struct gestures_dispatch *gestures, + const struct input_event *e) +{ + int button = 0; + int touches = 0; + + switch (e->code) { + case BTN_LEFT: + button = GESTURES_BUTTON_LEFT; + break; + case BTN_MIDDLE: + button = GESTURES_BUTTON_MIDDLE; + break; + case BTN_RIGHT: + button = GESTURES_BUTTON_RIGHT; + break; + case BTN_TOUCH: + touches = 1; + break; + case BTN_TOOL_DOUBLETAP: + touches = 2; + break; + case BTN_TOOL_TRIPLETAP: + touches = 3; + break; + case BTN_TOOL_QUADTAP: + touches = 4; + break; + case BTN_TOOL_QUINTTAP: + touches = 5; + break; + } + + if (button) { + if (e->value) + gestures->buttons_down |= button; + else + gestures->buttons_down &= ~button; + } + + if (touches) { + int mask = 1 << (touches - 1); + if (e->value) + gestures->touches_down |= mask; + else + gestures->touches_down &= ~mask; + } +} + +static void +gestures_process_syn(struct gestures_dispatch *gestures, + const struct input_event *e, + uint64_t time) +{ + struct HardwareState hwstate = { .timestamp = 0 }; + int i; + + hwstate.timestamp = time / 1000.0; + hwstate.buttons_down = gestures->buttons_down; + + hwstate.touch_cnt = 0; + for (i = 5; i > 0; i--) { + if (gestures->touches_down & (1 << (i - 1))) { + hwstate.touch_cnt = i; + break; + } + } + + hwstate.finger_cnt = 0; + for (i = 0; i < gestures->max_fingers; i++) { + if (gestures->fingers[i].tracking_id == -1) + continue; + + gestures->non_sparse_fingers[hwstate.finger_cnt] = + gestures->fingers[i]; + hwstate.finger_cnt++; + } + hwstate.fingers = gestures->non_sparse_fingers; + GestureInterpreterPushHardwareState(gestures->interpreter, &hwstate); +} + +static void +gestures_process(struct evdev_dispatch *dispatch, + struct evdev_device *device, + struct input_event *e, + uint64_t time) +{ + struct gestures_dispatch *gestures = + container_of(dispatch, gestures, base); + + switch (e->type) { + case EV_ABS: + gestures_process_absolute(gestures, e); + break; + case EV_KEY: + gestures_process_key(gestures, e); + break; + case EV_SYN: + gestures_process_syn(gestures, e, time); + break; + } +} + +static void +gestures_gesture_dispatch(void *data, const struct Gesture *gesture) +{ + struct gestures_dispatch *gestures = data; + + switch (gesture->type) { + case kGestureTypeMove: { + const GestureMove* move = &gesture->details.move; + printf("Gesture Move: (%f, %f)\n", move->dx, move->dy); + break; + } + case kGestureTypeScroll: { + const GestureScroll* scroll = &gesture->details.scroll; + printf("Gesture Scroll: (%f, %f)\n", scroll->dx, scroll->dy); + break; + } + case kGestureTypeButtonsChange: { + const GestureButtonsChange* buttons = &gesture->details.buttons; + printf("Gesture Button Change: down=0x%02x up=0x%02x\n", + buttons->down, buttons->up); + break; + } + default: + /* We don't handle things like swipe, etc. (yet) */ + break; + } +} + +static void +gestures_destroy(struct evdev_dispatch *dispatch) +{ + struct gestures_dispatch *gestures = + container_of(dispatch, gestures, base); + + DeleteGestureInterpreter(gestures->interpreter); + free(gestures->non_sparse_fingers); + free(gestures->fingers); + free(gestures); +} + +static struct evdev_dispatch_interface gestures_interface = { + gestures_process, + gestures_destroy +}; + +struct evdev_dispatch * +evdev_libgestures_create(struct evdev_device *device) +{ + struct gestures_dispatch *gestures; + struct HardwareProperties hwprops = { .left = 0 }; + const struct input_absinfo *absinfo; + struct map { + unsigned int code; + int ntouches; + } max_touches[] = { + { BTN_TOOL_QUINTTAP, 5 }, + { BTN_TOOL_QUADTAP, 4 }, + { BTN_TOOL_TRIPLETAP, 3 }, + { BTN_TOOL_DOUBLETAP, 2 }, + }; + struct map *m; + int i; + + gestures = zalloc(sizeof *gestures); + if (!gestures) + return NULL; + + gestures->interpreter = NewGestureInterpreter(); + if (!gestures->interpreter) { + free(gestures); + return NULL; + } + + hwprops.left = device->abs.min_x; + hwprops.right = device->abs.max_x; + hwprops.top = device->abs.min_y; + hwprops.bottom = device->abs.max_y; + /* hack for testing with kernels without Benjamin's res fix */ + hwprops.res_x = 33; /* device->abs.res_x; */ + hwprops.res_y = 33; /* device->abs.res_y; */ + /* Just hardcode this to 96 */ + hwprops.screen_x_dpi = 96; + hwprops.screen_y_dpi = 96; + + absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_ORIENTATION); + if (absinfo) { + hwprops.orientation_minimum = absinfo->minimum; + hwprops.orientation_maximum = absinfo->maximum; + } + + absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT); + if (absinfo) { + hwprops.max_finger_cnt = absinfo->maximum + 1; + gestures->slot = absinfo->value; + assert(gestures->slot < hwprops.max_finger_cnt); + } else { + hwprops.max_finger_cnt = 1; + } + + hwprops.max_touch_cnt = 1; + ARRAY_FOR_EACH(max_touches, m) { + if (libevdev_has_event_code(device->evdev, + EV_KEY, + m->code)) { + hwprops.max_touch_cnt = m->ntouches; + break; + } + } + + hwprops.supports_t5r2 = hwprops.max_touch_cnt > hwprops.max_finger_cnt; + hwprops.support_semi_mt = libevdev_has_property(device->evdev, + INPUT_PROP_SEMI_MT); + hwprops.is_button_pad = libevdev_has_property(device->evdev, + INPUT_PROP_BUTTONPAD); + + gestures->max_fingers = hwprops.max_finger_cnt; + gestures->fingers = calloc(gestures->max_fingers, + sizeof(struct FingerState)); + gestures->non_sparse_fingers = calloc(gestures->max_fingers, + sizeof(struct FingerState)); + if (!gestures->fingers || !gestures->non_sparse_fingers) { + gestures_destroy(&gestures->base); + return NULL; + } + + for (i = 0; i < gestures->max_fingers; i++) + gestures->fingers[i].tracking_id = -1; + + /* We only use libgestures with touchpads for now */ + GestureInterpreterInitialize(gestures->interpreter, + GESTURES_DEVCLASS_TOUCHPAD); + GestureInterpreterSetHardwareProperties(gestures->interpreter, + &hwprops); + GestureInterpreterSetTimerProvider(gestures->interpreter, + &gestures_timer_provider, device->base.seat->libinput); + GestureInterpreterSetCallback(gestures->interpreter, + gestures_gesture_dispatch, gestures); + + gestures->base.interface = &gestures_interface; + + return &gestures->base; +} + +/* libgestures needs us to export this */ +LIBINPUT_EXPORT void +gestures_log(int verb, const char *format, ...) +{ + enum libinput_log_priority priority = LIBINPUT_LOG_PRIORITY_ERROR; + va_list args; + + switch (verb) { + case GESTURES_LOG_ERROR: + priority = LIBINPUT_LOG_PRIORITY_ERROR; + break; + case GESTURES_LOG_INFO: + priority = LIBINPUT_LOG_PRIORITY_INFO; + break; + } + + va_start(args, format); + log_msg_va(priority, format, args); + va_end(args); +} diff --git a/src/evdev-libgestures.h b/src/evdev-libgestures.h new file mode 100644 index 0000000..a3e7a8c --- /dev/null +++ b/src/evdev-libgestures.h @@ -0,0 +1,32 @@ +/* + * Copyright © 2014 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef EVDEV_GESTURES_H +#define EVDEV_GESTURES_H + +#include "config.h" + +#include <gestures/gestures.h> + +extern GesturesTimerProvider gestures_timer_provider; + +#endif diff --git a/src/evdev.c b/src/evdev.c index b72e5e1..fcf8d8f 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -671,7 +671,7 @@ evdev_configure_device(struct evdev_device *device) libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_FINGER) && !libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_PEN) && (has_abs || has_mt)) { - device->dispatch = evdev_mt_touchpad_create(device); + device->dispatch = evdev_libgestures_create(device); log_info("input device '%s', %s is a touchpad\n", device->devname, device->devnode); } diff --git a/src/evdev.h b/src/evdev.h index 2db990f..62d8597 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -126,6 +126,9 @@ evdev_touchpad_create(struct evdev_device *device); struct evdev_dispatch * evdev_mt_touchpad_create(struct evdev_device *device); +struct evdev_dispatch * +evdev_libgestures_create(struct evdev_device *device); + void evdev_device_proces_event(struct libinput_event *event); |