diff --git a/src/evdev.c b/src/evdev.c index 346f11ab..12617245 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1924,6 +1924,7 @@ evdev_configure_device(struct evdev_device *device) if (udev_tags & EVDEV_UDEV_TAG_TOUCHPAD) { device->dispatch = evdev_mt_touchpad_create(device); + device->seat_caps |= EVDEV_DEVICE_GESTURE; log_info(libinput, "input device '%s', %s is a touchpad\n", device->devname, devnode); @@ -2287,6 +2288,8 @@ evdev_device_has_capability(struct evdev_device *device, return !!(device->seat_caps & EVDEV_DEVICE_KEYBOARD); case LIBINPUT_DEVICE_CAP_TOUCH: return !!(device->seat_caps & EVDEV_DEVICE_TOUCH); + case LIBINPUT_DEVICE_CAP_GESTURE: + return !!(device->seat_caps & EVDEV_DEVICE_GESTURE); default: return 0; } diff --git a/src/evdev.h b/src/evdev.h index aa548d2d..77db1b47 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -59,7 +59,8 @@ enum evdev_event_type { enum evdev_device_seat_capability { EVDEV_DEVICE_POINTER = (1 << 0), EVDEV_DEVICE_KEYBOARD = (1 << 1), - EVDEV_DEVICE_TOUCH = (1 << 2) + EVDEV_DEVICE_TOUCH = (1 << 2), + EVDEV_DEVICE_GESTURE = (1 << 5), }; enum evdev_device_tags { diff --git a/src/libinput-private.h b/src/libinput-private.h index d11f000f..d0299c61 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -365,6 +365,14 @@ touch_notify_touch_up(struct libinput_device *device, int32_t slot, int32_t seat_slot); +void +gesture_notify_swipe(struct libinput_device *device, + uint64_t time, + enum libinput_event_type type, + int finger_count, + const struct normalized_coords *delta, + const struct normalized_coords *unaccel); + void touch_notify_frame(struct libinput_device *device, uint64_t time); diff --git a/src/libinput.c b/src/libinput.c index d164604c..ceb47387 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -114,6 +114,14 @@ struct libinput_event_touch { struct device_coords point; }; +struct libinput_event_gesture { + struct libinput_event base; + uint32_t time; + int finger_count; + struct normalized_coords delta; + struct normalized_coords delta_unaccel; +}; + static void libinput_default_log_func(struct libinput *libinput, enum libinput_log_priority priority, @@ -237,6 +245,19 @@ libinput_event_get_touch_event(struct libinput_event *event) return (struct libinput_event_touch *) event; } +LIBINPUT_EXPORT struct libinput_event_gesture * +libinput_event_get_gesture_event(struct libinput_event *event) +{ + require_event_type(libinput_event_get_context(event), + event->type, + NULL, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END); + + return (struct libinput_event_gesture *) event; +} + LIBINPUT_EXPORT struct libinput_event_device_notify * libinput_event_get_device_notify_event(struct libinput_event *event) { @@ -637,6 +658,44 @@ libinput_event_touch_get_y(struct libinput_event_touch *event) return evdev_convert_to_mm(device->abs.absinfo_y, event->point.y); } +LIBINPUT_EXPORT uint32_t +libinput_event_gesture_get_time(struct libinput_event_gesture *event) +{ + return event->time; +} + +LIBINPUT_EXPORT int +libinput_event_gesture_get_finger_count(struct libinput_event_gesture *event) +{ + return event->finger_count; +} + +LIBINPUT_EXPORT double +libinput_event_gesture_get_dx(struct libinput_event_gesture *event) +{ + return event->delta.x; +} + +LIBINPUT_EXPORT double +libinput_event_gesture_get_dy(struct libinput_event_gesture *event) +{ + return event->delta.y; +} + +LIBINPUT_EXPORT double +libinput_event_gesture_get_dx_unaccelerated( + struct libinput_event_gesture *event) +{ + return event->delta_unaccel.x; +} + +LIBINPUT_EXPORT double +libinput_event_gesture_get_dy_unaccelerated( + struct libinput_event_gesture *event) +{ + return event->delta_unaccel.y; +} + struct libinput_source * libinput_add_fd(struct libinput *libinput, int fd, @@ -1086,6 +1145,9 @@ device_has_cap(struct libinput_device *device, case LIBINPUT_DEVICE_CAP_TOUCH: capability = "CAP_TOUCH"; break; + case LIBINPUT_DEVICE_CAP_GESTURE: + capability = "CAP_GESTURE"; + break; } log_bug_libinput(device->seat->libinput, @@ -1342,6 +1404,34 @@ touch_notify_frame(struct libinput_device *device, &touch_event->base); } +void +gesture_notify_swipe(struct libinput_device *device, + uint64_t time, + enum libinput_event_type type, + int finger_count, + const struct normalized_coords *delta, + const struct normalized_coords *unaccel) +{ + struct libinput_event_gesture *gesture_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_GESTURE)) + return; + + gesture_event = zalloc(sizeof *gesture_event); + if (!gesture_event) + return; + + *gesture_event = (struct libinput_event_gesture) { + .time = time, + .finger_count = finger_count, + .delta = *delta, + .delta_unaccel = *unaccel, + }; + + post_device_event(device, time, type, + &gesture_event->base); +} + static void libinput_post_event(struct libinput *libinput, struct libinput_event *event) @@ -1607,6 +1697,12 @@ libinput_event_touch_get_base_event(struct libinput_event_touch *event) return &event->base; } +LIBINPUT_EXPORT struct libinput_event * +libinput_event_gesture_get_base_event(struct libinput_event_gesture *event) +{ + return &event->base; +} + LIBINPUT_EXPORT struct libinput_device_group * libinput_device_group_ref(struct libinput_device_group *group) { diff --git a/src/libinput.h b/src/libinput.h index 5df71836..5cc7a4c5 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -57,7 +57,8 @@ enum libinput_log_priority { enum libinput_device_capability { LIBINPUT_DEVICE_CAP_KEYBOARD = 0, LIBINPUT_DEVICE_CAP_POINTER = 1, - LIBINPUT_DEVICE_CAP_TOUCH = 2 + LIBINPUT_DEVICE_CAP_TOUCH = 2, + LIBINPUT_DEVICE_CAP_GESTURE = 5, }; /** @@ -176,7 +177,11 @@ enum libinput_event_type { * Signals the end of a set of touchpoints at one device sample * time. This event has no coordinate information attached. */ - LIBINPUT_EVENT_TOUCH_FRAME + LIBINPUT_EVENT_TOUCH_FRAME, + + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END, }; /** @@ -360,6 +365,19 @@ libinput_event_get_keyboard_event(struct libinput_event *event); struct libinput_event_touch * libinput_event_get_touch_event(struct libinput_event *event); +/** + * @ingroup event + * + * Return the gesture event that is this input event. If the event type does + * not match the gesture event types, this function returns NULL. + * + * The inverse of this function is libinput_event_gesture_get_base_event(). + * + * @return A gesture event, or NULL for other events + */ +struct libinput_event_gesture * +libinput_event_get_gesture_event(struct libinput_event *event); + /** * @ingroup event * @@ -924,6 +942,132 @@ libinput_event_touch_get_y_transformed(struct libinput_event_touch *event, struct libinput_event * libinput_event_touch_get_base_event(struct libinput_event_touch *event); +/** + * @defgroup event_gesture Gesture events + * + * Gesture events are generated when a gesture is recognized on a touchpad. + * + * Gesture sequences always start with a LIBINPUT_EVENT_GESTURE_FOO_START + * event. All following gesture events will be of the + * LIBINPUT_EVENT_GESTURE_FOO_UPDATE type until a + * LIBINPUT_EVENT_GESTURE_FOO_END is generated which signals the end of the + * gesture. + */ + +/** + * @ingroup event_gesture + * + * @return The event time for this event + */ +uint32_t +libinput_event_gesture_get_time(struct libinput_event_gesture *event); + +/** + * @ingroup event_gesture + * + * @return The generic libinput_event of this event + */ +struct libinput_event * +libinput_event_gesture_get_base_event(struct libinput_event_gesture *event); + +/** + * @ingroup event_gesture + * + * Return the number of fingers used for a gesture. This can be used e.g. + * to differentiate between 3 or 4 finger swipes. + * + * This function can be called on all gesture events and the returned finger + * count value will not change during a sequence. + * + * @return the number of fingers used for a gesture + */ +int +libinput_event_gesture_get_finger_count(struct libinput_event_gesture *event); + +/** + * @ingroup event_gesture + * + * Return the delta between the last event and the current event. For gesture + * events that are not of type @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, this + * function returns 0. + * + * If a device employs pointer acceleration, the delta returned by this + * function is the accelerated delta. + * + * Relative motion deltas are normalized to represent those of a device with + * 1000dpi resolution. See @ref motion_normalization for more details. + * + * @note It is an application bug to call this function for events other than + * @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE. + * + * @return the relative x movement since the last event + */ +double +libinput_event_gesture_get_dx(struct libinput_event_gesture *event); + +/** + * @ingroup event_gesture + * + * Return the delta between the last event and the current event. For gesture + * events that are not of type @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, this + * function returns 0. + * + * If a device employs pointer acceleration, the delta returned by this + * function is the accelerated delta. + * + * Relative motion deltas are normalized to represent those of a device with + * 1000dpi resolution. See @ref motion_normalization for more details. + * + * @note It is an application bug to call this function for events other than + * @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE. + * + * @return the relative y movement since the last event + */ +double +libinput_event_gesture_get_dy(struct libinput_event_gesture *event); + +/** + * @ingroup event_gesture + * + * Return the relative delta of the unaccelerated motion vector of the + * current event. For gesture events that are not of type @ref + * LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, this function returns 0. + * + * Relative unaccelerated motion deltas are normalized to represent those of a + * device with 1000dpi resolution. See @ref motion_normalization for more + * details. Note that unaccelerated events are not equivalent to 'raw' events + * as read from the device. + * + * @note It is an application bug to call this function for events other than + * @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE. + * + * @return the unaccelerated relative x movement since the last event + */ +double +libinput_event_gesture_get_dx_unaccelerated( + struct libinput_event_gesture *event); + +/** + * @ingroup event_gesture + * + * Return the relative delta of the unaccelerated motion vector of the + * current event. For gesture events that are not of type @ref + * LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, this function returns 0. + * + * Relative unaccelerated motion deltas are normalized to represent those of a + * device with 1000dpi resolution. See @ref motion_normalization for more + * details. Note that unaccelerated events are not equivalent to 'raw' events + * as read from the device. + * + * @note It is an application bug to call this function for events other than + * @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE. + * + * @return the unaccelerated relative y movement since the last event + */ +double +libinput_event_gesture_get_dy_unaccelerated( + struct libinput_event_gesture *event); + /** * @defgroup base Initialization and manipulation of libinput contexts */ diff --git a/src/libinput.sym b/src/libinput.sym index 2c023367..f81ce0d7 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -146,3 +146,14 @@ LIBINPUT_0.19.0 { libinput_device_config_tap_get_drag_lock_enabled; libinput_device_config_tap_get_default_drag_lock_enabled; } LIBINPUT_0.15.0; + +TOUCHPAD_GESTURES { + libinput_event_gesture_get_base_event; + libinput_event_gesture_get_dx; + libinput_event_gesture_get_dx_unaccelerated; + libinput_event_gesture_get_dy; + libinput_event_gesture_get_dy_unaccelerated; + libinput_event_gesture_get_finger_count; + libinput_event_gesture_get_time; + libinput_event_get_gesture_event; +} LIBINPUT_0.19.0; diff --git a/test/litest.c b/test/litest.c index df521fe6..115c9ca8 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1655,6 +1655,15 @@ litest_event_type_str(struct libinput_event *event) case LIBINPUT_EVENT_TOUCH_FRAME: str = "TOUCH FRAME"; break; + case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: + str = "GESTURE SWIPE START"; + break; + case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: + str = "GESTURE SWIPE UPDATE"; + break; + case LIBINPUT_EVENT_GESTURE_SWIPE_END: + str = "GESTURE SWIPE END"; + break; } return str; } diff --git a/tools/event-debug.c b/tools/event-debug.c index 7f6c54ab..f3e52b45 100644 --- a/tools/event-debug.c +++ b/tools/event-debug.c @@ -90,6 +90,15 @@ print_event_header(struct libinput_event *ev) case LIBINPUT_EVENT_TOUCH_FRAME: type = "TOUCH_FRAME"; break; + case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: + type = "GESTURE_SWIPE_BEGIN"; + break; + case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: + type = "GESTURE_SWIPE_UPDATE"; + break; + case LIBINPUT_EVENT_GESTURE_SWIPE_END: + type = "GESTURE_SWIPE_END"; + break; } printf("%-7s %s ", libinput_device_get_sysname(dev), type); @@ -135,6 +144,9 @@ print_device_notify(struct libinput_event *ev) if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_TOUCH)) printf("t"); + if (libinput_device_has_capability(dev, + LIBINPUT_DEVICE_CAP_GESTURE)) + printf("g"); if (libinput_device_get_size(dev, &w, &h) == 0) printf("\tsize %.2f/%.2fmm", w, h); @@ -281,6 +293,31 @@ print_touch_event_with_coords(struct libinput_event *ev) xmm, ymm); } +static void +print_gesture_event_without_coords(struct libinput_event *ev) +{ + struct libinput_event_gesture *t = libinput_event_get_gesture_event(ev); + + print_event_time(libinput_event_gesture_get_time(t)); + printf("%d\n", libinput_event_gesture_get_finger_count(t)); +} + +static void +print_gesture_event_with_coords(struct libinput_event *ev) +{ + struct libinput_event_gesture *t = libinput_event_get_gesture_event(ev); + double dx = libinput_event_gesture_get_dx(t); + double dy = libinput_event_gesture_get_dy(t); + double dx_unaccel = libinput_event_gesture_get_dx_unaccelerated(t); + double dy_unaccel = libinput_event_gesture_get_dy_unaccelerated(t); + + print_event_time(libinput_event_gesture_get_time(t)); + + printf("%d %5.2f/%5.2f (%5.2f/%5.2f unaccelerated)\n", + libinput_event_gesture_get_finger_count(t), + dx, dy, dx_unaccel, dy_unaccel); +} + static int handle_and_print_events(struct libinput *li) { @@ -330,6 +367,15 @@ handle_and_print_events(struct libinput *li) case LIBINPUT_EVENT_TOUCH_FRAME: print_touch_event_without_coords(ev); break; + case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: + print_gesture_event_without_coords(ev); + break; + case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: + print_gesture_event_with_coords(ev); + break; + case LIBINPUT_EVENT_GESTURE_SWIPE_END: + print_gesture_event_without_coords(ev); + break; } libinput_event_destroy(ev); diff --git a/tools/event-gui.c b/tools/event-gui.c index 5736e979..0c2896a7 100644 --- a/tools/event-gui.c +++ b/tools/event-gui.c @@ -473,6 +473,10 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data) return FALSE; } break; + case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: + case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: + case LIBINPUT_EVENT_GESTURE_SWIPE_END: + break; } libinput_event_destroy(ev);