summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2014-06-04 14:04:08 +0200
committerHans de Goede <hdegoede@redhat.com>2014-06-17 15:46:48 +0200
commitff15ed82e3f416753f965831470057d2ab246304 (patch)
tree273ea23f35ea66b21c544dfa2145277874e0ee2b
parent81ed5950edc4910ada12d34b7ab26135fe35cef1 (diff)
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--src/Makefile.am3
-rw-r--r--src/evdev-libgestures-timer.c107
-rw-r--r--src/evdev-libgestures.c351
-rw-r--r--src/evdev-libgestures.h32
-rw-r--r--src/evdev.c2
-rw-r--r--src/evdev.h3
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);