libinput repository created
Hi guys after a bit of waiting time, we now have libinput in a fresh, still warm repository on freedesktop: http://cgit.freedesktop.org/wayland/libinput libinput is the weston input handling code forked off into a library. The goal of libinput is to provide a common code base for the various input-device related bits we need in all compositors. There's little point to every compositor having a separate implementation for touchpad tapping, scrolling, etc. Since Jonas' original announcement in November a few bits and pieces have changed. If you haven't followed the history on Jonas' github repository, here is a short summary: * the API is an event-based API as opposed to the original interface API, so the basic interaction with libinput is libinput_dispatch() followed by libinput_get_event() for the actual event handling in the compositor. The event types are one high-level type (libinput_event) and one for each logical group of events (libinput_event_pointer, libinput_event_keyboard, ...), each of which with their own accessors. * plenty of doxygen documentation was added, so it looks almost like a well-documented library now ;) * the udev discovery code is now inside libinput, so a simple libinput_create_from_udev() is enough to get libinput onto the device list * a path-based backend was added (mainly for Xorg drivers and the test suite) to create a context from a single device node * a test suite was added, still needs a few more tests but it's coming along well * seat events were removed as top-level events, libinput provides device added/removed events and if seat information is needed it can be obtained from the device directly I've collected the usual links and basic information on a small wiki page: http://freedesktop.org/wiki/Software/libinput/ Note that the project is still quite young, the actual code on features not related to transforming it to a library has changed very little so don't expect it to behave much different to what weston already uses. Specificially, two big bits that are currently missing are device capability discovery (is this a touchpad? what's the x axis resolution?) and a configuration interface (tapping enabled or disabled?). This will come over the next weeks and months. This email is mostly a heads-up that the project exists 'officially' now. And we'll be using wayland-devel as the discussion and patch review list, so expect to see a number of patches heading straight for here. Do chime in and comment. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 5/5] tools: add a tool for basic event debugging
Simply prints the various events to make it easier to check what's coming out of libinput. Works for --udev (the default) or for --device /dev/input/event0. Example output: event7 DEVICE_ADDEDseat0 default event8 DEVICE_ADDEDseat0 default event4 POINTER_BUTTON +1.35s 272 pressed event5 POINTER_MOTION +2.31s -3.00/ 2.00 Time is displayed relative to the starting time. Note: statically linked for easier debugging, but we don't distribute it (yet) anyway. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- Makefile.am | 2 +- configure.ac| 3 +- tools/.gitignore| 1 + tools/Makefile.am | 7 + tools/event-debug.c | 453 5 files changed, 464 insertions(+), 2 deletions(-) create mode 100644 tools/.gitignore create mode 100644 tools/Makefile.am create mode 100644 tools/event-debug.c diff --git a/Makefile.am b/Makefile.am index 07bfcd4..08bf7ce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = src doc test +SUBDIRS = src doc test tools ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} diff --git a/configure.ac b/configure.ac index 7281bb4..44729a9 100644 --- a/configure.ac +++ b/configure.ac @@ -87,5 +87,6 @@ AC_CONFIG_FILES([Makefile src/Makefile src/libinput.pc src/libinput-version.h -test/Makefile]) +test/Makefile +tools/Makefile]) AC_OUTPUT diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 000..2cdd654 --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1 @@ +event-debug diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 000..9c29f56 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,7 @@ +noinst_PROGRAMS = event-debug + +AM_CPPFLAGS = -I$(top_srcdir)/src + +event_debug_SOURCES = event-debug.c +event_debug_LDADD = ../src/libinput.la +event_debug_LDFLAGS = -static diff --git a/tools/event-debug.c b/tools/event-debug.c new file mode 100644 index 000..53e92b0 --- /dev/null +++ b/tools/event-debug.c @@ -0,0 +1,453 @@ +/* + * 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. + */ + +#define _GNU_SOURCE +#include errno.h +#include fcntl.h +#include getopt.h +#include poll.h +#include stdio.h +#include signal.h +#include string.h +#include time.h +#include unistd.h +#include linux/input.h +#include sys/ioctl.h +#include sys/signalfd.h + +#include libinput.h + +static enum { + MODE_UDEV, + MODE_DEVICE, +} mode = MODE_UDEV; +static const char *device; +static const char *seat = seat0; +static struct udev *udev; +uint32_t start_time; + +static void +usage(void) +{ + printf(Usage: %s [--udev [seat]|--device /dev/input/event0]\n + --udev seat Use udev device discovery (default).\n +Specifying a seat ID is optional.\n + --device /path/to/device open the given device only\n, + program_invocation_short_name); +} + +static int +parse_args(int argc, char **argv) +{ + while (1) { + int c; + int option_index = 0; + static struct option opts[] = { + { device, 1, 0, 'd' }, + { udev, 0, 0, 'u' }, + { help, 0, 0, 'h' }, + { 0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, h, opts, option_index); + if (c == -1) + break; + + switch(c) { + case 'h': /* --help */ + usage(); + exit(0); + case 'd': /* --device */ + mode = MODE_DEVICE; + if (!optarg
[PATCH libinput 3/5] path: print error when failing to open a device
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/path.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/path.c b/src/path.c index 2553005..2b8f530 100644 --- a/src/path.c +++ b/src/path.c @@ -130,7 +130,8 @@ path_input_enable(struct libinput *libinput) fd = open_restricted(libinput, input-path, O_RDWR|O_NONBLOCK); if (fd 0) { - log_info(opening input device '%s' failed.\n, devnode); + log_info(opening input device '%s' failed (%s).\n, +devnode, strerror(-fd)); return -1; } -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 4/5] test: Make sure the sysname of a device is correct
Currently this means start with event and don't contain /. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- test/path.c | 23 +++ test/udev.c | 34 ++ 2 files changed, 57 insertions(+) diff --git a/test/path.c b/test/path.c index 12787f6..875cd88 100644 --- a/test/path.c +++ b/test/path.c @@ -187,6 +187,28 @@ START_TEST(path_added_device) } END_TEST +START_TEST(path_device_sysname) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_event *ev; + struct libinput_device *device; + const char *sysname; + + libinput_dispatch(dev-libinput); + + while ((ev = libinput_get_event(dev-libinput))) { + if (libinput_event_get_type(ev) != LIBINPUT_EVENT_DEVICE_ADDED) + continue; + + device = libinput_event_get_device(ev); + sysname = libinput_device_get_sysname(device); + ck_assert(sysname != NULL strlen(sysname) 1); + ck_assert(strchr(sysname, '/') == NULL); + ck_assert_int_eq(strncmp(sysname, event, 5), 0); + } +} +END_TEST + START_TEST(path_suspend) { struct libinput *li; @@ -304,6 +326,7 @@ int main (int argc, char **argv) { litest_add(path:suspend, path_double_resume, LITEST_ANY, LITEST_ANY); litest_add(path:seat events, path_added_seat, LITEST_ANY, LITEST_ANY); litest_add(path:device events, path_added_device, LITEST_ANY, LITEST_ANY); + litest_add(path:device events, path_device_sysname, LITEST_ANY, LITEST_ANY); return litest_run(argc, argv); } diff --git a/test/udev.c b/test/udev.c index f61dd24..235d10e 100644 --- a/test/udev.c +++ b/test/udev.c @@ -294,6 +294,39 @@ START_TEST(udev_suspend_resume) } END_TEST +START_TEST(udev_device_sysname) +{ + struct libinput *li; + struct libinput_event *ev; + struct libinput_device *device; + const char *sysname; + struct udev *udev; + + udev = udev_new(); + ck_assert(udev != NULL); + + li = libinput_create_from_udev(simple_interface, NULL, udev, seat0); + ck_assert(li != NULL); + + libinput_dispatch(li); + + while ((ev = libinput_get_event(li))) { + if (libinput_event_get_type(ev) != LIBINPUT_EVENT_DEVICE_ADDED) + continue; + + device = libinput_event_get_device(ev); + sysname = libinput_device_get_sysname(device); + ck_assert(sysname != NULL strlen(sysname) 1); + ck_assert(strchr(sysname, '/') == NULL); + ck_assert_int_eq(strncmp(sysname, event, 5), 0); + libinput_event_destroy(ev); + } + + libinput_destroy(li); + udev_unref(udev); +} +END_TEST + int main (int argc, char **argv) { litest_add_no_device(udev:create, udev_create_NULL); @@ -305,6 +338,7 @@ int main (int argc, char **argv) { litest_add(udev:suspend, udev_double_suspend, LITEST_ANY, LITEST_ANY); litest_add(udev:suspend, udev_double_resume, LITEST_ANY, LITEST_ANY); litest_add(udev:suspend, udev_suspend_resume, LITEST_ANY, LITEST_ANY); + litest_add(udev:device events, udev_device_sysname, LITEST_ANY, LITEST_ANY); return litest_run(argc, argv); } -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 2/5] path: store the sysname, not the syspath, in the device
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/path.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/path.c b/src/path.c index 3b09cbe..2553005 100644 --- a/src/path.c +++ b/src/path.c @@ -75,7 +75,7 @@ path_seat_create(struct path_input *input, static int path_get_udev_properties(const char *path, -char **syspath, +char **sysname, char **seat_name, char **seat_logical_name) { @@ -96,7 +96,7 @@ path_get_udev_properties(const char *path, if (!device) goto out; - *syspath = strdup(udev_device_get_syspath(device)); + *sysname = strdup(udev_device_get_sysname(device)); seat = udev_device_get_property_value(device, ID_SEAT); *seat_name = strdup(seat ? seat : default_seat); @@ -121,7 +121,7 @@ path_input_enable(struct libinput *libinput) struct path_seat *seat; struct evdev_device *device; const char *devnode = input-path; - char *syspath; + char *sysname; int fd; char *seat_name, *seat_logical_name; @@ -134,10 +134,10 @@ path_input_enable(struct libinput *libinput) return -1; } - if (path_get_udev_properties(devnode, syspath, + if (path_get_udev_properties(devnode, sysname, seat_name, seat_logical_name) == -1) { close_restricted(libinput, fd); - log_info(failed to obtain syspath for device '%s'.\n, devnode); + log_info(failed to obtain sysname for device '%s'.\n, devnode); return -1; } @@ -145,8 +145,8 @@ path_input_enable(struct libinput *libinput) free(seat_name); free(seat_logical_name); - device = evdev_device_create(seat-base, devnode, syspath, fd); - free(syspath); + device = evdev_device_create(seat-base, devnode, sysname, fd); + free(sysname); libinput_seat_unref(seat-base); if (device == EVDEV_UNHANDLED_DEVICE) { -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
libinput requirements for feature parity with X
Here's a list of features I consider the minimum to get something akin to feature-parity with the current X.Org-based stack. This is not a wishlist for features, it's a list of minimum requirements that covers 90% of the user base. keyboard: I don't think there's much to do, keyboards are fairly simple and the hard bits are handled in the client with XKB. mouse-like pointer devices: * middle mouse button emulation (left+right → middle) * configuration interface for mouse button mapping, specifically left-handed * lower-priority: wheel emulation * lower-priority: rotation direct-touch touchscreens: * optional: configuration interface for rotation. can be achieved with the calibration matrix already touchpads: * clickpad-style software buttons * middle mouse button emulation (for physical buttons) * two/three-finger tapping + configuration interface * edge scrolling * support for Lenovo T440 style trackstick buttons * disable-while-typing * clickfinger handling * lower-priority: palm detection * lower-priority: accidental click detection graphics tablets: * extended axis event support * tool change notification (could be just button events? not sure) * interface to switch between relative and absolute mode * device rotation * touch-vs-pen event synchronization (disable touch while the pen is in use, etc.) generic: * type identifier interface, so that a compositor can tell that there's a touchpad present, or a mouse, or... * configuration interfaces for the various settings * device capability discovery interfaces for axis resolutions, number of buttons, etc. Anything obvious I missed here? Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 2/2] Remove mention of delta coordinates having device specific direction
On Wed, Jan 29, 2014 at 09:33:12PM +0100, Jonas Ådahl wrote: The event represent pointer motions on a screen, so this information is unnecessary. It could also be confused for meaning the provided coordinate's direction being device specific. Signed-off-by: Jonas Ådahl jad...@gmail.com just for the archives: what I meant with this sentence is that while the positive x/y coordinates are right/down on the screen, there is no guarantee that matches a device's notion of up/down. for example, if you hold a graphics tablet upside down, the positive y direction is actually up on the tablet (if it isn't software-rotated). This is probably obvious anyway, and the extra documentation does little other than adding confusion, so Reviewed-by: Peter Hutterer peter.hutte...@who-t.net. Cheers, Peter --- src/libinput.h | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libinput.h b/src/libinput.h index 8d347b9..e2d83bf 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -363,9 +363,9 @@ libinput_event_pointer_get_time( /** * @ingroup event_pointer * - * Return the delta between the last event and the current event. The axis' - * positive direction is device-specific. For pointer events that are - * not of type LIBINPUT_EVENT_POINTER_MOTION, this function returns 0. + * Return the delta between the last event and the current event. For pointer + * events that are not of type LIBINPUT_EVENT_POINTER_MOTION, this function + * returns 0. * * @note It is an application bug to call this function for events other than * LIBINPUT_EVENT_POINTER_MOTION. @@ -379,9 +379,9 @@ libinput_event_pointer_get_dx( /** * @ingroup event_pointer * - * Return the delta between the last event and the current event. The - * axis' positive direction is device-specific. For pointer events that are - * not of type LIBINPUT_EVENT_POINTER_MOTION, this function returns 0. + * Return the delta between the last event and the current event. For pointer + * events that are not of type LIBINPUT_EVENT_POINTER_MOTION, this function + * returns 0. * * @note It is an application bug to call this function for events other than * LIBINPUT_EVENT_POINTER_MOTION. -- 1.8.3.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 1/2] Replace output screen size callback with transform helpers
On Wed, Jan 29, 2014 at 09:33:11PM +0100, Jonas Ådahl wrote: Instead of automatically transforming absolute coordinates of touch and pointer events to screen coordinates, the user now uses the corresponding transform helper function. This means the coordinates returned by libinput_event_pointer_get_absolute_x(), libinput_event_pointer_get_absolute_y(), libinput_touch_get_x() and libinput_touch_get_y() has changed from being in output screen coordinate space to being in device specific coordinate space. For example, where one before would call libinput_event_touch_get_x(event), one now calls libinput_event_touch_get_x_transformed(event, output_width). Signed-off-by: Jonas Ådahl jad...@gmail.com --- src/evdev.c| 54 ++-- src/evdev.h| 10 + src/libinput.c | 44 src/libinput.h | 128 + test/litest.c | 11 - 5 files changed, 186 insertions(+), 61 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 46bd35a..cb83a1f 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -86,6 +86,24 @@ transform_absolute(struct evdev_device *device, int32_t *x, int32_t *y) } } +li_fixed_t +evdev_device_transform_x(struct evdev_device *device, + li_fixed_t x, + uint32_t width) +{ + return (x - device-abs.min_x) * width / + (device-abs.max_x - device-abs.min_x); +} + +li_fixed_t +evdev_device_transform_y(struct evdev_device *device, + li_fixed_t y, + uint32_t height) +{ + return (y - device-abs.min_y) * height / + (device-abs.max_y - device-abs.min_y); you're mixing coordinate systems here, x and y are in fixed_t but abs.min/max is in normal integers. that breaks if you have a non-zero min. You'll need to convert the rest to li_fixed_t too if you want to keep the integer division. also, should we add a non-zero min for width and height to scale to a screen not the top/left-most? The compositor can just add it afterwards, but it would have to convert to fixed_t as well: x = libinput_event_touch_get_x_transformed(event, screen_width); x += li_fixed_from_int(screen_offset); which is more error prone than something like: x = libinput_event_touch_get_x_transformed(event, screen_offset_x, screen_width); also, is it likely that the caller always has the screen dimensions handy when it comes to processing events? or would an config-style approach work better: libinput_device_set_output_dimensions(device, xoff, yoff, width, height); ... x = libinput_event_touch_get_x_transformed(event); y = libinput_event_touch_get_y_transformed(event); I also suspect that the device-specific dimensions will be rather useless if we don't have a call to get the min/max from each device. which I should be focusing on real soon :) Cheers, Peter +} + static void evdev_flush_pending_event(struct evdev_device *device, uint32_t time) { @@ -242,16 +260,6 @@ evdev_process_touch(struct evdev_device *device, struct input_event *e, uint32_t time) { - struct libinput *libinput = device-base.seat-libinput; - int screen_width; - int screen_height; - - libinput-interface-get_current_screen_dimensions( - device-base, - screen_width, - screen_height, - libinput-user_data); - switch (e-code) { case ABS_MT_SLOT: evdev_flush_pending_event(device, time); @@ -267,16 +275,12 @@ evdev_process_touch(struct evdev_device *device, device-pending_event = EVDEV_ABSOLUTE_MT_UP; break; case ABS_MT_POSITION_X: - device-mt.slots[device-mt.slot].x = - (e-value - device-abs.min_x) * screen_width / - (device-abs.max_x - device-abs.min_x); + device-mt.slots[device-mt.slot].x = e-value; if (device-pending_event == EVDEV_NONE) device-pending_event = EVDEV_ABSOLUTE_MT_MOTION; break; case ABS_MT_POSITION_Y: - device-mt.slots[device-mt.slot].y = - (e-value - device-abs.min_y) * screen_height / - (device-abs.max_y - device-abs.min_y); + device-mt.slots[device-mt.slot].y = e-value; if (device-pending_event == EVDEV_NONE) device-pending_event = EVDEV_ABSOLUTE_MT_MOTION; break; @@ -287,28 +291,14 @@ static inline void evdev_process_absolute_motion(struct evdev_device *device, struct input_event *e) { - struct libinput *libinput = device-base.seat-libinput; - int screen_width; - int screen_height; - - libinput-interface-get_current_screen_dimensions( - device-base, -
Re: libinput requirements for feature parity with X
On Thu, Jan 30, 2014 at 10:30:40AM -0800, Ping Cheng wrote: On Tue, Jan 28, 2014 at 6:18 PM, Peter Hutterer peter.hutte...@who-t.netwrote: Here's a list of features I consider the minimum to get something akin to feature-parity with the current X.Org-based stack. This is not a wishlist for features, it's a list of minimum requirements that covers 90% of the user base. keyboard: I don't think there's much to do, keyboards are fairly simple and the hard bits are handled in the client with XKB. mouse-like pointer devices: * middle mouse button emulation (left+right → middle) * configuration interface for mouse button mapping, specifically left-handed * lower-priority: wheel emulation * lower-priority: rotation direct-touch touchscreens: * optional: configuration interface for rotation. can be achieved with the calibration matrix already touchpads: * clickpad-style software buttons * middle mouse button emulation (for physical buttons) * two/three-finger tapping + configuration interface * edge scrolling * support for Lenovo T440 style trackstick buttons * disable-while-typing * clickfinger handling * lower-priority: palm detection * lower-priority: accidental click detection graphics tablets: * extended axis event support * tool change notification (could be just button events? not sure) Will tool id, serial number, and tool type be supported here? eventually, yes, though I'm not quite sure yet how. Cheers, Peter * interface to switch between relative and absolute mode * device rotation * touch-vs-pen event synchronization (disable touch while the pen is in use, etc.) generic: * type identifier interface, so that a compositor can tell that there's a touchpad present, or a mouse, or... * configuration interfaces for the various settings * device capability discovery interfaces for axis resolutions, number of buttons, etc. Anything obvious I missed here? Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: libinput requirements for feature parity with X
On Thu, Jan 30, 2014 at 01:42:20PM -0800, Bill Spitzak wrote: Ping Cheng wrote: graphics tablets: * extended axis event support * tool change notification (could be just button events? not sure) Will tool id, serial number, and tool type be supported here? Shouldn't each tool be a different pointing device? That largely depends on where tools are expected to be unified. Some pens (Intuos 4, 5, Pro series) have unique IDs. So if you take them from one tablet to the next, the ID obviously stays the same so in theory you could attach a color to that tool and have it span multiple tablets. I think this is something the client stack should provide, if at all. That leaves libinput with the tablet as the main device, and the tool as a subfeature on it. It at least needs to know which tool is being used when moving it, it can't be deferred until the first button is being pushed. Are tablets capable of handling more than one tool at a time? If In the Wacom range the answer to that is some old serial ones did, but none of the tablets that came out in recent years. And I think it's unlikely to happen again. this is at all plausable I think they all have to be different pointers since otherwise there is no way to indicate which x/y position is which tool. Otherwise I guess a tool changed event would work. You can augment events through other means to indicate the tool in use, you don't need several devices. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 1/2] Replace output screen size callback with transform helpers
On Thu, Jan 30, 2014 at 08:38:02AM +0100, Jonas Ådahl wrote: On Thu, Jan 30, 2014 at 01:02:15PM +1000, Peter Hutterer wrote: On Wed, Jan 29, 2014 at 09:33:11PM +0100, Jonas Ådahl wrote: Instead of automatically transforming absolute coordinates of touch and pointer events to screen coordinates, the user now uses the corresponding transform helper function. This means the coordinates returned by libinput_event_pointer_get_absolute_x(), libinput_event_pointer_get_absolute_y(), libinput_touch_get_x() and libinput_touch_get_y() has changed from being in output screen coordinate space to being in device specific coordinate space. For example, where one before would call libinput_event_touch_get_x(event), one now calls libinput_event_touch_get_x_transformed(event, output_width). Signed-off-by: Jonas Ådahl jad...@gmail.com --- src/evdev.c| 54 ++-- src/evdev.h| 10 + src/libinput.c | 44 src/libinput.h | 128 + test/litest.c | 11 - 5 files changed, 186 insertions(+), 61 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 46bd35a..cb83a1f 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -86,6 +86,24 @@ transform_absolute(struct evdev_device *device, int32_t *x, int32_t *y) } } +li_fixed_t +evdev_device_transform_x(struct evdev_device *device, + li_fixed_t x, + uint32_t width) +{ + return (x - device-abs.min_x) * width / + (device-abs.max_x - device-abs.min_x); +} + +li_fixed_t +evdev_device_transform_y(struct evdev_device *device, + li_fixed_t y, + uint32_t height) +{ + return (y - device-abs.min_y) * height / + (device-abs.max_y - device-abs.min_y); you're mixing coordinate systems here, x and y are in fixed_t but abs.min/max is in normal integers. that breaks if you have a non-zero min. You'll need to convert the rest to li_fixed_t too if you want to keep the integer division. Yea, missed the wl_fixed_from_int here (and in _x), and they were all 0 so didn't notice it either. For multiplication, one of the factors cannot be li_fixed_t though. Same goes for division where the denominator needs to be a normal int even if the numerator is li_fixed_t. I agree, but cannot should read does not need to be. the complete formula is: scaled = (x - xmin) * (screen_max_x - screen_min_x)/(xmax - xmin) + screen_min_x fixed_t is essentially (foo * 256), so if we assume x is in fixed_t and we convert everything to fixed, we have = (x - xmin * 256) * (screen_max_x * 256 - screen_min_x * 256)/(xmax * 256 - xmin * 256) + screen_min_x * 256 = (x - xmin * 256) * (screen_max_x - screen_min_x) * 256/((xmax - xmin) * 256) + screen_min_x * 256 = (x - xmin * 256) * (screen_max_x - screen_min_x)/(xmax - xmin) + screen_min_x * 256 and because we have an offset of 0, and thus screen_max_x == width, we end up with = (x - xmin * 256) * width/(xmax - xmin) so yes, you only need to convert xmin to li_fixed_t, but that only applies because we expect a 0 screen offset. and that concludes today's math tutorial. (which I mainly did because I wasn't 100% sure on this either ;) It'd probably be worth noting this somewhere, or at least writing down the base formula so that if there are ever patches that change this at least the base formula is clear. We've messed up missing out on (+ screen_min_x) a few times in the X stack over the years. Also, there is one problem with the formula. the screen dimensions are exclusive [0,width[, the device coordinates are inclusive [min, max]. so the correct scaling should be (xmax - xmin + 1). also, should we add a non-zero min for width and height to scale to a screen not the top/left-most? The compositor can just add it afterwards, but it would have to convert to fixed_t as well: x = libinput_event_touch_get_x_transformed(event, screen_width); x += li_fixed_from_int(screen_offset); which is more error prone than something like: x = libinput_event_touch_get_x_transformed(event, screen_offset_x, screen_width); That transform wouldn't be enough. We'd have to rotate etc as well. See http://cgit.freedesktop.org/wayland/weston/tree/src/compositor.c#n3408 . Given that, I think its easiest to let libinput do the device specific transform (device coords - output coords) and then have the user translate, and do other transformations. fair enough. There is an argument to be made for libinput to do these things, or provide helper functions to avoid callers writing potentially buggy code. but not this time :) also, is it likely that the caller always has the screen dimensions handy when it comes to processing events? or would an config-style approach work better
Re: libinput mouse mode for tablets
On Thu, Jan 30, 2014 at 02:14:30PM -0800, Bill Spitzak wrote: It is not clear from this discussion what support there will be for mouse mode for the tablets. A problem I have had with the current tablet api is that it is designed for mapping the tablet to the bounding box surrounding all the outputs. mouse mode simply means that the movement is relative and does not change this scaling. What is wanted in mouse mode is a fixed translation of a 1 square on the tablet to a square in output space. Other operating systems do this when you switch to mouse mode. I have to run a rather annoying Python program every time the screen layout is changed to calculate the very non-intuitive rectangle I have to send to the mouse driver. Also I only want mouse mode when I have two outputs. If I have one the tablet can be used in direct mode. This may also be true if a program could grab the tablet and direct it to it's window that turning off mouse mode would be useful. I also have a smaller tablet that I would like to be in mouse mode all the time. I think a much more intelligent version can be done, which automatically goes into mouse mode. Basically the user chooses how big a 1-inch square on the tablet turns into in output space, and a limit to how distorted this output square can be (perhaps from 1.5:1 to 1:1.5). On every change of the tablet or outputs wayland/libinput then figures out a mapping that is not too far from this scale and within the distortion dimensions for non-mouse-mode, if that is impossible it goes to mouse mode. this has so many more cases where it won't work correctly from the user's POV that it's likely easier to just have an easily accessible way of switching between absolute and relative mode. other than that, there will be support for relative mouse mode on tablet hardware. Your general use-case is not unique, though I don't think I've heard of the the case of mapping a tablet area to the exact screen area before. Mapping it so that a square is a square, yes, but the requirement for exact size matches is new to me. Cheers, Peter I don't know if this would be libinput or the compositor but the ability to do this would be a nice addition to Wayland. ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 4/4] path: add error handling for failing to create a seat
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/path.c | 5 + 1 file changed, 5 insertions(+) diff --git a/src/path.c b/src/path.c index 7a00c0b..a2878f9 100644 --- a/src/path.c +++ b/src/path.c @@ -144,6 +144,11 @@ path_input_enable(struct libinput *libinput) seat = path_seat_create(input, seat_name, seat_logical_name); + if (!seat) { + log_info(failed to create seat for device '%s'.\n, devnode); + goto out; + } + device = evdev_device_create(seat-base, devnode, sysname, fd); libinput_seat_unref(seat-base); -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 2/4] Move closing the device fd into evdev.c
evdev_device_remove() already calls close(device-fd). Move the close_restricted call there to avoid one privileged call in the backend and one in the device. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev.c | 2 +- src/path.c | 1 - src/udev-seat.c | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 46bd35a..c1d33a9 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -720,7 +720,7 @@ evdev_device_remove(struct evdev_device *device) if (device-mtdev) mtdev_close_delete(device-mtdev); - close(device-fd); + close_restricted(device-base.seat-libinput, device-fd); list_remove(device-base.link); notify_removed_device(device-base); diff --git a/src/path.c b/src/path.c index 2893ad4..29d722b 100644 --- a/src/path.c +++ b/src/path.c @@ -42,7 +42,6 @@ path_input_disable(struct libinput *libinput) struct evdev_device *device = input-device; if (device) { - close_restricted(libinput, device-fd); evdev_device_remove(device); input-device = NULL; } diff --git a/src/udev-seat.c b/src/udev-seat.c index 5936511..86b17d7 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -169,7 +169,6 @@ static void evdev_udev_handler(void *data) { struct udev_input *input = data; - struct libinput *libinput = input-base; struct udev_device *udev_device; struct evdev_device *device, *next; const char *action; @@ -198,7 +197,6 @@ evdev_udev_handler(void *data) if (!strcmp(device-devnode, devnode)) { log_info(input device %s, %s removed\n, device-devname, device-devnode); - close_restricted(libinput, device-fd); evdev_device_remove(device); break; } @@ -219,7 +217,6 @@ udev_input_remove_devices(struct udev_input *input) libinput_seat_ref(seat-base); list_for_each_safe(device, next, seat-base.devices_list, base.link) { - close_restricted(input-base, device-fd); evdev_device_remove(device); if (list_empty(seat-base.devices_list)) { /* if the seat may be referenced by the -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH v2 libinput 2/4] Move opening and closing the device fd into evdev.c
evdev_device_remove() already calls close(device-fd). Move the close_restricted call there to avoid one privileged call in the backend and one in the device. And move the open_restricted() into the evdev device too to reduce the duplicated code in the two backends. Update to one of the tests: since we'd now fail getting the device node from the invalid /tmp path, the open_func_count is 0. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- Changes to v1: - move open_restricted into evdev_device_create() If we really get an fd open failure, we now get two error messages, but I'll fix that up in a follow-up restructure. src/evdev.c | 18 +++--- src/evdev.h | 3 +-- src/path.c | 14 +- src/udev-seat.c | 20 +--- test/path.c | 2 +- 5 files changed, 19 insertions(+), 38 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 2bc301b..61ab083 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -600,12 +600,22 @@ evdev_configure_device(struct evdev_device *device) struct evdev_device * evdev_device_create(struct libinput_seat *seat, const char *devnode, - const char *sysname, - int fd) + const char *sysname) { struct libinput *libinput = seat-libinput; struct evdev_device *device; char devname[256] = unknown; + int fd; + + /* Use non-blocking mode so that we can loop on read on +* evdev_device_data() until all events on the fd are +* read. mtdev_get() also expects this. */ + fd = open_restricted(libinput, devnode, O_RDWR | O_NONBLOCK); + if (fd 0) { + log_info(opening input device '%s' failed (%s).\n, +devnode, strerror(-fd)); + return NULL; + } device = zalloc(sizeof *device); if (device == NULL) @@ -655,6 +665,8 @@ evdev_device_create(struct libinput_seat *seat, return device; err: + if (fd = 0) + close_restricted(libinput, fd); evdev_device_destroy(device); return NULL; } @@ -710,7 +722,7 @@ evdev_device_remove(struct evdev_device *device) if (device-mtdev) mtdev_close_delete(device-mtdev); - close(device-fd); + close_restricted(device-base.seat-libinput, device-fd); list_remove(device-base.link); notify_removed_device(device-base); diff --git a/src/evdev.h b/src/evdev.h index 37c32e5..3c9f93a 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -118,8 +118,7 @@ struct evdev_dispatch { struct evdev_device * evdev_device_create(struct libinput_seat *seat, const char *devnode, - const char *sysname, - int fd); + const char *sysname); struct evdev_dispatch * evdev_touchpad_create(struct evdev_device *device); diff --git a/src/path.c b/src/path.c index 2893ad4..2254bbe 100644 --- a/src/path.c +++ b/src/path.c @@ -42,7 +42,6 @@ path_input_disable(struct libinput *libinput) struct evdev_device *device = input-device; if (device) { - close_restricted(libinput, device-fd); evdev_device_remove(device); input-device = NULL; } @@ -122,22 +121,13 @@ path_input_enable(struct libinput *libinput) struct evdev_device *device; const char *devnode = input-path; char *sysname; - int fd; char *seat_name, *seat_logical_name; if (input-device) return 0; - fd = open_restricted(libinput, devnode, O_RDWR|O_NONBLOCK); - if (fd 0) { - log_info(opening input device '%s' failed (%s).\n, -devnode, strerror(-fd)); - return -1; - } - if (path_get_udev_properties(devnode, sysname, seat_name, seat_logical_name) == -1) { - close_restricted(libinput, fd); log_info(failed to obtain sysname for device '%s'.\n, devnode); return -1; } @@ -146,16 +136,14 @@ path_input_enable(struct libinput *libinput) free(seat_name); free(seat_logical_name); - device = evdev_device_create(seat-base, devnode, sysname, fd); + device = evdev_device_create(seat-base, devnode, sysname); free(sysname); libinput_seat_unref(seat-base); if (device == EVDEV_UNHANDLED_DEVICE) { - close_restricted(libinput, fd); log_info(not using input device '%s'.\n, devnode); return -1; } else if (device == NULL) { - close_restricted(libinput, fd); log_info(failed to create input device '%s'.\n, devnode); return -1; } diff --git a/src/udev-seat.c b/src/udev-seat.c index 5936511..957e762 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -44,13 +44,11
[PATCH libinput 3/6] path: add libinput_path_add_device() and libinput_path_remove_device()
This allows multiple devices to share a single libinput context. The new function returns the newly added device immediately. Unlike the udev seat where devices may or may not be added - over the lifetime of the seat - a path-based backend knows immediately if device exists or doesn't exist. Returning the device is required by callers that have the event processing separate from adding devices - by the time we have the DEVICE_ADDED event in the queue we may have other events to process first. And the DEVICE_ADDED event won't easily link to the path we gave it anyway, so it's hard to figure out which DEVICE_ADDED event corresponds to the new device. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/libinput.h | 45 +++ src/path.c | 104 ++-- test/path.c| 114 + 3 files changed, 252 insertions(+), 11 deletions(-) diff --git a/src/libinput.h b/src/libinput.h index e2d83bf..e1d1ffb 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -729,6 +729,51 @@ libinput_create_from_path(const struct libinput_interface *interface, /** * @ingroup base * + * Add a device to a libinput context initialized with + * libinput_path_create_from_device(). If successful, the device will be + * added to the internal list and re-opened on libinput_resume(). The device + * can be removed with libinput_path_remove_device(). + * + * If the device was successfully initialized, it is returned in the device + * argument. The lifetime of the returned device pointer is limited until + * the next linput_dispatch(), use libinput_device_ref() to keep a permanent + * reference. + * + * @param libinput A previously initialized libinput context + * @param path Path to an input device + * @return The newly initiated device on success, or NULL on failure. + * + * @note It is an application bug to call this function on a libinput + * context initialize with libinput_udev_create_for_seat(). + */ +struct libinput_device * +libinput_path_add_device(struct libinput *libinput, +const char *path); + +/** + * @ingroup base + * + * Remove a device from a libinput context initialized with + * libinput_path_create_from_device() or added to such a context with + * libinput_path_add_device(). + * + * Events already processed from this input device are kept in the queue, + * the LIBINPUT_EVENT_DEVICE_REMOVED event marks the end of events for this + * device. + * + * If no matching device exists, this function does nothing. + * + * @param device A libinput device + * + * @note It is an application bug to call this function on a libinput + * context initialize with libinput_udev_create_for_seat(). + */ +void +libinput_path_remove_device(struct libinput_device *device); + +/** + * @ingroup base + * * libinput keeps a single file descriptor for all events. Call into * libinput_dispatch() if any events become available on this fd. * diff --git a/src/path.c b/src/path.c index 32483df..a5b3338 100644 --- a/src/path.c +++ b/src/path.c @@ -22,6 +22,7 @@ #include config.h +#include errno.h #include fcntl.h #include string.h #include libudev.h @@ -36,6 +37,31 @@ int path_input_process_event(struct libinput_event); static void path_seat_destroy(struct libinput_seat *seat); static void +path_disable_device(struct libinput *libinput, + struct evdev_device *device) +{ + struct libinput_seat *seat = device-base.seat; + struct evdev_device *dev, *next; + + list_for_each_safe(dev, next, + seat-devices_list, base.link) { + if (dev != device) + continue; + + evdev_device_remove(device); + if (list_empty(seat-devices_list)) { + /* if the seat may be referenced by the + client, so make sure it's dropped from + the seat list now, to be freed whenever +* the device is removed */ + list_remove(seat-link); + list_init(seat-link); + } + break; + } +} + +static void path_input_disable(struct libinput *libinput) { struct path_input *input = (struct path_input*)libinput; @@ -45,17 +71,8 @@ path_input_disable(struct libinput *libinput) list_for_each_safe(seat, tmp, input-base.seat_list, base.link) { libinput_seat_ref(seat-base); list_for_each_safe(device, next, - seat-base.devices_list, base.link) { - evdev_device_remove(device); - if (list_empty(seat-base.devices_list)) { - /* if the seat may be referenced by the - client, so make sure it's dropped from - the seat list now, to be freed
[PATCH libinput 6/6] test: Add tests for adding/removing devices
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- test/path.c | 317 1 file changed, 317 insertions(+) diff --git a/test/path.c b/test/path.c index 3aade76..59d3e5f 100644 --- a/test/path.c +++ b/test/path.c @@ -252,6 +252,25 @@ START_TEST(path_add_device) } END_TEST +START_TEST(path_add_invalid_path) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev-libinput; + struct libinput_event *event; + struct libinput_device *device; + + litest_drain_events(li); + + device = libinput_path_add_device(li, /tmp/); + ck_assert(device == NULL); + + libinput_dispatch(li); + + while ((event = libinput_get_event(li))) + ck_abort(); +} +END_TEST + START_TEST(path_device_sysname) { struct litest_device *dev = litest_current_device(); @@ -465,6 +484,300 @@ START_TEST(path_double_resume) } END_TEST +START_TEST(path_add_device_suspend_resume) +{ + struct libinput *li; + struct libinput_device *device; + struct libinput_event *event; + struct libevdev *evdev; + struct libevdev_uinput *uinput1, *uinput2; + int rc; + int nevents; + void *userdata = rc; + + evdev = libevdev_new(); + ck_assert(evdev != NULL); + + libevdev_set_name(evdev, test device); + libevdev_enable_event_code(evdev, EV_KEY, BTN_LEFT, NULL); + libevdev_enable_event_code(evdev, EV_KEY, BTN_RIGHT, NULL); + libevdev_enable_event_code(evdev, EV_REL, REL_X, NULL); + libevdev_enable_event_code(evdev, EV_REL, REL_Y, NULL); + + rc = libevdev_uinput_create_from_device(evdev, + LIBEVDEV_UINPUT_OPEN_MANAGED, + uinput1); + ck_assert_int_eq(rc, 0); + + libevdev_set_name(evdev, test device 2); + rc = libevdev_uinput_create_from_device(evdev, + LIBEVDEV_UINPUT_OPEN_MANAGED, + uinput2); + ck_assert_int_eq(rc, 0); + + libevdev_free(evdev); + + li = libinput_path_create_context(simple_interface, userdata); + ck_assert(li != NULL); + + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput1)); + ck_assert(device != NULL); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput2)); + + libinput_dispatch(li); + + nevents = 0; + while ((event = libinput_get_event(li))) { + enum libinput_event_type type; + type = libinput_event_get_type(event); + ck_assert_int_eq(type, LIBINPUT_EVENT_DEVICE_ADDED); + libinput_event_destroy(event); + nevents++; + } + + ck_assert_int_eq(nevents, 2); + + + libinput_suspend(li); + libinput_dispatch(li); + + nevents = 0; + while ((event = libinput_get_event(li))) { + enum libinput_event_type type; + type = libinput_event_get_type(event); + ck_assert_int_eq(type, LIBINPUT_EVENT_DEVICE_REMOVED); + libinput_event_destroy(event); + nevents++; + } + + ck_assert_int_eq(nevents, 2); + + libinput_resume(li); + libinput_dispatch(li); + + nevents = 0; + while ((event = libinput_get_event(li))) { + enum libinput_event_type type; + type = libinput_event_get_type(event); + ck_assert_int_eq(type, LIBINPUT_EVENT_DEVICE_ADDED); + libinput_event_destroy(event); + nevents++; + } + + ck_assert_int_eq(nevents, 2); + + libevdev_uinput_destroy(uinput1); + libevdev_uinput_destroy(uinput2); + libinput_destroy(li); + + open_func_count = 0; + close_func_count = 0; +} +END_TEST + +START_TEST(path_add_device_suspend_resume_fail) +{ + struct libinput *li; + struct libinput_device *device; + struct libinput_event *event; + struct libevdev *evdev; + struct libevdev_uinput *uinput1, *uinput2; + int rc; + int nevents; + void *userdata = rc; + + evdev = libevdev_new(); + ck_assert(evdev != NULL); + + libevdev_set_name(evdev, test device); + libevdev_enable_event_code(evdev, EV_KEY, BTN_LEFT, NULL); + libevdev_enable_event_code(evdev, EV_KEY, BTN_RIGHT, NULL); + libevdev_enable_event_code(evdev, EV_REL, REL_X, NULL); + libevdev_enable_event_code(evdev, EV_REL, REL_Y, NULL); + + rc = libevdev_uinput_create_from_device(evdev, + LIBEVDEV_UINPUT_OPEN_MANAGED, + uinput1); + ck_assert_int_eq(rc, 0); + + libevdev_set_name
[PATCH libinput 0/6] Add dynamic devices to the path backend
This patchset revamps the path backend to allow for more than one path-based device per context. I thought the initial approach of having one context per device is sufficient but there are a few use-cases that can really only be solved by having libinput control all devices. A common example is disabling the touchpad while typing, or making the trackstick buttons on the Lenovo T440s useful. So for my little libinput-based xorg driver [1] I need to have a shared context between the various devices added. The change looks bigger than it is, it largely just replicates what the udev-seat backend already does anyway. Most notable there are a few API changes: - libinput_create_from_path() has been removed, a caller should now use libinput_path_create_context(), then libinput_path_add_device() I found this to be nicer in the caller code than having libinput_path_create_from_device() and then adding devices. - more devices can be added or removed with libinput_path_add_device and libinput_path_remove_device - to ensure proper namespacing, libinput_create_from_udev is now libinput_udev_create_for_seat() So far this looks flexible enough for the xorg drivers which have different use-cases than in weston, specifically each device can be disabled and enabled individually. I just call remove/add device when that happens. What's not so nice is a shortcut in libinput_path_add_device(). Instead of just succeeding and letting the caller handle the DEVICE_ADDED event, it returns the struct libinput_device directly. At least within the xorg driver context I found it too hard to work with the events (long description on request) but the short summary is that I'd need to cache any events before DEVICE_ADDED and use timers to re-trigger the read once I have the device, aside from the problem of not being able to figure out which device is which based on the events only (we don't expose the devnode to the caller). On the positive side, the xorg driver seems to be working quite nicely already, though it is rather featureless. Cheers, Peter [1] https://github.com/whot/xf86-input-libinput ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 1/6] Store the backend type in the interface
This enables us to prevent callers from calling backend-specific functions on mismatching backends. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/libinput-private.h | 6 ++ src/path.c | 1 + src/udev-seat.c| 1 + 3 files changed, 8 insertions(+) diff --git a/src/libinput-private.h b/src/libinput-private.h index 0d7de90..ee5a17d 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -26,7 +26,13 @@ #include libinput.h #include libinput-util.h +enum libinput_backend_type { + BACKEND_UDEV, + BACKEND_PATH, +}; + struct libinput_interface_backend { + enum libinput_backend_type backend_type; int (*resume)(struct libinput *libinput); void (*suspend)(struct libinput *libinput); void (*destroy)(struct libinput *libinput); diff --git a/src/path.c b/src/path.c index de2ca49..4924b31 100644 --- a/src/path.c +++ b/src/path.c @@ -167,6 +167,7 @@ path_input_destroy(struct libinput *input) } static const struct libinput_interface_backend interface_backend = { + .backend_type = BACKEND_PATH, .resume = path_input_enable, .suspend = path_input_disable, .destroy = path_input_destroy, diff --git a/src/udev-seat.c b/src/udev-seat.c index 957e762..b564c83 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -330,6 +330,7 @@ udev_seat_get_named(struct udev_input *input, const char *seat_name) } static const struct libinput_interface_backend interface_backend = { + .backend_type = BACKEND_UDEV, .resume = udev_input_enable, .suspend = udev_input_disable, .destroy = udev_input_destroy, -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 2/6] path: modify backend to allow for more than one device
The previous path backend created a libinput context attached to a single device. This is insufficient when we need to use cross-device functionality. One example of this cross-device functionality include disabling a touchpad while the trackstick is in use (Lenovo T440 and related models). This patch merely adds the infrastructure to support multiple devices for a path backend. Follow-up patches add the function calls to add and remove devices. This is needed by Xorg input drivers that still make use of the server's device hotplug mechanisms but want to otherwise use libinput. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/path.c | 120 +++-- src/path.h | 6 +++- 2 files changed, 99 insertions(+), 27 deletions(-) diff --git a/src/path.c b/src/path.c index 4924b31..32483df 100644 --- a/src/path.c +++ b/src/path.c @@ -39,11 +39,24 @@ static void path_input_disable(struct libinput *libinput) { struct path_input *input = (struct path_input*)libinput; - struct evdev_device *device = input-device; + struct path_seat *seat, *tmp; + struct evdev_device *device, *next; - if (device) { - evdev_device_remove(device); - input-device = NULL; + list_for_each_safe(seat, tmp, input-base.seat_list, base.link) { + libinput_seat_ref(seat-base); + list_for_each_safe(device, next, + seat-base.devices_list, base.link) { + evdev_device_remove(device); + if (list_empty(seat-base.devices_list)) { + /* if the seat may be referenced by the + client, so make sure it's dropped from + the seat list now, to be freed whenever +* the device is removed */ + list_remove(seat-base.link); + list_init(seat-base.link); + } + } + libinput_seat_unref(seat-base); } } @@ -72,6 +85,22 @@ path_seat_create(struct path_input *input, return seat; } +static struct path_seat* +path_seat_get_named(struct path_input *input, + const char *seat_name_physical, + const char *seat_name_logical) +{ + struct path_seat *seat; + + list_for_each(seat, input-base.seat_list, base.link) { + if (strcmp(seat-base.physical_name, seat_name_physical) == 0 + strcmp(seat-base.logical_name, seat_name_logical) == 0) + return seat; + } + + return NULL; +} + static int path_get_udev_properties(const char *path, char **sysname, @@ -113,48 +142,64 @@ out: return rc; } -static int -path_input_enable(struct libinput *libinput) +static struct libinput_device * +path_device_enable(struct path_input *input, const char *devnode) { - struct path_input *input = (struct path_input*)libinput; struct path_seat *seat; - struct evdev_device *device; - const char *devnode = input-path; + struct evdev_device *device = NULL; char *sysname; char *seat_name, *seat_logical_name; - if (input-device) - return 0; - if (path_get_udev_properties(devnode, sysname, seat_name, seat_logical_name) == -1) { log_info(failed to obtain sysname for device '%s'.\n, devnode); - return -1; + return NULL; } - seat = path_seat_create(input, seat_name, seat_logical_name); - free(seat_name); - free(seat_logical_name); + seat = path_seat_get_named(input, seat_name, seat_logical_name); - if (!seat) { - log_info(failed to create seat for device '%s'.\n, devnode); - free(sysname); - return -1; + if (seat) { + libinput_seat_ref(seat-base); + } else { + seat = path_seat_create(input, seat_name, seat_logical_name); + if (!seat) { + log_info(failed to create seat for device '%s'.\n, devnode); + goto out; + } } device = evdev_device_create(seat-base, devnode, sysname); - free(sysname); libinput_seat_unref(seat-base); if (device == EVDEV_UNHANDLED_DEVICE) { + device = NULL; log_info(not using input device '%s'.\n, devnode); - return -1; + goto out; } else if (device == NULL) { log_info(failed to create input device '%s'.\n, devnode); - return -1; + goto out; } - input-device = device; +out: + free(sysname); + free(seat_name); + free
Re: [PATCH libinput 1/6] Store the backend type in the interface
On Thu, Feb 06, 2014 at 10:11:34PM +0100, Jonas Ådahl wrote: On Thu, Feb 06, 2014 at 02:13:05PM +1000, Peter Hutterer wrote: This enables us to prevent callers from calling backend-specific functions on mismatching backends. This can be done instead by comparing the backend interface pointer in struct libinput to the one defined in either path.c or udev-seat.c. if (libinput-interface_backend != interface_backend) { log(...); return NULL; } I think doing it like that is preferred, since we should avoid per-backend logic in the front end anyway. ok, no problem. amended locally, and that drops this patch completely and replaces it with the above condition in 3/6. Cheers, Peter Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/libinput-private.h | 6 ++ src/path.c | 1 + src/udev-seat.c| 1 + 3 files changed, 8 insertions(+) diff --git a/src/libinput-private.h b/src/libinput-private.h index 0d7de90..ee5a17d 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -26,7 +26,13 @@ #include libinput.h #include libinput-util.h +enum libinput_backend_type { + BACKEND_UDEV, + BACKEND_PATH, +}; + struct libinput_interface_backend { + enum libinput_backend_type backend_type; int (*resume)(struct libinput *libinput); void (*suspend)(struct libinput *libinput); void (*destroy)(struct libinput *libinput); diff --git a/src/path.c b/src/path.c index de2ca49..4924b31 100644 --- a/src/path.c +++ b/src/path.c @@ -167,6 +167,7 @@ path_input_destroy(struct libinput *input) } static const struct libinput_interface_backend interface_backend = { + .backend_type = BACKEND_PATH, .resume = path_input_enable, .suspend = path_input_disable, .destroy = path_input_destroy, diff --git a/src/udev-seat.c b/src/udev-seat.c index 957e762..b564c83 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -330,6 +330,7 @@ udev_seat_get_named(struct udev_input *input, const char *seat_name) } static const struct libinput_interface_backend interface_backend = { + .backend_type = BACKEND_UDEV, .resume = udev_input_enable, .suspend = udev_input_disable, .destroy = udev_input_destroy, -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 0/6] Add dynamic devices to the path backend
On Thu, Feb 06, 2014 at 10:23:57PM +0100, Jonas Ådahl wrote: On Thu, Feb 06, 2014 at 02:13:04PM +1000, Peter Hutterer wrote: This patchset revamps the path backend to allow for more than one path-based device per context. I thought the initial approach of having one context per device is sufficient but there are a few use-cases that can really only be solved by having libinput control all devices. A common example is disabling the touchpad while typing, or making the trackstick buttons on the Lenovo T440s useful. So for my little libinput-based xorg driver [1] I need to have a shared context between the various devices added. The change looks bigger than it is, it largely just replicates what the udev-seat backend already does anyway. Most notable there are a few API changes: - libinput_create_from_path() has been removed, a caller should now use libinput_path_create_context(), then libinput_path_add_device() Why not just libinput_path_create()? I wanted to make it explicit that all this call does is create the context, as opposed to e.g. udev_create_... which adds devices too. I found this to be nicer in the caller code than having libinput_path_create_from_device() and then adding devices. - more devices can be added or removed with libinput_path_add_device and libinput_path_remove_device - to ensure proper namespacing, libinput_create_from_udev is now libinput_udev_create_for_seat() These API changes looks good to me, but should maybe suspend and resume behaviour be documented? Is it required to re-add devices after having resumed? it's not required, the behaviour is that suspend/resume removes and re-adds all devices, or fails if a device cannot be added. exactly the same behavour as the udev seat. I'll expand on the suspend/resume documentation in a separate patch. So far this looks flexible enough for the xorg drivers which have different use-cases than in weston, specifically each device can be disabled and enabled individually. I just call remove/add device when that happens. What's not so nice is a shortcut in libinput_path_add_device(). Instead of just succeeding and letting the caller handle the DEVICE_ADDED event, it returns the struct libinput_device directly. At least within the xorg driver context I found it too hard to work with the events (long description on request) but the short summary is that I'd need to cache any events before DEVICE_ADDED and use timers to re-trigger the read once I have the device, aside from the problem of not being able to figure out which device is which based on the events only (we don't expose the devnode to the caller). So I guess you can't just add and then flush and process the queue right there, as the DEVICE_ADDED event will already have been queued when calling libinput_path_add_device()? Not without doing some work to the server, the enable/disable bits are in a quirky order and called from different places than the actual event processing. So without auditing the call paths I can't guarantee that the server is in the correct state for handling events when you get the first couple of events. Returning the device pointer was the less-intrusive but still somewhat-sensible approach :) We could also simply expose the devnode to the caller as well, caching and matching later is not very nice. IMO we should do this anyway, otherwise we'd require the caller to use udev and subsystem guessing* to match it up themselves. At least a devnode is non-ambiguous. Cheers, Peter * probably not much of an issue since we don't deal with serial devices, so we can assume subsystem is always input ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [RFC] libinput configuration interface
On Thu, Feb 06, 2014 at 11:28:49PM +0100, Eugen Friedrich wrote: Hi together, i would like to put some input from the embedded/ automotive perspective. you can think about huge amount of different configurations for different device types. A lot of configuration in the initial post deals with behavior of buttons and scrolling areas of the touch panels. The good approach could be a kind of general configuration of button and scrolling areas of the touch panels the button area could contain a position and dimension of the button in the device coordinate system and the button code the slider area could contain a position and dimension of the slider along with the range. generally for real touch screens (i.e. not touchpads) I think any interpretation of the values should be on the client side, not in the input library. There just isn't enough context to interpret it otherwise since you're at least partially reliant on UI hints or other elements to make sure you're emulating the right thing. For specialized cases like having a permanent input region that maps into semantic buttons (e.g. the button bar on the Android phones) this should IMO be handled by the compositor. Also the weston code contains calibration of the absolute values. It would be good also to have a calibration possibilities in libinput. Yes, calibration is a required feature, I forgot to mention that since it's already supported. Cheers, Peter What do you think? 2014-02-03 6:11 GMT+01:00 Alexander E. Patrakov patra...@gmail.com: 2014-02-03 Peter Hutterer peter.hutte...@who-t.net: On Fri, Jan 31, 2014 at 08:26:54PM +0600, Alexander E. Patrakov wrote: Peter Hutterer wrote: I've been thinking about how to add a device configuration interface to libinput, and after getting feedback from Jonas and Benjamin, here's a proposal (no code yet). First, I think the configuration should be feature-specific, not device specific, so it is independent of a classification or capabilities of a device. To the user it doesn't matter if we classify something as touchpad or as mouse, if middle mouse button emulation works that's the only thing that counts. At least for configuration purposes, this also avoids the difficult task of classifying a device correctly. Those pesky HW manufacturers do have a habit of coming up with devices that elude previously agreed-on classification schemes, e.g. mice with touchpads on them. Aside from setting an item, there should be calls to get the current value, and a call to reset to the built-in defaults. And, since we're feature-based, a call to check if the config item is possible for a device. Which leads us the the following quartet for each item: int libinput_device_config_set_foo(device, value); int libinput_device_config_get_foo(device, value); int libinput_device_config_reset_foo(device); bool libinput_device_config_has_foo(device); And the actual configuration items I've come up with so far: * {set|get|reset|has}_tap_single_finger_button * tap_double_finger_button * tap_triple_finger_button * click_finger_single * click_finger_double * click_finger_triple * twofinger_scroll_vertical * twofinger_scroll_horizonal * edge_scroll_vertical * edge_scroll_horizontal * disable_while_typing * disable_touch (while pen is in use) these two could be merged into disable while linked device is in use * softbutton_left * softbutton_middle * softbutton_right * emulate_middle_button * button_mapping * emulate_wheel * rotation * palm_detection * mode (relative/absolute) * valid_area This is needed on tablets that have a different ratio than the monitor. Mapping them to the monitor results in uneven x/y movements, so the easiest approach here is to cut a portion of the tablet off to match the ratio. * stylus_button_behaviour(some enum) Some tablets don't report proximity, the only way to get a right-button click is to hold the right button down and then tip with the stylus. Note that the above is not a 1:1 API mapping, e.g. tapping configuration could be an API taking nfingers as argument as opposed to 3 different calls. Likewise, they can take more than one value argument, e.g. middle button emulation could take a boolean to enable it, and a timeout. This list excludes options we currently have in the X drivers to adjust for hw-specific quirks. Such as defining which pressure makes up a tap, etc. I really hope this is something we can work out based on the device. It also excludes configurations that I'd really like to hide away if possible. For example, on the new T440-style touchpads the top part of it is a set of buttons for the trackstick. There's nothing
Re: [RFC] libinput configuration interface
On Sun, Feb 09, 2014 at 01:32:41PM +0100, Eugen Friedrich wrote: On 09.02.2014 05:10, Peter Hutterer wrote: On Thu, Feb 06, 2014 at 11:28:49PM +0100, Eugen Friedrich wrote: Hi together, i would like to put some input from the embedded/ automotive perspective. you can think about huge amount of different configurations for different device types. A lot of configuration in the initial post deals with behavior of buttons and scrolling areas of the touch panels. The good approach could be a kind of general configuration of button and scrolling areas of the touch panels the button area could contain a position and dimension of the button in the device coordinate system and the button code the slider area could contain a position and dimension of the slider along with the range. generally for real touch screens (i.e. not touchpads) I think any interpretation of the valthis should IMO be handled by the compositorues should be on the client side, not in the input library. There just isn't enough context to interpret it otherwise since you're at least partially reliant on UI hints or other elements to make sure you're emulating the right thing. Completely agree, active input elements which are drawn by some application should be handled by this application. For specialized cases like having a permanent input region that maps into semantic buttons (e.g. the button bar on the Android phones) this should IMO be handled by the compositor. Yes this was the aim of my proposal. This would give a flexibility to use different touch panel with different screens and put you permanent buttons and slider wherever you like. Such cases are maybe only important if you are building up a new devices but this configuration possibility would add a big value for the libinput. my main worry here is that the semantics of such buttons are unknown to anyone but the compositor. libinput has _no_ semantics other than here's and area but especially with direct-touch devices you get more complex interactions to this. For example, let's say we have a defined button area at the bottom of the screen: - should the button trigger if the finger moved from the outside into the area? - should the button trigger if the finger left and re-entered the area? - should the button trigger if the finger left the area? -- oh, btw, now you need enter/leave events to notify the compositor - should the button trigger if there is another finger within the area? - should the button trigger if there was extensive movement between press/release in the button area? .. All these usually have fairly obvious answers from a UI perspective, but a low-level library without semantic context would have to provide some matrix to enable all of them or restrict itself to a set of the above. The latter wouldn't be a problem, but we'd have to really see some good use-cases to justify the extra complexity. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH v2 libinput] Make it possible to have persistent libinput_seat instances
From: Jonas Ådahl jad...@gmail.com With this patch, a user can keep a reference to a libinput_seat instance, which will cause the seat to never be unlinked from the libinput context nor destroyed. Previously, a when the last device of a seat was removed, the seat was unlinked and if a new device was discovered with a previously empty seat a new seat instance would always be created, meaning two potential seat instances with identical physical and logical seat name pairs. Signed-off-by: Jonas Ådahl jad...@gmail.com Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- Changes to v1: - rebased on top of my path add/remove devices patch, the changes to path and udev backends are now identical - use litest_drain_events() instead of manual loop in tests - destroy the uinput device when done with it, closes a leak in the test src/libinput.c | 1 + src/libinput.h | 5 +++ src/path.c | 9 -- src/udev-seat.c | 9 -- test/path.c | 96 + test/udev.c | 75 6 files changed, 177 insertions(+), 18 deletions(-) diff --git a/src/libinput.c b/src/libinput.c index cfce2c5..cc84fb5 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -508,6 +508,7 @@ libinput_seat_init(struct libinput_seat *seat, seat-logical_name = strdup(logical_name); seat-destroy = destroy; list_init(seat-devices_list); + list_insert(libinput-seat_list, seat-link); } LIBINPUT_EXPORT void diff --git a/src/libinput.h b/src/libinput.h index e87b2b7..2fd9638 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1069,6 +1069,11 @@ libinput_device_get_output_name(struct libinput_device *device); * * Get the seat associated with this input device. * + * A seat can be uniquely identified by the physical and logical seat name. + * There will ever be only one seat instance with a given physical and logical + * seat name pair at any given time, but if no external reference is kept, it + * may be destroyed if no device belonging to it is left. + * * @param device A previously obtained device * @return The seat this input device belongs to */ diff --git a/src/path.c b/src/path.c index 31a916a..1b929e8 100644 --- a/src/path.c +++ b/src/path.c @@ -49,14 +49,6 @@ path_disable_device(struct libinput *libinput, continue; evdev_device_remove(device); - if (list_empty(seat-devices_list)) { - /* if the seat may be referenced by the - client, so make sure it's dropped from - the seat list now, to be freed whenever -* the device is removed */ - list_remove(seat-link); - list_init(seat-link); - } break; } } @@ -97,7 +89,6 @@ path_seat_create(struct path_input *input, libinput_seat_init(seat-base, input-base, seat_name, seat_logical_name, path_seat_destroy); - list_insert(input-base.seat_list, seat-base.link); return seat; } diff --git a/src/udev-seat.c b/src/udev-seat.c index 9b807be..e622de2 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -203,14 +203,6 @@ udev_input_remove_devices(struct udev_input *input) list_for_each_safe(device, next, seat-base.devices_list, base.link) { evdev_device_remove(device); - if (list_empty(seat-base.devices_list)) { - /* if the seat may be referenced by the - client, so make sure it's dropped from - the seat list now, to be freed whenever -* the device is removed */ - list_remove(seat-base.link); - list_init(seat-base.link); - } } libinput_seat_unref(seat-base); } @@ -311,7 +303,6 @@ udev_seat_create(struct udev_input *input, libinput_seat_init(seat-base, input-base, device_seat, seat_name, udev_seat_destroy); - list_insert(input-base.seat_list, seat-base.link); return seat; } diff --git a/test/path.c b/test/path.c index 59d3e5f..41ee5c6 100644 --- a/test/path.c +++ b/test/path.c @@ -778,6 +778,100 @@ START_TEST(path_add_device_suspend_resume_remove_device) } END_TEST +START_TEST(path_seat_recycle) +{ + struct libinput *li; + struct libevdev *evdev; + struct libevdev_uinput *uinput; + int rc; + void *userdata = rc; + struct libinput_event *ev; + struct libinput_device *device; + struct libinput_seat *saved_seat = NULL; + struct libinput_seat *seat; + int data = 0; + int found = 0
[PATCH libinput] evdev: restore EVDEV_UNHANDLED_DEVICE error code
If we don't have capabilities we can deal with, return a different error so the backends can handle it separately (they already do). Signe-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/evdev.c b/src/evdev.c index 9c6d116..d8dff65 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -606,6 +606,7 @@ evdev_device_create(struct libinput_seat *seat, struct evdev_device *device; char devname[256] = unknown; int fd; + int unhandled_device = 0; /* Use non-blocking mode so that we can loop on read on * evdev_device_data() until all events on the fd are @@ -645,6 +646,7 @@ evdev_device_create(struct libinput_seat *seat, goto err; if (device-seat_caps == 0) { + unhandled_device = 1; goto err; } @@ -668,7 +670,8 @@ err: if (fd = 0) close_restricted(libinput, fd); evdev_device_destroy(device); - return NULL; + + return unhandled_device ? EVDEV_UNHANDLED_DEVICE : NULL; } int -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput] Make touch event slots seat wide
On Mon, Feb 10, 2014 at 10:11:47AM +0100, Jonas Ådahl wrote: On Mon, Feb 10, 2014 at 03:13:55PM +1000, Peter Hutterer wrote: On Thu, Feb 06, 2014 at 10:27:54PM +0100, Jonas Ådahl wrote: Since a Wayland compositor have to represent all touch devices of a seat as one virtual device, lets make that easier by making the slots of touch events seat wide unique. is this really something we want to expose from libinput? it seems odd, given that everything else is per-device and even seats themselves are almost second-class citizens - i.e. you don't have to care about them at all if you don't need them. I don't think tying slot number to seats is a good idea here. I think it could be good to have libinput help out with virtual seat devices, such as ways to avoid double button and key presses, overlapping touch point slots, etc, as this is as well something that would otherwise need to be duplicated in almost every (seat aware) application. Regarding seat slots, it's more convenient to manage these in libinput since we already do keep track of per slot state, and with this patch, at least weston doesn't need to be aware of per-device slots at all. What do you think of providing this but not via the _get_slot() function? I fully agree that we should abstract this. something like libinput_event_pointer_get_seat_button() libinput_event_touch_get_seat_slot() would probably work and provide essentially the same API depending on the use-case. the only other option I can come up with right now is having a wl_pointer-like fake device in the list, but that seems about as insane as XI2 :) As a side note, making slots seat wide does not make them any less device wide. of course. what it does change though is that if we add a function to retrieve the number of simultaneous touches (i.e. slots) per device, this wouldn't map easily anymore and would in fact be rather unpredictable (since it depends on the number of devices). Cheers, Peter Signed-off-by: Jonas Ådahl jad...@gmail.com --- src/evdev.c| 24 +--- src/evdev.h| 3 +++ src/libinput-private.h | 1 + src/libinput.h | 4 ++-- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 2bc301b..80210fb 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -109,7 +109,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) { int32_t cx, cy; int slot; + uint32_t seat_slot; struct libinput_device *base = device-base; + struct libinput_seat *seat = base-seat; slot = device-mt.slot; @@ -128,9 +130,13 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = ffs(~seat-slot_map) - 1; + device-mt.slots[slot].seat_slot = seat_slot; + seat-slot_map |= 1 seat_slot; + touch_notify_touch(base, time, -slot, +seat_slot, li_fixed_from_int(device-mt.slots[slot].x), li_fixed_from_int(device-mt.slots[slot].y), LIBINPUT_TOUCH_TYPE_DOWN); @@ -139,6 +145,8 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = device-mt.slots[slot].seat_slot; + touch_notify_touch(base, time, slot, @@ -150,9 +158,12 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = device-mt.slots[slot].seat_slot; + seat-slot_map = ~(1 seat_slot); + touch_notify_touch(base, time, -slot, +seat_slot, 0, 0, LIBINPUT_TOUCH_TYPE_UP); break; @@ -160,6 +171,10 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = ffs(~seat-slot_map) - 1; + device-abs.seat_slot = seat_slot; + seat-slot_map |= 1 seat_slot; + transform_absolute(device, cx, cy); touch_notify_touch(base, time, @@ -173,7 +188,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (device-seat_caps EVDEV_DEVICE_TOUCH
Re: [PATCH libinput 5/5] Add seat wide slot to touch events
On Wed, Feb 12, 2014 at 09:36:42PM +0100, Jonas Ådahl wrote: Since a Wayland compositor have to represent all touch devices of a seat as one virtual device, lets make that easier by also providing seat wide slots with touch events. Seat wide slots may be accessed using libinput_event_touch_get_seat_slot(). Signed-off-by: Jonas Ådahl jad...@gmail.com --- src/evdev.c| 24 src/evdev.h| 3 +++ src/libinput-private.h | 2 ++ src/libinput.c | 9 + src/libinput.h | 13 + 5 files changed, 51 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index 3fe28e4..7393df7 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -109,7 +109,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) { int32_t cx, cy; int slot; + uint32_t seat_slot; struct libinput_device *base = device-base; + struct libinput_seat *seat = base-seat; slot = device-mt.slot; @@ -128,9 +130,14 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = ffs(~seat-slot_map) - 1; this needs some check for ffs() returning 0, it's not that hard to create 32 touchpoints. + device-mt.slots[slot].seat_slot = seat_slot; + seat-slot_map |= 1 seat_slot; + touch_notify_touch(base, time, slot, +seat_slot, li_fixed_from_int(device-mt.slots[slot].x), li_fixed_from_int(device-mt.slots[slot].y), LIBINPUT_TOUCH_TYPE_DOWN); @@ -139,9 +146,12 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = device-mt.slots[slot].seat_slot; + touch_notify_touch(base, time, slot, +seat_slot, li_fixed_from_int(device-mt.slots[slot].x), li_fixed_from_int(device-mt.slots[slot].y), LIBINPUT_TOUCH_TYPE_MOTION); @@ -150,9 +160,13 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = device-mt.slots[slot].seat_slot; + seat-slot_map = ~(1 seat_slot); + touch_notify_touch(base, time, slot, +seat_slot, 0, 0, LIBINPUT_TOUCH_TYPE_UP); break; @@ -160,10 +174,15 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = ffs(~seat-slot_map) - 1; + device-abs.seat_slot = seat_slot; + seat-slot_map |= 1 seat_slot; I think in light of 4/5 it should be documented that the seat_slot is never -1, lest people expect the same behaviour for both functions. Reviewed-by: Peter Hutterer peter.hutte...@who-t.net for the series otherwise. Cheers, Peter + transform_absolute(device, cx, cy); touch_notify_touch(base, time, -1, +seat_slot, li_fixed_from_int(cx), li_fixed_from_int(cy), LIBINPUT_TOUCH_TYPE_DOWN); @@ -174,6 +193,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) touch_notify_touch(base, time, -1, +device-abs.seat_slot, li_fixed_from_int(cx), li_fixed_from_int(cy), LIBINPUT_TOUCH_TYPE_DOWN); @@ -188,9 +208,13 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = device-abs.seat_slot; + seat-slot_map = ~(1 seat_slot); + touch_notify_touch(base, time, -1, +seat_slot
[PATCH libinput] Add a customizable log handler
The previous log handler wasn't actually hooked up to anything. Add a public API for the log handler with priority filtering, defaulting to priority 'error' and stderr as output stream. And to keep the diff down and convenience up, provide a few simple wrappers for logging. The generic is log_msg(), but let's use log_info, log_error, etc. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/libinput-private.h | 7 ++ src/libinput-util.c| 20 -- src/libinput.c | 62 ++ src/libinput.h | 76 ++ src/path.c | 4 +- test/Makefile.am | 7 +- test/log.c | 169 + 7 files changed, 322 insertions(+), 23 deletions(-) create mode 100644 test/log.c diff --git a/src/libinput-private.h b/src/libinput-private.h index 0d7de90..1fff7de 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -74,6 +74,13 @@ typedef void (*libinput_source_dispatch_t)(void *data); struct libinput_source; +#define log_debug(...) log_msg(LIBINPUT_LOG_PRIORITY_DEBUG, __VA_ARGS__) +#define log_info(...) log_msg(LIBINPUT_LOG_PRIORITY_INFO, __VA_ARGS__) +#define log_error(...) log_msg(LIBINPUT_LOG_PRIORITY_ERROR, __VA_ARGS__) + +void +log_msg(enum libinput_log_priority priority, const char *format, ...); + int libinput_init(struct libinput *libinput, const struct libinput_interface *interface, diff --git a/src/libinput-util.c b/src/libinput-util.c index a3534e1..eeb9786 100644 --- a/src/libinput-util.c +++ b/src/libinput-util.c @@ -35,26 +35,6 @@ #include libinput-util.h #include libinput-private.h -static FILE *g_log_file = NULL; - -void -set_logging_enabled(int enabled) -{ - g_log_file = enabled ? stdout : NULL; -} - -void -log_info(const char *format, ...) -{ - va_list ap; - - if (g_log_file) { - va_start(ap, format); - vfprintf(g_log_file, format, ap); - va_end(ap); - } -} - void list_init(struct list *list) { diff --git a/src/libinput.c b/src/libinput.c index cfce2c5..b4879af 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -78,6 +78,68 @@ struct libinput_event_touch { }; static void +libinput_default_log_func(enum libinput_log_priority priority, + void *data, + const char *format, va_list args) +{ + const char *prefix; + + switch(priority) { + case LIBINPUT_LOG_PRIORITY_DEBUG: prefix = debug; break; + case LIBINPUT_LOG_PRIORITY_INFO: prefix = info; break; + case LIBINPUT_LOG_PRIORITY_ERROR: prefix = error; break; + default: prefix=invalid priority; break; + } + + fprintf(stderr, libinput %s: , prefix); + vfprintf(stderr, format, args); +} + +struct log_data { + enum libinput_log_priority priority; + libinput_log_handler handler; + void *user_data; +}; + +static struct log_data log_data = { + .priority = LIBINPUT_LOG_PRIORITY_ERROR, + .handler = libinput_default_log_func, + .user_data = NULL, +}; + +void +log_msg(enum libinput_log_priority priority, const char *format, ...) +{ + va_list args; + + if (log_data.handler log_data.priority = priority) { + va_start(args, format); + log_data.handler(priority, log_data.user_data, format, args); + va_end(args); + } +} + +LIBINPUT_EXPORT void +libinput_log_set_priority(enum libinput_log_priority priority) +{ + log_data.priority = priority; +} + +LIBINPUT_EXPORT enum libinput_log_priority +libinput_log_get_priority(void) +{ + return log_data.priority; +} + +LIBINPUT_EXPORT void +libinput_log_set_handler(libinput_log_handler log_handler, +void *user_data) +{ + log_data.handler = log_handler; + log_data.user_data = user_data; +} + +static void libinput_post_event(struct libinput *libinput, struct libinput_event *event); diff --git a/src/libinput.h b/src/libinput.h index e87b2b7..6bf538a 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -42,6 +42,15 @@ typedef int32_t li_fixed_t; /** + * Log priority for internal logging messages. + */ +enum libinput_log_priority { + LIBINPUT_LOG_PRIORITY_DEBUG = 10, + LIBINPUT_LOG_PRIORITY_INFO = 20, + LIBINPUT_LOG_PRIORITY_ERROR = 30, +}; + +/** * @ingroup device * * Capabilities on a device. A device may have one or more capabilities @@ -875,6 +884,73 @@ void libinput_destroy(struct libinput *libinput); /** + * @ingroup base + * + * Set the global log priority. Messages with priorities equal to or + * higher than the argument will be printed to the current log handler. + * + * The default log priority is LIBINPUT_LOG_PRIORITY_ERROR. + * + * @param priority The minimum priority of log messages to print. + * + * @see libinput_log_set_handler + */ +void +libinput_log_set_priority(enum libinput_log_priority
[PATCH libinput 01/19] Add the shell for a multitouch-compatible touchpad implementation
Doesn't do anything but initialize and destroy. This is not a permanent separate implementation, it's just easier to start this way and then switch over than to add to the current one. Temporary measure: LIBINPUT_NEW_TOUCHPAD_DRIVER environment variable can be used to enable the new driver Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/Makefile.am | 1 + src/evdev-mt-touchpad.c | 76 + src/evdev.c | 5 +++- src/evdev.h | 3 ++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 src/evdev-mt-touchpad.c diff --git a/src/Makefile.am b/src/Makefile.am index 6e27b3b..c6afb82 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,6 +10,7 @@ libinput_la_SOURCES = \ libinput-util.h \ evdev.c \ evdev.h \ + evdev-mt-touchpad.c \ evdev-touchpad.c\ filter.c\ filter.h\ diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c new file mode 100644 index 000..a360651 --- /dev/null +++ b/src/evdev-mt-touchpad.c @@ -0,0 +1,76 @@ +/* + * 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 evdev.h + +struct touchpad_dispatch { + struct evdev_dispatch base; + struct evdev_device *device; +}; + +static void +touchpad_process(struct evdev_dispatch *dispatch, +struct evdev_device *device, +struct input_event *e, +uint32_t time) +{ +} + +static void +touchpad_destroy(struct evdev_dispatch *dispatch) +{ + free(dispatch); +} + +static struct evdev_dispatch_interface touchpad_interface = { + touchpad_process, + touchpad_destroy +}; + +static int +touchpad_init(struct touchpad_dispatch *touchpad, + struct evdev_device *device) +{ + touchpad-base.interface = touchpad_interface; + touchpad-device = device; + + return 0; +} + +struct evdev_dispatch * +evdev_mt_touchpad_create(struct evdev_device *device) +{ + struct touchpad_dispatch *touchpad; + + touchpad = zalloc(sizeof *touchpad); + if (!touchpad) + return NULL; + + if (touchpad_init(touchpad, device) != 0) { + free(touchpad); + return NULL; + } + + return touchpad-base; +} diff --git a/src/evdev.c b/src/evdev.c index d8dff65..ffa8557 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -565,7 +565,10 @@ evdev_configure_device(struct evdev_device *device) if (TEST_BIT(key_bits, BTN_TOOL_FINGER) !TEST_BIT(key_bits, BTN_TOOL_PEN) (has_abs || has_mt)) { - device-dispatch = evdev_touchpad_create(device); + if (getenv(LIBINPUT_NEW_TOUCHPAD_DRIVER) has_mt) + device-dispatch = evdev_mt_touchpad_create(device); + else + device-dispatch = evdev_touchpad_create(device); } for (i = KEY_ESC; i KEY_MAX; i++) { if (i = BTN_MISC i KEY_OK) diff --git a/src/evdev.h b/src/evdev.h index 3c9f93a..ce7fbb3 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -123,6 +123,9 @@ evdev_device_create(struct libinput_seat *seat, struct evdev_dispatch * evdev_touchpad_create(struct evdev_device *device); +struct evdev_dispatch * +evdev_mt_touchpad_create(struct evdev_device *device); + void evdev_device_proces_event(struct libinput_event *event); -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org
[PATCH libinput 05/19] touchpad: add two-finger average scrolling
If two fingers are down and moving, take the average movement of both fingers and use that for scrolling. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 44 +++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 1968199..6d1793b 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -332,13 +332,55 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time) } static void +tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time) +{ + struct tp_touch *t; + int nchanged = 0; + double dx = 0, dy =0; + double tmpx, tmpy; + + tp_for_each_touch(tp, t) { + if (t-dirty) { + nchanged++; + tp_get_delta(t, tmpx, tmpy); + + dx += tmpx; + dy += tmpy; + } + } + + if (nchanged == 0) + return; + + dx /= nchanged; + dy /= nchanged; + + tp_filter_motion(tp, dx, dy, time); + + if (dx != 0.0) + pointer_notify_axis(tp-device-base, + time, + LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL, + li_fixed_from_double(dx)); + if (dy != 0.0) + pointer_notify_axis(tp-device-base, + time, + LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL, + li_fixed_from_double(dy)); +} + +static void tp_post_events(struct tp_dispatch *tp, uint32_t time) { struct tp_touch *t = tp_current_touch(tp); double dx, dy; - if (tp-nfingers_down != 1) + if (tp-nfingers_down 2) { return; + } else if (tp-nfingers_down == 2) { + tp_post_twofinger_scroll(tp, time); + return; + } if (t-history.count 4) -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 04/19] touchpad: hook up the pointer acceleration
Same algorithm as in evdev-touchpad.c Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 76 + 1 file changed, 76 insertions(+) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index f625814..1968199 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -27,7 +27,11 @@ #include stdbool.h #include evdev.h +#include filter.h +#define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50 +#define DEFAULT_MIN_ACCEL_FACTOR 0.16 +#define DEFAULT_MAX_ACCEL_FACTOR 1.0 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0 #define TOUCHPAD_HISTORY_LENGTH 4 @@ -78,6 +82,14 @@ struct tp_dispatch { int32_t margin_x; int32_t margin_y; } hysteresis; + + struct motion_filter *filter; + + struct { + double constant_factor; + double min_factor; + double max_factor; + } accel; }; static inline int @@ -94,6 +106,27 @@ tp_hysteresis(int in, int center, int margin) return center + diff; } +static double +tp_accel_profile(struct motion_filter *filter, +void *data, +double velocity, +uint32_t time) +{ + struct tp_dispatch *tp = + (struct tp_dispatch *) data; + + double accel_factor; + + accel_factor = velocity * tp-accel.constant_factor; + + if (accel_factor tp-accel.max_factor) + accel_factor = tp-accel.max_factor; + else if (accel_factor tp-accel.min_factor) + accel_factor = tp-accel.min_factor; + + return accel_factor; +} + static inline struct tp_motion * tp_motion_history_offset(struct tp_touch *t, int offset) { @@ -104,6 +137,21 @@ tp_motion_history_offset(struct tp_touch *t, int offset) return t-history.samples[offset_index]; } +static void +tp_filter_motion(struct tp_dispatch *tp, +double *dx, double *dy, uint32_t time) +{ + struct motion_params motion; + + motion.dx = *dx; + motion.dy = *dy; + + filter_dispatch(tp-filter, motion, tp, time); + + *dx = motion.dx; + *dy = motion.dy; +} + static inline void tp_motion_history_push(struct tp_touch *t) { @@ -292,7 +340,12 @@ tp_post_events(struct tp_dispatch *tp, uint32_t time) if (tp-nfingers_down != 1) return; + + if (t-history.count 4) + return; + tp_get_delta(t, dx, dy); + tp_filter_motion(tp, dx, dy, time); if (dx != 0 || dy != 0) pointer_notify_motion( @@ -332,6 +385,8 @@ tp_destroy(struct evdev_dispatch *dispatch) struct tp_dispatch *tp = (struct tp_dispatch*)dispatch; + if (tp-filter) + tp-filter-interface-destroy(tp-filter); free(tp-touches); free(tp); } @@ -357,6 +412,24 @@ tp_init_slots(struct tp_dispatch *tp, return 0; } +static int +tp_init_accel(struct tp_dispatch *touchpad, double diagonal) +{ + struct motion_filter *accel; + + touchpad-accel.constant_factor = + DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal; + touchpad-accel.min_factor = DEFAULT_MIN_ACCEL_FACTOR; + touchpad-accel.max_factor = DEFAULT_MAX_ACCEL_FACTOR; + + accel = create_pointer_accelator_filter(tp_accel_profile); + if (accel == NULL) + return -1; + + touchpad-filter = accel; + + return 0; +} static int tp_init(struct tp_dispatch *tp, @@ -380,6 +453,9 @@ tp_init(struct tp_dispatch *tp, tp-hysteresis.margin_y = diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; + if (tp_init_accel(tp, diagonal) != 0) + return -1; + return 0; } -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 02/19] touchpad: add a touchpad driver based on per-finger tracking
This patch is a mixture of an experimental project (libtouchpad) and evdev-touchpad.c. It adds a new touchpad driver for multi-touch touchpads that tracks each touchpoint separately. This makes it a lot easier to handle multi-finger tapping, software button areas, etc. libtouchpad used a slightly different coding style, this is the attempt to get closer to the one used in libinput. Currently sends motion events for single-finger motion, button events only for physical buttons. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 300 +--- 1 file changed, 281 insertions(+), 19 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index a360651..856d54f 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -22,38 +22,300 @@ #include config.h +#include assert.h +#include stdbool.h + #include evdev.h -struct touchpad_dispatch { +#define TOUCHPAD_HISTORY_LENGTH 4 + +#define tp_for_each_touch(_tp, _t) \ + for (unsigned int _i = 0; _i (_tp)-ntouches (_t = (_tp)-touches[_i]); _i++) + +enum touch_state { + TOUCH_NONE = 0, + TOUCH_BEGIN, + TOUCH_UPDATE, + TOUCH_END +}; + +struct tp_motion { + int32_t x; + int32_t y; +}; + +struct tp_touch { + enum touch_state state; + bool dirty; + int32_t x; + int32_t y; + uint32_t millis; + + struct { + struct tp_motion samples[TOUCHPAD_HISTORY_LENGTH]; + unsigned int index; + unsigned int count; + } history; +}; + +struct tp_dispatch { struct evdev_dispatch base; struct evdev_device *device; + unsigned int nfingers_down; /* number of fingers down */ + unsigned int slot; /* current slot */ + + unsigned int ntouches; /* number of slots */ + struct tp_touch *touches; /* len == ntouches */ }; +static inline struct tp_motion * +tp_motion_history_offset(struct tp_touch *t, int offset) +{ + int offset_index = + (t-history.index - offset + TOUCHPAD_HISTORY_LENGTH) % + TOUCHPAD_HISTORY_LENGTH; + + return t-history.samples[offset_index]; +} + +static inline void +tp_motion_history_push(struct tp_touch *t) +{ + int motion_index = (t-history.index + 1) % TOUCHPAD_HISTORY_LENGTH; + + if (t-history.count TOUCHPAD_HISTORY_LENGTH) + t-history.count++; + + t-history.samples[motion_index].x = t-x; + t-history.samples[motion_index].y = t-y; + t-history.index = motion_index; +} + +static inline void +tp_motion_history_reset(struct tp_touch *t) +{ + t-history.count = 0; +} + +static inline struct tp_touch * +tp_current_touch(struct tp_dispatch *tp) +{ + return tp-touches[min(tp-slot, tp-ntouches)]; +} + +static inline void +tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t) +{ + if (t-state != TOUCH_UPDATE) { + tp_motion_history_reset(t); + t-dirty = true; + t-state = TOUCH_BEGIN; + tp-nfingers_down++; + assert(tp-nfingers_down = 1); + } +} + +static inline void +tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t) +{ + if (t-state == TOUCH_NONE) + return; + + t-dirty = true; + t-state = TOUCH_END; + assert(tp-nfingers_down = 1); + tp-nfingers_down--; +} + +static double +tp_estimate_delta(int x0, int x1, int x2, int x3) +{ + return (x0 + x1 - x2 - x3) / 4; +} + static void -touchpad_process(struct evdev_dispatch *dispatch, -struct evdev_device *device, -struct input_event *e, -uint32_t time) +tp_get_delta(struct tp_touch *t, double *dx, double *dy) { + if (t-history.count 4) { + *dx = 0; + *dy = 0; + return; + } + + *dx = tp_estimate_delta(tp_motion_history_offset(t, 0)-x, + tp_motion_history_offset(t, 1)-x, + tp_motion_history_offset(t, 2)-x, + tp_motion_history_offset(t, 3)-x); + *dy = tp_estimate_delta(tp_motion_history_offset(t, 0)-y, + tp_motion_history_offset(t, 1)-y, + tp_motion_history_offset(t, 2)-y, + tp_motion_history_offset(t, 3)-y); +} + +static void +tp_process_absolute(struct tp_dispatch *tp, + const struct input_event *e, + uint32_t time) +{ + struct tp_touch *t = tp_current_touch(tp); + + switch(e-code) { + case ABS_MT_POSITION_X: + t-x = e-value; + t-millis = time; + t-dirty = true; + break; + case ABS_MT_POSITION_Y: + t-y = e-value; + t-millis = time
[PATCH libinput 03/19] touchpad: add hysteresis smoothing for input coordinates
Same algorithm as in evdev-touchpad. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 63 + 1 file changed, 63 insertions(+) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 856d54f..f625814 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -23,10 +23,12 @@ #include config.h #include assert.h +#include math.h #include stdbool.h #include evdev.h +#define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0 #define TOUCHPAD_HISTORY_LENGTH 4 #define tp_for_each_touch(_tp, _t) \ @@ -56,6 +58,11 @@ struct tp_touch { unsigned int index; unsigned int count; } history; + + struct { + int32_t center_x; + int32_t center_y; + } hysteresis; }; struct tp_dispatch { @@ -66,8 +73,27 @@ struct tp_dispatch { unsigned int ntouches; /* number of slots */ struct tp_touch *touches; /* len == ntouches */ + + struct { + int32_t margin_x; + int32_t margin_y; + } hysteresis; }; +static inline int +tp_hysteresis(int in, int center, int margin) +{ + int diff = in - center; + if (abs(diff) = margin) + return center; + + if (diff margin) + return center + diff - margin; + else if (diff -margin) + return center + diff + margin; + return center + diff; +} + static inline struct tp_motion * tp_motion_history_offset(struct tp_touch *t, int offset) { @@ -92,6 +118,30 @@ tp_motion_history_push(struct tp_touch *t) } static inline void +tp_motion_hysteresis(struct tp_dispatch *tp, +struct tp_touch *t) +{ + int x = t-x, + y = t-y; + + if (t-history.count == 0) { + t-hysteresis.center_x = t-x; + t-hysteresis.center_y = t-y; + } else { + x = tp_hysteresis(x, + t-hysteresis.center_x, + tp-hysteresis.margin_x); + y = tp_hysteresis(y, + t-hysteresis.center_y, + tp-hysteresis.margin_y); + t-hysteresis.center_x = x; + t-hysteresis.center_y = y; + t-x = x; + t-y = y; + } +} + +static inline void tp_motion_history_reset(struct tp_touch *t) { t-history.count = 0; @@ -210,6 +260,7 @@ tp_process_state(struct tp_dispatch *tp, uint32_t time) if (!t-dirty) continue; + tp_motion_hysteresis(tp, t); tp_motion_history_push(t); } } @@ -311,12 +362,24 @@ static int tp_init(struct tp_dispatch *tp, struct evdev_device *device) { + int width, height; + double diagonal; + tp-base.interface = tp_interface; tp-device = device; if (tp_init_slots(tp, device) != 0) return -1; + width = abs(device-abs.max_x - device-abs.min_x); + height = abs(device-abs.max_y - device-abs.min_y); + diagonal = sqrt(width*width + height*height); + + tp-hysteresis.margin_x = + diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; + tp-hysteresis.margin_y = + diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; + return 0; } -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 19/19] evdev: drop hook to init old touchpad driver
Still leaving the driver itself in place for removal later, but only initialize the new driver now. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev.c | 5 + 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index ffa8557..7d91e09 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -565,10 +565,7 @@ evdev_configure_device(struct evdev_device *device) if (TEST_BIT(key_bits, BTN_TOOL_FINGER) !TEST_BIT(key_bits, BTN_TOOL_PEN) (has_abs || has_mt)) { - if (getenv(LIBINPUT_NEW_TOUCHPAD_DRIVER) has_mt) - device-dispatch = evdev_mt_touchpad_create(device); - else - device-dispatch = evdev_touchpad_create(device); + device-dispatch = evdev_mt_touchpad_create(device); } for (i = KEY_ESC; i KEY_MAX; i++) { if (i = BTN_MISC i KEY_OK) -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 16/19] touchpad: add support for clickfingers
On touchpads without physical buttons, the number of fingers on the touchpad at the time the physical click happens decides the button type. 1/2/3 fingers is handled left/right/middle. We also swallow the motion event on the actual click event, this reduces erroneous motion events by a bit. More processing is needed here though. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 67 +++-- src/evdev-mt-touchpad.h | 1 + test/pointer.c | 2 +- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index d0864fe..154df85 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -461,14 +461,42 @@ tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time) return 0; } -static void -tp_post_button_events(struct tp_dispatch *tp, uint32_t time) +static int +tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint32_t time) { uint32_t current, old, button; + enum libinput_pointer_button_state state; - if ((tp-queued - (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0) - return; + current = tp-buttons.state; + old = tp-buttons.old_state; + + if (current == old) + return 0; + + switch (tp-nfingers_down) { + case 1: button = BTN_LEFT; break; + case 2: button = BTN_RIGHT; break; + case 3: button = BTN_MIDDLE; break; + default: + return 0; + } + + if (current) + state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; + else + state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; + + pointer_notify_button(tp-device-base, + time, + button, + state); + return 1; +} + +static int +tp_post_physical_buttons(struct tp_dispatch *tp, uint32_t time) +{ + uint32_t current, old, button; current = tp-buttons.state; old = tp-buttons.old_state; @@ -493,6 +521,25 @@ tp_post_button_events(struct tp_dispatch *tp, uint32_t time) current = 1; old = 1; } + + return 0; +} + +static int +tp_post_button_events(struct tp_dispatch *tp, uint32_t time) +{ + int rc; + + if ((tp-queued + (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0) + return 0; + + if (tp-buttons.has_buttons) + rc = tp_post_physical_buttons(tp, time); + else + rc = tp_post_clickfinger_buttons(tp, time); + + return rc; } static void @@ -501,6 +548,9 @@ tp_post_events(struct tp_dispatch *tp, uint32_t time) struct tp_touch *t = tp_current_touch(tp); double dx, dy; + if (tp_post_button_events(tp, time) != 0) + return; + if (tp_tap_handle_state(tp, time) != 0) return; @@ -519,8 +569,6 @@ tp_post_events(struct tp_dispatch *tp, uint32_t time) li_fixed_from_double(dx), li_fixed_from_double(dy)); } - - tp_post_button_events(tp, time); } static void @@ -622,6 +670,7 @@ tp_init(struct tp_dispatch *tp, { int width, height; double diagonal; + unsigned long key_bits[NBITS(KEY_MAX)]; tp-base.interface = tp_interface; tp-device = device; @@ -638,6 +687,10 @@ tp_init(struct tp_dispatch *tp, tp-hysteresis.margin_y = diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; + ioctl(device-fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits); + if (TEST_BIT(key_bits, BTN_RIGHT) || TEST_BIT(key_bits, BTN_MIDDLE)) + tp-buttons.has_buttons = true; + if (tp_init_scroll(tp) != 0) return -1; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 84d8cec..327ce11 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -117,6 +117,7 @@ struct tp_dispatch { } accel; struct { + bool has_buttons; /* true for physical LMR buttons */ uint32_t state; uint32_t old_state; } buttons; /* physical buttons */ diff --git a/test/pointer.c b/test/pointer.c index e864169..59fe818 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -186,7 +186,7 @@ END_TEST int main (int argc, char **argv) { litest_add(pointer:motion, pointer_motion_relative, LITEST_POINTER, LITEST_ANY); - litest_add(pointer:button, pointer_button, LITEST_BUTTON, LITEST_ANY); + litest_add(pointer:button, pointer_button, LITEST_BUTTON, LITEST_CLICKPAD); litest_add(pointer:scroll, pointer_scroll_wheel, LITEST_WHEEL, LITEST_ANY); return
[PATCH libinput 12/19] touchpad: require minimum scroll distance and lock scroll direction
This is a fairly rough approach, but can be handled more fine-grained later. Require a minimum of 1 unit to start scrolling and lock the scrolling in the initial direction, so further scroll events are limited to that direction only. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 82 + src/evdev-mt-touchpad.h | 10 ++ 2 files changed, 79 insertions(+), 13 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 873ddf0..14fb7f3 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -310,16 +310,64 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time) tp_filter_motion(tp, dx, dy, time); - if (dx != 0.0) - pointer_notify_axis(tp-device-base, - time, - LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL, - li_fixed_from_double(dx)); - if (dy != 0.0) + if (tp-scroll.state == SCROLL_STATE_NONE) { + /* Require at least one px scrolling to start */ + if (dx = -1.0 || dx = 1.0) { + tp-scroll.state = SCROLL_STATE_SCROLLING; + tp-scroll.direction |= (1 LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL); + } + + if (dy = -1.0 || dy = 1.0) { + tp-scroll.state = SCROLL_STATE_SCROLLING; + tp-scroll.direction |= (1 LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL); + } + + if (tp-scroll.state == SCROLL_STATE_NONE) + return; + } + + if (dy != 0.0 + (tp-scroll.direction (1 LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL))) { pointer_notify_axis(tp-device-base, time, LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL, li_fixed_from_double(dy)); + } + + if (dx != 0.0 + (tp-scroll.direction (1 LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL))) { + pointer_notify_axis(tp-device-base, + time, + LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL, + li_fixed_from_double(dx)); + } +} + +static int +tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time) +{ + if (tp-nfingers_down != 2) { + /* terminate scrolling with a zero scroll event to notify +* caller that it really ended now */ + if (tp-scroll.state != SCROLL_STATE_NONE) { + tp-scroll.state = SCROLL_STATE_NONE; + tp-scroll.direction = 0; + if (tp-scroll.direction LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL) + pointer_notify_axis(tp-device-base, + time, + LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL, + 0); + if (tp-scroll.direction LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL) + pointer_notify_axis(tp-device-base, + time, + LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL, + 0); + } + } else { + tp_post_twofinger_scroll(tp, time); + return 1; + } + return 0; } static void @@ -362,16 +410,12 @@ tp_post_events(struct tp_dispatch *tp, uint32_t time) struct tp_touch *t = tp_current_touch(tp); double dx, dy; - if (tp-nfingers_down 2) { - return; - } else if (tp-nfingers_down == 2) { - tp_post_twofinger_scroll(tp, time); - return; - } - if (tp_tap_handle_state(tp, time) != 0) return; + if (tp_post_scroll_events(tp, time) != 0) + return; + if (t-history.count = TOUCHPAD_MIN_SAMPLES) { tp_get_delta(t, dx, dy); tp_filter_motion(tp, dx, dy, time); @@ -464,6 +508,15 @@ tp_init_accel(struct tp_dispatch *touchpad, double diagonal) } static int +tp_init_scroll(struct tp_dispatch *tp) +{ + tp-scroll.direction = 0; + tp-scroll.state = SCROLL_STATE_NONE; + + return 0; +} + +static int tp_init(struct tp_dispatch *tp, struct evdev_device *device) { @@ -485,6 +538,9 @@ tp_init(struct tp_dispatch *tp, tp-hysteresis.margin_y = diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; + if (tp_init_scroll(tp) != 0) + return -1; + if (tp_init_accel(tp, diagonal) != 0) return -1; diff --git a/src/evdev-mt
[PATCH libinput 14/19] touchpad: support single-touch touchpads
Touchpads without ABS_MT_SLOT create 5 slots by default (for up to QUINTTAP) and ABS_X/Y is mapped to the 0-slot touchpoint. This commit adds handling for a single finger, no BTN_TOOL_DOUBLETAP or similar is being processed yet. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 57 +++-- src/evdev-mt-touchpad.h | 2 ++ 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index c4c4c41..f8edb8c 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -226,6 +226,28 @@ tp_process_absolute(struct tp_dispatch *tp, } static void +tp_process_absolute_st(struct tp_dispatch *tp, + const struct input_event *e, + uint32_t time) +{ + struct tp_touch *t = tp_current_touch(tp); + + switch(e-code) { + case ABS_X: + t-x = e-value; + t-millis = time; + t-dirty = true; + break; + case ABS_Y: + t-y = e-value; + t-millis = time; + t-dirty = true; + tp-queued |= TOUCHPAD_EVENT_MOTION; + break; + } +} + +static void tp_process_key(struct tp_dispatch *tp, const struct input_event *e, uint32_t time) @@ -245,6 +267,18 @@ tp_process_key(struct tp_dispatch *tp, tp-queued |= TOUCHPAD_EVENT_BUTTON_RELEASE; } break; + case BTN_TOUCH: + if (!tp-has_mt) { + struct tp_touch *t = tp_current_touch(tp); + if (e-value) { + tp_begin_touch(tp, t); + t-fake = true; + } else { + tp_end_touch(tp, t); + } + t-millis = time; + } + break; } } @@ -271,9 +305,10 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time) if (!t-dirty) continue; - if (t-state == TOUCH_END) + if (t-state == TOUCH_END) { t-state = TOUCH_NONE; - else if (t-state == TOUCH_BEGIN) + t-fake = false; + } else if (t-state == TOUCH_BEGIN) t-state = TOUCH_UPDATE; t-dirty = false; @@ -443,7 +478,10 @@ tp_process(struct evdev_dispatch *dispatch, switch (e-type) { case EV_ABS: - tp_process_absolute(tp, e, time); + if (tp-has_mt) + tp_process_absolute(tp, e, time); + else + tp_process_absolute_st(tp, e, time); break; case EV_KEY: tp_process_key(tp, e, time); @@ -479,12 +517,17 @@ tp_init_slots(struct tp_dispatch *tp, { struct input_absinfo absinfo = {0}; - ioctl(device-fd, EVIOCGABS(ABS_MT_SLOT), absinfo); - - tp-ntouches = absinfo.maximum + 1; + if (ioctl(device-fd, EVIOCGABS(ABS_MT_SLOT), absinfo) == -1) { + tp-ntouches = 5; /* FIXME: based on DOUBLETAP, etc. */ + tp-slot = 0; + tp-has_mt = false; + } else { + tp-ntouches = absinfo.maximum + 1; + tp-slot = absinfo.value; + tp-has_mt = true; + } tp-touches = calloc(tp-ntouches, sizeof(struct tp_touch)); - tp-slot = absinfo.value; return 0; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 17e9055..1e09497 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -75,6 +75,7 @@ struct tp_motion { struct tp_touch { enum touch_state state; bool dirty; + bool fake; /* a fake touch */ int32_t x; int32_t y; uint32_t millis; @@ -96,6 +97,7 @@ struct tp_dispatch { struct evdev_device *device; unsigned int nfingers_down; /* number of fingers down */ unsigned int slot; /* current slot */ + bool has_mt; unsigned int ntouches; /* number of slots */ struct tp_touch *touches; /* len == ntouches */ -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 09/19] touchpad: Make touchpad_get_delta() available from other files
No functional changes. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 2 +- src/evdev-mt-touchpad.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index e25997d..73ea8a8 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -174,7 +174,7 @@ tp_estimate_delta(int x0, int x1, int x2, int x3) return (x0 + x1 - x2 - x3) / 4; } -static void +void tp_get_delta(struct tp_touch *t, double *dx, double *dy) { if (t-history.count 4) { diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index d12647d..907aec8 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -102,4 +102,7 @@ struct tp_dispatch { #define tp_for_each_touch(_tp, _t) \ for (unsigned int _i = 0; _i (_tp)-ntouches (_t = (_tp)-touches[_i]); _i++) +void +tp_get_delta(struct tp_touch *t, double *dx, double *dy); + #endif -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 06/19] touchpad: move structs into a header file
The tapping state implementation will be in a separate file, so let's make sure we can access the structs we need. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/Makefile.am | 1 + src/evdev-mt-touchpad.c | 61 + src/evdev-mt-touchpad.h | 91 + 3 files changed, 93 insertions(+), 60 deletions(-) create mode 100644 src/evdev-mt-touchpad.h diff --git a/src/Makefile.am b/src/Makefile.am index c6afb82..f6d0335 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,6 +11,7 @@ libinput_la_SOURCES = \ evdev.c \ evdev.h \ evdev-mt-touchpad.c \ + evdev-mt-touchpad.h \ evdev-touchpad.c\ filter.c\ filter.h\ diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 6d1793b..8a8586a 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -26,71 +26,12 @@ #include math.h #include stdbool.h -#include evdev.h -#include filter.h +#include evdev-mt-touchpad.h #define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50 #define DEFAULT_MIN_ACCEL_FACTOR 0.16 #define DEFAULT_MAX_ACCEL_FACTOR 1.0 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0 -#define TOUCHPAD_HISTORY_LENGTH 4 - -#define tp_for_each_touch(_tp, _t) \ - for (unsigned int _i = 0; _i (_tp)-ntouches (_t = (_tp)-touches[_i]); _i++) - -enum touch_state { - TOUCH_NONE = 0, - TOUCH_BEGIN, - TOUCH_UPDATE, - TOUCH_END -}; - -struct tp_motion { - int32_t x; - int32_t y; -}; - -struct tp_touch { - enum touch_state state; - bool dirty; - int32_t x; - int32_t y; - uint32_t millis; - - struct { - struct tp_motion samples[TOUCHPAD_HISTORY_LENGTH]; - unsigned int index; - unsigned int count; - } history; - - struct { - int32_t center_x; - int32_t center_y; - } hysteresis; -}; - -struct tp_dispatch { - struct evdev_dispatch base; - struct evdev_device *device; - unsigned int nfingers_down; /* number of fingers down */ - unsigned int slot; /* current slot */ - - unsigned int ntouches; /* number of slots */ - struct tp_touch *touches; /* len == ntouches */ - - struct { - int32_t margin_x; - int32_t margin_y; - } hysteresis; - - struct motion_filter *filter; - - struct { - double constant_factor; - double min_factor; - double max_factor; - } accel; -}; static inline int tp_hysteresis(int in, int center, int margin) diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h new file mode 100644 index 000..f7f413b --- /dev/null +++ b/src/evdev-mt-touchpad.h @@ -0,0 +1,91 @@ +/* + * 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_MT_TOUCHPAD_H +#define EVDEV_MT_TOUCHPAD_H + +#include stdbool.h + +#include evdev.h +#include filter.h + +#define TOUCHPAD_HISTORY_LENGTH 4 + +enum touch_state { + TOUCH_NONE = 0, + TOUCH_BEGIN, + TOUCH_UPDATE, + TOUCH_END +}; + +struct tp_motion { + int32_t x; + int32_t y; +}; + +struct tp_touch { + enum touch_state state; + bool dirty; + int32_t x; + int32_t y; + uint32_t millis; + + struct { + struct tp_motion samples[TOUCHPAD_HISTORY_LENGTH]; + unsigned int index; + unsigned int count; + } history; + + struct { + int32_t center_x; + int32_t
[PATCH libinput 13/19] touchpad: Only move the pointer when there's a single finger down
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 14fb7f3..c4c4c41 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -416,7 +416,8 @@ tp_post_events(struct tp_dispatch *tp, uint32_t time) if (tp_post_scroll_events(tp, time) != 0) return; - if (t-history.count = TOUCHPAD_MIN_SAMPLES) { + if (t-history.count = TOUCHPAD_MIN_SAMPLES + tp-nfingers_down == 1) { tp_get_delta(t, dx, dy); tp_filter_motion(tp, dx, dy, time); -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 08/19] touchpad: add a struct for handling physical button event state changes
On ClickPads (touchpads without phys. middle/right buttons) it is important to know whether a physical click is queued up. The finger position or number of fingers decide which button event to send. This isn't currently used, we still just send the button number at the moment. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 54 +++-- src/evdev-mt-touchpad.h | 5 + 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 1d34df8..e25997d 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -230,16 +230,20 @@ tp_process_key(struct tp_dispatch *tp, const struct input_event *e, uint32_t time) { + uint32_t mask; + switch (e-code) { case BTN_LEFT: case BTN_MIDDLE: case BTN_RIGHT: - pointer_notify_button( - tp-device-base, - time, - e-code, - e-value ? LIBINPUT_POINTER_BUTTON_STATE_PRESSED : - LIBINPUT_POINTER_BUTTON_STATE_RELEASED); + mask = 1 (e-code - BTN_LEFT); + if (e-value) { + tp-buttons.state |= mask; + tp-queued |= TOUCHPAD_EVENT_BUTTON_PRESS; + } else { + tp-buttons.state = ~mask; + tp-queued |= TOUCHPAD_EVENT_BUTTON_RELEASE; + } break; } } @@ -275,6 +279,8 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time) t-dirty = false; } + tp-buttons.old_state = tp-buttons.state; + tp-queued = TOUCHPAD_EVENT_NONE; } @@ -317,6 +323,40 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time) } static void +tp_post_button_events(struct tp_dispatch *tp, uint32_t time) +{ + uint32_t current, old, button; + + if ((tp-queued + (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0) + return; + + current = tp-buttons.state; + old = tp-buttons.old_state; + button = BTN_LEFT; + + while (current || old) { + enum libinput_pointer_button_state state; + + if ((current 0x1) ^ (old 0x1)) { + if (!!(current 0x1)) + state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; + else + state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; + + pointer_notify_button(tp-device-base, + time, + button, + state); + } + + button++; + current = 1; + old = 1; + } +} + +static void tp_post_events(struct tp_dispatch *tp, uint32_t time) { struct tp_touch *t = tp_current_touch(tp); @@ -342,6 +382,8 @@ tp_post_events(struct tp_dispatch *tp, uint32_t time) time, li_fixed_from_double(dx), li_fixed_from_double(dy)); + + tp_post_button_events(tp, time); } static void diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 52ad3ab..d12647d 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -91,6 +91,11 @@ struct tp_dispatch { double max_factor; } accel; + struct { + uint32_t state; + uint32_t old_state; + } buttons; /* physical buttons */ + enum touchpad_event queued; }; -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 11/19] touchpad: Filter motion in a certain number of tap states
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad-tap.c | 23 ++- src/evdev-mt-touchpad.c | 22 +++--- src/evdev-mt-touchpad.h | 1 + 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 7ac592b..bc7acbd 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -504,6 +504,7 @@ int tp_tap_handle_state(struct tp_dispatch *tp, uint32_t time) { struct tp_touch *t; + int filter_motion = 0; if (tp-queued TOUCHPAD_EVENT_BUTTON_PRESS) tp_tap_handle_event(tp, TAP_EVENT_BUTTON, time); @@ -521,7 +522,27 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint32_t time) tp_tap_handle_event(tp, TAP_EVENT_MOTION, time); } - return 0; + /** +* In any state where motion exceeding the move threshold would +* move to the next state, filter that motion until we actually +* exceed it. This prevents small motion events while we're waiting +* on a decision if a tap is a tap. +*/ + switch (tp-tap.state) { + case TAP_STATE_TOUCH: + case TAP_STATE_TAPPED: + case TAP_STATE_DRAGGING_OR_DOUBLETAP: + case TAP_STATE_TOUCH_2: + case TAP_STATE_TOUCH_3: + filter_motion = 1; + break; + + default: + break; + + } + + return filter_motion; } static void diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index d1268f6..873ddf0 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -369,20 +369,20 @@ tp_post_events(struct tp_dispatch *tp, uint32_t time) return; } - tp_tap_handle_state(tp, time); - - if (t-history.count 4) + if (tp_tap_handle_state(tp, time) != 0) return; - tp_get_delta(t, dx, dy); - tp_filter_motion(tp, dx, dy, time); + if (t-history.count = TOUCHPAD_MIN_SAMPLES) { + tp_get_delta(t, dx, dy); + tp_filter_motion(tp, dx, dy, time); - if (dx != 0 || dy != 0) - pointer_notify_motion( - tp-device-base, - time, - li_fixed_from_double(dx), - li_fixed_from_double(dy)); + if (dx != 0 || dy != 0) + pointer_notify_motion( + tp-device-base, + time, + li_fixed_from_double(dx), + li_fixed_from_double(dy)); + } tp_post_button_events(tp, time); } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 973b478..a5cfaa6 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -30,6 +30,7 @@ #include filter.h #define TOUCHPAD_HISTORY_LENGTH 4 +#define TOUCHPAD_MIN_SAMPLES 4 enum touchpad_event { TOUCHPAD_EVENT_NONE = 0, -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 17/19] touchpad: mark the first finger as pointer-controlling finger
Unused at the moment, but will be used later to determine if a finger should trigger motion events. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 4 src/evdev-mt-touchpad.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 154df85..84764ac 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -159,6 +159,9 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t) tp-nfingers_down++; assert(tp-nfingers_down = 1); tp-queued |= TOUCHPAD_EVENT_MOTION; + + if (tp-nfingers_down == 1) + t-is_pointer = true; } } @@ -169,6 +172,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t) return; t-dirty = true; + t-is_pointer = false; t-state = TOUCH_END; assert(tp-nfingers_down = 1); tp-nfingers_down--; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 327ce11..df83b2c 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -76,6 +76,7 @@ struct tp_touch { enum touch_state state; bool dirty; bool fake; /* a fake touch */ + bool is_pointer;/* the pointer-controlling touch */ int32_t x; int32_t y; uint32_t millis; -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 07/19] touchpad: mark which events are currently pending processing
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 6 ++ src/evdev-mt-touchpad.h | 9 + 2 files changed, 15 insertions(+) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 8a8586a..1d34df8 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -151,6 +151,7 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t) t-state = TOUCH_BEGIN; tp-nfingers_down++; assert(tp-nfingers_down = 1); + tp-queued |= TOUCHPAD_EVENT_MOTION; } } @@ -164,6 +165,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t) t-state = TOUCH_END; assert(tp-nfingers_down = 1); tp-nfingers_down--; + tp-queued |= TOUCHPAD_EVENT_MOTION; } static double @@ -203,11 +205,13 @@ tp_process_absolute(struct tp_dispatch *tp, t-x = e-value; t-millis = time; t-dirty = true; + tp-queued |= TOUCHPAD_EVENT_MOTION; break; case ABS_MT_POSITION_Y: t-y = e-value; t-millis = time; t-dirty = true; + tp-queued |= TOUCHPAD_EVENT_MOTION; break; case ABS_MT_SLOT: tp-slot = e-value; @@ -270,6 +274,8 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time) t-dirty = false; } + + tp-queued = TOUCHPAD_EVENT_NONE; } static void diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index f7f413b..52ad3ab 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -31,6 +31,13 @@ #define TOUCHPAD_HISTORY_LENGTH 4 +enum touchpad_event { + TOUCHPAD_EVENT_NONE = 0, + TOUCHPAD_EVENT_MOTION = (1 0), + TOUCHPAD_EVENT_BUTTON_PRESS = (1 1), + TOUCHPAD_EVENT_BUTTON_RELEASE = (1 2), +}; + enum touch_state { TOUCH_NONE = 0, TOUCH_BEGIN, @@ -83,6 +90,8 @@ struct tp_dispatch { double min_factor; double max_factor; } accel; + + enum touchpad_event queued; }; #define tp_for_each_touch(_tp, _t) \ -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 15/19] touchpad: add fake-touch support for BTN_TOOL_DOUBLETAP and friends
This enables two-finger scrolling and two- and three-finger tapping on a single-touch touchpad if BTN_TOOL_DOUBLETAP and BTN_TOOL_TRIPLETAP is set. These require a bit of special processing: BTN_TOUCH is set with the first finger down, but somewhat randomly unset and re-set when switching between the various BTN_TOOL_*TAP values. BTN_TOOL_NTAP is only set for N fingers down, thus a double-triple move will see a release for DOUBLETAP and a press for TRIPLETAP. This may happen in the same event, or across two consecutive events. This patch adds a fake_touches mask to the touchpad struct. The mask is set for each matching BTN_* event and used to count the number of expected fake touchpoints. From that we begin/end the number of actual touchpoints required. Fake touchpoints take their x/y coordinates from the first touchpoint, which reads ABS_X/ABS_Y. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 78 ++--- src/evdev-mt-touchpad.h | 1 + 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index f8edb8c..d0864fe 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -142,6 +142,13 @@ tp_current_touch(struct tp_dispatch *tp) return tp-touches[min(tp-slot, tp-ntouches)]; } +static inline struct tp_touch * +tp_get_touch(struct tp_dispatch *tp, unsigned int slot) +{ + assert(slot tp-ntouches); + return tp-touches[slot]; +} + static inline void tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t) { @@ -248,6 +255,54 @@ tp_process_absolute_st(struct tp_dispatch *tp, } static void +tp_process_fake_touch(struct tp_dispatch *tp, + const struct input_event *e, + uint32_t time) +{ + struct tp_touch *t; + unsigned int fake_touches; + unsigned int nfake_touches; + unsigned int i; + unsigned int shift; + + if (e-code != BTN_TOUCH + (e-code BTN_TOOL_DOUBLETAP || e-code BTN_TOOL_QUADTAP)) + return; + + shift = e-code == BTN_TOUCH ? 0 : (e-code - BTN_TOOL_DOUBLETAP + 1); + + if (e-value) + tp-fake_touches |= 1 shift; + else + tp-fake_touches = ~(0x1 shift); + + fake_touches = tp-fake_touches; + nfake_touches = 0; + while (fake_touches) { + nfake_touches++; + fake_touches = 1; + } + + for (i = 0; i tp-ntouches; i++) { + t = tp_get_touch(tp, i); + if (i = nfake_touches) { + if (t-state != TOUCH_NONE) { + tp_end_touch(tp, t); + t-millis = time; + } + } else if (t-state != TOUCH_UPDATE + t-state != TOUCH_BEGIN) { + t-state = TOUCH_NONE; + tp_begin_touch(tp, t); + t-millis = time; + t-fake =true; + } + } + + assert(tp-nfingers_down == nfake_touches); +} + +static void tp_process_key(struct tp_dispatch *tp, const struct input_event *e, uint32_t time) @@ -268,16 +323,11 @@ tp_process_key(struct tp_dispatch *tp, } break; case BTN_TOUCH: - if (!tp-has_mt) { - struct tp_touch *t = tp_current_touch(tp); - if (e-value) { - tp_begin_touch(tp, t); - t-fake = true; - } else { - tp_end_touch(tp, t); - } - t-millis = time; - } + case BTN_TOOL_DOUBLETAP: + case BTN_TOOL_TRIPLETAP: + case BTN_TOOL_QUADTAP: + if (!tp-has_mt) + tp_process_fake_touch(tp, e, time); break; } } @@ -286,9 +336,15 @@ static void tp_process_state(struct tp_dispatch *tp, uint32_t time) { struct tp_touch *t; + struct tp_touch *first = tp_get_touch(tp, 0); tp_for_each_touch(tp, t) { - if (!t-dirty) + if (!tp-has_mt t != first first-fake) { + t-x = first-x; + t-y = first-y; + if (!t-dirty) + t-dirty = first-dirty; + } else if (!t-dirty) continue; tp_motion_hysteresis(tp, t); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 1e09497..84d8cec 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -101,6 +101,7 @@ struct tp_dispatch
[PATCH libinput 18/19] touchpad: Support finger-pinnnig during physical button presses
On a clickpad, one finger has be on the trackpad to trigger a physical button press. For drag and drop, we still want motion events though when a second finger is down. This patch adds finger-pinning. If the touchpad is pressed, the pressing finger is pinned and ignored for further motion events. A second finger may then be used to drag. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 87 +++-- src/evdev-mt-touchpad.h | 1 + 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 84764ac..dea99a9 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -152,6 +152,8 @@ tp_get_touch(struct tp_dispatch *tp, unsigned int slot) static inline void tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t) { + struct tp_touch *tmp; + if (t-state != TOUCH_UPDATE) { tp_motion_history_reset(t); t-dirty = true; @@ -160,8 +162,14 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t) assert(tp-nfingers_down = 1); tp-queued |= TOUCHPAD_EVENT_MOTION; - if (tp-nfingers_down == 1) + tp_for_each_touch(tp, tmp) { + if (tmp-is_pointer) + break; + } + + if (!tmp-is_pointer) { t-is_pointer = true; + } } } @@ -337,6 +345,53 @@ tp_process_key(struct tp_dispatch *tp, } static void +tp_unpin_finger(struct tp_dispatch *tp) +{ + struct tp_touch *t; + tp_for_each_touch(tp, t) { + if (t-is_pinned) { + t-is_pinned = false; + + if (t-state != TOUCH_END + tp-nfingers_down == 1) + t-is_pointer = true; + break; + } + } +} + +static void +tp_pin_finger(struct tp_dispatch *tp) +{ + struct tp_touch *t, + *pinned = NULL; + + tp_for_each_touch(tp, t) { + if (t-is_pinned) { + pinned = t; + break; + } + } + + assert(!pinned); + + pinned = tp_current_touch(tp); + + if (tp-nfingers_down != 1) { + tp_for_each_touch(tp, t) { + if (t == pinned) + continue; + + if (t-y pinned-y) + pinned = t; + } + } + + pinned-is_pinned = true; + pinned-is_pointer = false; +} + +static void tp_process_state(struct tp_dispatch *tp, uint32_t time) { struct tp_touch *t; @@ -354,6 +409,15 @@ tp_process_state(struct tp_dispatch *tp, uint32_t time) tp_motion_hysteresis(tp, t); tp_motion_history_push(t); } + + /* We have a physical button down event on a clickpad. For drag and + drop, this means we try to identify which finger pressed the + physical button and pin it, i.e. remove pointer-moving + capabilities from it. +*/ + if ((tp-queued TOUCHPAD_EVENT_BUTTON_PRESS) + !tp-buttons.has_buttons) + tp_pin_finger(tp); } static void @@ -376,6 +440,9 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time) tp-buttons.old_state = tp-buttons.state; + if (tp-queued TOUCHPAD_EVENT_BUTTON_RELEASE) + tp_unpin_finger(tp); + tp-queued = TOUCHPAD_EVENT_NONE; } @@ -441,6 +508,11 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time) static int tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time) { + /* don't scroll if a clickpad is held down */ + if (!tp-buttons.has_buttons + (tp-buttons.state || tp-buttons.old_state)) + return 0; + if (tp-nfingers_down != 2) { /* terminate scrolling with a zero scroll event to notify * caller that it really ended now */ @@ -561,8 +633,17 @@ tp_post_events(struct tp_dispatch *tp, uint32_t time) if (tp_post_scroll_events(tp, time) != 0) return; - if (t-history.count = TOUCHPAD_MIN_SAMPLES - tp-nfingers_down == 1) { + if (t-history.count = TOUCHPAD_MIN_SAMPLES) { + if (!t-is_pointer) { + tp_for_each_touch(tp, t) { + if (t-is_pointer) + break; + } + } + + if (!t-is_pointer) + return; + tp_get_delta(t, dx, dy); tp_filter_motion(tp, dx, dy, time); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index df83b2c..c30dc9e 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev
Re: [PATCH libinput] evdev: fix device_transform_ functions
On Mon, Feb 17, 2014 at 01:42:52PM -0500, Benjamin Tissoires wrote: X and Y are li_fixed_t, which is 24.8 fixed point real number. li_fixed_t max is thus ~8388607. On a touchscreen with a range of 32767 values (like a 3M sensor), and mapped on monitor with a resolution of 1920x1080, we currently have: (x - li_fixed_from_int(device-abs.min_x)) * width == 62912640 which is 7 times bigger than li_fixed_t max. To keep the precision of the sensor, first compute the uniformized coordinate (in range 0 .. 1.0) of the touch point, then multiply it by the screen dimension, and revert it to a li_fixed_t. Signed-off-by: Benjamin Tissoires benjamin.tissoi...@gmail.com --- Hi, I have hit this problem by playing with a touchscreen reporting 4096 values, on xf86-input-libinput. xf86-input-libinput does not use the real screen size, but 0x instead. This allows to report a touchscreen with a range of 128 values to work properly :( I went through the multitouch device database, and took one example of a more real use-case (xf86-input-libinput is still in an early shape). fwiw, this is exactly the type of use-case where it would be simple and worth it to knock up a test for a single device and make sure that the coordinates are correct. which gives us a nice reproducer and prevents us from errors like this in the future. src/evdev.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index d8dff65..0d033b8 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -91,8 +91,9 @@ evdev_device_transform_x(struct evdev_device *device, li_fixed_t x, uint32_t width) { - return (x - li_fixed_from_int(device-abs.min_x)) * width / + double x_scaled = (li_fixed_to_double(x) - device-abs.min_x) / (device-abs.max_x - device-abs.min_x + 1); + return li_fixed_from_double(x_scaled * width); A simple 1L * should suffice, right? Cheers, Peter } li_fixed_t @@ -100,8 +101,9 @@ evdev_device_transform_y(struct evdev_device *device, li_fixed_t y, uint32_t height) { - return (y - li_fixed_from_int(device-abs.min_y)) * height / + double y_scaled = (li_fixed_to_double(y) - device-abs.min_y) / (device-abs.max_y - device-abs.min_y + 1); + return li_fixed_from_double(y_scaled * height); } static void -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 1/2] Hook up libevdev as backend
libevdev wraps the various peculiarities of the evdev kernel API into a type-safe API. It also buffers the device so checking for specific features at a later time is easier than re-issuing the ioctls. Plus, it gives us almost free support for SYN_DROPPED events (in the following patch). This patch switches all the bit checks over to libevdev and leaves the event processing as-is. Makes it easier to review. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- configure.ac | 7 ++--- src/Makefile.am | 2 ++ src/evdev-touchpad.c | 25 ++- src/evdev.c | 87 +--- src/evdev.h | 14 ++--- 5 files changed, 52 insertions(+), 83 deletions(-) diff --git a/configure.ac b/configure.ac index 44729a9..68e1d35 100644 --- a/configure.ac +++ b/configure.ac @@ -44,6 +44,7 @@ AC_CHECK_DECL(CLOCK_MONOTONIC,[], PKG_PROG_PKG_CONFIG() PKG_CHECK_MODULES(MTDEV, [mtdev = 1.1.0]) PKG_CHECK_MODULES(LIBUDEV, [libudev]) +PKG_CHECK_MODULES(LIBEVDEV, [libevdev = 0.4]) if test x$GCC = xyes; then GCC_CFLAGS=-Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden @@ -64,20 +65,16 @@ AC_ARG_ENABLE(tests, [build_tests=$enableval], [build_tests=auto]) -PKG_CHECK_MODULES(LIBEVDEV, [libevdev = 0.4], [HAVE_LIBEVDEV=yes], [HAVE_LIBEVDEV=no]) PKG_CHECK_MODULES(CHECK, [check = 0.9.9], [HAVE_CHECK=yes], [HAVE_CHECK=no]) if test x$build_tests = xauto; then - if test x$HAVE_CHECK = xyes -a x$HAVE_LIBEVDEV = xyes; then + if test x$HAVE_CHECK = xyes; then build_tests=yes fi fi if test x$build_tests = xyes -a x$HAVE_CHECK = xno; then AC_MSG_ERROR([Cannot build tests, check is missing]) fi -if test x$build_tests = xyes -a x$HAVE_LIBEVDEV = xno; then - AC_MSG_ERROR([Cannot build tests, libevdev is missing]) -fi AM_CONDITIONAL(BUILD_TESTS, [test x$build_tests = xyes]) diff --git a/src/Makefile.am b/src/Makefile.am index 6e27b3b..f544ccd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,9 +20,11 @@ libinput_la_SOURCES =\ libinput_la_LIBADD = $(MTDEV_LIBS) \ $(LIBUDEV_LIBS) \ +$(LIBEVDEV_LIBS) \ -lm libinput_la_CFLAGS = $(MTDEV_CFLAGS) \ $(LIBUDEV_CFLAGS) \ +$(LIBEVDEV_CFLAGS) \ $(GCC_CFLAGS) pkgconfigdir = $(libdir)/pkgconfig diff --git a/src/evdev-touchpad.c b/src/evdev-touchpad.c index d65ebb2..8185bf2 100644 --- a/src/evdev-touchpad.c +++ b/src/evdev-touchpad.c @@ -170,16 +170,16 @@ struct touchpad_dispatch { static enum touchpad_model get_touchpad_model(struct evdev_device *device) { - struct input_id id; + int vendor, product; unsigned int i; - if (ioctl(device-fd, EVIOCGID, id) 0) - return TOUCHPAD_MODEL_UNKNOWN; + vendor = libevdev_get_id_vendor(device-evdev); + product = libevdev_get_id_product(device-evdev); for (i = 0; i ARRAY_LENGTH(touchpad_spec_table); i++) - if (touchpad_spec_table[i].vendor == id.vendor + if (touchpad_spec_table[i].vendor == vendor (!touchpad_spec_table[i].product || -touchpad_spec_table[i].product == id.product)) +touchpad_spec_table[i].product == product)) return touchpad_spec_table[i].model; return TOUCHPAD_MODEL_UNKNOWN; @@ -730,9 +730,7 @@ touchpad_init(struct touchpad_dispatch *touchpad, { struct motion_filter *accel; - unsigned long prop_bits[INPUT_PROP_MAX]; - struct input_absinfo absinfo; - unsigned long abs_bits[NBITS(ABS_MAX)]; + const struct input_absinfo *absinfo; bool has_buttonpad; @@ -746,16 +744,13 @@ touchpad_init(struct touchpad_dispatch *touchpad, /* Detect model */ touchpad-model = get_touchpad_model(device); - ioctl(device-fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits); - has_buttonpad = TEST_BIT(prop_bits, INPUT_PROP_BUTTONPAD); + has_buttonpad = libevdev_has_property(device-evdev, INPUT_PROP_BUTTONPAD); /* Configure pressure */ - ioctl(device-fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits); - if (TEST_BIT(abs_bits, ABS_PRESSURE)) { - ioctl(device-fd, EVIOCGABS(ABS_PRESSURE), absinfo); + if ((absinfo = libevdev_get_abs_info(device-evdev, ABS_PRESSURE))) { configure_touchpad_pressure(touchpad, - absinfo.minimum, - absinfo.maximum); + absinfo-minimum, + absinfo-maximum); } /* Configure acceleration factor */ diff --git a/src/evdev.c b/src/evdev.c index d8dff65..ba28fc6 100644
[PATCH libinput] evdev: set CLOCK_MONOTONIC as the time source
Avoids erroneous timestamps when the system time is reset. This used to a be a problem with the X.Org synaptics driver where taps, scrolling and a couple of other things would potentially lock up. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index 2c88c04..ab5a0c9 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -31,6 +31,7 @@ #include fcntl.h #include mtdev-plumbing.h #include assert.h +#include time.h #include libinput.h #include evdev.h @@ -639,6 +640,8 @@ evdev_device_create(struct libinput_seat *seat, if (rc != 0) return NULL; + libevdev_set_clock_id(device-evdev, CLOCK_MONOTONIC); + device-seat_caps = 0; device-is_mt = 0; device-mtdev = NULL; -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [RFC] libinput configuration interface
On Tue, Feb 18, 2014 at 04:33:53PM +, Dominic Jänichen wrote: On Mon, 03 Feb 2014 11:02:42 +1000, Peter Hutterer wrote: tbh, I'm not planning to support every potential option under the sun. There's a fine and rather blurry line between what is a preference and what is merely configuration because we can't commit to a single default. I'd rather have less configuration options and support those well and do the synaptics approach of supporting everything but being quite bad at how the various options interact. snip As for the softbuttons config items, I'm somewhat leaning towards finger movement in the button areas, but no clicks outside the button area. And to actually trigger a button, you need to start inside the button area - which becomes easier when you have proper finger tracking (synaptics currently doesn't). Does that imply the following use case will be supported? Being used to TP trackpoints, I am using the index finger outside the button area (on a touchpad that doubles as one hardware button) and the thumb to click. I'd expect to able to move the pointer with the index finger while clicking, disregarding slight thumb movements while doing so. This seems to very difficult to archieve (if at all) with the synaptics driver; the points jumps widely, especially if the index finger is removed from the touch pad immediately before clicking. I can imagine that this boils down to having areas insensitive to motion, but still working as softbuttons. The set of touchpad patches I sent out recently already handle this by default. When the physical clickpad button is depressed, the driver picks the finger that is pressing the button (sometimes guessing, but hey...). That finger cannot control the pointer movement until the button is released again. In your specific use case, the driver would see two touchpoints and it will select the one closer to the bottom edge as the pressing finger (i.e. your thumb). The index finger can still move while the button is down. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 2/2] test: Add scale li_fixed overflow test
On Tue, Feb 18, 2014 at 08:13:58PM +0100, Jonas Ådahl wrote: Add a test case and test device that checks if the scale transform can handle high resolution devices and output monitor resolutions. The test case is created in a way that it will fail if the coordinate transform expression will overflow if only 32 bit integer data containers are used. Signed-off-by: Jonas Ådahl jad...@gmail.com --- fwiw, this is exactly the type of use-case where it would be simple and worth it to knock up a test for a single device and make sure that the coordinates are correct. which gives us a nice reproducer and prevents us from errors like this in the future. And here is such a test case. It will fail as is, but pass if either the expression uses 64 bit integers or doubles. Jonas test/Makefile.am| 1 + test/litest-generic-highres-touch.c | 139 test/litest.c | 2 + test/litest.h | 1 + test/touch.c| 40 ++- 5 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 test/litest-generic-highres-touch.c diff --git a/test/Makefile.am b/test/Makefile.am index 59687f6..4b923aa 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -14,6 +14,7 @@ liblitest_la_SOURCES = \ litest-synaptics.c \ litest-trackpoint.c \ litest-wacom-touch.c \ + litest-generic-highres-touch.c \ litest.c run_tests = test-udev test-path test-pointer test-touch diff --git a/test/litest-generic-highres-touch.c b/test/litest-generic-highres-touch.c new file mode 100644 index 000..bd326ce --- /dev/null +++ b/test/litest-generic-highres-touch.c @@ -0,0 +1,139 @@ +/* + * Copyright © 2013 Red Hat, Inc. + * Copyright © 2014 Jonas Ådahl + * + * 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 litest.h +#include litest-int.h +#include libinput-util.h + +void litest_generic_highres_touch_setup(void) +{ + struct litest_device *d = + litest_create_device(LITEST_GENERIC_HIGHRES_TOUCH); + litest_set_current_device(d); +} + +void +litest_generic_highres_touch_touch_down(struct litest_device *d, + unsigned int slot, + int x, int y) +{ + static int tracking_id; + struct input_event *ev; + struct input_event down[] = { + { .type = EV_ABS, .code = ABS_X, .value = x }, + { .type = EV_ABS, .code = ABS_Y, .value = y }, + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = slot }, + { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = ++tracking_id }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = x }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = y }, + { .type = EV_KEY, .code = BTN_TOUCH, .value = 1 }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + }; + + down[0].value = litest_scale(d, ABS_X, x); + down[1].value = litest_scale(d, ABS_Y, y); + down[4].value = litest_scale(d, ABS_X, x); + down[5].value = litest_scale(d, ABS_Y, y); + + ARRAY_FOR_EACH(down, ev) + litest_event(d, ev-type, ev-code, ev-value); +} + +void +litest_generic_highres_touch_move(struct litest_device *d, + unsigned int slot, + int x, int y) +{ + struct input_event *ev; + struct input_event move[] = { + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = slot }, + { .type = EV_ABS, .code = ABS_X, .value = x }, + { .type = EV_ABS, .code = ABS_Y, .value = y }, + { .type = EV_ABS,
Re: [PATCH libinput] evdev: set CLOCK_MONOTONIC as the time source
On Wed, Feb 19, 2014 at 07:19:15PM +0100, Rui Tiago Cação Matos wrote: On 19 February 2014 13:35, Daniel Stone dan...@fooishbar.org wrote: Can this be CLOCK_MONOTONIC_COARSE instead, to avoid griefing HPET and thus causing much higher power usage? Makes sense and indeed the X server seems to use _COARSE if it's available and has good enough resolution: http://cgit.freedesktop.org/xorg/xserver/tree/os/utils.c#n440 Perhaps libevdev should do something like that too? Note that this doesn't affect clock_gettime like the server's code does, it only affects the timestamps of the events as reported by the kernel. It's a wrapper around the EVIOCSCLOCKID ioctl and that only allows for CLOCK_MONOTONIC and CLOCK_REALTIME (as of 3.14-rc3). So using _COARSE here would merely yield -EINVAL. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput] evdev: set CLOCK_MONOTONIC as the time source
On Tue, Feb 18, 2014 at 07:44:54PM -0800, Thiago Macieira wrote: Em ter 18 fev 2014, às 22:33:26, Jasper St. Pierre escreveu: ... and what if it fails? I'd say that requiring CLOCK_MONOTONIC is fine. Are there any popular Linux setups that don't have CLOCK_MONOTONIC? I'm guessing that some weird and niche embedded boards might not support it. Which is a use-case for libinput. However, I'm guessing that it's ok to let the ioctl fail. No need to check if it will fail, simply let it. if the ioctl fails the time reported will be in CLOCK_REALTIME, which is the default. So aside from optionally printing an error there isn't much of a recovery path anyway, I don't think failing to set the clock id is a fatal condition for a device. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 1/2] Add seat wide slot to touch events
On Wed, Feb 19, 2014 at 10:04:10PM +0100, Jonas Ådahl wrote: Since a Wayland compositor have to represent all touch devices of a seat as one virtual device, lets make that easier by also providing seat wide slots with touch events. Seat wide slots may be accessed using libinput_event_touch_get_seat_slot(). Signed-off-by: Jonas Ådahl jad...@gmail.com --- src/evdev.c| 24 src/evdev.h| 3 +++ src/libinput-private.h | 2 ++ src/libinput.c | 9 + src/libinput.h | 16 tools/event-debug.c| 3 ++- 6 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/evdev.c b/src/evdev.c index d2cdbaf..2b7070a 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -111,7 +111,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) { int32_t cx, cy; int slot; + uint32_t seat_slot; struct libinput_device *base = device-base; + struct libinput_seat *seat = base-seat; slot = device-mt.slot; @@ -130,9 +132,14 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = ffs(~seat-slot_map) - 1; funny, had a bit of a deja-vu here :) see http://lists.freedesktop.org/archives/wayland-devel/2014-February/013238.html for my comments, both still apply. Cheers, Peter + device-mt.slots[slot].seat_slot = seat_slot; + seat-slot_map |= 1 seat_slot; + touch_notify_touch(base, time, slot, +seat_slot, li_fixed_from_int(device-mt.slots[slot].x), li_fixed_from_int(device-mt.slots[slot].y), LIBINPUT_TOUCH_TYPE_DOWN); @@ -141,9 +148,12 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = device-mt.slots[slot].seat_slot; + touch_notify_touch(base, time, slot, +seat_slot, li_fixed_from_int(device-mt.slots[slot].x), li_fixed_from_int(device-mt.slots[slot].y), LIBINPUT_TOUCH_TYPE_MOTION); @@ -152,9 +162,13 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = device-mt.slots[slot].seat_slot; + seat-slot_map = ~(1 seat_slot); + touch_notify_touch(base, time, slot, +seat_slot, 0, 0, LIBINPUT_TOUCH_TYPE_UP); break; @@ -162,10 +176,15 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = ffs(~seat-slot_map) - 1; + device-abs.seat_slot = seat_slot; + seat-slot_map |= 1 seat_slot; + transform_absolute(device, cx, cy); touch_notify_touch(base, time, -1, +seat_slot, li_fixed_from_int(cx), li_fixed_from_int(cy), LIBINPUT_TOUCH_TYPE_DOWN); @@ -176,6 +195,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) touch_notify_touch(base, time, -1, +device-abs.seat_slot, li_fixed_from_int(cx), li_fixed_from_int(cy), LIBINPUT_TOUCH_TYPE_DOWN); @@ -190,9 +210,13 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = device-abs.seat_slot; + seat-slot_map = ~(1 seat_slot); + touch_notify_touch(base, time, -1, +seat_slot, 0, 0, LIBINPUT_TOUCH_TYPE_UP); break; diff
Re: [RFC] libinput configuration interface
On Wed, Feb 19, 2014 at 11:55:28AM +0600, Alexander E. Patrakov wrote: 19.02.2014 04:52, Peter Hutterer wrote: The set of touchpad patches I sent out recently already handle this by default. When the physical clickpad button is depressed, the driver picks the finger that is pressing the button (sometimes guessing, but hey...). That finger cannot control the pointer movement until the button is released again. In your specific use case, the driver would see two touchpoints and it will select the one closer to the bottom edge as the pressing finger (i.e. your thumb). The index finger can still move while the button is down. From my experience with the Sony touchpad (Vaio Z23A4R laptop), I'd say that it doesn't solve the whole problem. Here is what goes wrong with the old synaptics driver by default and can be worked around with AreaBottomEdge. Option SoftButtonAreas 4360 0 4000 0 2880 4359 3500 0 Option AreaBottomEdge 3500 1. I move the right-hand index finger on the touchpad, thus moving the pointer to the place where I want to click. 2. I place the left-hand index finger into the virtual-button area, while still keeping the right finger on the touchpad. I cannot remove the right-hand finger: if I do that, while the contact area shrinks, its center also moves, and the driver picks that up. 3. As I increase the pressure on the left-hand finger until the touchpad clicks, the contact area increases. Unfortunately, its center moves, too, and this can accumulate to ~2-3 pixels until it clicks. The important point is that the bad thing happens before the hardware button click, so the quoted solution totally misses the point. So we need something, either a sledgehammer solution in the form of ignoring all motion in the virtual button area (but that would break Sony Vaio Duo 13 because the only usable height of the virtual button area is 100% there), or some very good filter that pays can you expand on the 100% comment here? is the touchpad too small for anything else? attention to changes in pressure and filters any spurious movement (i.e. any movement that is combined with significant pressure changes) out. But hey, Sony in their new laptops started to ignore the problem under Windows, too, so I think I just have to swallow this and/or use my Bluetooth mouse. couple of comments here: 2 is a synaptics bug that should really be fixed, the driver shouldn't be that sensible - in fact there's probably something that can be done about making the driver more sensible while the finger is moving and less sensible while the finger is still (just an idea, may not work for small movements). there is also the option of using pressure to counteract movements, i.e. a pressure change will increase the hysteresis to avoid erroneous movements. If you have that many issues with the Sony, I really recommend looking at the evdev-mt-touchpad patches I sent to this list, it'll allow for things like that relatively simple. the xorg synaptics driver has for historical reasons and portability a different approach to finger tracking and some of the misbehaviours are easier to fix now. The proposed patches have a different approach to the above: 1 - would be recognised as touchpoint, since no other finger is active it is designated as the pointer-moving touchpoint 2 - second finger recognised, but not assigned as pointer-moving. Movements on that finger have no effect, unless 2-finger scrolling is triggered. 3 - no effect, finger is not moving So really, the goal here is that whatever the motion we see in 2 and 3 is to not go past the trigger 2-finger scrolling threshold. I do have a set of patches not yet ported for the virtual buttons and they add additional tracking, so that a finger that starts (and stays) inside a softbutton area won't contribute to movements, but as you said above that may not work with the vaio. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [RFC] libinput configuration interface
On Thu, Feb 20, 2014 at 12:21:53PM +0600, Alexander E. Patrakov wrote: 20.02.2014 11:14, Peter Hutterer wrote: On Wed, Feb 19, 2014 at 11:55:28AM +0600, Alexander E. Patrakov wrote: 19.02.2014 04:52, Peter Hutterer wrote: The set of touchpad patches I sent out recently already handle this by default. When the physical clickpad button is depressed, the driver picks the finger that is pressing the button (sometimes guessing, but hey...). That finger cannot control the pointer movement until the button is released again. In your specific use case, the driver would see two touchpoints and it will select the one closer to the bottom edge as the pressing finger (i.e. your thumb). The index finger can still move while the button is down. From my experience with the Sony touchpad (Vaio Z23A4R laptop), I'd say that it doesn't solve the whole problem. Here is what goes wrong with the old synaptics driver by default and can be worked around with AreaBottomEdge. Option SoftButtonAreas 4360 0 4000 0 2880 4359 3500 0 Option AreaBottomEdge 3500 1. I move the right-hand index finger on the touchpad, thus moving the pointer to the place where I want to click. 2. I place the left-hand index finger into the virtual-button area, while still keeping the right finger on the touchpad. I cannot remove the right-hand finger: if I do that, while the contact area shrinks, its center also moves, and the driver picks that up. 3. As I increase the pressure on the left-hand finger until the touchpad clicks, the contact area increases. Unfortunately, its center moves, too, and this can accumulate to ~2-3 pixels until it clicks. The important point is that the bad thing happens before the hardware button click, so the quoted solution totally misses the point. So we need something, either a sledgehammer solution in the form of ignoring all motion in the virtual button area (but that would break Sony Vaio Duo 13 because the only usable height of the virtual button area is 100% there), or some very good filter that pays can you expand on the 100% comment here? is the touchpad too small for anything else? The height of the touchpad is too small (the width is OK). See e.g. http://www.blogcdn.com/www.engadget.com/media/2013/06/dsc00149-1370365891.jpg (Just to avoid confusion: I have a Sony Vaio Z23A4R, don't have a Sony Vaio Duo 13, and don't have a Sony Vaio Pro 13. As for my accent on Sony laptops, that's only because there is a Sony shop nearby.) quite frankly, I think this touchpad is one where you (the user) would have to get used to tap-and-drag and two-finger tapping or two-finger clicking instead virtual button areas. I think that'd be a much better fit for a touchpad like this. Cheers, Peter attention to changes in pressure and filters any spurious movement (i.e. any movement that is combined with significant pressure changes) out. But hey, Sony in their new laptops started to ignore the problem under Windows, too, so I think I just have to swallow this and/or use my Bluetooth mouse. couple of comments here: 2 is a synaptics bug that should really be fixed, the driver shouldn't be that sensible - in fact there's probably something that can be done about making the driver more sensible while the finger is moving and less sensible while the finger is still (just an idea, may not work for small movements). there is also the option of using pressure to counteract movements, i.e. a pressure change will increase the hysteresis to avoid erroneous movements. If you have that many issues with the Sony, I really recommend looking at the evdev-mt-touchpad patches I sent to this list, it'll allow for things like that relatively simple. OK, I will build this on my laptop from git later today. the xorg synaptics driver has for historical reasons and portability a different approach to finger tracking and some of the misbehaviours are easier to fix now. The proposed patches have a different approach to the above: 1 - would be recognised as touchpoint, since no other finger is active it is designated as the pointer-moving touchpoint 2 - second finger recognised, but not assigned as pointer-moving. Movements on that finger have no effect, unless 2-finger scrolling is triggered. 3 - no effect, finger is not moving So really, the goal here is that whatever the motion we see in 2 and 3 is to not go past the trigger 2-finger scrolling threshold. Yes, I think we agree on that. I do have a set of patches not yet ported for the virtual buttons and they add additional tracking, so that a finger that starts (and stays) inside a softbutton area won't contribute to movements, but as you said above that may not work with the vaio. Yes, I would like to see that on my Z23A4R (and it matches the Windows default), but users of Duo 13 definitely would not want that enabled on their laptops. As for Sony Vaio Pro 13
Re: [PATCH libinput 1/2] Add seat wide slot to touch events
On Thu, Feb 20, 2014 at 08:39:08AM +0100, Jonas Ådahl wrote: On Thu, Feb 20, 2014 at 02:53:18PM +1000, Peter Hutterer wrote: On Wed, Feb 19, 2014 at 10:04:10PM +0100, Jonas Ådahl wrote: Since a Wayland compositor have to represent all touch devices of a seat as one virtual device, lets make that easier by also providing seat wide slots with touch events. Seat wide slots may be accessed using libinput_event_touch_get_seat_slot(). Signed-off-by: Jonas Ådahl jad...@gmail.com --- src/evdev.c| 24 src/evdev.h| 3 +++ src/libinput-private.h | 2 ++ src/libinput.c | 9 + src/libinput.h | 16 tools/event-debug.c| 3 ++- 6 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/evdev.c b/src/evdev.c index d2cdbaf..2b7070a 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -111,7 +111,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) { int32_t cx, cy; int slot; + uint32_t seat_slot; struct libinput_device *base = device-base; + struct libinput_seat *seat = base-seat; slot = device-mt.slot; @@ -130,9 +132,14 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = ffs(~seat-slot_map) - 1; funny, had a bit of a deja-vu here :) see http://lists.freedesktop.org/archives/wayland-devel/2014-February/013238.html for my comments, both still apply. Hmm :) ... 32 touch points ... Oops, seems I stashed away that part together with the unfinished test case. ... seat_slot is never -1, ... This I did address without stashing away though. oh, right, non-negative, I read over that searching for something that explicitly uses -1... Cheers, Peter Cheers, Peter + device-mt.slots[slot].seat_slot = seat_slot; + seat-slot_map |= 1 seat_slot; + touch_notify_touch(base, time, slot, +seat_slot, li_fixed_from_int(device-mt.slots[slot].x), li_fixed_from_int(device-mt.slots[slot].y), LIBINPUT_TOUCH_TYPE_DOWN); @@ -141,9 +148,12 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = device-mt.slots[slot].seat_slot; + touch_notify_touch(base, time, slot, +seat_slot, li_fixed_from_int(device-mt.slots[slot].x), li_fixed_from_int(device-mt.slots[slot].y), LIBINPUT_TOUCH_TYPE_MOTION); @@ -152,9 +162,13 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = device-mt.slots[slot].seat_slot; + seat-slot_map = ~(1 seat_slot); + touch_notify_touch(base, time, slot, +seat_slot, 0, 0, LIBINPUT_TOUCH_TYPE_UP); break; @@ -162,10 +176,15 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + seat_slot = ffs(~seat-slot_map) - 1; + device-abs.seat_slot = seat_slot; + seat-slot_map |= 1 seat_slot; + transform_absolute(device, cx, cy); touch_notify_touch(base, time, -1, +seat_slot, li_fixed_from_int(cx), li_fixed_from_int(cy), LIBINPUT_TOUCH_TYPE_DOWN); @@ -176,6 +195,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) touch_notify_touch(base, time, -1, +device-abs.seat_slot, li_fixed_from_int(cx), li_fixed_from_int(cy), LIBINPUT_TOUCH_TYPE_DOWN); @@ -190,9 +210,13 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps
Re: [RFC] libinput configuration interface
On Fri, Feb 21, 2014 at 01:29:05AM +0600, Alexander E. Patrakov wrote: 20.02.2014 12:21, I wrote: 20.02.2014 11:14, Peter Hutterer wrote: On Wed, Feb 19, 2014 at 11:55:28AM +0600, Alexander E. Patrakov wrote: From my experience with the Sony touchpad (Vaio Z23A4R laptop), I'd say that it doesn't solve the whole problem. Here is what goes wrong with the old synaptics driver by default and can be worked around with AreaBottomEdge. Option SoftButtonAreas 4360 0 4000 0 2880 4359 3500 0 Option AreaBottomEdge 3500 1. I move the right-hand index finger on the touchpad, thus moving the pointer to the place where I want to click. 2. I place the left-hand index finger into the virtual-button area, while still keeping the right finger on the touchpad. I cannot remove the right-hand finger: if I do that, while the contact area shrinks, its center also moves, and the driver picks that up. 3. As I increase the pressure on the left-hand finger until the touchpad clicks, the contact area increases. Unfortunately, its center moves, too, and this can accumulate to ~2-3 pixels until it clicks. The important point is that the bad thing happens before the hardware button click, so the quoted solution totally misses the point. So we need something, either a sledgehammer solution in the form of ignoring all motion in the virtual button area (but that would break Sony Vaio Duo 13 because the only usable height of the virtual button area is 100% there), or some very good filter that pays couple of comments here: 2 is a synaptics bug that should really be fixed, the driver shouldn't be that sensible - in fact there's probably something that can be done about making the driver more sensible while the finger is moving and less sensible while the finger is still (just an idea, may not work for small movements). there is also the option of using pressure to counteract movements, i.e. a pressure change will increase the hysteresis to avoid erroneous movements. If you have that many issues with the Sony, I really recommend looking at the evdev-mt-touchpad patches I sent to this list, it'll allow for things like that relatively simple. OK, I will build this on my laptop from git later today. Just did this, but have not looked at the code yet. Tested with xf86-input-libinput, thus had no chance to configure anything specific to libinput. If this has any chance of yielding different results, I will retest with Weston on Saturday. libinput currently exposes no configuration interfaces, so the only differences you may see is in pointer acceleration. Software versions: * mtdev 1.1.4 (Gentoo) * xorg-server 1.15.0 (Gentoo) * libevdev from git, cf70d0 * libinput from git, 128f98 + your 19 patches * xf86-input-libinput from git, 761603 Hardware: Sony VAIO Z23A4R, the touchpad identifies itself as follows: I: Bus=0011 Vendor=0002 Product=0007 Version=01b1 N: Name=SynPS/2 Synaptics TouchPad P: Phys=isa0060/serio1/input0 S: Sysfs=/devices/platform/i8042/serio1/input/input4 U: Uniq= H: Handlers=mouse0 event3 B: PROP=5 B: EV=b B: KEY=e520 1 0 0 0 0 B: ABS=66080001103 Pointer movement works, but it is too slow by default on this laptop. That is, a VERY quick swipe (not expected during normal work and even during games) from left to right is just enough to move the pointer across the entire screen (1920x1080). Setting constant deceleration to 0.3 or 0.4 makes it more usable in terms of speed, but this might be my personal preference, and I am not sure if the constant deceleration is the correct knob here. I have not yet looked into pointer-accel fine-tuning on the touchpad or in xf86-input-libinput. What you're seeing is quite simliar to what I have here - it's slow but not unusable. Sorry, just haven't focused on that yet by any help would be appreciated. I don't think deceleration is the right nob here, but I can't remember what you need to tweak. Generally I try not to touch constant deceleration unless the device is a high-resolution device that sends way too many events. If you need to use a value 0..1 for CD then you're effectively using it to speed things up, the term deceleration should hint that this may not work perfectly :) With the default constant deceleration (1.0), pointer movement is very precise. It follows the finger equally well in all parts of the touchpad and in all directions, as expected. I get no misplaced clicks. With constant deceleration 0.3, this is not true. It works better in the central part of the touchpad, but, when crossing the physical border between the area for pointer movement (which is rough) and the area for virtual buttons (which is smooth), it starts to behave like a dirty mechanical mouse. Here is what I mean by that: hard to move the cursor diagonally (i.e. there is a strong preference towards horizontal or vertical movements), and the motion is uneven if I move
Re: [PATCH libinput 1/2] Hook up libevdev as backend
On Sat, Feb 22, 2014 at 03:51:57PM +0100, Jonas Ådahl wrote: On Tue, Feb 18, 2014 at 04:09:09PM +1000, Peter Hutterer wrote: libevdev wraps the various peculiarities of the evdev kernel API into a type-safe API. It also buffers the device so checking for specific features at a later time is easier than re-issuing the ioctls. Plus, it gives us almost free support for SYN_DROPPED events (in the following patch). This patch switches all the bit checks over to libevdev and leaves the event processing as-is. Makes it easier to review. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net Looks good to me as well, with one comment inline. Reviewed-by: Jonas Ådahl jad...@gmail.com .. @@ -624,6 +607,10 @@ evdev_device_create(struct libinput_seat *seat, libinput_device_init(device-base, seat); + rc = libevdev_new_from_fd(fd, device-evdev); + if (rc != 0) + return NULL; + device-seat_caps = 0; device-is_mt = 0; device-mtdev = NULL; @@ -635,10 +622,7 @@ evdev_device_create(struct libinput_seat *seat, device-dispatch = NULL; device-fd = fd; device-pending_event = EVDEV_NONE; - - ioctl(device-fd, EVIOCGNAME(sizeof(devname)), devname); - devname[sizeof(devname) - 1] = '\0'; - device-devname = strdup(devname); + device-devname = libevdev_get_name(device-evdev); This makes the assumption that the const char * returned by libevdev_get_name() is valid until we destroy the device. Is this guaranteed anywhere by libevdev? It's guaranteed by the kernel. There is no facility to set the name through the API and there is no facility to notify the caller if the name would change. so libevdev (which has a copy, obviuosly) wouldn't know that it changed. libevdev_change_fd() doesn't re-sync the name, so yes, this name is constant. Cheers, Peter libinput_seat_ref(seat); @@ -742,8 +726,7 @@ evdev_device_destroy(struct evdev_device *device) dispatch-interface-destroy(dispatch); libinput_seat_unref(device-base.seat); - - free(device-devname); + libevdev_free(device-evdev); free(device-devnode); free(device-sysname); free(device); diff --git a/src/evdev.h b/src/evdev.h index 3c9f93a..a9e27bf 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -27,6 +27,7 @@ #include config.h #include linux/input.h +#include libevdev/libevdev.h #include libinput-private.h @@ -55,10 +56,11 @@ struct evdev_device { struct libinput_source *source; struct evdev_dispatch *dispatch; + struct libevdev *evdev; char *output_name; char *devnode; char *sysname; - char *devname; + const char *devname; int fd; struct { int min_x, max_x, min_y, max_y; @@ -86,16 +88,6 @@ struct evdev_device { int is_mt; }; -/* copied from udev/extras/input_id/input_id.c */ -/* we must use this kernel-compatible implementation */ -#define BITS_PER_LONG (sizeof(unsigned long) * 8) -#define NBITS(x) x)-1)/BITS_PER_LONG)+1) -#define OFF(x) ((x)%BITS_PER_LONG) -#define BIT(x) (1ULOFF(x)) -#define LONG(x) ((x)/BITS_PER_LONG) -#define TEST_BIT(array, bit)((array[LONG(bit)] OFF(bit)) 1) -/* end copied */ - #define EVDEV_UNHANDLED_DEVICE ((struct evdev_device *) 1) struct evdev_dispatch; -- 1.8.4.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 1/2] Hook up libevdev as backend
On Mon, Feb 24, 2014 at 09:28:49AM +1000, Peter Hutterer wrote: On Sat, Feb 22, 2014 at 03:51:57PM +0100, Jonas Ådahl wrote: On Tue, Feb 18, 2014 at 04:09:09PM +1000, Peter Hutterer wrote: libevdev wraps the various peculiarities of the evdev kernel API into a type-safe API. It also buffers the device so checking for specific features at a later time is easier than re-issuing the ioctls. Plus, it gives us almost free support for SYN_DROPPED events (in the following patch). This patch switches all the bit checks over to libevdev and leaves the event processing as-is. Makes it easier to review. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net Looks good to me as well, with one comment inline. Reviewed-by: Jonas Ådahl jad...@gmail.com ... @@ -624,6 +607,10 @@ evdev_device_create(struct libinput_seat *seat, libinput_device_init(device-base, seat); + rc = libevdev_new_from_fd(fd, device-evdev); + if (rc != 0) + return NULL; + device-seat_caps = 0; device-is_mt = 0; device-mtdev = NULL; @@ -635,10 +622,7 @@ evdev_device_create(struct libinput_seat *seat, device-dispatch = NULL; device-fd = fd; device-pending_event = EVDEV_NONE; - - ioctl(device-fd, EVIOCGNAME(sizeof(devname)), devname); - devname[sizeof(devname) - 1] = '\0'; - device-devname = strdup(devname); + device-devname = libevdev_get_name(device-evdev); This makes the assumption that the const char * returned by libevdev_get_name() is valid until we destroy the device. Is this guaranteed anywhere by libevdev? It's guaranteed by the kernel. There is no facility to set the name through the API and there is no facility to notify the caller if the name would change. so libevdev (which has a copy, obviuosly) wouldn't know that it changed. libevdev_change_fd() doesn't re-sync the name, so yes, this name is constant. I should've been more precise here: there is no facility to set the name through the _kernel_ API. libevdev enables a caller to change the name (and thus free the string) though I'm strongly inclined to say that's a caller problem that we don't need to worry about. I'll add some extra notes to the libevdev documentation here. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput] test: Add seat slot tests
On Sat, Feb 22, 2014 at 03:38:28PM +0100, Jonas Ådahl wrote: Add one test that checks uniqueness of seat slots when having multiple devices with active touch points. Add one test that checks that libinput drops touch points when it could not represent them with a seat wide slot. This commit also adds support for from a test case add test devices to an existing libinput context. Only litest-wacom-touch supports this so far. Signed-off-by: Jonas Ådahl jad...@gmail.com --- Needs to be applied after 'Split up the touch event into the different touch types'. test/litest-wacom-touch.c | 24 ++- test/litest.c | 30 - test/litest.h | 13 +++- test/touch.c | 156 ++ 4 files changed, 217 insertions(+), 6 deletions(-) diff --git a/test/litest-wacom-touch.c b/test/litest-wacom-touch.c index 464d541..a6c22ef 100644 --- a/test/litest-wacom-touch.c +++ b/test/litest-wacom-touch.c @@ -24,11 +24,22 @@ #include config.h #endif +#include stdio.h + #include litest.h #include litest-int.h #include libinput-util.h -void litest_wacom_touch_setup(void) +static int device_ids = 0; + +static void +litest_wacom_touch_destroy(struct litest_device *dev) +{ + device_ids = ~dev-device_id; +} + +void +litest_wacom_touch_setup(void) { struct litest_device *d = litest_create_device(LITEST_WACOM_TOUCH); litest_set_current_device(d); @@ -104,14 +115,23 @@ litest_create_wacom_touch(struct litest_device *d) { ABS_MT_TRACKING_ID, 0, 65535, 0 }, }; struct input_absinfo *a; + char name[256]; + int device_id; int rc; d-interface = interface; + d-destroy = litest_wacom_touch_destroy; dev = libevdev_new(); ck_assert(dev != NULL); - libevdev_set_name(dev, Wacom ISDv4 E6 Finger); + device_id = ffs(~device_ids) - 1; + ck_assert_int_ge(device_id, 0); + device_ids |= 1 device_id; + d-device_id = device_id; + snprintf(name, sizeof name, Wacom ISDv4 E6 Finger (%d), device_id); + libevdev_set_name(dev, name); + IMO the actual devices should stay as close to the real thing as possible. That leaves us, for this test, with two options: put a 1.5s sleep in to avoid the uinput duplicate issue, or push this code into the generic touch device that you created for the scaling overflow issue. with that we have more freedom of messing around with the device name. libevdev_set_id_bustype(dev, 0x3); libevdev_set_id_vendor(dev, 0x56a); libevdev_set_id_product(dev, 0xe6); diff --git a/test/litest.c b/test/litest.c index 78a0472..e69f354 100644 --- a/test/litest.c +++ b/test/litest.c @@ -325,8 +325,15 @@ const struct libinput_interface interface = { .close_restricted = close_restricted, }; +const struct libinput_interface * +litest_get_libinput_interface() +{ + return interface; +} + struct litest_device * -litest_create_device(enum litest_device_type which) +litest_create_device_for(struct libinput *libinput, + enum litest_device_type which) { struct litest_device *d = zalloc(sizeof(*d)); int fd; @@ -358,7 +365,7 @@ litest_create_device(enum litest_device_type which) rc = libevdev_new_from_fd(fd, d-evdev); ck_assert_int_eq(rc, 0); - d-libinput = libinput_path_create_context(interface, NULL); + d-libinput = libinput; ck_assert(d-libinput != NULL); d-libinput_device = libinput_path_add_device(d-libinput, path); @@ -372,6 +379,19 @@ litest_create_device(enum litest_device_type which) return d; } +struct litest_device * +litest_create_device(enum litest_device_type which) +{ + struct libinput *libinput; + struct litest_device *d; + + libinput = libinput_path_create_context(interface, NULL); + d = litest_create_device_for(libinput, which); + d-owns_context = true; + + return d; +} + int litest_handle_events(struct litest_device *d) { @@ -392,8 +412,12 @@ litest_delete_device(struct litest_device *d) if (!d) return; + if (d-destroy) + d-destroy(d); + libinput_device_unref(d-libinput_device); - libinput_destroy(d-libinput); + if (d-owns_context) + libinput_destroy(d-libinput); libevdev_free(d-evdev); libevdev_uinput_destroy(d-uinput); memset(d,0, sizeof(*d)); diff --git a/test/litest.h b/test/litest.h index 9cc0ff5..fef051d 100644 --- a/test/litest.h +++ b/test/litest.h @@ -60,8 +60,11 @@ struct litest_device { struct libevdev *evdev; struct libevdev_uinput *uinput; struct libinput *libinput; + void (*destroy)(struct litest_device *d); + bool owns_context; struct libinput_device *libinput_device; struct litest_device_interface *interface; + int
Re: [PATCH libinput 2/2] Hook up event processing to libevdev
On Mon, Feb 24, 2014 at 10:03:59PM +0100, Jonas Ådahl wrote: On Mon, Feb 24, 2014 at 09:44:34AM +1000, Peter Hutterer wrote: On Sat, Feb 22, 2014 at 04:44:06PM +0100, Jonas Ådahl wrote: On Tue, Feb 18, 2014 at 04:09:10PM +1000, Peter Hutterer wrote: This gives us the ability to handle SYN_DROPPED transparently to the caller. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev.c | 90 +++-- 1 file changed, 58 insertions(+), 32 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index ba28fc6..836d0af 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -29,7 +29,7 @@ #include linux/input.h #include unistd.h #include fcntl.h -#include mtdev.h +#include mtdev-plumbing.h #include assert.h #include libinput.h @@ -436,56 +436,82 @@ fallback_dispatch_create(void) return dispatch; } -static void -evdev_process_events(struct evdev_device *device, -struct input_event *ev, int count) +static inline void +evdev_process_event(struct evdev_device *device, struct input_event *e) { struct evdev_dispatch *dispatch = device-dispatch; - struct input_event *e, *end; - uint32_t time = 0; + uint32_t time = e-time.tv_sec * 1000 + e-time.tv_usec / 1000; - e = ev; - end = e + count; - for (e = ev; e end; e++) { - time = e-time.tv_sec * 1000 + e-time.tv_usec / 1000; + dispatch-interface-process(dispatch, device, e, time); +} - dispatch-interface-process(dispatch, device, e, time); +static inline void +evdev_device_dispatch_one(struct evdev_device *device, + struct input_event *ev) +{ + if (!device-mtdev) { + evdev_process_event(device, ev); + } else { + mtdev_put_event(device-mtdev, ev); + if (libevdev_event_is_code(ev, EV_SYN, SYN_REPORT)) { + while(!mtdev_empty(device-mtdev)) { Nit (coding style): space between while and ( amended, thanks. .. static void evdev_device_dispatch(void *data) { struct evdev_device *device = data; struct libinput *libinput = device-base.seat-libinput; - int fd = device-fd; - struct input_event ev[32]; - int len; + struct input_event ev; + int rc; /* If the compositor is repainting, this function is called only once * per frame and we have to process all the events available on the * fd, otherwise there will be input lag. */ do { - if (device-mtdev) - len = mtdev_get(device-mtdev, fd, ev, - ARRAY_LENGTH(ev)) * - sizeof (struct input_event); - else - len = read(fd, ev, sizeof ev); + rc = libevdev_next_event(device-evdev, +LIBEVDEV_READ_FLAG_NORMAL, ev); + if (rc == LIBEVDEV_READ_STATUS_SYNC) { + /* send one more sync event so we handle all + currently pending events before we sync up + to the current state */ + ev.code = SYN_REPORT; + evdev_device_dispatch_one(device, ev); Is this really correct? Shouldn't calling libevdev_next_event() in SYNC mode return a SYN_REPORT event as part of the synchronization? If we do like this it looks like we might cut one series of events that would otherwise be grouped using SYN_REPORT in half. I think you may have misread the diff, this code is only ever called once, on the SYN_DROPPED, all the other events are handled in evdev_sync_device(). libevdev guarantees that the event you pass in when you get LIBEVDEV_READ_STATUS_SYNC is the SYN_DROPPED event that triggered the sync. All we do here is change from EV_SYN/SYN_DROPPED to EV_SYN/SYN_REPORT and process that normally. That finishes the current event sequence. We then call evdev_sync_device() which empties and processes the sync queue until -EAGAIN. That queue is also guaranteed to end with a EV_SYN/SYN_REPORT. Once that is done, we jump back here and continue with the loop, which now hopefully has SUCCESS on the next read. My concern is not that we would add several extra SYN_REPORT splitting event series when synchronizing, but that when we have reached the state where libevdev_next_event() returns LIBEVDEV_READ_STATUS_SYNC, we might be in progress of queuing up a series of events waiting for the next SYN_REPORT. What
Re: [PATCH libinput 2/2] Hook up event processing to libevdev
On Tue, Feb 25, 2014 at 08:17:24AM +1000, Peter Hutterer wrote: static void evdev_device_dispatch(void *data) { struct evdev_device *device = data; struct libinput *libinput = device-base.seat-libinput; - int fd = device-fd; - struct input_event ev[32]; - int len; + struct input_event ev; + int rc; /* If the compositor is repainting, this function is called only once * per frame and we have to process all the events available on the * fd, otherwise there will be input lag. */ do { - if (device-mtdev) - len = mtdev_get(device-mtdev, fd, ev, - ARRAY_LENGTH(ev)) * - sizeof (struct input_event); - else - len = read(fd, ev, sizeof ev); + rc = libevdev_next_event(device-evdev, + LIBEVDEV_READ_FLAG_NORMAL, ev); + if (rc == LIBEVDEV_READ_STATUS_SYNC) { + /* send one more sync event so we handle all +currently pending events before we sync up +to the current state */ + ev.code = SYN_REPORT; + evdev_device_dispatch_one(device, ev); Is this really correct? Shouldn't calling libevdev_next_event() in SYNC mode return a SYN_REPORT event as part of the synchronization? If we do like this it looks like we might cut one series of events that would otherwise be grouped using SYN_REPORT in half. I think you may have misread the diff, this code is only ever called once, on the SYN_DROPPED, all the other events are handled in evdev_sync_device(). libevdev guarantees that the event you pass in when you get LIBEVDEV_READ_STATUS_SYNC is the SYN_DROPPED event that triggered the sync. All we do here is change from EV_SYN/SYN_DROPPED to EV_SYN/SYN_REPORT and process that normally. That finishes the current event sequence. We then call evdev_sync_device() which empties and processes the sync queue until -EAGAIN. That queue is also guaranteed to end with a EV_SYN/SYN_REPORT. Once that is done, we jump back here and continue with the loop, which now hopefully has SUCCESS on the next read. My concern is not that we would add several extra SYN_REPORT splitting event series when synchronizing, but that when we have reached the state where libevdev_next_event() returns LIBEVDEV_READ_STATUS_SYNC, we might be in progress of queuing up a series of events waiting for the next SYN_REPORT. What the documentation[0] states regarding this is that all events up and including the next SYN_REPORT should be ignored and the device should be synchronized. The way I'm reading that is when we reach SYN_DROPPED, we should wait with flushing the queue until we can synchronize and can provide a more complete state. However, we could as well in this case end up with multiple events with the same time in the same series (for example if we already queued ABS_X but x has since then changed, which would mean we'd have two ABS_X in the same series) so I guess its not really better to not flush there. I think the documentation is a bit off here. As of 3.7 (4369c64c79a22b98d3b7eff9d089196cd878a10a) events are now atomic, the kernel doesn't write until the SYN_REPORT is ready so there aren't any events left that we haven't read yet. the documentation predates that commit (2.6.39). I double-checked this and it's a bit different than I wrote above. the kernel input code submits this as a single frame but we may still get a buffer overflow and thus SYN_DROPPED (at random times) in evdev when we're not reading fast enough. However, this is exactly the kind of problem that libevdev is there for, so I'll add the handling there so that what comes out of libevdev is consistent. Cheers, Peter The only exception is SYN_REPORT with value 1 which I've been told doesn't really happen anymore and in any way should be handled within libevdev, so we don't need to cater for it here. ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput] libinput: Fix the close_restricted interface callback
On Sat, Mar 01, 2014 at 02:19:03PM -0500, Jasper St. Pierre wrote: libinput is supposed to take a close callback in its interface to allow you to call out to a privileged API to close FDs. But the FD that libinput passes you is bogus, because libinput_remove_source closes the FD on which it's passed. This is really bad, as the libinput_source really doesn't own the FD which it's passed, so it shouldn't be trying to close() it. Only one out of the four users of libinput_remove_source actually wants their FD closed, so move the close() call there. pushed, thanks. Cheers, Peter --- src/evdev-touchpad.c | 1 + src/libinput.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evdev-touchpad.c b/src/evdev-touchpad.c index 8185bf2..65c5ea0 100644 --- a/src/evdev-touchpad.c +++ b/src/evdev-touchpad.c @@ -714,6 +714,7 @@ touchpad_destroy(struct evdev_dispatch *dispatch) struct libinput *libinput = touchpad-device-base.seat-libinput; touchpad-filter-interface-destroy(touchpad-filter); + close(touchpad-fsm.timer.fd); libinput_remove_source(libinput, touchpad-fsm.timer.source); free(touchpad-fsm.events); free(dispatch); diff --git a/src/libinput.c b/src/libinput.c index 58b87b0..182c401 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -442,7 +442,6 @@ libinput_remove_source(struct libinput *libinput, struct libinput_source *source) { epoll_ctl(libinput-epoll_fd, EPOLL_CTL_DEL, source-fd, NULL); - close(source-fd); source-fd = -1; list_insert(libinput-source_destroy_list, source-link); } -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[RFC PATCH libinput] udev: add libinput_udev_rescan_devices()
When a libinput context for a given seat is initialized, not all devices may be available. Some or all devices may be paused by systemd-logind. Waiting for a unplug event is not appropriate here as the devices are physically available, just prevented from getting access. Add a libinput_udev_rescan_devices() function that triggers a scan of all devices on the current udev seat. Devices that do not exist on the seat are added, devices that already exist on the seat but have been revoked are removed. Note that devices that have been physically removed are not removed, instead we wait for the udev event to handle this for us. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- The idea here is basically to start a udev context as usual. If the compositor doesn't have the session, open_restricted will fail. Once the ResumeDevice signals are handled by the compositor it can ask libinput to rescan the device list to add the ones that failed before (or remove revoked ones). Notes on why this approach: * libinput_device_suspend()/resume() seems nicer at first but if a device fails to open, we don't have a libinput_device context. handling that would make the API complicated since we cannot guarantee that all libinput_device_* functions (specificall has_capability) work on all devices anymore. * I suspect in the 90% case the the PauseDevice/ResumeDevice signals come in in a batch anyway, so the compositor should be able to optimise this to one single call * this is a udev specific call, for the path backend the compositor can and should maintain the devices manually anyway * EVIOCGVERSION was picked because it always succeeds, except after revoke This is an RFC at this point, let me know if that approach works. Still need to write tests and better evdev duplicate detection - right now there is a race condition that could remove the wrong device. src/evdev.c | 15 +++ src/evdev.h | 2 ++ src/libinput.h | 21 + src/udev-seat.c | 46 +- 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index ba7c8b3..018fbb1 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -790,3 +790,18 @@ evdev_device_destroy(struct evdev_device *device) free(device-sysname); free(device); } + +int +evdev_device_is_alive(struct evdev_device *device) +{ + int rc; + int version; + + rc = ioctl(device-fd, EVIOCGVERSION, version); + + if (rc 0 errno != ENODEV) + log_info(evdev: %s failed with errno %d (%s)\n, +__func__, errno, strerror(errno)); + + return rc != -1; +} diff --git a/src/evdev.h b/src/evdev.h index b83a2f9..82a3873 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -156,4 +156,6 @@ evdev_device_remove(struct evdev_device *device); void evdev_device_destroy(struct evdev_device *device); +int +evdev_device_is_alive(struct evdev_device *device); #endif /* EVDEV_H */ diff --git a/src/libinput.h b/src/libinput.h index 3e09871..dadcac2 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -715,6 +715,27 @@ libinput_udev_create_for_seat(const struct libinput_interface *interface, /** * @ingroup base * + * Re-scan the list of devices available to this context. Devices in the + * seat specified in libinput_udev_create_for_seat() that previously have + * failed to initialize are re-initialized. Devices that have successfully + * re-initialized but are now revoked are removed. + * + * Calling libinput_udev_rescan_devices() on a context suspended with + * libinput_suspend() does nothing. + * + * @note This function should not be used for detection of physically added + * or removed devices, libinput_dispatch() detects those. This function + * should only be used to re-open or close existing devices, e.g. if + * systemd-logind prevented access to a device before. + * + * @param libinput The previously initialized libinput context + */ +void +libinput_udev_rescan_devices(struct libinput *libinput); + +/** + * @ingroup base + * * Create a new libinput context that requires the caller to manually add or * remove devices with libinput_path_add_device() and * libinput_path_remove_device(). diff --git a/src/udev-seat.c b/src/udev-seat.c index 366c92b..5b09e4b 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -136,12 +136,28 @@ device_removed(struct udev_device *udev_device, struct udev_input *input) } } +static struct evdev_device* +udev_input_find_device_by_sysname(struct udev_input *input, const char *sysname) +{ + struct udev_seat *seat; + struct evdev_device *device; + + list_for_each(seat, input-base.seat_list, base.link) { + list_for_each(device, seat-base.devices_list, base.link) + if (!strcmp(device-sysname, sysname)) { + return device; + } + } + return NULL; +} + static
Re: [RFC PATCH libinput] udev: add libinput_udev_rescan_devices()
On Sat, Mar 15, 2014 at 07:59:29PM +0100, Jonas Ådahl wrote: On Thu, Mar 13, 2014 at 04:18:20PM +1000, Peter Hutterer wrote: When a libinput context for a given seat is initialized, not all devices may be available. Some or all devices may be paused by systemd-logind. Waiting for a unplug event is not appropriate here as the devices are physically available, just prevented from getting access. Add a libinput_udev_rescan_devices() function that triggers a scan of all devices on the current udev seat. Devices that do not exist on the seat are added, devices that already exist on the seat but have been revoked are removed. Note that devices that have been physically removed are not removed, instead we wait for the udev event to handle this for us. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- The idea here is basically to start a udev context as usual. If the compositor doesn't have the session, open_restricted will fail. Once the ResumeDevice signals are handled by the compositor it can ask libinput to rescan the device list to add the ones that failed before (or remove revoked ones). Notes on why this approach: * libinput_device_suspend()/resume() seems nicer at first but if a device fails to open, we don't have a libinput_device context. handling that would make the API complicated since we cannot guarantee that all libinput_device_* functions (specificall has_capability) work on all devices anymore. * I suspect in the 90% case the the PauseDevice/ResumeDevice signals come in in a batch anyway, so the compositor should be able to optimise this to one single call * this is a udev specific call, for the path backend the compositor can and should maintain the devices manually anyway * EVIOCGVERSION was picked because it always succeeds, except after revoke This is an RFC at this point, let me know if that approach works. Still need to write tests and better evdev duplicate detection - right now there is a race condition that could remove the wrong device. Hi, So what this patch is trying to solve is handling the following flow: * create libinput udev context - some or all devices will fail to open due to being paused * devices are resumed What stops us from simply doing * devices are resumed * create libinput udev context Jasper? you can answer that better than me As you say, a compositor should be able to know when it should rescan, and in most cases (?) before this, we won't get a single device anyway so whats the point of creating earlier than that? For resuming after session switch I suppose we'd have the same problem, but this would then just work the same: * devices are resumed * resume libinput context the question here is: is there a use-case for a single device to be paused/resumed outside of the usual process? David? We're struggling with this in X but that's caused by a completely different problem and is rather orthogonal to this. Cheers, Peter src/evdev.c | 15 +++ src/evdev.h | 2 ++ src/libinput.h | 21 + src/udev-seat.c | 46 +- 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index ba7c8b3..018fbb1 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -790,3 +790,18 @@ evdev_device_destroy(struct evdev_device *device) free(device-sysname); free(device); } + +int +evdev_device_is_alive(struct evdev_device *device) +{ + int rc; + int version; + + rc = ioctl(device-fd, EVIOCGVERSION, version); + + if (rc 0 errno != ENODEV) + log_info(evdev: %s failed with errno %d (%s)\n, +__func__, errno, strerror(errno)); + + return rc != -1; +} diff --git a/src/evdev.h b/src/evdev.h index b83a2f9..82a3873 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -156,4 +156,6 @@ evdev_device_remove(struct evdev_device *device); void evdev_device_destroy(struct evdev_device *device); +int +evdev_device_is_alive(struct evdev_device *device); #endif /* EVDEV_H */ diff --git a/src/libinput.h b/src/libinput.h index 3e09871..dadcac2 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -715,6 +715,27 @@ libinput_udev_create_for_seat(const struct libinput_interface *interface, /** * @ingroup base * + * Re-scan the list of devices available to this context. Devices in the + * seat specified in libinput_udev_create_for_seat() that previously have + * failed to initialize are re-initialized. Devices that have successfully + * re-initialized but are now revoked are removed. + * + * Calling libinput_udev_rescan_devices() on a context suspended with + * libinput_suspend() does nothing. + * + * @note This function should not be used for detection of physically added + * or removed devices
[PATCH libinput 3/3] Expand documentation for libinput_udev_create_for_seat
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/libinput.h | 6 ++ 1 file changed, 6 insertions(+) diff --git a/src/libinput.h b/src/libinput.h index d6bf9f8..3e09871 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -691,6 +691,12 @@ struct libinput_interface { * the given seat ID. New devices or devices removed will appear as events * during libinput_dispatch. * + * libinput_udev_create_for_seat() fails for internal values only. No + * guarantee is made that a device is available once the call finishes, and + * only devices handled by libinput are avialable. Devices that cannot be + * opened in @ref libinput_interface::open_restricted or do not match + * libinput requirements are ignored. + * * @param interface The callback interface * @param user_data Caller-specific data passed to the various callback * interfaces. -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 1/3] Return the length or a neg errno from libinput_device_get_keys()
Previous return value was the straight ioctl, we should try to avoid errno mangling. This changes the API, if not the ABI. Callers with code along the lines of if (libinput_device_get_keys() == -1) will now break. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- weston is not affected by this, it checks for . src/evdev.c| 6 +- src/libinput.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/evdev.c b/src/evdev.c index 5d01e3b..ba7c8b3 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -715,8 +715,12 @@ err: int evdev_device_get_keys(struct evdev_device *device, char *keys, size_t size) { + int len; + memset(keys, 0, size); - return ioctl(device-fd, EVIOCGKEY(size), keys); + len = ioctl(device-fd, EVIOCGKEY(size), keys); + + return (len == -1) ? -errno : len; } const char * diff --git a/src/libinput.h b/src/libinput.h index 9a9cd8c..d6bf9f8 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1169,6 +1169,8 @@ libinput_device_led_update(struct libinput_device *device, * @param device A current input device * @param keys An array filled with the bitmask for the keys * @param size Size of the keys array + * + * @return The number of valid bytes in keys, or a negative errno on failure */ int libinput_device_get_keys(struct libinput_device *device, -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 2/3] udev: factor out device_removed handling
No functional changes Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- I needed this for the rescan patch but it makes the calls more symmetrical, so we might as well push it independently. src/udev-seat.c | 41 +++-- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/udev-seat.c b/src/udev-seat.c index e622de2..366c92b 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -116,6 +116,26 @@ device_added(struct udev_device *udev_device, struct udev_input *input) return 0; } +static void +device_removed(struct udev_device *udev_device, struct udev_input *input) +{ + const char *devnode; + struct evdev_device *device, *next; + struct udev_seat *seat; + + devnode = udev_device_get_devnode(udev_device); + list_for_each(seat, input-base.seat_list, base.link) { + list_for_each_safe(device, next, + seat-base.devices_list, base.link) + if (!strcmp(device-devnode, devnode)) { + log_info(input device %s, %s removed\n, + device-devname, device-devnode); + evdev_device_remove(device); + break; + } + } +} + static int udev_input_add_devices(struct udev_input *input, struct udev *udev) { @@ -155,10 +175,7 @@ evdev_udev_handler(void *data) { struct udev_input *input = data; struct udev_device *udev_device; - struct evdev_device *device, *next; const char *action; - const char *devnode; - struct udev_seat *seat; udev_device = udev_monitor_receive_device(input-udev_monitor); if (!udev_device) @@ -171,22 +188,10 @@ evdev_udev_handler(void *data) if (strncmp(event, udev_device_get_sysname(udev_device), 5) != 0) goto out; - if (!strcmp(action, add)) { + if (!strcmp(action, add)) device_added(udev_device, input); - } - else if (!strcmp(action, remove)) { - devnode = udev_device_get_devnode(udev_device); - list_for_each(seat, input-base.seat_list, base.link) { - list_for_each_safe(device, next, - seat-base.devices_list, base.link) - if (!strcmp(device-devnode, devnode)) { - log_info(input device %s, %s removed\n, -device-devname, device-devnode); - evdev_device_remove(device); - break; - } - } - } + else if (!strcmp(action, remove)) + device_removed(udev_device, input); out: udev_device_unref(udev_device); -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [RFC PATCH libinput] udev: add libinput_udev_rescan_devices()
On Fri, Mar 21, 2014 at 12:27:45AM -0400, Jasper St. Pierre wrote: So you're saying that every time we're suspended, we simply throw out the entire context and drop all the devices on the floor, as if you just unplugged all of them? fwiw, this is effectively what happens internally anyway, you get removed events for every device on suspend, and added events on resume for those still there. I suppose I just never thought of that. On first though, I don't see anything wrong with that. If that's what we should do, should we remove libinput_suspend / libinput_resume then? libinput_suspend/resume only tear down the devices, but not anything else. there isn't much global state that's kept across suspend/resume yet (seats are one example though) but the biggest difference is that that you can't use _any_ object around after libinput_destroy(). suspend/resume keeps them alive until you unref them. Cheers, Peter On Mon, Mar 17, 2014 at 11:21 PM, Peter Hutterer peter.hutte...@who-t.netwrote: On Sat, Mar 15, 2014 at 07:59:29PM +0100, Jonas Ådahl wrote: On Thu, Mar 13, 2014 at 04:18:20PM +1000, Peter Hutterer wrote: When a libinput context for a given seat is initialized, not all devices may be available. Some or all devices may be paused by systemd-logind. Waiting for a unplug event is not appropriate here as the devices are physically available, just prevented from getting access. Add a libinput_udev_rescan_devices() function that triggers a scan of all devices on the current udev seat. Devices that do not exist on the seat are added, devices that already exist on the seat but have been revoked are removed. Note that devices that have been physically removed are not removed, instead we wait for the udev event to handle this for us. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- The idea here is basically to start a udev context as usual. If the compositor doesn't have the session, open_restricted will fail. Once the ResumeDevice signals are handled by the compositor it can ask libinput to rescan the device list to add the ones that failed before (or remove revoked ones). Notes on why this approach: * libinput_device_suspend()/resume() seems nicer at first but if a device fails to open, we don't have a libinput_device context. handling that would make the API complicated since we cannot guarantee that all libinput_device_* functions (specificall has_capability) work on all devices anymore. * I suspect in the 90% case the the PauseDevice/ResumeDevice signals come in in a batch anyway, so the compositor should be able to optimise this to one single call * this is a udev specific call, for the path backend the compositor can and should maintain the devices manually anyway * EVIOCGVERSION was picked because it always succeeds, except after revoke This is an RFC at this point, let me know if that approach works. Still need to write tests and better evdev duplicate detection - right now there is a race condition that could remove the wrong device. Hi, So what this patch is trying to solve is handling the following flow: * create libinput udev context - some or all devices will fail to open due to being paused * devices are resumed What stops us from simply doing * devices are resumed * create libinput udev context Jasper? you can answer that better than me As you say, a compositor should be able to know when it should rescan, and in most cases (?) before this, we won't get a single device anyway so whats the point of creating earlier than that? For resuming after session switch I suppose we'd have the same problem, but this would then just work the same: * devices are resumed * resume libinput context the question here is: is there a use-case for a single device to be paused/resumed outside of the usual process? David? We're struggling with this in X but that's caused by a completely different problem and is rather orthogonal to this. Cheers, Peter src/evdev.c | 15 +++ src/evdev.h | 2 ++ src/libinput.h | 21 + src/udev-seat.c | 46 +- 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index ba7c8b3..018fbb1 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -790,3 +790,18 @@ evdev_device_destroy(struct evdev_device *device) free(device-sysname); free(device); } + +int +evdev_device_is_alive(struct evdev_device *device) +{ + int rc; + int version; + + rc = ioctl(device-fd, EVIOCGVERSION, version); + + if (rc 0 errno != ENODEV) + log_info(evdev: %s failed
Re: [PATCH libinput 00/19] mt touchpad implementation
On Mon, Feb 17, 2014 at 04:48:19PM +1000, Peter Hutterer wrote: Here's the base of a touchpad implementation that's more geared towards modern multitouch-capable touchpads than the current xorg synaptics driver or, for that matter, the libinput one. just for the archives, I've pushed this driver now. The old one is still in the repo so if this one really doesn't work on your hardware you can revert 6a6103262530d8fca66ee3847d5664824158c12b locally. While you hopefully file a bug and give us a chance to fix the new one :) Cheers, Peter This isn't a completely new implementation, I worked on a project named libtouchpad a few months back, most of this is porting things over to libinput. Note that parts are still work in progress, but I'd like to merge it soon so we can concentrate on fixing it instead of me rebasing a massive patchset. The big difference to other existing drivers is that each touchpoint is handled separately. That allows us to do a couple of things better than before: because we can tell where each finger is, software button handling, clickpad drag-and-drop, etc. becomes a lot easier to handle. The features already working in this driver: - 1, 2, 3-finger tapping - 2-finger scrolling - clickfinger, 1-2-3 fingers on the touchpad when clicking cause LRM click - drag-n-drop on clickpads - single-touch touchpad support (+ tapping and 2 finger scrolling) Features in the pipe (i.e. need porting): - clickpad software button support - better timeout handling (a read delay coupled with a timeout may trigger the wrong events) Features planned: - top software button area - trackstick mode (T440) - disable-while-typing - better motion filters, especially during tapping and clicking - pinch/rotation support - better handling of vert → horizontal scrolling. Right now the scroll direction is locked after the first movement, I'd like to use a time-dependent vector to decide when a sideways motion enables horizontal scrolling I think that about covers it for now. You can test the code on http://github.com/whot/libinput wip/mt-touchpad and a basic X driver is here: http://github.com/whot/xf86-input-libinput Any comments? ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [RFC] libinput configuration interface
hey, sorry about the delay, I got moved to other stuff for a while and only now just picked up libinput again. On Sat, Feb 22, 2014 at 03:33:26PM +0600, Alexander E. Patrakov wrote: 2014-02-21 5:26 GMT+06:00 Peter Hutterer peter.hutte...@who-t.net: On Fri, Feb 21, 2014 at 01:29:05AM +0600, Alexander E. Patrakov wrote: Vertical two-finger scrolling works, but is way too sensitive both with constant deceleration 1.0 and with 0.3. that's a xf86-input-libinput bug, Benjamin fixed that but I forgot to push. 761603d..bee8989 now, please re-test that. The speed is now fixed indeed, but scrolling is now subject to the same dirty mouse bug. See the badscroll.rec file in the attached archive. It contains two scoll gestures - one down, and one up. The driver has picked up only the beginning of the up-scroll (i.e. the chromium window was not scrolled as far as I wanted, even though I continued moving both fingers). I've looked at this and I think I know what you mean. I get a massive jump down first, then a slight up only. Looking at the ./tools/event-debug output from libinput it looks like the coordinates for downward scroll are massive too (between 10 and 48), the upwards ones are hanging around the -3 to -4 mark. That would explain the different scrolling. however, that matches the recordings. I think what may be the problem here is the motion averaging between the fingers. the driver currently takes the changed touchpoints and averages the motion between the two for the actual scroll distance. this may slow down slow scrolls, I'll need to run some tests on this. Tapping and tap-and-drag are not usable. They require not tapping, but knocking with force. So this points to the driver being miscalibrated on the pressure axis. Can this also be the reason of the low x/y sensitivity and dirty mouse feeling? that's a bit odd. I'd like to see an evemu-record output from that then. Currently I ignore pressure completely, so any touch should be detected. Actually the first tap after the server start is detected reliably. The problem only affects other taps. See the file tap-libinput.rec in the attached archive. I had a look at the recording files, mainly with the event-debug tools but I'm struggingling to see the same issues. the tap recording has 6 touches, some of which are taps, others are moves. I can spot three taps in there, one in the middle somewhere, two towards the end and that seems to match the recordings. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 2/8] evdev: Avoid double touch down/up events
On Wed, Mar 26, 2014 at 07:45:32AM +0100, Michael Schellenberger Costa wrote: I might be dumb but doesnt this require motion between clicks? In that case you would lose for example track balls which do not necessary move between clicks. this is for touch events only here, and the only way you can get here is if you have a SYN_DROPPED event and you're losing one of the ABS_MT_TRACKING_ID. This is fixed with libevdev 1.1, but better be safe than sorry here. Cheers, Peter On 25.03.2014 21:45, Jonas Ådahl wrote: When the kernel sends multiple touch down or touch up for the same slot in a row, ignore any such subsequent event ensuring libinput always produces 1 x touch down - [n x touch motion] - 1 x touch up event series. Signed-off-by: Jonas Ådahl jad...@gmail.com --- src/evdev.c | 13 + 1 file changed, 13 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index ff8b27a..729e1f4 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -135,6 +135,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (slot = MAX_SLOTS) break; + if (device-mt.slots[slot].seat_slot != -1) + break; + seat_slot = ffs(~seat-slot_map) - 1; device-mt.slots[slot].seat_slot = seat_slot; @@ -171,6 +174,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) break; seat_slot = device-mt.slots[slot].seat_slot; + device-mt.slots[slot].seat_slot = -1; if (seat_slot == -1) break; @@ -183,6 +187,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + if (device-abs.seat_slot != -1) + break; + seat_slot = ffs(~seat-slot_map) - 1; device-abs.seat_slot = seat_slot; @@ -218,6 +225,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) break; seat_slot = device-abs.seat_slot; +device-abs.seat_slot = -1; if (seat_slot == -1) break; @@ -655,6 +663,7 @@ evdev_device_create(struct libinput_seat *seat, int rc; int fd; int unhandled_device = 0; + int i; /* Use non-blocking mode so that we can loop on read on * evdev_device_data() until all events on the fd are @@ -712,6 +721,10 @@ evdev_device_create(struct libinput_seat *seat, if (!device-source) goto err; + device-abs.seat_slot = -1; + for (i = 0; i MAX_SLOTS; ++i) + device-mt.slots[i].seat_slot = -1; + list_insert(seat-devices_list.prev, device-base.link); notify_added_device(device-base); ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 2/8] evdev: Avoid double touch down/up events
On Wed, Mar 26, 2014 at 08:40:43AM +0100, Jonas Ådahl wrote: On Wed, Mar 26, 2014 at 05:30:14PM +1000, Peter Hutterer wrote: On Wed, Mar 26, 2014 at 07:45:32AM +0100, Michael Schellenberger Costa wrote: I might be dumb but doesnt this require motion between clicks? In that case you would lose for example track balls which do not necessary move between clicks. this is for touch events only here, and the only way you can get here is if you have a SYN_DROPPED event and you're losing one of the ABS_MT_TRACKING_ID. This is fixed with libevdev 1.1, but better be safe than sorry here. We can also get this if we have an libevdev managed uinput device with mt slot limit x while sending mt slot x + n events. libevdev will sanitize the events making any mt slot x + n event a mt slot x event. huh, right, I didn't think of that. I'll see if I can fix this in libevdev. Cheers, Peter On 25.03.2014 21:45, Jonas Ådahl wrote: When the kernel sends multiple touch down or touch up for the same slot in a row, ignore any such subsequent event ensuring libinput always produces 1 x touch down - [n x touch motion] - 1 x touch up event series. Signed-off-by: Jonas Ådahl jad...@gmail.com --- src/evdev.c | 13 + 1 file changed, 13 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index ff8b27a..729e1f4 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -135,6 +135,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (slot = MAX_SLOTS) break; + if (device-mt.slots[slot].seat_slot != -1) + break; + seat_slot = ffs(~seat-slot_map) - 1; device-mt.slots[slot].seat_slot = seat_slot; @@ -171,6 +174,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) break; seat_slot = device-mt.slots[slot].seat_slot; + device-mt.slots[slot].seat_slot = -1; if (seat_slot == -1) break; @@ -183,6 +187,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + if (device-abs.seat_slot != -1) + break; + seat_slot = ffs(~seat-slot_map) - 1; device-abs.seat_slot = seat_slot; @@ -218,6 +225,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) break; seat_slot = device-abs.seat_slot; +device-abs.seat_slot = -1; if (seat_slot == -1) break; @@ -655,6 +663,7 @@ evdev_device_create(struct libinput_seat *seat, int rc; int fd; int unhandled_device = 0; + int i; /* Use non-blocking mode so that we can loop on read on * evdev_device_data() until all events on the fd are @@ -712,6 +721,10 @@ evdev_device_create(struct libinput_seat *seat, if (!device-source) goto err; + device-abs.seat_slot = -1; + for (i = 0; i MAX_SLOTS; ++i) + device-mt.slots[i].seat_slot = -1; + list_insert(seat-devices_list.prev, device-base.link); notify_added_device(device-base); ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 4/8] test: Test handling of many touch points
On Tue, Mar 25, 2014 at 09:45:55PM +0100, Jonas Ådahl wrote: libinput currently handles 16 per device touch points. Test that we behave as expected when a device has an even higher number of active touch points. Signed-off-by: Jonas Ådahl jad...@gmail.com --- test/touch.c | 50 ++ 1 file changed, 50 insertions(+) diff --git a/test/touch.c b/test/touch.c index 9354c25..61d8762 100644 --- a/test/touch.c +++ b/test/touch.c @@ -275,6 +275,54 @@ START_TEST(touch_seat_slot_drop) } END_TEST +START_TEST(touch_many_slots) +{ + struct libinput *libinput; + struct litest_device *dev; + struct libinput_event *ev; + int slot; + const int num_tps = 100; + int slot_count = 0; + enum libinput_event_type type; + + dev = litest_current_device(); + libinput = dev-libinput; + + for (slot = 0; slot num_tps; ++slot) + litest_touch_down(dev, slot, 0, 0); + for (slot = 0; slot num_tps; ++slot) + litest_touch_up(dev, slot); + + libinput_dispatch(libinput); + while ((ev = libinput_get_event(libinput))) { + type = libinput_event_get_type(ev); + + if (type == LIBINPUT_EVENT_TOUCH_DOWN) + slot_count++; + else if (type == LIBINPUT_EVENT_TOUCH_UP) + break; + + libinput_dispatch(libinput); + } + + ck_assert_notnull(ev); + ck_assert_int_gt(slot_count, 0); + + libinput_dispatch(libinput); + do { + type = libinput_event_get_type(ev); + ck_assert_int_ne(type, LIBINPUT_EVENT_TOUCH_DOWN); + if (type == LIBINPUT_EVENT_TOUCH_UP) { + slot_count--; + } + + libinput_dispatch(libinput); + } while ((ev = libinput_get_event(libinput))); + + ck_assert_int_eq(slot_count, 0); +} +END_TEST + int main(int argc, char **argv) { @@ -283,6 +331,8 @@ main(int argc, char **argv) LITEST_TOUCH, LITEST_ANY); litest_add_no_device(touch:seat-slot, touch_seat_slots); litest_add_no_device(touch:seat-slot-drop, touch_seat_slot_drop); + litest_add(touch:many-slots, touch_many_slots, +LITEST_TOUCH, LITEST_ANY); even though it breaks the 80 char width, I'd really prefer it if the tests would just be on one line, it's a lot easier to view them on screens that are less than 10 years old :) Cheers, Peter return litest_run(argc, argv); } -- 1.8.3.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 1/8] evdev: Don't write out of bounds when mt slot is too large
On Tue, Mar 25, 2014 at 09:45:52PM +0100, Jonas Ådahl wrote: Signed-off-by: Jonas Ådahl jad...@gmail.com patch looks good, but I do wonder if it'd be better to just dynamically allocate slots based on the number of touches. A quick glance shows we don't really need this a fixed length anyway, MAX_SLOTS is unnecessary. Cheers, Peter --- src/evdev.c | 13 + 1 file changed, 13 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index 72e4086..ff8b27a 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -132,6 +132,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + if (slot = MAX_SLOTS) + break; + seat_slot = ffs(~seat-slot_map) - 1; device-mt.slots[slot].seat_slot = seat_slot; @@ -148,6 +151,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + if (slot = MAX_SLOTS) + break; + seat_slot = device-mt.slots[slot].seat_slot; x = li_fixed_from_int(device-mt.slots[slot].x); y = li_fixed_from_int(device-mt.slots[slot].y); @@ -161,6 +167,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + if (slot = MAX_SLOTS) + break; + seat_slot = device-mt.slots[slot].seat_slot; if (seat_slot == -1) @@ -300,11 +309,15 @@ evdev_process_touch(struct evdev_device *device, device-pending_event = EVDEV_ABSOLUTE_MT_UP; break; case ABS_MT_POSITION_X: + if (device-mt.slot = MAX_SLOTS) + break; device-mt.slots[device-mt.slot].x = e-value; if (device-pending_event == EVDEV_NONE) device-pending_event = EVDEV_ABSOLUTE_MT_MOTION; break; case ABS_MT_POSITION_Y: + if (device-mt.slot = MAX_SLOTS) + break; device-mt.slots[device-mt.slot].y = e-value; if (device-pending_event == EVDEV_NONE) device-pending_event = EVDEV_ABSOLUTE_MT_MOTION; -- 1.8.3.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 1/8] evdev: Don't write out of bounds when mt slot is too large
On Wed, Mar 26, 2014 at 09:20:27AM +0100, Jonas Ådahl wrote: On Wed, Mar 26, 2014 at 06:05:19PM +1000, Peter Hutterer wrote: On Tue, Mar 25, 2014 at 09:45:52PM +0100, Jonas Ådahl wrote: Signed-off-by: Jonas Ådahl jad...@gmail.com patch looks good, but I do wonder if it'd be better to just dynamically allocate slots based on the number of touches. A quick glance shows we don't really need this a fixed length anyway, MAX_SLOTS is unnecessary. We probably want a MAX_SLOTS anyway if we want to structure it as slot = index in (dynamically allocated) array, in order to protect from misbehaving drivers. the kernel filters slots outside the ranges, so we should be good for the normal use-case. using a min macro that caps it to num_slots when we assign the slot number should be enough too (that's essentially what libevdev does). You'll overwrite stuff in the same slot but by then you already have a misbehaving device anyway. Cheers, Peter --- src/evdev.c | 13 + 1 file changed, 13 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index 72e4086..ff8b27a 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -132,6 +132,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + if (slot = MAX_SLOTS) + break; + seat_slot = ffs(~seat-slot_map) - 1; device-mt.slots[slot].seat_slot = seat_slot; @@ -148,6 +151,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + if (slot = MAX_SLOTS) + break; + seat_slot = device-mt.slots[slot].seat_slot; x = li_fixed_from_int(device-mt.slots[slot].x); y = li_fixed_from_int(device-mt.slots[slot].y); @@ -161,6 +167,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) if (!(device-seat_caps EVDEV_DEVICE_TOUCH)) break; + if (slot = MAX_SLOTS) + break; + seat_slot = device-mt.slots[slot].seat_slot; if (seat_slot == -1) @@ -300,11 +309,15 @@ evdev_process_touch(struct evdev_device *device, device-pending_event = EVDEV_ABSOLUTE_MT_UP; break; case ABS_MT_POSITION_X: + if (device-mt.slot = MAX_SLOTS) + break; device-mt.slots[device-mt.slot].x = e-value; if (device-pending_event == EVDEV_NONE) device-pending_event = EVDEV_ABSOLUTE_MT_MOTION; break; case ABS_MT_POSITION_Y: + if (device-mt.slot = MAX_SLOTS) + break; device-mt.slots[device-mt.slot].y = e-value; if (device-pending_event == EVDEV_NONE) device-pending_event = EVDEV_ABSOLUTE_MT_MOTION; -- 1.8.3.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 4/8] test: Test handling of many touch points
On Wed, Mar 26, 2014 at 09:24:08AM +0100, Jonas Ådahl wrote: On Wed, Mar 26, 2014 at 06:02:46PM +1000, Peter Hutterer wrote: On Tue, Mar 25, 2014 at 09:45:55PM +0100, Jonas Ådahl wrote: libinput currently handles 16 per device touch points. Test that we behave as expected when a device has an even higher number of active touch points. Signed-off-by: Jonas Ådahl jad...@gmail.com --- test/touch.c | 50 ++ 1 file changed, 50 insertions(+) diff --git a/test/touch.c b/test/touch.c index 9354c25..61d8762 100644 --- a/test/touch.c +++ b/test/touch.c @@ -275,6 +275,54 @@ START_TEST(touch_seat_slot_drop) } END_TEST +START_TEST(touch_many_slots) +{ + struct libinput *libinput; + struct litest_device *dev; + struct libinput_event *ev; + int slot; + const int num_tps = 100; + int slot_count = 0; + enum libinput_event_type type; + + dev = litest_current_device(); + libinput = dev-libinput; + + for (slot = 0; slot num_tps; ++slot) + litest_touch_down(dev, slot, 0, 0); + for (slot = 0; slot num_tps; ++slot) + litest_touch_up(dev, slot); + + libinput_dispatch(libinput); + while ((ev = libinput_get_event(libinput))) { + type = libinput_event_get_type(ev); + + if (type == LIBINPUT_EVENT_TOUCH_DOWN) + slot_count++; + else if (type == LIBINPUT_EVENT_TOUCH_UP) + break; + + libinput_dispatch(libinput); + } + + ck_assert_notnull(ev); + ck_assert_int_gt(slot_count, 0); + + libinput_dispatch(libinput); + do { + type = libinput_event_get_type(ev); + ck_assert_int_ne(type, LIBINPUT_EVENT_TOUCH_DOWN); + if (type == LIBINPUT_EVENT_TOUCH_UP) { + slot_count--; + } + + libinput_dispatch(libinput); + } while ((ev = libinput_get_event(libinput))); + + ck_assert_int_eq(slot_count, 0); +} +END_TEST + int main(int argc, char **argv) { @@ -283,6 +331,8 @@ main(int argc, char **argv) LITEST_TOUCH, LITEST_ANY); litest_add_no_device(touch:seat-slot, touch_seat_slots); litest_add_no_device(touch:seat-slot-drop, touch_seat_slot_drop); + litest_add(touch:many-slots, touch_many_slots, +LITEST_TOUCH, LITEST_ANY); even though it breaks the 80 char width, I'd really prefer it if the tests would just be on one line, it's a lot easier to view them on screens that are less than 10 years old :) I tend to use vertical split screen on a laptop and in those cases 80 char length limit makes code more readable. I guess I could change it to ignore the 80 char limit for test case adding lines, albeit reluctantly. thanks. I'm not proposing to change it for the rest of the code, but it really makes the code nicer to look at. this isn't code that gets edited frequently, so the exception shouldn't hurt too much. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 3/8] test: Add seat slot tests
On Tue, Mar 25, 2014 at 09:45:54PM +0100, Jonas Ådahl wrote: Add one test that checks uniqueness of seat slots when having multiple devices with active touch points. Add one test that checks that libinput drops touch points when it could not represent them with a seat wide slot. This commit also adds support for from a test case add test devices to an existing libinput context. Only litest-genric-highres-touch supports this so far and only generic artifical test devices should, in order to keep emulated devices closer to their originals. I'm generally happy with the test itself, but the extension to the litest framework I'm not convinced. There are a bunch of tests already that need specific devices and they just create a uinput device. I've got an unfinished series here that adds a wrapper to make this easier and with less boilerplate. My main worries with this here is that the deviceid is part of the litest_device now but meaningless for all other devices. And for this specific test you're essentially hiding one of the main features in the generic_highres device - that it has MAX_SLOT slots. Plus the extra bits that elevate litest from a initializes behind the scenes for multiple devices to something that almost looks like an API when it really doesn't give you that much benefit over just creating a uinput device. Finally, we already have generic devices, you could simply add a generic_toomanyslots device. I'll try to clean up the uinput wrapper I mentioned above tomorrow, maybe that will be enough for this patch. a few other comments inline Signed-off-by: Jonas Ådahl jad...@gmail.com --- test/litest-generic-highres-touch.c | 28 +- test/litest.c | 33 ++- test/litest.h | 13 ++- test/touch.c| 184 4 files changed, 251 insertions(+), 7 deletions(-) diff --git a/test/litest-generic-highres-touch.c b/test/litest-generic-highres-touch.c index 68615c3..5f2f023 100644 --- a/test/litest-generic-highres-touch.c +++ b/test/litest-generic-highres-touch.c @@ -23,11 +23,22 @@ #include config.h +#include stdio.h + #include litest.h #include litest-int.h #include libinput-util.h -void litest_generic_highres_touch_setup(void) +static int device_ids = 0; + +static void +litest_generic_highres_touch_destroy(struct litest_device *dev) +{ + device_ids = ~dev-device_id; +} + +void +litest_generic_highres_touch_setup(void) { struct litest_device *d = litest_create_device(LITEST_GENERIC_HIGHRES_TOUCH); @@ -96,22 +107,33 @@ litest_create_generic_highres_touch(struct litest_device *d) { struct libevdev *dev; int rc; + int device_id; + char name[255]; struct input_absinfo *a; struct input_absinfo abs[] = { { ABS_X, 0, 32767, 75 }, { ABS_Y, 0, 32767, 129 }, - { ABS_MT_SLOT, 0, 1, 0 }, + { ABS_MT_SLOT, 0, 40, 0 }, { ABS_MT_POSITION_X, 0, 32767, 0, 0, 10 }, { ABS_MT_POSITION_Y, 0, 32767, 0, 0, 9 }, { ABS_MT_TRACKING_ID, 0, 65535, 0 }, }; d-interface = interface; + d-destroy = litest_generic_highres_touch_destroy; dev = libevdev_new(); ck_assert(dev != NULL); - libevdev_set_name(dev, Generic emulated highres touch device); + device_id = ffs(~device_ids) - 1; + ck_assert_int_ge(device_id, 0); + device_ids |= 1 device_id; + d-device_id = device_id; + snprintf(name, sizeof name, + Generic emulated highres touch device (%d), + device_id); + libevdev_set_name(dev, name); + libevdev_set_id_bustype(dev, 0x3); libevdev_set_id_vendor(dev, 0xabcd); /* Some random vendor. */ libevdev_set_id_product(dev, 0x1234); /* Some random product id. */ diff --git a/test/litest.c b/test/litest.c index 9241623..0e7da70 100644 --- a/test/litest.c +++ b/test/litest.c @@ -328,7 +328,8 @@ const struct libinput_interface interface = { }; struct litest_device * -litest_create_device(enum litest_device_type which) +litest_create_device_for(struct libinput *libinput, + enum litest_device_type which) { struct litest_device *d = zalloc(sizeof(*d)); int fd; @@ -360,7 +361,7 @@ litest_create_device(enum litest_device_type which) rc = libevdev_new_from_fd(fd, d-evdev); ck_assert_int_eq(rc, 0); - d-libinput = libinput_path_create_context(interface, NULL); + d-libinput = libinput; ck_assert(d-libinput != NULL); d-libinput_device = libinput_path_add_device(d-libinput, path); @@ -374,6 +375,28 @@ litest_create_device(enum litest_device_type which) return d; } +struct libinput * +litest_create_context(void) +{ + struct libinput *libinput = +
Re: [PATCH libinput 5/8] test: Check that libinput doesn't send double touch down/up events
On Tue, Mar 25, 2014 at 09:45:56PM +0100, Jonas Ådahl wrote: Signed-off-by: Jonas Ådahl jad...@gmail.com --- test/touch.c | 43 +++ 1 file changed, 43 insertions(+) diff --git a/test/touch.c b/test/touch.c index 61d8762..4a6af21 100644 --- a/test/touch.c +++ b/test/touch.c @@ -323,6 +323,47 @@ START_TEST(touch_many_slots) } END_TEST +START_TEST(touch_double_touch_down_up) +{ + struct libinput *libinput; + struct litest_device *dev; + struct libinput_event *ev; + bool got_down = false; + bool got_up = false; + + dev = litest_current_device(); + libinput = dev-libinput; + + litest_touch_down(dev, 0, 0, 0); + litest_touch_down(dev, 0, 0, 0); with this the kernel will filter the coordinates. This only works because the tracking_id is automatically picked in touch_down. IMO it might be worth changing the coordinates here too. It has no real effect but it'll look more like two touchpoints and the evdev events will be more obvious to read too. Reviewed-by: Peter Hutterer peter.hutte...@who-t.net for the patches where I didn't complain about something :) Cheers, Peter + litest_touch_up(dev, 0); + litest_touch_up(dev, 0); + + libinput_dispatch(libinput); + + while ((ev = libinput_get_event(libinput))) { + switch (libinput_event_get_type(ev)) { + case LIBINPUT_EVENT_TOUCH_DOWN: + ck_assert(!got_down); + got_down = true; + break; + case LIBINPUT_EVENT_TOUCH_UP: + ck_assert(got_down); + ck_assert(!got_up); + got_up = true; + break; + default: + break; + } + + libinput_dispatch(libinput); + } + + ck_assert(got_down); + ck_assert(got_up); +} +END_TEST + int main(int argc, char **argv) { @@ -333,6 +374,8 @@ main(int argc, char **argv) litest_add_no_device(touch:seat-slot-drop, touch_seat_slot_drop); litest_add(touch:many-slots, touch_many_slots, LITEST_TOUCH, LITEST_ANY); + litest_add(touch:double-touch-down-up, touch_double_touch_down_up, +LITEST_TOUCH, LITEST_ANY); return litest_run(argc, argv); } -- 1.8.3.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput] test: add litest helper functions for creating uinput devices
Both functions accept a series of event types/codes tuples, terminated by -1. For the even type INPUT_PROP_MAX (an invalid type otherwise) the code is used as a property to enable. The _abs function als takes an array of absinfo, with absinfo.value determining the axis to change. If none are given, abs axes are initialized with default settings. Both functions abort on failure, so the caller does not need to check the return value. Example code for creating a rel device: struct libevdev_uinput *uinput; struct input_id id = { ... }; uinput = litest_create_uinput_device(foo, id, EV_REL, REL_X, EV_REL, REL_Y, EV_KEY, BTN_LEFT, INPUT_PROP_MAX, INPUT_PROP_BUTTONPAD, -1); libevdev_uinput_write_event(uinput, EV_REL, REL_X, -1); libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0); .. libevdev_uinput_destroy(uinput); Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- test/litest-bcm5974.c | 43 +++- test/litest-generic-highres-touch.c | 34 +++--- test/litest-synaptics-st.c | 37 +++ test/litest-synaptics.c | 43 +++- test/litest-trackpoint.c| 32 +++--- test/litest-wacom-touch.c | 33 ++ test/litest.c | 89 test/litest.h | 9 ++ test/path.c | 207 9 files changed, 244 insertions(+), 283 deletions(-) diff --git a/test/litest-bcm5974.c b/test/litest-bcm5974.c index 5a8ce8a..c76a892 100644 --- a/test/litest-bcm5974.c +++ b/test/litest-bcm5974.c @@ -95,7 +95,6 @@ static struct litest_device_interface interface = { void litest_create_bcm5974(struct litest_device *d) { - struct libevdev *dev; struct input_absinfo abs[] = { { ABS_X, 1472, 5472, 75 }, { ABS_Y, 1408, 4448, 129 }, @@ -107,34 +106,24 @@ litest_create_bcm5974(struct litest_device *d) { ABS_MT_TRACKING_ID, 0, 65535, 0 }, { ABS_MT_PRESSURE, 0, 255, 0 } }; - struct input_absinfo *a; - int rc; + struct input_id id = { + .bustype = 0x3, + .vendor = 0x5ac, + .product = 0x249, + }; d-interface = interface; - - dev = libevdev_new(); - ck_assert(dev != NULL); - - libevdev_set_name(dev, bcm5974); - libevdev_set_id_bustype(dev, 0x3); - libevdev_set_id_vendor(dev, 0x5ac); - libevdev_set_id_product(dev, 0x249); - libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL); - libevdev_enable_event_code(dev, EV_KEY, BTN_TOOL_FINGER, NULL); - libevdev_enable_event_code(dev, EV_KEY, BTN_TOOL_QUINTTAP, NULL); - libevdev_enable_event_code(dev, EV_KEY, BTN_TOUCH, NULL); - libevdev_enable_event_code(dev, EV_KEY, BTN_TOOL_DOUBLETAP, NULL); - libevdev_enable_event_code(dev, EV_KEY, BTN_TOOL_TRIPLETAP, NULL); - libevdev_enable_event_code(dev, EV_KEY, BTN_TOOL_QUADTAP, NULL); - - ARRAY_FOR_EACH(abs, a) - libevdev_enable_event_code(dev, EV_ABS, a-value, a); - - rc = libevdev_uinput_create_from_device(dev, - LIBEVDEV_UINPUT_OPEN_MANAGED, - d-uinput); - ck_assert_int_eq(rc, 0); - libevdev_free(dev); + d-uinput = litest_create_uinput_abs_device(bcm5974, id, + ARRAY_LENGTH(abs), + abs, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_TOOL_FINGER, + EV_KEY, BTN_TOOL_QUINTTAP, + EV_KEY, BTN_TOUCH, + EV_KEY, BTN_TOOL_DOUBLETAP, + EV_KEY, BTN_TOOL_TRIPLETAP, + EV_KEY, BTN_TOOL_QUADTAP, + -1, -1); } struct litest_test_device litest_bcm5974_device = { diff --git a/test/litest-generic-highres-touch.c b/test/litest-generic-highres-touch.c index 68615c3..0d239fd 100644 --- a/test/litest-generic-highres-touch.c +++ b/test/litest-generic-highres-touch.c @@ -94,9 +94,6 @@ static struct litest_device_interface interface = { void litest_create_generic_highres_touch(struct litest_device *d) { - struct libevdev *dev; - int rc; - struct input_absinfo *a; struct input_absinfo abs[] = { { ABS_X, 0, 32767, 75 }, { ABS_Y, 0, 32767, 129 }, @@ -105,27 +102,20 @@ litest_create_generic_highres_touch
Re: [RFC] libinput configuration interface
On Thu, Mar 27, 2014 at 07:34:37PM +0600, Alexander E. Patrakov wrote: 2014-03-27 19:22 GMT+06:00 Alexander E. Patrakov patra...@gmail.com: (regarding slow scrolling) I don't think so. I have tried to reproduce the bug by hand. It still exists, but ./tools/event-debug still picks the scrolling up correctly. I guess that this tool output already has the finger motion averaging logic applied, so this speaks against your hypothesis. An interesting observation that can ring some bells: Chromium picks up the scroll events if and only if event-debug prints values whose absolute value is greater than 10. Maybe the driver fails to combine several small scroll events into a big one, or rounds the individual scroll amounts instead of the accumulated value? I have also tested regular (X/Y) pointer motion, and noticed the same pattern. event-debug properly reports sub-pixel motion (i.e. prints values below 1.0 if I move the finger slowly), but such multiple sub-pixel motions are never added up into proper pointer events that actually move the X pointer by at least one pixel. yeah, I found that yesterday and it's a xf86-input-libinput issue. Conversion to integers would just drop small values. I've pushed a fix to use valuator masks with doubles now and that seems to fix the issue. Try 1ab6637b56272bb5cef0568a785e2e5948e6b022. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 2/9] Fix up ARRAY_FOR_EACH macro
Remove compiler warning about signed/unsigned comparison. And while we're at it, rename i to _i in the macro to avoid name clashes. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/libinput-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libinput-util.h b/src/libinput-util.h index 2fbce72..c920568 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -71,7 +71,7 @@ int list_empty(const struct list *list); #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) #define ARRAY_FOR_EACH(_arr, _elem) \ - for (int i = 0; (_elem = _arr[i]) i ARRAY_LENGTH(_arr); i++) + for (size_t _i = 0; (_elem = _arr[_i]) _i ARRAY_LENGTH(_arr); _i++) #define min(a, b) (((a) (b)) ? (a) : (b)) #define max(a, b) (((a) (b)) ? (a) : (b)) -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 5/9] test: disable parallel build in test directory
We depend on device creation on the host system, having the tests run in parallel runs a risk of random failure. Ideally we'd just disable for the actual run target, but I couldn't figure out how to do that. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- test/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/Makefile.am b/test/Makefile.am index b59d4a9..9b71511 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,4 +1,6 @@ if BUILD_TESTS +# Disable parallel build, running tests in parallel will screw things up +AM_MAKEFLAGS = -j1 AM_CPPFLAGS = -I$(top_srcdir)/src $(CHECK_CFLAGS) $(LIBEVDEV_CFLAGS) TEST_LIBS = liblitest.la $(CHECK_LIBS) $(LIBUDEV_LIBS) $(LIBEVDEV_LIBS) $(top_builddir)/src/libinput.la -lm -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 9/9] Add libinput_device_get_name() to advertise the kernel name
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- I didn't end up needing this but it seems a nice to have. However, it does lead to a discussion on how much of the device should we expose to the caller through libinput. Right now libinput hides virtually everthing but the sysname and even that may not be enough to even get a udev reference. It is enough for now though because we only handle one subsystem. If a caller needs settings or get other information on the device, they need to be able to query udev or the fd, but the latter then needs needs open_restricted-like hooks. src/libinput.c | 6 ++ src/libinput.h | 12 tools/event-debug.c | 5 +++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/libinput.c b/src/libinput.c index 1e31be3..2863f1d 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1043,6 +1043,12 @@ libinput_device_get_user_data(struct libinput_device *device) } LIBINPUT_EXPORT const char * +libinput_device_get_name(struct libinput_device *device) +{ + return ((struct evdev_device *) device)-devname; +} + +LIBINPUT_EXPORT const char * libinput_device_get_sysname(struct libinput_device *device) { return evdev_device_get_sysname((struct evdev_device *) device); diff --git a/src/libinput.h b/src/libinput.h index 6e43181..f291ce8 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1158,6 +1158,18 @@ libinput_device_get_user_data(struct libinput_device *device); /** * @ingroup device * + * Get the name of the device. + * + * @param device A previously obtained device + * @return The product name of the device + * + */ +const char* +libinput_device_get_name(struct libinput_device *device); + +/** + * @ingroup device + * * Get the system name of the device. * * @param device A previously obtained device diff --git a/tools/event-debug.c b/tools/event-debug.c index c0a08a7..3d0a383 100644 --- a/tools/event-debug.c +++ b/tools/event-debug.c @@ -231,9 +231,10 @@ print_device_notify(struct libinput_event *ev) struct libinput_device *dev = libinput_event_get_device(ev); struct libinput_seat *seat = libinput_device_get_seat(dev); - printf(%s %s\n, + printf(%s %s %s\n, libinput_seat_get_physical_name(seat), - libinput_seat_get_logical_name(seat)); + libinput_seat_get_logical_name(seat), + libinput_device_get_name(dev)); } static void -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 3/9] tools: add --verbose to event-debug
And redirect the log to stdout. libinput logs to stderr by default, but if we're running with --verbose we want all msgs on the same stream. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- tools/event-debug.c | 20 +++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tools/event-debug.c b/tools/event-debug.c index 12a2df8..c0a08a7 100644 --- a/tools/event-debug.c +++ b/tools/event-debug.c @@ -46,11 +46,13 @@ static struct udev *udev; uint32_t start_time; static const uint32_t screen_width = 100; static const uint32_t screen_height = 100; +static int verbose = 0; static void usage(void) { - printf(Usage: %s [--udev [seat]|--device /dev/input/event0]\n + printf(Usage: %s [--verbose] [--udev [seat]|--device /dev/input/event0]\n + --verbose ... Print debugging output.\n --udev seat Use udev device discovery (default).\n Specifying a seat ID is optional.\n --device /path/to/device open the given device only\n, @@ -67,6 +69,7 @@ parse_args(int argc, char **argv) { device, 1, 0, 'd' }, { udev, 0, 0, 'u' }, { help, 0, 0, 'h' }, + { verbose, 0, 0, 'v'}, { 0, 0, 0, 0} }; @@ -91,6 +94,9 @@ parse_args(int argc, char **argv) if (optarg) seat = optarg; break; + case 'v': /* --verbose */ + verbose = 1; + break; default: usage(); return 1; @@ -430,6 +436,13 @@ mainloop(struct libinput *li) close(fds[1].fd); } +static void log_handler(enum libinput_log_priority priority, + void *user_data, + const char *format, va_list args) +{ + vprintf(format, args); +} + int main(int argc, char **argv) { @@ -439,6 +452,11 @@ main(int argc, char **argv) if (parse_args(argc, argv)) return 1; + if (verbose) { + libinput_log_set_handler(log_handler, NULL); + libinput_log_set_priority(LIBINPUT_LOG_PRIORITY_DEBUG); + } + if (mode == MODE_UDEV) { if (open_udev(li)) return 1; -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 1/9] Use log_error instead of fprintf in old touchpad code
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-touchpad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evdev-touchpad.c b/src/evdev-touchpad.c index 65c5ea0..1a48441 100644 --- a/src/evdev-touchpad.c +++ b/src/evdev-touchpad.c @@ -454,7 +454,7 @@ fsm_timeout_handler(void *data) /* This will only happen if the application made the fd * non-blocking, but this function should only be called * upon the timeout, so lets continue anyway. */ - fprintf(stderr, timerfd read error: %m\n); + log_error(timerfd read error: %m\n); if (touchpad-fsm.events_count == 0) { clock_gettime(CLOCK_MONOTONIC, ts); -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 8/9] test: add tests for event conversion and back
Looks a bit excessive given how simple the base is but hey, we don't want to ever break that bit. That'd be embarrassing. And while we're at it make sure that the 'wrong' event getters return NULL for each event. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- This requires the uinput device creation patch I sent out yesterday. test/Makefile.am | 7 +- test/misc.c | 377 +++ 2 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 test/misc.c diff --git a/test/Makefile.am b/test/Makefile.am index adb58e9..44afc95 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -20,7 +20,7 @@ liblitest_la_SOURCES = \ litest-generic-highres-touch.c \ litest.c -run_tests = test-udev test-path test-pointer test-touch test-log test-touchpad +run_tests = test-udev test-path test-pointer test-touch test-log test-touchpad test-misc build_tests = test-build-linker test-build-pedantic-c99 test-build-std-gnuc90 noinst_PROGRAMS = $(build_tests) $(run_tests) @@ -56,6 +56,11 @@ test_touchpad_CFLAGS = $(AM_CPPFLAGS) test_touchpad_LDADD = $(TEST_LIBS) test_touchpad_LDFLAGS = -static +test_misc_SOURCES = misc.c +test_misc_CFLAGS = $(AM_CPPFLAGS) +test_misc_LDADD = $(TEST_LIBS) +test_misc_LDFLAGS = -static + # build-test only test_build_pedantic_c99_SOURCES = build-pedantic.c test_build_pedantic_c99_CFLAGS = $(AM_CPPFLAGS) -std=c99 -pedantic -Werror diff --git a/test/misc.c b/test/misc.c new file mode 100644 index 000..5bf9477 --- /dev/null +++ b/test/misc.c @@ -0,0 +1,377 @@ +/* + * 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 check.h +#include errno.h +#include fcntl.h +#include libinput.h +#include unistd.h + +#include litest.h + +static int open_restricted(const char *path, int flags, void *data) +{ + int fd = open(path, flags); + return fd 0 ? -errno : fd; +} +static void close_restricted(int fd, void *data) +{ + close(fd); +} + +const struct libinput_interface simple_interface = { + .open_restricted = open_restricted, + .close_restricted = close_restricted, +}; + +static struct libevdev_uinput * +create_simple_test_device(const char *name, ...) +{ + va_list args; + struct libevdev_uinput *uinput; + struct libevdev *evdev; + unsigned int type, code; + int rc; + struct input_absinfo abs = { + .value = -1, + .minimum = 0, + .maximum = 100, + .fuzz = 0, + .flat = 0, + .resolution = 100, + }; + + evdev = libevdev_new(); + ck_assert(evdev != NULL); + libevdev_set_name(evdev, name); + + va_start(args, name); + + while ((type = va_arg(args, unsigned int)) != -1 + (code = va_arg(args, unsigned int)) != -1) { + const struct input_absinfo *a = NULL; + if (type == EV_ABS) + a = abs; + libevdev_enable_event_code(evdev, type, code, a); + } + + va_end(args); + + rc = libevdev_uinput_create_from_device(evdev, + LIBEVDEV_UINPUT_OPEN_MANAGED, + uinput); + ck_assert_int_eq(rc, 0); + libevdev_free(evdev); + + return uinput; +} + +START_TEST(event_conversion_device_notify) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_event *event; + int device_added = 0, device_removed = 0; + + uinput = create_simple_test_device(test device, + EV_REL, REL_X, + EV_REL, REL_Y, + EV_KEY, BTN_LEFT
Re: SynPS/2 Synaptics TouchPad firmware bug
On Thu, Mar 27, 2014 at 10:19:50PM +0600, Alexander E. Patrakov wrote: Hello. This is a report of a touchpad firmware bug that I want you to work around in libinput. I found this bug while testing xf86-input-libinput. I guess that the synaptics driver already has a workaround, or the bug does not manifest itself with the following options: Option SoftButtonAreas 4360 0 4000 0 2880 4359 3500 0 Option AreaBottomEdge 3500 Option VertTwoFingerScroll true Option HorizTwoFingerScroll true Option MinSpeed 1 Option MaxSpeed 10 Option FingerLow 60 Option FingerHigh 70 (indeed, FingerLow would have prevented this bug for the attached trace). for the xorg driver this is correct, for libinput it's a bit different. it largely depends on whether we want the pressure to filter events, or to filter completely. I haven't done anything in that direction yet at all though. To reproduce the bug, get the affected touchpad, move the cursor as you would normally do using a finger on the right hand, then use the finger on the left hand to click in the bottom area of the touchpad. Usually the driver would register the click as expected, but sometimes it would move the pointer to the lower left corner and click there. I have managed to capture one of these cases using evemu-record. The compressed file is attached. Please ignore the first 240 seconds or so, they contain some movements, scrolling and clicks. The interesting part is: E: 249.206319 # SYN_REPORT (0) -- E: 249.218008 0003 0035 3764# EV_ABS / ABS_MT_POSITION_X3764 E: 249.218008 0003 0036 2221# EV_ABS / ABS_MT_POSITION_Y2221 E: 249.218008 0003 003a 0065# EV_ABS / ABS_MT_PRESSURE 65 E: 249.218008 0003 3764# EV_ABS / ABS_X3764 E: 249.218008 0003 0001 2216# EV_ABS / ABS_Y2216 E: 249.218008 0003 0018 0065# EV_ABS / ABS_PRESSURE 65 E: 249.218008 # SYN_REPORT (0) -- E: 249.230881 0003 0035 3752# EV_ABS / ABS_MT_POSITION_X3752 E: 249.230881 0003 003a 0046# EV_ABS / ABS_MT_PRESSURE 46 E: 249.230881 0003 3758# EV_ABS / ABS_X3758 E: 249.230881 0003 0018 0046# EV_ABS / ABS_PRESSURE 46 E: 249.230881 # SYN_REPORT (0) -- E: 249.242648 0003 0035 1640# EV_ABS / ABS_MT_POSITION_X1640 E: 249.242648 0003 0036 4681# EV_ABS / ABS_MT_POSITION_Y4681 E: 249.242648 0003 003a 0025# EV_ABS / ABS_MT_PRESSURE 25 E: 249.242648 0003 1640# EV_ABS / ABS_X1640 E: 249.242648 0003 0001 4681# EV_ABS / ABS_Y4681 E: 249.242648 0003 0018 0025# EV_ABS / ABS_PRESSURE 25 E: 249.242648 # SYN_REPORT (0) -- E: 249.254568 0003 0035 1648# EV_ABS / ABS_MT_POSITION_X1648 E: 249.254568 0003 003a 0027# EV_ABS / ABS_MT_PRESSURE 27 E: 249.254568 0003 1644# EV_ABS / ABS_X1644 E: 249.254568 0003 0018 0027# EV_ABS / ABS_PRESSURE 27 As you see, the touchpad reports a huge jump in the touch position without getting a new tracking ID. I.e. produces garbage data. A non-buggy touchpad would have recognized that this is in fact a different finger. So, I would like libinput to recognize such huge jumps (e.g. any movements by more than 15% of the touchpad width in less than 0.03 seconds) as firmware bugs and treat them as if this indicated a completely new touch. please file this in bugzilla, this really is something that we need to keep in one place because it'll likely have a rather complex solution that I'd like to be able to link to. having said that, I'm currently struggling with getting libinput up to feature parity with the xorg drivers, hacking around broken devices will have to wait a bit, sorry. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 6/9] doc: add state machine SVG to EXTRA_DIST
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- doc/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index 31b673b..75fa98a 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,3 +1,5 @@ +EXTRA_DIST = touchpad-tap-state-machine.svg + if HAVE_DOXYGEN noinst_DATA = html/index.html @@ -12,7 +14,7 @@ clean-local: $(AM_V_at)rm -rf html doc_src= $(shell find html -type f -printf html/%P\n 2/dev/null) -EXTRA_DIST = $(builddir)/html/index.html $(doc_src) +EXTRA_DIST += $(builddir)/html/index.html $(doc_src) endif -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 8/9] touchpad: Only enable clickfingers on Apple touchpads
Apple touchpads don't have visible markings for the software button areas that almost all other vendors use. OS X provides clickfinger behaviour instead, where a click with two fingers on the touchpad generate a right button click. Use that same behaviour in libinput. For all other touchpads, use the software button areas introduced in a follow-up commit. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- This should probably be configurable at some point in the future... src/evdev-mt-touchpad-buttons.c | 7 ++- src/evdev-mt-touchpad.h | 1 + test/touchpad.c | 12 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index c3c97b0..08783a3 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -60,6 +60,11 @@ tp_init_buttons(struct tp_dispatch *tp, tp-buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD; + if (libevdev_get_id_vendor(device-evdev) == 0x5ac) /* Apple */ + tp-buttons.use_clickfinger = true; + else + tp-buttons.use_clickfinger = false; + return 0; } @@ -142,7 +147,7 @@ tp_post_button_events(struct tp_dispatch *tp, uint32_t time) if (tp-buttons.has_buttons) rc = tp_post_physical_buttons(tp, time); - else + else if (tp-buttons.use_clickfinger) rc = tp_post_clickfinger_buttons(tp, time); return rc; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 1dee663..f3e5b31 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -135,6 +135,7 @@ struct tp_dispatch { struct { bool has_buttons; /* true for physical LMR buttons */ + bool use_clickfinger; /* number of fingers decides button number */ uint32_t state; uint32_t old_state; uint32_t motion_dist; /* for pinned touches */ diff --git a/test/touchpad.c b/test/touchpad.c index f4d7839..bbae6cd 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -217,7 +217,7 @@ END_TEST START_TEST(touchpad_1fg_clickfinger) { - struct litest_device *dev = litest_current_device(); + struct litest_device *dev = litest_create_device(LITEST_BCM5974); struct libinput *li = dev-libinput; struct libinput_event *event; struct libinput_event_pointer *ptrev; @@ -237,12 +237,14 @@ START_TEST(touchpad_1fg_clickfinger) LIBINPUT_POINTER_BUTTON_STATE_PRESSED); assert_button_event(li, BTN_LEFT, LIBINPUT_POINTER_BUTTON_STATE_RELEASED); + + litest_delete_device(dev); } END_TEST START_TEST(touchpad_2fg_clickfinger) { - struct litest_device *dev = litest_current_device(); + struct litest_device *dev = litest_create_device(LITEST_BCM5974); struct libinput *li = dev-libinput; struct libinput_event *event; struct libinput_event_pointer *ptrev; @@ -264,6 +266,8 @@ START_TEST(touchpad_2fg_clickfinger) LIBINPUT_POINTER_BUTTON_STATE_PRESSED); assert_button_event(li, BTN_RIGHT, LIBINPUT_POINTER_BUTTON_STATE_RELEASED); + + litest_delete_device(dev); } END_TEST @@ -362,8 +366,8 @@ int main(int argc, char **argv) { litest_add(touchpad:tap, touchpad_1fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_ANY); litest_add(touchpad:tap, touchpad_2fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add(touchpad:clickfinger, touchpad_1fg_clickfinger, LITEST_TOUCHPAD, LITEST_ANY); - litest_add(touchpad:clickfinger, touchpad_2fg_clickfinger, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add_no_device(touchpad:clickfinger, touchpad_1fg_clickfinger); + litest_add_no_device(touchpad:clickfinger, touchpad_2fg_clickfinger); litest_add(touchpad:click, touchpad_btn_left, LITEST_TOUCHPAD, LITEST_CLICKPAD); litest_add(touchpad:click, clickpad_btn_left, LITEST_CLICKPAD, LITEST_ANY); -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 7/9] touchpad: save the active clickfinger button
To avoid having a button left press and a button right release if the number of fingers changes. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad-buttons.c | 22 +- src/evdev-mt-touchpad.h | 1 + 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 8946fc7..c3c97b0 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -75,23 +75,27 @@ tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint32_t time) if (current == old) return 0; - switch (tp-nfingers_down) { + if (current) { + switch (tp-nfingers_down) { case 1: button = BTN_LEFT; break; case 2: button = BTN_RIGHT; break; case 3: button = BTN_MIDDLE; break; default: return 0; - } - - if (current) + } + tp-buttons.active = button; state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; - else + } else { + button = tp-buttons.active; + tp-buttons.active = 0; state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; + } - pointer_notify_button(tp-device-base, - time, - button, - state); + if (button) + pointer_notify_button(tp-device-base, + time, + button, + state); return 1; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 0879776..1dee663 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -138,6 +138,7 @@ struct tp_dispatch { uint32_t state; uint32_t old_state; uint32_t motion_dist; /* for pinned touches */ + unsigned int active;/* currently active button, for release event */ } buttons; /* physical buttons */ struct { -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 4/9] touchpad: don't allow tapping while any button is down
Immediately set the state to DEAD, waiting for the tap release to go back to idle. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad-tap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index bcc5700..863e004 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -508,7 +508,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint32_t time) struct tp_touch *t; int filter_motion = 0; - if (tp-queued TOUCHPAD_EVENT_BUTTON_PRESS) + if (tp-buttons.state != 0) tp_tap_handle_event(tp, TAP_EVENT_BUTTON, time); tp_for_each_touch(tp, t) { -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 2/9] touchpad: after a click, lock the finger to its current position
On clickpads, releasing the button usually causes some motion events. To avoid erroneous movements, lock the finger into position on the up event and don't allow for motion events until we move past a given threshold (currently 2% of the touchpad diagonal). Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad.c | 70 + src/evdev-mt-touchpad.h | 18 - 2 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 8021db2..5318b8f 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -32,6 +32,7 @@ #define DEFAULT_MIN_ACCEL_FACTOR 0.16 #define DEFAULT_MAX_ACCEL_FACTOR 1.0 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0 +#define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* in percent of size */ static inline int tp_hysteresis(int in, int center, int margin) @@ -346,16 +347,36 @@ tp_process_key(struct tp_dispatch *tp, } static void -tp_unpin_finger(struct tp_dispatch *tp) +tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t) +{ + unsigned int xdist, ydist; + + if (t-pinned.state != PIN_STATE_UP) + return; + + xdist = abs(t-x - t-pinned.center_x); + ydist = abs(t-y - t-pinned.center_y); + + if (xdist * xdist + ydist * ydist + tp-buttons.motion_dist * tp-buttons.motion_dist) + return; + + t-pinned.state = PIN_STATE_NONE; + + if (t-state != TOUCH_END tp-nfingers_down == 1) + t-is_pointer = true; +} + +static void +tp_lift_pinned_finger(struct tp_dispatch *tp) { struct tp_touch *t; + tp_for_each_touch(tp, t) { - if (t-is_pinned) { - t-is_pinned = false; - - if (t-state != TOUCH_END - tp-nfingers_down == 1) - t-is_pointer = true; + if (t-pinned.state == PIN_STATE_DOWN) { + t-pinned.state = PIN_STATE_UP; + t-pinned.center_x = t-x; + t-pinned.center_y = t-y; break; } } @@ -368,15 +389,14 @@ tp_pin_finger(struct tp_dispatch *tp) *pinned = NULL; tp_for_each_touch(tp, t) { - if (t-is_pinned) { + if (t-pinned.state != PIN_STATE_NONE) { pinned = t; break; } } - assert(!pinned); - - pinned = tp_current_touch(tp); + if (!pinned) + pinned = tp_current_touch(tp); if (tp-nfingers_down != 1) { tp_for_each_touch(tp, t) { @@ -388,7 +408,7 @@ tp_pin_finger(struct tp_dispatch *tp) } } - pinned-is_pinned = true; + pinned-pinned.state = PIN_STATE_DOWN; pinned-is_pointer = false; } @@ -409,16 +429,21 @@ tp_process_state(struct tp_dispatch *tp, uint32_t time) tp_motion_hysteresis(tp, t); tp_motion_history_push(t); + + tp_unpin_finger(tp, t); } - /* We have a physical button down event on a clickpad. For drag and - drop, this means we try to identify which finger pressed the - physical button and pin it, i.e. remove pointer-moving - capabilities from it. -*/ - if ((tp-queued TOUCHPAD_EVENT_BUTTON_PRESS) - !tp-buttons.has_buttons) - tp_pin_finger(tp); + if (!tp-buttons.has_buttons) { + /* We have a physical button down event on a clickpad. For drag and + drop, this means we try to identify which finger pressed the + physical button and pin it, i.e. remove pointer-moving + capabilities from it. +*/ + if (tp-queued TOUCHPAD_EVENT_BUTTON_PRESS) + tp_pin_finger(tp); + else if ((tp-queued TOUCHPAD_EVENT_BUTTON_RELEASE)) + tp_lift_pinned_finger(tp); + } } static void @@ -441,9 +466,6 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time) tp-buttons.old_state = tp-buttons.state; - if (tp-queued TOUCHPAD_EVENT_BUTTON_RELEASE) - tp_unpin_finger(tp); - tp-queued = TOUCHPAD_EVENT_NONE; } @@ -796,6 +818,8 @@ tp_init(struct tp_dispatch *tp, tp-hysteresis.margin_y = diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; + tp-buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD; + if (libevdev_has_event_code(device-evdev, EV_KEY, BTN_MIDDLE) || libevdev_has_event_code(device-evdev, EV_KEY, BTN_RIGHT)) tp-buttons.has_buttons = true; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 2bdb329..51e7702 100644 --- a/src/evdev-mt-touchpad.h
[PATCH libinput 3/9] touchpad: reset the tap timer_fd to -1 on destroy
No real effect, just for safety Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/evdev-mt-touchpad-tap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 5fa712f..bcc5700 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -615,6 +615,8 @@ tp_destroy_tap(struct tp_dispatch *tp) libinput_remove_source(tp-device-base.seat-libinput, tp-tap.source); tp-tap.source = NULL; } - if (tp-tap.timer_fd -1) + if (tp-tap.timer_fd -1) { close(tp-tap.timer_fd); + tp-tap.timer_fd = -1; + } } -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: SynPS/2 Synaptics TouchPad firmware bug
On 29/03/2014 04:54 , Alexander E. Patrakov wrote: 2014-03-29 0:16 GMT+06:00 Alexander E. Patrakov patra...@gmail.com: No problem, I just did that for you. See the attached patch. Seems to work here, but I am not 100% sure, especially about the non-mt case. It does prevent sudden pointer jumps to the bottom left corner of the screen (survived a while round of the Harvest Honors game, something that the original driver cound not do!), but I also get some click attempts mistreated as right-clicks. Probably because there are in fact some moments when the touchpad thinks that two fingers are on it. And now rebased on top of your wip/clickpad-improvements branch (which works otherwise). Note that now I can get a right-click both using a software button area and using a two-finger tap. Is this intentional? yes, tapping and software button areas are independent of each other and are enabled at the same time. clickfinger and software buttons are mutually exclusive (and the former is only enabled on apple touchpads anyway). Other than that anytime a click isn't what you expect it to be is likely a bug. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [libinput] AC_PROG_CXX missing in libinput/configure.ac
On Sat, Mar 29, 2014 at 07:12:59PM +0100, Sylvain BERTRAND wrote: On Sat, Mar 29, 2014 at 06:59:12PM +0100, Jonas Ådahl wrote: Yes, for now at least. Sad. But till there is no crazy code generator, it should be easy to write a makefile/shell script to by-pass the autotools and build the lib. note that the only binary that needs a C++ compiler is the C++ build test. the library itself only needs a C compiler. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 2/5] test: if no teardown func is set, use the default
Reduces the amount of boilerplate code. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- test/litest-bcm5974.c | 2 +- test/litest-generic-highres-touch.c | 2 +- test/litest-keyboard.c | 2 +- test/litest-mouse.c | 2 +- test/litest-synaptics-st.c | 2 +- test/litest-trackpoint.c| 2 +- test/litest-wacom-touch.c | 2 +- test/litest.c | 3 ++- 8 files changed, 9 insertions(+), 8 deletions(-) diff --git a/test/litest-bcm5974.c b/test/litest-bcm5974.c index 6b7a22b..ff822f9 100644 --- a/test/litest-bcm5974.c +++ b/test/litest-bcm5974.c @@ -131,6 +131,6 @@ struct litest_test_device litest_bcm5974_device = { .features = LITEST_TOUCHPAD | LITEST_CLICKPAD | LITEST_BUTTON, .shortname = bcm5974, .setup = litest_bcm5974_setup, - .teardown = litest_generic_device_teardown, + .teardown = NULL, .create = litest_create_bcm5974, }; diff --git a/test/litest-generic-highres-touch.c b/test/litest-generic-highres-touch.c index bb226d6..4d21b0d 100644 --- a/test/litest-generic-highres-touch.c +++ b/test/litest-generic-highres-touch.c @@ -123,6 +123,6 @@ struct litest_test_device litest_generic_highres_touch_device = { .features = LITEST_TOUCH, .shortname = generic-highres-touch, .setup = litest_generic_highres_touch_setup, - .teardown = litest_generic_device_teardown, + .teardown = NULL, .create = litest_create_generic_highres_touch, }; diff --git a/test/litest-keyboard.c b/test/litest-keyboard.c index dd91158..ab05014 100644 --- a/test/litest-keyboard.c +++ b/test/litest-keyboard.c @@ -109,6 +109,6 @@ struct litest_test_device litest_keyboard_device = { .features = LITEST_KEYS, .shortname = default keyboard, .setup = litest_keyboard_setup, - .teardown = litest_generic_device_teardown, + .teardown = NULL, .create = litest_create_keyboard, }; diff --git a/test/litest-mouse.c b/test/litest-mouse.c index 2fde095..2f70767 100644 --- a/test/litest-mouse.c +++ b/test/litest-mouse.c @@ -70,6 +70,6 @@ struct litest_test_device litest_mouse_device = { .features = LITEST_POINTER | LITEST_BUTTON | LITEST_WHEEL, .shortname = mouse, .setup = litest_mouse_setup, - .teardown = litest_generic_device_teardown, + .teardown = NULL, .create = litest_create_mouse, }; diff --git a/test/litest-synaptics-st.c b/test/litest-synaptics-st.c index d13d9a2..de56c22 100644 --- a/test/litest-synaptics-st.c +++ b/test/litest-synaptics-st.c @@ -126,6 +126,6 @@ struct litest_test_device litest_synaptics_touchpad_device = { .features = LITEST_TOUCHPAD | LITEST_BUTTON | LITEST_SINGLE_TOUCH, .shortname = synaptics ST, .setup = litest_synaptics_touchpad_setup, - .teardown = litest_generic_device_teardown, + .teardown = NULL, .create = litest_create_synaptics_touchpad, }; diff --git a/test/litest-trackpoint.c b/test/litest-trackpoint.c index e0b79c5..1c0fb0a 100644 --- a/test/litest-trackpoint.c +++ b/test/litest-trackpoint.c @@ -61,6 +61,6 @@ struct litest_test_device litest_trackpoint_device = { .features = LITEST_POINTER | LITEST_BUTTON, .shortname = trackpoint, .setup = litest_trackpoint_setup, - .teardown = litest_generic_device_teardown, + .teardown = NULL, .create = litest_create_trackpoint, }; diff --git a/test/litest-wacom-touch.c b/test/litest-wacom-touch.c index 01a5a5d..e9119a9 100644 --- a/test/litest-wacom-touch.c +++ b/test/litest-wacom-touch.c @@ -122,6 +122,6 @@ struct litest_test_device litest_wacom_touch_device = { .features = LITEST_TOUCH, .shortname = wacom-touch, .setup = litest_wacom_touch_setup, - .teardown = litest_generic_device_teardown, + .teardown = NULL, .create = litest_create_wacom_touch, }; diff --git a/test/litest.c b/test/litest.c index f7fe24e..6767952 100644 --- a/test/litest.c +++ b/test/litest.c @@ -119,7 +119,8 @@ litest_add_tcase_for_device(struct suite *suite, t-name = strdup(test_name); t-tc = tcase_create(test_name); list_insert(suite-tests, t-node); - tcase_add_checked_fixture(t-tc, dev-setup, dev-teardown); + tcase_add_checked_fixture(t-tc, dev-setup, + dev-teardown ? dev-teardown : litest_generic_device_teardown); tcase_add_test(t-tc, func); suite_add_tcase(suite-suite, t-tc); } -- 1.9.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput 5/5] test: switch the remaining devices to a description-based device
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- test/litest-bcm5974.c | 147 ++- test/litest-generic-highres-touch.c | 128 test/litest-keyboard.c | 231 +--- test/litest-mouse.c | 48 test/litest-synaptics-st.c | 131 test/litest-trackpoint.c| 39 +++--- test/litest-wacom-touch.c | 127 7 files changed, 419 insertions(+), 432 deletions(-) diff --git a/test/litest-bcm5974.c b/test/litest-bcm5974.c index ff822f9..ab944a7 100644 --- a/test/litest-bcm5974.c +++ b/test/litest-bcm5974.c @@ -34,97 +34,66 @@ static void litest_bcm5974_setup(void) litest_set_current_device(d); } -static void -litest_bcm5974_touch_down(struct litest_device *d, - unsigned int slot, - int x, int y) -{ - static int tracking_id; - struct input_event *ev; - struct input_event down[] = { - { .type = EV_KEY, .code = BTN_TOOL_FINGER, .value = 1 }, - { .type = EV_KEY, .code = BTN_TOUCH, .value = 1 }, - { .type = EV_ABS, .code = ABS_X, .value = x }, - { .type = EV_ABS, .code = ABS_Y, .value = y }, - { .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 }, - { .type = EV_ABS, .code = ABS_MT_SLOT, .value = slot }, - { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = ++tracking_id }, - { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = x }, - { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = y }, - { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, - }; +struct input_event down[] = { + { .type = EV_KEY, .code = BTN_TOOL_FINGER, .value = 1 }, + { .type = EV_KEY, .code = BTN_TOUCH, .value = 1 }, + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 }, + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; - down[2].value = litest_scale(d, ABS_X, x); - down[3].value = litest_scale(d, ABS_Y, y); - down[7].value = litest_scale(d, ABS_X, x); - down[8].value = litest_scale(d, ABS_Y, y); - - ARRAY_FOR_EACH(down, ev) - litest_event(d, ev-type, ev-code, ev-value); -} - -void -litest_bcm5974_move(struct litest_device *d, unsigned int slot, int x, int y) -{ - struct input_event *ev; - struct input_event move[] = { - { .type = EV_ABS, .code = ABS_MT_SLOT, .value = slot }, - { .type = EV_ABS, .code = ABS_X, .value = x }, - { .type = EV_ABS, .code = ABS_Y, .value = y }, - { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = x }, - { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = y }, - { .type = EV_KEY, .code = BTN_TOOL_FINGER, .value = 1 }, - { .type = EV_KEY, .code = BTN_TOUCH, .value = 1 }, - { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, - }; - - move[1].value = litest_scale(d, ABS_X, x); - move[2].value = litest_scale(d, ABS_Y, y); - move[3].value = litest_scale(d, ABS_X, x); - move[4].value = litest_scale(d, ABS_Y, y); - - ARRAY_FOR_EACH(move, ev) - litest_event(d, ev-type, ev-code, ev-value); -} +static struct input_event move[] = { + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_KEY, .code = BTN_TOOL_FINGER, .value = 1 }, + { .type = EV_KEY, .code = BTN_TOUCH, .value = 1 }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; static struct litest_device_interface interface = { - .touch_down = litest_bcm5974_touch_down, - .touch_move = litest_bcm5974_move, + .touch_down_events = down, + .touch_move_events = move, }; -void -litest_create_bcm5974(struct litest_device *d) -{ - struct input_absinfo abs[] = { - { ABS_X, 1472, 5472, 75 }, - { ABS_Y, 1408, 4448, 129