diff --git a/configure.ac b/configure.ac index 85db1fd6..141f97ac 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_PREREQ([2.64]) m4_define([libinput_major_version], [0]) -m4_define([libinput_minor_version], [12]) +m4_define([libinput_minor_version], [13]) m4_define([libinput_micro_version], [0]) m4_define([libinput_version], [libinput_major_version.libinput_minor_version.libinput_micro_version]) @@ -31,7 +31,7 @@ AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) # b) If interfaces have been changed or added, but binary compatibility has # been preserved, change to C+1:0:A+1 # c) If the interface is the same as the previous version, change to C:R+1:A -LIBINPUT_LT_VERSION=10:0:0 +LIBINPUT_LT_VERSION=10:1:0 AC_SUBST(LIBINPUT_LT_VERSION) AM_SILENT_RULES([yes]) diff --git a/doc/device-configuration-via-udev.dox b/doc/device-configuration-via-udev.dox index 87e92e6e..fc1c0af8 100644 --- a/doc/device-configuration-via-udev.dox +++ b/doc/device-configuration-via-udev.dox @@ -57,11 +57,6 @@ See @ref motion_normalization for details.
The angle in degrees for each click on a mouse wheel. See libinput_pointer_get_axis_source() for details.
-
TOUCHPAD_RESOLUTION
-
The x and y resolution in units/mm for a touchpad. This value is only -used if the touchpad kernel driver does not supply a valid resolution. It -is only used on touchpad devices. The format is two unsigned integer values -separated by a literal 'x', e.g. "42x129".
Below is an example udev rule to assign "seat1" to a device from vendor diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 1650a35a..6282b71e 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -64,21 +64,27 @@ tp_filter_motion(struct tp_dispatch *tp, double *dx_unaccel, double *dy_unaccel, uint64_t time) { - struct motion_params motion; + struct normalized_coords unaccelerated; + struct normalized_coords accelerated; - motion.dx = *dx; - motion.dy = *dy; + unaccelerated.x = *dx; + unaccelerated.y = *dy; + + if (unaccelerated.x != 0.0 || unaccelerated.y != 0.0) + accelerated = filter_dispatch(tp->device->pointer.filter, + &unaccelerated, + tp, + time); + else + accelerated = unaccelerated; if (dx_unaccel) - *dx_unaccel = motion.dx; + *dx_unaccel = unaccelerated.x; if (dy_unaccel) - *dy_unaccel = motion.dy; + *dy_unaccel = unaccelerated.y; - if (motion.dx != 0.0 || motion.dy != 0.0) - filter_dispatch(tp->device->pointer.filter, &motion, tp, time); - - *dx = motion.dx; - *dy = motion.dy; + *dx = accelerated.x; + *dy = accelerated.y; } static inline void @@ -967,22 +973,6 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal) res_x = tp->device->abs.absinfo_x->resolution; res_y = tp->device->abs.absinfo_y->resolution; - /* Mac touchpads seem to all be the same size (except the most - * recent ones) - * http://www.moshi.com/trackpad-protector-trackguard-macbook-pro#silver - */ - if (tp->model == MODEL_UNIBODY_MACBOOK && tp->device->abs.fake_resolution) { - const struct input_absinfo *abs; - int width, height; - - abs = tp->device->abs.absinfo_x; - width = abs->maximum - abs->minimum; - abs = tp->device->abs.absinfo_y; - height = abs->maximum - abs->minimum; - res_x = width/104.4; - res_y = height/75.4; - } - /* * Not all touchpads report the same amount of units/mm (resolution). * Normalize motion events to the default mouse DPI as base @@ -1134,32 +1124,6 @@ tp_init_sendevents(struct tp_dispatch *tp, return 0; } -static void -tp_fix_resolution(struct tp_dispatch *tp, struct evdev_device *device) -{ - struct libinput *libinput = device->base.seat->libinput; - const char *prop; - unsigned int resx, resy; - - prop = udev_device_get_property_value(device->udev_device, - "TOUCHPAD_RESOLUTION"); - if (!prop) - return; - - if (parse_touchpad_resolution_property(prop, &resx, &resy) == -1) { - log_error(libinput, - "Touchpad resolution property set for '%s', but invalid.\n", - device->devname); - return; - } - - if (evdev_fix_abs_resolution(device, - tp->has_mt ? ABS_MT_POSITION_X : ABS_X, - tp->has_mt ? ABS_MT_POSITION_Y : ABS_Y, - resx, resy)) - device->abs.fake_resolution = 0; -} - static int tp_init(struct tp_dispatch *tp, struct evdev_device *device) @@ -1173,8 +1137,6 @@ tp_init(struct tp_dispatch *tp, if (tp_init_slots(tp, device) != 0) return -1; - tp_fix_resolution(tp, device); - width = abs(device->abs.absinfo_x->maximum - device->abs.absinfo_x->minimum); height = abs(device->abs.absinfo_y->maximum - diff --git a/src/evdev.c b/src/evdev.c index c0351983..6a3526a8 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -238,7 +238,6 @@ static void evdev_flush_pending_event(struct evdev_device *device, uint64_t time) { struct libinput *libinput = device->base.seat->libinput; - struct motion_params motion; int slot; int seat_slot; struct libinput_device *base = &device->base; @@ -267,11 +266,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) } /* Apply pointer acceleration. */ - motion.dx = unaccel.x; - motion.dy = unaccel.y; - filter_dispatch(device->pointer.filter, &motion, device, time); - accel.x = motion.dx; - accel.y = motion.dy; + accel = filter_dispatch(device->pointer.filter, &unaccel, device, time); if (accel.x == 0.0 && accel.y == 0.0 && unaccel.x == 0.0 && unaccel.y == 0.0) { @@ -1458,10 +1453,32 @@ evdev_fix_android_mt(struct evdev_device *device) libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y)); } +static inline int +evdev_check_min_max(struct evdev_device *device, unsigned int code) +{ + struct libevdev *evdev = device->evdev; + const struct input_absinfo *absinfo; + + if (!libevdev_has_event_code(evdev, EV_ABS, code)) + return 0; + + absinfo = libevdev_get_abs_info(evdev, code); + if (absinfo->minimum == absinfo->maximum) { + log_bug_kernel(device->base.seat->libinput, + "Device '%s' has min == max on %s\n", + device->devname, + libevdev_event_code_get_name(EV_ABS, code)); + return -1; + } + + return 0; +} + static int evdev_reject_device(struct evdev_device *device) { struct libevdev *evdev = device->evdev; + unsigned int code; if (libevdev_has_event_code(evdev, EV_ABS, ABS_X) ^ libevdev_has_event_code(evdev, EV_ABS, ABS_Y)) @@ -1471,6 +1488,18 @@ evdev_reject_device(struct evdev_device *device) libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y)) return -1; + for (code = 0; code < ABS_CNT; code++) { + switch (code) { + case ABS_MISC: + case ABS_MT_SLOT: + case ABS_MT_TOOL_TYPE: + break; + default: + if (evdev_check_min_max(device, code) == -1) + return -1; + } + } + return 0; } diff --git a/src/filter-private.h b/src/filter-private.h index f0d35b40..0e796f1a 100644 --- a/src/filter-private.h +++ b/src/filter-private.h @@ -28,9 +28,10 @@ #include "filter.h" struct motion_filter_interface { - void (*filter)(struct motion_filter *filter, - struct motion_params *motion, - void *data, uint64_t time); + struct normalized_coords (*filter)( + struct motion_filter *filter, + const struct normalized_coords *unaccelerated, + void *data, uint64_t time); void (*destroy)(struct motion_filter *filter); bool (*set_speed)(struct motion_filter *filter, double speed); diff --git a/src/filter.c b/src/filter.c index 306a2fe6..dc299286 100644 --- a/src/filter.c +++ b/src/filter.c @@ -33,12 +33,12 @@ #include "libinput-util.h" #include "filter-private.h" -void +struct normalized_coords filter_dispatch(struct motion_filter *filter, - struct motion_params *motion, + const struct normalized_coords *unaccelerated, void *data, uint64_t time) { - filter->interface->filter(filter, motion, data, time); + return filter->interface->filter(filter, unaccelerated, data, time); } void @@ -80,8 +80,7 @@ filter_get_speed(struct motion_filter *filter) #define NUM_POINTER_TRACKERS 16 struct pointer_tracker { - double dx; /* delta to most recent event, in device units */ - double dy; /* delta to most recent event, in device units */ + struct normalized_coords delta; /* delta to most recent event */ uint64_t time; /* ms */ int dir; }; @@ -94,8 +93,7 @@ struct pointer_accelerator { double velocity; /* units/ms */ double last_velocity; /* units/ms */ - int last_dx; /* device units */ - int last_dy; /* device units */ + struct normalized_coords last; struct pointer_tracker *trackers; int cur_tracker; @@ -107,24 +105,24 @@ struct pointer_accelerator { static void feed_trackers(struct pointer_accelerator *accel, - double dx, double dy, + const struct normalized_coords *delta, uint64_t time) { int i, current; struct pointer_tracker *trackers = accel->trackers; for (i = 0; i < NUM_POINTER_TRACKERS; i++) { - trackers[i].dx += dx; - trackers[i].dy += dy; + trackers[i].delta.x += delta->x; + trackers[i].delta.y += delta->y; } current = (accel->cur_tracker + 1) % NUM_POINTER_TRACKERS; accel->cur_tracker = current; - trackers[current].dx = 0.0; - trackers[current].dy = 0.0; + trackers[current].delta.x = 0.0; + trackers[current].delta.y = 0.0; trackers[current].time = time; - trackers[current].dir = vector_get_direction(dx, dy); + trackers[current].dir = vector_get_direction(delta->x, delta->y); } static struct pointer_tracker * @@ -139,14 +137,11 @@ tracker_by_offset(struct pointer_accelerator *accel, unsigned int offset) static double calculate_tracker_velocity(struct pointer_tracker *tracker, uint64_t time) { - double dx; - double dy; double distance; + double tdelta = time - tracker->time + 1; - dx = tracker->dx; - dy = tracker->dy; - distance = sqrt(dx*dx + dy*dy); - return distance / (double)(time - tracker->time); /* units/ms */ + distance = hypot(tracker->delta.x, tracker->delta.y); + return distance / tdelta; /* units/ms */ } static double @@ -220,27 +215,29 @@ calculate_acceleration(struct pointer_accelerator *accel, return factor; /* unitless factor */ } -static void +static struct normalized_coords accelerator_filter(struct motion_filter *filter, - struct motion_params *motion, + const struct normalized_coords *unaccelerated, void *data, uint64_t time) { struct pointer_accelerator *accel = (struct pointer_accelerator *) filter; double velocity; /* units/ms */ double accel_value; /* unitless factor */ + struct normalized_coords accelerated; - feed_trackers(accel, motion->dx, motion->dy, time); + feed_trackers(accel, unaccelerated, time); velocity = calculate_velocity(accel, time); accel_value = calculate_acceleration(accel, data, velocity, time); - motion->dx = accel_value * motion->dx; - motion->dy = accel_value * motion->dy; + accelerated.x = accel_value * unaccelerated->x; + accelerated.y = accel_value * unaccelerated->y; - accel->last_dx = motion->dx; - accel->last_dy = motion->dy; + accel->last = *unaccelerated; accel->last_velocity = velocity; + + return accelerated; } static void @@ -294,8 +291,8 @@ create_pointer_accelerator_filter(accel_profile_func_t profile) filter->profile = profile; filter->last_velocity = 0.0; - filter->last_dx = 0; - filter->last_dy = 0; + filter->last.x = 0; + filter->last.y = 0; filter->trackers = calloc(NUM_POINTER_TRACKERS, sizeof *filter->trackers); diff --git a/src/filter.h b/src/filter.h index f23b691b..70363a62 100644 --- a/src/filter.h +++ b/src/filter.h @@ -28,15 +28,13 @@ #include #include -struct motion_params { - double dx, dy; /* in units/ms @ DEFAULT_MOUSE_DPI resolution */ -}; +#include "libinput-private.h" struct motion_filter; -void +struct normalized_coords filter_dispatch(struct motion_filter *filter, - struct motion_params *motion, + const struct normalized_coords *unaccelerated, void *data, uint64_t time); void filter_destroy(struct motion_filter *filter); diff --git a/src/libinput-util.c b/src/libinput-util.c index cd3b18dc..49e297af 100644 --- a/src/libinput-util.c +++ b/src/libinput-util.c @@ -201,33 +201,3 @@ parse_mouse_wheel_click_angle_property(const char *prop) return angle; } - -/** - * Helper function to parse the TOUCHPAD_RESOLUTION property from udev. - * Property is of the form - * TOUCHPAD_RESOLUTION=x - * With both integer values in device units per mm. - * @param prop The value of the udev property (without the - * TOUCHPAD_RESOLUTION=) - * @return - */ -int -parse_touchpad_resolution_property(const char *prop, - unsigned int *res_x, - unsigned int *res_y) -{ - int nconverted = 0; - unsigned int rx, ry; - nconverted = sscanf(prop, "%ux%u", &rx, &ry); - if (nconverted != 2 || rx == 0 || ry == 0) - return -1; - - if (rx > 1000 || ry > 1000 || /* yeah, right... */ - rx < 10 || ry < 10) /* what is this? the 90s? */ - return -1; - - *res_x = rx; - *res_y = ry; - - return 0; -} diff --git a/src/libinput-util.h b/src/libinput-util.h index 60fe7931..7e19bf0e 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -135,28 +135,28 @@ enum directions { }; static inline int -vector_get_direction(int dx, int dy) +vector_get_direction(double dx, double dy) { int dir = UNDEFINED_DIRECTION; int d1, d2; double r; - if (abs(dx) < 2 && abs(dy) < 2) { - if (dx > 0 && dy > 0) + if (fabs(dx) < 2.0 && fabs(dy) < 2.0) { + if (dx > 0.0 && dy > 0.0) dir = S | SE | E; - else if (dx > 0 && dy < 0) + else if (dx > 0.0 && dy < 0.0) dir = N | NE | E; - else if (dx < 0 && dy > 0) + else if (dx < 0.0 && dy > 0.0) dir = S | SW | W; - else if (dx < 0 && dy < 0) + else if (dx < 0.0 && dy < 0.0) dir = N | NW | W; - else if (dx > 0) + else if (dx > 0.0) dir = NE | E | SE; - else if (dx < 0) + else if (dx < 0.0) dir = NW | W | SW; - else if (dy > 0) + else if (dy > 0.0) dir = SE | S | SW; - else if (dy < 0) + else if (dy < 0.0) dir = NE | N | NW; } else { /* Calculate r within the interval [0 to 8) @@ -323,8 +323,5 @@ enum ratelimit_state ratelimit_test(struct ratelimit *r); int parse_mouse_dpi_property(const char *prop); int parse_mouse_wheel_click_angle_property(const char *prop); -int parse_touchpad_resolution_property(const char *prop, - unsigned int *res_x, - unsigned int *res_y); #endif /* LIBINPUT_UTIL_H */ diff --git a/test/device.c b/test/device.c index 374e9190..4c4e2532 100644 --- a/test/device.c +++ b/test/device.c @@ -814,6 +814,86 @@ START_TEST(abs_mt_device_no_absx) } END_TEST +START_TEST(abs_device_no_range) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_device *device; + int code; + /* set x/y so libinput doesn't just reject for missing axes */ + struct input_absinfo absinfo[] = { + { ABS_X, 0, 10, 0, 0, 0 }, + { ABS_Y, 0, 10, 0, 0, 0 }, + { -1, 0, 0, 0, 0, 0 }, + { -1, -1, -1, -1, -1, -1 } + }; + + li = litest_create_context(); + litest_disable_log_handler(li); + + for (code = 0; code < ABS_MT_SLOT; code++) { + if (code == ABS_MISC) + continue; + absinfo[2].value = code; + uinput = litest_create_uinput_abs_device("test device", NULL, + absinfo, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + -1); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device == NULL); + libevdev_uinput_destroy(uinput); + } + + litest_restore_log_handler(li); + libinput_unref(li); +} +END_TEST + +START_TEST(abs_mt_device_no_range) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_device *device; + int code; + /* set x/y so libinput doesn't just reject for missing axes */ + struct input_absinfo absinfo[] = { + { ABS_X, 0, 10, 0, 0, 0 }, + { ABS_Y, 0, 10, 0, 0, 0 }, + { ABS_MT_SLOT, 0, 10, 0, 0, 0 }, + { ABS_MT_TRACKING_ID, 0, 255, 0, 0, 0 }, + { ABS_MT_POSITION_X, 0, 10, 0, 0, 0 }, + { ABS_MT_POSITION_Y, 0, 10, 0, 0, 0 }, + { -1, 0, 0, 0, 0, 0 }, + { -1, -1, -1, -1, -1, -1 } + }; + + li = litest_create_context(); + litest_disable_log_handler(li); + + for (code = ABS_MT_SLOT + 1; code < ABS_CNT; code++) { + if (code == ABS_MT_TOOL_TYPE || + code == ABS_MT_TRACKING_ID) /* kernel overrides it */ + continue; + + absinfo[6].value = code; + uinput = litest_create_uinput_abs_device("test device", NULL, + absinfo, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + -1); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device == NULL); + libevdev_uinput_destroy(uinput); + } + + litest_restore_log_handler(li); + libinput_unref(li); +} +END_TEST + int main (int argc, char **argv) { litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_TOUCHPAD|LITEST_TABLET); @@ -847,6 +927,8 @@ int main (int argc, char **argv) litest_add_no_device("device:invalid devices", abs_device_no_absy); litest_add_no_device("device:invalid devices", abs_mt_device_no_absx); litest_add_no_device("device:invalid devices", abs_mt_device_no_absy); + litest_add_no_device("device:invalid devices", abs_device_no_range); + litest_add_no_device("device:invalid devices", abs_mt_device_no_range); return litest_run(argc, argv); } diff --git a/test/misc.c b/test/misc.c index 947d48fa..0b6532ca 100644 --- a/test/misc.c +++ b/test/misc.c @@ -595,54 +595,6 @@ START_TEST(wheel_click_parser) } END_TEST -struct res_parser_test { - const char *value; - int retvalue; - int rx, ry; -}; - -START_TEST(touchpad_resolution_parser) -{ - struct res_parser_test tests[] = { - { "43x85", 0, 43, 85}, - { "242x428", 0, 242, 428 }, - { "1x1", -1, 0, 0}, - { "abcd", -1, 0, 0}, - { "", -1, 0, 0 }, - { "x", -1, 0, 0 }, - { "23x", -1, 0, 0 }, - { "x58", -1, 0, 0 }, - { "1x1", -1, 0, 0 }, - { "9x9", -1, 0, 0 }, - { "-34x-19", -1, 0, 0 }, - { "-34x19", -1, 0, 0 }, - { "34x-19", -1, 0, 0 }, - { NULL, 0, 0, 0 } - - }; - - struct res_parser_test *test = tests; - int rc; - unsigned int rx, ry; - - while (test->value != NULL) { - rx = 0xab; - ry = 0xcd; - rc = parse_touchpad_resolution_property(test->value, &rx, &ry); - ck_assert_int_eq(rc, test->retvalue); - if (rc == 0) { - ck_assert_int_eq(rx, test->rx); - ck_assert_int_eq(ry, test->ry); - } else { - ck_assert_int_eq(rx, 0xab); - ck_assert_int_eq(ry, 0xcd); - } - - test++; - } -} -END_TEST - int main (int argc, char **argv) { litest_add_no_device("events:conversion", event_conversion_device_notify); litest_add_for_device("events:conversion", event_conversion_pointer, LITEST_MOUSE); @@ -659,7 +611,6 @@ int main (int argc, char **argv) { litest_add_no_device("misc:ratelimit", ratelimit_helpers); litest_add_no_device("misc:dpi parser", dpi_parser); litest_add_no_device("misc:wheel click parser", wheel_click_parser); - litest_add_no_device("misc:touchpad resolution parser", touchpad_resolution_parser); return litest_run(argc, argv); } diff --git a/test/pointer.c b/test/pointer.c index 23bf0d7c..745af638 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -812,6 +812,48 @@ START_TEST(pointer_accel_defaults_absolute) } END_TEST +START_TEST(pointer_accel_direction_change) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *pev; + int i; + double delta; + double max_accel; + + litest_drain_events(li); + + for (i = 0; i < 10; i++) { + litest_event(dev, EV_REL, REL_X, -1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + litest_event(dev, EV_REL, REL_X, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + litest_wait_for_event_of_type(li, + LIBINPUT_EVENT_POINTER_MOTION, + -1); + event = libinput_get_event(li); + do { + pev = libinput_event_get_pointer_event(event); + + delta = libinput_event_pointer_get_dx(pev); + ck_assert(delta <= 0.0); + max_accel = delta; + libinput_event_destroy(event); + event = libinput_get_event(li); + } while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE); + + pev = libinput_event_get_pointer_event(event); + delta = libinput_event_pointer_get_dx(pev); + ck_assert(delta > 0.0); + ck_assert(delta < -max_accel); + libinput_event_destroy(event); +} +END_TEST + int main (int argc, char **argv) { litest_add("pointer:motion", pointer_motion_relative, LITEST_RELATIVE, LITEST_ANY); @@ -837,6 +879,7 @@ int main (int argc, char **argv) { litest_add("pointer:accel", pointer_accel_defaults, LITEST_RELATIVE, LITEST_ANY); litest_add("pointer:accel", pointer_accel_invalid, LITEST_RELATIVE, LITEST_ANY); litest_add("pointer:accel", pointer_accel_defaults_absolute, LITEST_ABSOLUTE, LITEST_ANY); + litest_add("pointer:accel", pointer_accel_direction_change, LITEST_RELATIVE, LITEST_ANY); return litest_run(argc, argv); } diff --git a/tools/event-gui.c b/tools/event-gui.c index f544b6f9..370df4a7 100644 --- a/tools/event-gui.c +++ b/tools/event-gui.c @@ -172,6 +172,8 @@ static void map_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) { struct window *w = data; + GdkDisplay *display; + GdkWindow *window; gtk_window_get_size(GTK_WINDOW(widget), &w->width, &w->height); @@ -185,8 +187,12 @@ map_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) g_signal_connect(G_OBJECT(w->area), "draw", G_CALLBACK(draw), w); + window = gdk_event_get_window(event); + display = gdk_window_get_display(window); + gdk_window_set_cursor(gtk_widget_get_window(w->win), - gdk_cursor_new(GDK_BLANK_CURSOR)); + gdk_cursor_new_for_display(display, + GDK_BLANK_CURSOR)); } static void