diff --git a/configure.ac b/configure.ac index f227b42a..3defe293 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], [18]) +m4_define([libinput_minor_version], [19]) 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=12:3:2 +LIBINPUT_LT_VERSION=13:0:3 AC_SUBST(LIBINPUT_LT_VERSION) AM_SILENT_RULES([yes]) diff --git a/doc/normalization-of-relative-motion.dox b/doc/normalization-of-relative-motion.dox index aaa1735f..dd5d39b3 100644 --- a/doc/normalization-of-relative-motion.dox +++ b/doc/normalization-of-relative-motion.dox @@ -12,10 +12,33 @@ physical movement or 10 millimeters, depending on the sensor. This affects pointer acceleration in libinput and interpretation of relative coordinates in callers. -libinput normalizes all relative input to a physical resolution of -1000dpi, the same delta from two different devices thus represents the -same physical movement of those two devices (within sensor error -margins). +libinput does partial normalization of relative input. For devices with a +resolution of 1000dpi and higher, motion events are normalized to a default +of 1000dpi before pointer acceleration is applied. As a result, devices with +1000dpi and above feel the same. + +Devices below 1000dpi are not normalized (normalization of a 1-device unit +movement on a 400dpi mouse would cause a 2.5 pixel movement). Instead, +libinput applies a dpi-dependent acceleration function. At low speeds, a +1-device unit movement usually translates into a 1-pixel movements. As the +movement speed increases, acceleration is applied - at high speeds a low-dpi +device will roughly feel the same as a higher-dpi mouse. + +This normalization only applies to accelerated coordinates, unaccelerated +coordiantes are left in device-units. It is up to the caller to interpret +those coordinates correctly. + +@section Normalization of touchpad coordinates + +Touchpads may have a different resolution for the horizontal and vertical +axis. Interpreting coordinates from the touchpad without taking resolutino +into account results in uneven motion. + +libinput scales unaccelerated touchpad motion do the resolution of the +touchpad's x axis, i.e. the unaccelerated value for the y axis is: + y = (x / resolution_x) * resolution_y + +@section Setting custom DPI settings Devices usually do not advertise their resolution and libinput relies on the udev property MOUSE_DPI for this information. This property is usually diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 328a744b..e85a9d77 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -91,6 +91,7 @@ static void tp_gesture_post_pointer_motion(struct tp_dispatch *tp, uint64_t time) { struct normalized_coords delta, unaccel; + struct device_float_coords raw; /* When a clickpad is clicked, combine motion of all active touches */ if (tp->buttons.is_clickpad && tp->buttons.state) @@ -101,8 +102,11 @@ tp_gesture_post_pointer_motion(struct tp_dispatch *tp, uint64_t time) delta = tp_filter_motion(tp, &unaccel, time); if (!normalized_is_zero(delta) || !normalized_is_zero(unaccel)) { - pointer_notify_motion(&tp->device->base, time, - &delta, &unaccel); + raw = tp_unnormalize_for_xaxis(tp, unaccel); + pointer_notify_motion(&tp->device->base, + time, + &delta, + &raw); } } diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index f19f434e..9d4c27d9 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -34,7 +34,7 @@ * TP_MAGIC_SLOWDOWN in filter.c */ #define DEFAULT_ACCEL_NUMERATOR 3000.0 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0 -#define DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT 500 /* ms */ +#define DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT 300 /* ms */ #define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_1 200 /* ms */ #define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_2 500 /* ms */ #define FAKE_FINGER_OVERFLOW (1 << 7) @@ -211,6 +211,7 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) t->state = TOUCH_BEGIN; t->millis = time; tp->nfingers_down++; + t->palm.time = time; assert(tp->nfingers_down >= 1); } @@ -491,7 +492,6 @@ tp_palm_detect_dwt(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) if (tp->dwt.keyboard_active && t->state == TOUCH_BEGIN) { t->palm.state = PALM_TYPING; - t->palm.time = time; t->palm.first = t->point; return 1; } else if (!tp->dwt.keyboard_active && @@ -515,6 +515,34 @@ tp_palm_detect_dwt(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) return 0; } +static int +tp_palm_detect_trackpoint(struct tp_dispatch *tp, + struct tp_touch *t, + uint64_t time) +{ + if (!tp->palm.monitor_trackpoint) + return 0; + + if (t->palm.state == PALM_NONE && + t->state == TOUCH_BEGIN && + tp->palm.trackpoint_active) { + t->palm.state = PALM_TRACKPOINT; + return 1; + } else if (t->palm.state == PALM_TRACKPOINT && + t->state == TOUCH_UPDATE && + !tp->palm.trackpoint_active) { + + if (t->palm.time == 0 || + t->palm.time > tp->palm.trackpoint_last_event_time) { + t->palm.state = PALM_NONE; + log_debug(tp_libinput_context(tp), + "palm: touch released, timeout after trackpoint\n"); + } + } + + return 0; +} + static void tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) { @@ -526,6 +554,9 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) if (tp_palm_detect_dwt(tp, t, time)) goto out; + if (tp_palm_detect_trackpoint(tp, t, time)) + goto out; + /* If labelled a touch as palm, we unlabel as palm when we move out of the palm edge zone within the timeout, provided the direction is within 45 degrees of the horizontal. @@ -568,7 +599,8 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) out: log_debug(tp_libinput_context(tp), "palm: palm detected (%s)\n", - t->palm.state == PALM_EDGE ? "edge" : "typing"); + t->palm.state == PALM_EDGE ? "edge" : + t->palm.state == PALM_TYPING ? "typing" : "trackpoint"); } static void @@ -762,7 +794,7 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time) filter_motion |= tp_post_button_events(tp, time); if (filter_motion || - tp->sendevents.trackpoint_active || + tp->palm.trackpoint_active || tp->dwt.keyboard_active) { tp_edge_scroll_stop_events(tp, time); tp_gesture_stop(tp, time); @@ -812,12 +844,13 @@ tp_interface_process(struct evdev_dispatch *dispatch, static void tp_remove_sendevents(struct tp_dispatch *tp) { - libinput_timer_cancel(&tp->sendevents.trackpoint_timer); + libinput_timer_cancel(&tp->palm.trackpoint_timer); libinput_timer_cancel(&tp->dwt.keyboard_timer); - if (tp->buttons.trackpoint) + if (tp->buttons.trackpoint && + tp->palm.monitor_trackpoint) libinput_device_remove_event_listener( - &tp->sendevents.trackpoint_listener); + &tp->palm.trackpoint_listener); if (tp->dwt.keyboard) libinput_device_remove_event_listener( @@ -928,7 +961,7 @@ tp_trackpoint_timeout(uint64_t now, void *data) struct tp_dispatch *tp = data; tp_tap_resume(tp, now); - tp->sendevents.trackpoint_active = false; + tp->palm.trackpoint_active = false; } static void @@ -941,14 +974,15 @@ tp_trackpoint_event(uint64_t time, struct libinput_event *event, void *data) if (event->type == LIBINPUT_EVENT_POINTER_BUTTON) return; - if (!tp->sendevents.trackpoint_active) { + if (!tp->palm.trackpoint_active) { tp_edge_scroll_stop_events(tp, time); tp_gesture_stop(tp, time); tp_tap_suspend(tp, time); - tp->sendevents.trackpoint_active = true; + tp->palm.trackpoint_active = true; } - libinput_timer_set(&tp->sendevents.trackpoint_timer, + tp->palm.trackpoint_last_event_time = time; + libinput_timer_set(&tp->palm.trackpoint_timer, time + DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT); } @@ -1079,9 +1113,10 @@ tp_interface_device_added(struct evdev_device *device, /* Don't send any pending releases to the new trackpoint */ tp->buttons.active_is_topbutton = false; tp->buttons.trackpoint = added_device; - libinput_device_add_event_listener(&added_device->base, - &tp->sendevents.trackpoint_listener, - tp_trackpoint_event, tp); + if (tp->palm.monitor_trackpoint) + libinput_device_add_event_listener(&added_device->base, + &tp->palm.trackpoint_listener, + tp_trackpoint_event, tp); } if (added_device->tags & EVDEV_TAG_KEYBOARD && @@ -1120,8 +1155,9 @@ tp_interface_device_removed(struct evdev_device *device, tp->buttons.active = 0; tp->buttons.active_is_topbutton = false; } - libinput_device_remove_event_listener( - &tp->sendevents.trackpoint_listener); + if (tp->palm.monitor_trackpoint) + libinput_device_remove_event_listener( + &tp->palm.trackpoint_listener); tp->buttons.trackpoint = NULL; } @@ -1426,6 +1462,8 @@ tp_init_palmdetect(struct tp_dispatch *tp, tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05; tp->palm.vert_center = device->abs.absinfo_y->minimum + height/2; + tp->palm.monitor_trackpoint = true; + return 0; } @@ -1433,7 +1471,7 @@ static int tp_init_sendevents(struct tp_dispatch *tp, struct evdev_device *device) { - libinput_timer_init(&tp->sendevents.trackpoint_timer, + libinput_timer_init(&tp->palm.trackpoint_timer, tp_libinput_context(tp), tp_trackpoint_timeout, tp); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 36260c68..edad6110 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -64,6 +64,7 @@ enum touch_palm_state { PALM_NONE = 0, PALM_EDGE, PALM_TYPING, + PALM_TRACKPOINT, }; enum button_event { @@ -277,15 +278,17 @@ struct tp_dispatch { int32_t right_edge; /* in device coordinates */ int32_t left_edge; /* in device coordinates */ int32_t vert_center; /* in device coordinates */ + + bool trackpoint_active; + struct libinput_event_listener trackpoint_listener; + struct libinput_timer trackpoint_timer; + uint64_t trackpoint_last_event_time; + bool monitor_trackpoint; } palm; struct { struct libinput_device_config_send_events config; enum libinput_config_send_events_mode current_mode; - - bool trackpoint_active; - struct libinput_event_listener trackpoint_listener; - struct libinput_timer trackpoint_timer; } sendevents; struct { @@ -318,6 +321,21 @@ tp_normalize_delta(struct tp_dispatch *tp, struct device_float_coords delta) return normalized; } +/** + * Takes a dpi-normalized set of coordinates, returns a set of coordinates + * in the x-axis' coordinate space. + */ +static inline struct device_float_coords +tp_unnormalize_for_xaxis(struct tp_dispatch *tp, struct normalized_coords delta) +{ + struct device_float_coords raw; + + raw.x = delta.x / tp->accel.x_scale_coeff; + raw.y = delta.y / tp->accel.x_scale_coeff; /* <--- not a typo */ + + return raw; +} + struct normalized_coords tp_get_delta(struct tp_touch *t); diff --git a/src/evdev.c b/src/evdev.c index c18279a6..e0bfe2ed 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -281,6 +281,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) struct libinput_seat *seat = base->seat; struct normalized_coords accel, unaccel; struct device_coords point; + struct device_float_coords raw; slot = device->mt.slot; @@ -289,6 +290,8 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) return; case EVDEV_RELATIVE_MOTION: normalize_delta(device, &device->rel, &unaccel); + raw.x = device->rel.x; + raw.y = device->rel.y; device->rel.x = 0; device->rel.y = 0; @@ -305,7 +308,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) if (normalized_is_zero(accel) && normalized_is_zero(unaccel)) break; - pointer_notify_motion(base, time, &accel, &unaccel); + pointer_notify_motion(base, time, &accel, &raw); break; case EVDEV_ABSOLUTE_MT_DOWN: if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) @@ -1408,7 +1411,8 @@ int evdev_device_init_pointer_acceleration(struct evdev_device *device, accel_profile_func_t profile) { - device->pointer.filter = create_pointer_accelerator_filter(profile); + device->pointer.filter = create_pointer_accelerator_filter(profile, + device->dpi); if (!device->pointer.filter) return -1; @@ -1549,7 +1553,7 @@ evdev_read_model(struct evdev_device *device) } /* Return 1 if the given resolutions have been set, or 0 otherwise */ -inline int +static inline int evdev_fix_abs_resolution(struct evdev_device *device, unsigned int xcode, unsigned int ycode, @@ -1825,6 +1829,19 @@ evdev_configure_mt_device(struct evdev_device *device) return 0; } +static inline int +evdev_init_accel(struct evdev_device *device) +{ + accel_profile_func_t profile; + + if (device->dpi < DEFAULT_MOUSE_DPI) + profile = pointer_accel_profile_linear_low_dpi; + else + profile = pointer_accel_profile_linear; + + return evdev_device_init_pointer_acceleration(device, profile); +} + static int evdev_configure_device(struct evdev_device *device) { @@ -1936,9 +1953,7 @@ evdev_configure_device(struct evdev_device *device) udev_tags & EVDEV_UDEV_TAG_POINTINGSTICK) { if (libevdev_has_event_code(evdev, EV_REL, REL_X) && libevdev_has_event_code(evdev, EV_REL, REL_Y) && - evdev_device_init_pointer_acceleration( - device, - pointer_accel_profile_linear) == -1) + evdev_init_accel(device) == -1) return -1; device->seat_caps |= EVDEV_DEVICE_POINTER; diff --git a/src/evdev.h b/src/evdev.h index 8787d0c7..b9082d2d 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -36,9 +36,6 @@ #include "timer.h" #include "filter.h" -/* The HW DPI rate we normalize to before calculating pointer acceleration */ -#define DEFAULT_MOUSE_DPI 1000 - /* * The constant (linear) acceleration factor we use to normalize trackpoint * deltas before calculating pointer acceleration. @@ -284,13 +281,6 @@ struct evdev_device * evdev_device_create(struct libinput_seat *seat, struct udev_device *device); -int -evdev_fix_abs_resolution(struct evdev_device *device, - unsigned int xcode, - unsigned int ycode, - int yresolution, - int xresolution); - int evdev_device_init_pointer_acceleration(struct evdev_device *device, accel_profile_func_t profile); diff --git a/src/filter.c b/src/filter.c index b37ca766..35449f56 100644 --- a/src/filter.c +++ b/src/filter.c @@ -111,6 +111,8 @@ struct pointer_accelerator { double threshold; /* units/ms */ double accel; /* unitless factor */ double incline; /* incline of the function */ + + double dpi_factor; }; static void @@ -262,8 +264,16 @@ accelerator_filter(struct motion_filter *filter, double velocity; /* units/ms */ double accel_value; /* unitless factor */ struct normalized_coords accelerated; + struct normalized_coords unnormalized; + double dpi_factor = accel->dpi_factor; - feed_trackers(accel, unaccelerated, time); + /* For low-dpi mice, use device units, everything else uses + 1000dpi normalized */ + dpi_factor = min(1.0, dpi_factor); + unnormalized.x = unaccelerated->x * dpi_factor; + unnormalized.y = unaccelerated->y * dpi_factor; + + feed_trackers(accel, &unnormalized, time); velocity = calculate_velocity(accel, time); accel_value = calculate_acceleration(accel, data, @@ -271,10 +281,10 @@ accelerator_filter(struct motion_filter *filter, accel->last_velocity, time); - accelerated.x = accel_value * unaccelerated->x; - accelerated.y = accel_value * unaccelerated->y; + accelerated.x = accel_value * unnormalized.x; + accelerated.y = accel_value * unnormalized.y; - accel->last = *unaccelerated; + accel->last = unnormalized; accel->last_velocity = velocity; @@ -346,7 +356,8 @@ struct motion_filter_interface accelerator_interface = { }; struct motion_filter * -create_pointer_accelerator_filter(accel_profile_func_t profile) +create_pointer_accelerator_filter(accel_profile_func_t profile, + int dpi) { struct pointer_accelerator *filter; @@ -369,13 +380,51 @@ create_pointer_accelerator_filter(accel_profile_func_t profile) filter->accel = DEFAULT_ACCELERATION; filter->incline = DEFAULT_INCLINE; + filter->dpi_factor = dpi/(double)DEFAULT_MOUSE_DPI; + return &filter->base; } +/** + * Custom acceleration function for mice < 1000dpi. + * At slow motion, a single device unit causes a one-pixel movement. + * The threshold/max accel depends on the DPI, the smaller the DPI the + * earlier we accelerate and the higher the maximum acceleration is. Result: + * at low speeds we get pixel-precision, at high speeds we get approx. the + * same movement as a high-dpi mouse. + * + * Note: data fed to this function is in device units, not normalized. + */ +double +pointer_accel_profile_linear_low_dpi(struct motion_filter *filter, + void *data, + double speed_in, /* in device units */ + uint64_t time) +{ + struct pointer_accelerator *accel_filter = + (struct pointer_accelerator *)filter; + + double s1, s2; + double max_accel = accel_filter->accel; /* unitless factor */ + const double threshold = accel_filter->threshold; /* units/ms */ + const double incline = accel_filter->incline; + double factor; + double dpi_factor = accel_filter->dpi_factor; + + max_accel /= dpi_factor; + + s1 = min(1, 0.3 + speed_in * 10); + s2 = 1 + (speed_in - threshold * dpi_factor) * incline; + + factor = min(max_accel, s2 > 1 ? s2 : s1); + + return factor; +} + double pointer_accel_profile_linear(struct motion_filter *filter, void *data, - double speed_in, + double speed_in, /* 1000-dpi normalized */ uint64_t time) { struct pointer_accelerator *accel_filter = @@ -387,7 +436,7 @@ pointer_accel_profile_linear(struct motion_filter *filter, const double incline = accel_filter->incline; double factor; - s1 = min(1, 0.3 + speed_in * 4); + s1 = min(1, 0.3 + speed_in * 10); s2 = 1 + (speed_in - threshold) * incline; factor = min(max_accel, s2 > 1 ? s2 : s1); diff --git a/src/filter.h b/src/filter.h index de949979..617fab1f 100644 --- a/src/filter.h +++ b/src/filter.h @@ -58,13 +58,19 @@ typedef double (*accel_profile_func_t)(struct motion_filter *filter, uint64_t time); struct motion_filter * -create_pointer_accelerator_filter(accel_profile_func_t filter); +create_pointer_accelerator_filter(accel_profile_func_t filter, + int dpi); /* * Pointer acceleration profiles. */ double +pointer_accel_profile_linear_low_dpi(struct motion_filter *filter, + void *data, + double speed_in, + uint64_t time); +double pointer_accel_profile_linear(struct motion_filter *filter, void *data, double speed_in, diff --git a/src/libinput-private.h b/src/libinput-private.h index c6514c6a..766f09b2 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -339,7 +339,7 @@ void pointer_notify_motion(struct libinput_device *device, uint64_t time, const struct normalized_coords *delta, - const struct normalized_coords *unaccel); + const struct device_float_coords *raw); void pointer_notify_motion_absolute(struct libinput_device *device, diff --git a/src/libinput-util.h b/src/libinput-util.h index 50edb492..0ad550f1 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -37,6 +37,9 @@ #define VENDOR_ID_APPLE 0x5ac #define VENDOR_ID_WACOM 0x56a +/* The HW DPI rate we normalize to before calculating pointer acceleration */ +#define DEFAULT_MOUSE_DPI 1000 + void set_logging_enabled(int enabled); diff --git a/src/libinput.c b/src/libinput.c index 7f2c15d1..5fccf941 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -96,7 +96,7 @@ struct libinput_event_pointer { struct libinput_event base; uint32_t time; struct normalized_coords delta; - struct normalized_coords delta_unaccel; + struct device_float_coords delta_raw; struct device_coords absolute; struct discrete_coords discrete; uint32_t button; @@ -364,7 +364,7 @@ libinput_event_pointer_get_dx_unaccelerated( 0, LIBINPUT_EVENT_POINTER_MOTION); - return event->delta_unaccel.x; + return event->delta_raw.x; } LIBINPUT_EXPORT double @@ -376,7 +376,7 @@ libinput_event_pointer_get_dy_unaccelerated( 0, LIBINPUT_EVENT_POINTER_MOTION); - return event->delta_unaccel.y; + return event->delta_raw.y; } LIBINPUT_EXPORT double @@ -1394,7 +1394,7 @@ void pointer_notify_motion(struct libinput_device *device, uint64_t time, const struct normalized_coords *delta, - const struct normalized_coords *unaccel) + const struct device_float_coords *raw) { struct libinput_event_pointer *motion_event; @@ -1408,7 +1408,7 @@ pointer_notify_motion(struct libinput_device *device, *motion_event = (struct libinput_event_pointer) { .time = time, .delta = *delta, - .delta_unaccel = *unaccel, + .delta_raw = *raw, }; post_device_event(device, time, diff --git a/src/libinput.h b/src/libinput.h index f2bc96b4..82e4fadd 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -582,8 +582,8 @@ libinput_event_pointer_get_time(struct libinput_event_pointer *event); * If a device employs pointer acceleration, the delta returned by this * function is the accelerated delta. * - * Relative motion deltas are normalized to represent those of a device with - * 1000dpi resolution. See @ref motion_normalization for more details. + * Relative motion deltas are to be interpreted as pixel movement of a + * standardized mouse. See @ref motion_normalization for more details. * * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. @@ -603,8 +603,8 @@ libinput_event_pointer_get_dx(struct libinput_event_pointer *event); * If a device employs pointer acceleration, the delta returned by this * function is the accelerated delta. * - * Relative motion deltas are normalized to represent those of a device with - * 1000dpi resolution. See @ref motion_normalization for more details. + * Relative motion deltas are to be interpreted as pixel movement of a + * standardized mouse. See @ref motion_normalization for more details. * * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. @@ -621,10 +621,11 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event); * current event. For pointer events that are not of type @ref * LIBINPUT_EVENT_POINTER_MOTION, this function returns 0. * - * Relative unaccelerated motion deltas are normalized to represent those of a - * device with 1000dpi resolution. See @ref motion_normalization for more - * details. Note that unaccelerated events are not equivalent to 'raw' events - * as read from the device. + * Relative unaccelerated motion deltas are raw device coordinates. + * Note that these coordinates are subject to the device's native + * resolution. Touchpad coordinates represent raw device coordinates in the + * X resolution of the touchpad. See @ref motion_normalization for more + * details. * * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. @@ -642,10 +643,11 @@ libinput_event_pointer_get_dx_unaccelerated( * current event. For pointer events that are not of type @ref * LIBINPUT_EVENT_POINTER_MOTION, this function returns 0. * - * Relative unaccelerated motion deltas are normalized to represent those of a - * device with 1000dpi resolution. See @ref motion_normalization for more - * details. Note that unaccelerated events are not equivalent to 'raw' events - * as read from the device. + * Relative unaccelerated motion deltas are raw device coordinates. + * Note that these coordinates are subject to the device's native + * resolution. Touchpad coordinates represent raw device coordinates in the + * X resolution of the touchpad. See @ref motion_normalization for more + * details. * * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. diff --git a/src/libinput.sym b/src/libinput.sym index bc2c73e7..eeb16ee6 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -143,6 +143,7 @@ global: } LIBINPUT_0.14.0; LIBINPUT_0.19.0 { +global: libinput_device_config_tap_set_drag_lock_enabled; libinput_device_config_tap_get_drag_lock_enabled; libinput_device_config_tap_get_default_drag_lock_enabled; diff --git a/test/Makefile.am b/test/Makefile.am index dda37617..c6a52afe 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -23,6 +23,7 @@ liblitest_la_SOURCES = \ litest-logitech-trackball.c \ litest-mouse.c \ litest-mouse-roccat.c \ + litest-mouse-low-dpi.c \ litest-ms-surface-cover.c \ litest-protocol-a-touch-screen.c \ litest-qemu-usb-tablet.c \ diff --git a/test/device.c b/test/device.c index 1751d48c..25fccd1f 100644 --- a/test/device.c +++ b/test/device.c @@ -947,6 +947,65 @@ START_TEST(device_wheel_only) } END_TEST +START_TEST(device_udev_tag_alps) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + struct udev_device *d; + const char *prop; + + d = libinput_device_get_udev_device(device); + prop = udev_device_get_property_value(d, + "LIBINPUT_MODEL_ALPS_TOUCHPAD"); + + if (strstr(libinput_device_get_name(device), "ALPS")) + ck_assert_notnull(prop); + else + ck_assert(prop == NULL); + + udev_device_unref(d); +} +END_TEST + +START_TEST(device_udev_tag_wacom) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + struct udev_device *d; + const char *prop; + + d = libinput_device_get_udev_device(device); + prop = udev_device_get_property_value(d, + "LIBINPUT_MODEL_WACOM_TOUCHPAD"); + + if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM) + ck_assert_notnull(prop); + else + ck_assert(prop == NULL); + + udev_device_unref(d); +} +END_TEST + +START_TEST(device_udev_tag_apple) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + struct udev_device *d; + const char *prop; + + d = libinput_device_get_udev_device(device); + prop = udev_device_get_property_value(d, + "LIBINPUT_MODEL_WACOM_TOUCHPAD"); + + if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM) + ck_assert_notnull(prop); + else + ck_assert(prop == NULL); + + udev_device_unref(d); +} +END_TEST void litest_setup_tests(void) { @@ -989,4 +1048,8 @@ litest_setup_tests(void) litest_add_no_device("device:invalid devices", abs_mt_device_missing_res); litest_add("device:wheel", device_wheel_only, LITEST_WHEEL, LITEST_RELATIVE|LITEST_ABSOLUTE|LITEST_TABLET); + + litest_add("device:udev tags", device_udev_tag_alps, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("device:udev tags", device_udev_tag_wacom, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("device:udev tags", device_udev_tag_apple, LITEST_TOUCHPAD, LITEST_ANY); } diff --git a/test/litest-mouse-low-dpi.c b/test/litest-mouse-low-dpi.c new file mode 100644 index 00000000..dccf40fa --- /dev/null +++ b/test/litest-mouse-low-dpi.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2015 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "litest.h" +#include "litest-int.h" + +static void litest_mouse_setup(void) +{ + struct litest_device *d = litest_create_device(LITEST_MOUSE_LOW_DPI); + litest_set_current_device(d); +} + +static struct input_id input_id = { + .bustype = 0x3, + .vendor = 0x1, + .product = 0x1, +}; + +static int events[] = { + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + EV_KEY, BTN_MIDDLE, + EV_REL, REL_X, + EV_REL, REL_Y, + EV_REL, REL_WHEEL, + -1 , -1, +}; + +static const char udev_rule[] = +"ACTION==\"remove\", GOTO=\"touchpad_end\"\n" +"KERNEL!=\"event*\", GOTO=\"touchpad_end\"\n" +"ENV{ID_INPUT_TOUCHPAD}==\"\", GOTO=\"touchpad_end\"\n" +"\n" +"ATTRS{name}==\"litest Low DPI Mouse*\",\\\n" +" ENV{MOUSE_DPI}=\"400@125\"\n" +"\n" +"LABEL=\"touchpad_end\""; + +struct litest_test_device litest_mouse_low_dpi_device = { + .type = LITEST_MOUSE_LOW_DPI, + .features = LITEST_RELATIVE | LITEST_BUTTON | LITEST_WHEEL, + .shortname = "low-dpi mouse", + .setup = litest_mouse_setup, + .interface = NULL, + + .name = "Low DPI Mouse", + .id = &input_id, + .absinfo = NULL, + .events = events, + .udev_rule = udev_rule, +}; diff --git a/test/litest.c b/test/litest.c index ea73d6ee..0835ddfd 100644 --- a/test/litest.c +++ b/test/litest.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "litest.h" #include "litest-int.h" @@ -52,7 +53,7 @@ #define UDEV_RULES_D "/run/udev/rules.d" #define UDEV_RULE_PREFIX "99-litest-" #define UDEV_HWDB_D "/etc/udev/hwdb.d" -#define UDEV_COMMON_RULE_FILE UDEV_RULES_D "/91-litest-model-quirks.rules" +#define UDEV_COMMON_RULE_FILE UDEV_RULES_D "/91-litest-model-quirks-REMOVEME.rules" #define UDEV_COMMON_HWDB_FILE UDEV_HWDB_D "/91-litest-model-quirks-REMOVEME.hwdb" static int in_debugger = -1; @@ -356,6 +357,7 @@ extern struct litest_test_device litest_ms_surface_cover_device; extern struct litest_test_device litest_logitech_trackball_device; extern struct litest_test_device litest_atmel_hover_device; extern struct litest_test_device litest_alps_dualpoint_device; +extern struct litest_test_device litest_mouse_low_dpi_device; extern struct litest_test_device litest_waltop_tablet_device; struct litest_test_device* devices[] = { @@ -387,6 +389,7 @@ struct litest_test_device* devices[] = { &litest_logitech_trackball_device, &litest_atmel_hover_device, &litest_alps_dualpoint_device, + &litest_mouse_low_dpi_device, &litest_waltop_tablet_device, NULL, }; @@ -933,16 +936,20 @@ litest_copy_file(const char *dest, const char *src, const char *header) static inline void litest_install_model_quirks(void) { - litest_copy_file(UDEV_COMMON_RULE_FILE, LIBINPUT_UDEV_RULES_FILE, NULL); - litest_copy_file(UDEV_COMMON_HWDB_FILE, - LIBINPUT_UDEV_HWDB_FILE, + const char *warning = "#################################################################\n" "# WARNING: REMOVE THIS FILE\n" - "# This is the run-time hwdb file for the libinput test suite and\n" + "# This is a run-time file for the libinput test suite and\n" "# should be removed on exit. If the test-suite is not currently \n" "# running, remove this file and update your hwdb: \n" "# sudo udevadm hwdb --update\n" - "#################################################################\n\n"); + "#################################################################\n\n"; + litest_copy_file(UDEV_COMMON_RULE_FILE, + LIBINPUT_UDEV_RULES_FILE, + warning); + litest_copy_file(UDEV_COMMON_HWDB_FILE, + LIBINPUT_UDEV_HWDB_FILE, + warning); } static inline void @@ -1083,32 +1090,6 @@ litest_restore_log_handler(struct libinput *libinput) libinput_log_set_handler(libinput, litest_log_handler); } -static inline void -litest_wait_for_udev(int fd) -{ - struct udev *udev; - struct udev_device *device; - struct stat st; - int loop_count = 0; - - litest_assert_int_ge(fstat(fd, &st), 0); - - udev = udev_new(); - device = udev_device_new_from_devnum(udev, 'c', st.st_rdev); - litest_assert_ptr_notnull(device); - while (device && !udev_device_get_property_value(device, "ID_INPUT")) { - loop_count++; - litest_assert_int_lt(loop_count, 300); - - udev_device_unref(device); - msleep(2); - device = udev_device_new_from_devnum(udev, 'c', st.st_rdev); - } - - udev_device_unref(device); - udev_unref(udev); -} - struct litest_device * litest_add_device_with_overrides(struct libinput *libinput, enum litest_device_type which, @@ -1136,8 +1117,6 @@ litest_add_device_with_overrides(struct libinput *libinput, rc = libevdev_new_from_fd(fd, &d->evdev); litest_assert_int_eq(rc, 0); - litest_wait_for_udev(fd); - d->libinput = libinput; d->libinput_device = libinput_path_add_device(d->libinput, path); litest_assert(d->libinput_device != NULL); @@ -1224,11 +1203,6 @@ litest_delete_device(struct litest_device *d) free(d->private); memset(d,0, sizeof(*d)); free(d); - - /* zzz so udev can catch up with things, so we don't accidentally open - * an old device in the next test and then get all upset when things blow - * up */ - msleep(10); } void @@ -1685,6 +1659,7 @@ litest_wait_for_event_of_type(struct libinput *li, ...) enum libinput_event_type types[32] = {LIBINPUT_EVENT_NONE}; size_t ntypes = 0; enum libinput_event_type type; + struct pollfd fds; va_start(args, li); type = va_arg(args, int); @@ -1696,12 +1671,16 @@ litest_wait_for_event_of_type(struct libinput *li, ...) } va_end(args); + fds.fd = libinput_get_fd(li); + fds.events = POLLIN; + fds.revents = 0; + while (1) { size_t i; struct libinput_event *event; while ((type = libinput_next_event_type(li)) == LIBINPUT_EVENT_NONE) { - msleep(10); + poll(&fds, 1, -1); libinput_dispatch(li); } @@ -1858,11 +1837,11 @@ litest_assert_empty_queue(struct libinput *li) litest_assert(empty_queue); } -struct libevdev_uinput * -litest_create_uinput_device_from_description(const char *name, - const struct input_id *id, - const struct input_absinfo *abs_info, - const int *events) +static struct libevdev_uinput * +litest_create_uinput(const char *name, + const struct input_id *id, + const struct input_absinfo *abs_info, + const int *events) { struct libevdev_uinput *uinput; struct libevdev *dev; @@ -1950,6 +1929,58 @@ litest_create_uinput_device_from_description(const char *name, return uinput; } +struct libevdev_uinput * +litest_create_uinput_device_from_description(const char *name, + const struct input_id *id, + const struct input_absinfo *abs_info, + const int *events) +{ + struct libevdev_uinput *uinput; + const char *syspath; + + struct udev *udev; + struct udev_monitor *udev_monitor; + struct udev_device *udev_device; + const char *udev_action; + const char *udev_syspath = NULL; + + udev = udev_new(); + litest_assert_notnull(udev); + udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + litest_assert_notnull(udev_monitor); + udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input", + NULL); + /* remove O_NONBLOCK */ + fcntl(udev_monitor_get_fd(udev_monitor), F_SETFL, 0); + litest_assert_int_eq(udev_monitor_enable_receiving(udev_monitor), + 0); + + uinput = litest_create_uinput(name, id, abs_info, events); + + syspath = libevdev_uinput_get_syspath(uinput); + + /* blocking, we don't want to continue until udev is ready */ + do { + udev_device = udev_monitor_receive_device(udev_monitor); + litest_assert_notnull(udev_device); + udev_action = udev_device_get_action(udev_device); + if (strcmp(udev_action, "add") != 0) { + udev_device_unref(udev_device); + continue; + } + + udev_syspath = udev_device_get_syspath(udev_device); + } while (!udev_syspath || strcmp(udev_syspath, syspath) != 0); + + litest_assert(udev_device_get_property_value(udev_device, "ID_INPUT")); + + udev_device_unref(udev_device); + udev_monitor_unref(udev_monitor); + udev_unref(udev); + + return uinput; +} + static struct libevdev_uinput * litest_create_uinput_abs_device_v(const char *name, struct input_id *id, @@ -2493,6 +2524,8 @@ main(int argc, char **argv) list_init(&all_tests); + setenv("CK_DEFAULT_TIMEOUT", "10", 0); + mode = litest_parse_argv(argc, argv); if (mode == LITEST_MODE_ERROR) return EXIT_FAILURE; diff --git a/test/litest.h b/test/litest.h index 8daa69c0..d7c2fb29 100644 --- a/test/litest.h +++ b/test/litest.h @@ -137,11 +137,12 @@ enum litest_device_type { LITEST_LOGITECH_TRACKBALL = -23, LITEST_ATMEL_HOVER = -24, LITEST_ALPS_DUALPOINT = -25, - LITEST_WACOM_BAMBOO = -26, - LITEST_WACOM_CINTIQ = -27, - LITEST_WACOM_INTUOS = -28, - LITEST_WACOM_ISDV4 = -29, - LITEST_WALTOP = -30, + LITEST_MOUSE_LOW_DPI = -26, + LITEST_WACOM_BAMBOO = -27, + LITEST_WACOM_CINTIQ = -28, + LITEST_WACOM_INTUOS = -29, + LITEST_WACOM_ISDV4 = -30, + LITEST_WALTOP = -31, }; enum litest_device_feature { diff --git a/test/misc.c b/test/misc.c index bf65abec..b4b16bc0 100644 --- a/test/misc.c +++ b/test/misc.c @@ -690,7 +690,7 @@ litest_setup_tests(void) litest_add_no_device("misc:matrix", matrix_helpers); 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:trackpoint accel parser", trackpoint_accel_parser); + litest_add_no_device("misc:parser", dpi_parser); + litest_add_no_device("misc:parser", wheel_click_parser); + litest_add_no_device("misc:parser", trackpoint_accel_parser); } diff --git a/test/pointer.c b/test/pointer.c index 836964dc..0c244f2d 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -35,52 +35,26 @@ #include "libinput-util.h" #include "litest.h" -static struct libinput_event_pointer * -get_accelerated_motion_event(struct libinput *li) -{ - struct libinput_event *event; - struct libinput_event_pointer *ptrev; - - while (1) { - event = libinput_get_event(li); - ptrev = litest_is_motion_event(event); - - if (fabs(libinput_event_pointer_get_dx(ptrev)) < DBL_MIN && - fabs(libinput_event_pointer_get_dy(ptrev)) < DBL_MIN) { - libinput_event_destroy(event); - continue; - } - - return ptrev; - } - - litest_abort_msg("No accelerated pointer motion event found"); - return NULL; -} - static void test_relative_event(struct litest_device *dev, int dx, int dy) { struct libinput *li = dev->libinput; struct libinput_event_pointer *ptrev; + struct libinput_event *event; double ev_dx, ev_dy; double expected_dir; double expected_length; double actual_dir; double actual_length; - /* Send two deltas, as the first one may be eaten up by an - * acceleration filter. */ - litest_event(dev, EV_REL, REL_X, dx); - litest_event(dev, EV_REL, REL_Y, dy); - litest_event(dev, EV_SYN, SYN_REPORT, 0); litest_event(dev, EV_REL, REL_X, dx); litest_event(dev, EV_REL, REL_Y, dy); litest_event(dev, EV_SYN, SYN_REPORT, 0); libinput_dispatch(li); - ptrev = get_accelerated_motion_event(li); + event = libinput_get_event(li); + ptrev = litest_is_motion_event(event); expected_length = sqrt(4 * dx*dx + 4 * dy*dy); expected_dir = atan2(dx, dy); @@ -97,7 +71,7 @@ test_relative_event(struct litest_device *dev, int dx, int dy) * indifference). */ litest_assert(fabs(expected_dir - actual_dir) < M_PI_2); - libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev)); + libinput_event_destroy(event); litest_drain_events(dev->libinput); } @@ -120,6 +94,13 @@ START_TEST(pointer_motion_relative) { struct litest_device *dev = litest_current_device(); + /* send a single event, the first movement + is always decelerated by 0.3 */ + litest_event(dev, EV_REL, REL_X, 1); + litest_event(dev, EV_REL, REL_Y, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(dev->libinput); + litest_drain_events(dev->libinput); test_relative_event(dev, 1, 0); @@ -134,6 +115,95 @@ START_TEST(pointer_motion_relative) } END_TEST +START_TEST(pointer_motion_relative_zero) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + int i; + + /* NOTE: this test does virtually nothing. The kernel should not + * allow 0/0 events to be passed to userspace. If it ever happens, + * let's hope this test fails if we do the wrong thing. + */ + litest_drain_events(li); + + for (i = 0; i < 5; i++) { + litest_event(dev, EV_REL, REL_X, 0); + litest_event(dev, EV_REL, REL_Y, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + } + litest_assert_empty_queue(li); + + /* send a single event, the first movement + is always decelerated by 0.3 */ + litest_event(dev, EV_REL, REL_X, 1); + litest_event(dev, EV_REL, REL_Y, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + libinput_event_destroy(libinput_get_event(li)); + litest_assert_empty_queue(li); + + for (i = 0; i < 5; i++) { + litest_event(dev, EV_REL, REL_X, 0); + litest_event(dev, EV_REL, REL_Y, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(dev->libinput); + } + litest_assert_empty_queue(li); + +} +END_TEST + +START_TEST(pointer_motion_relative_min_decel) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event_pointer *ptrev; + struct libinput_event *event; + double evx, evy; + int dx, dy; + int cardinal = _i; /* ranged test */ + double len; + + int deltas[8][2] = { + /* N, NE, E, ... */ + { 0, 1 }, + { 1, 1 }, + { 1, 0 }, + { 1, -1 }, + { 0, -1 }, + { -1, -1 }, + { -1, 0 }, + { -1, 1 }, + }; + + litest_drain_events(dev->libinput); + + dx = deltas[cardinal][0]; + dy = deltas[cardinal][1]; + + litest_event(dev, EV_REL, REL_X, dx); + litest_event(dev, EV_REL, REL_Y, dy); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + event = libinput_get_event(li); + ptrev = litest_is_motion_event(event); + evx = libinput_event_pointer_get_dx(ptrev); + evy = libinput_event_pointer_get_dy(ptrev); + + ck_assert((evx == 0.0) == (dx == 0)); + ck_assert((evy == 0.0) == (dy == 0)); + + len = vector_length(evx, evy); + ck_assert(fabs(len) >= 0.3); + + libinput_event_destroy(event); +} +END_TEST + static void test_absolute_event(struct litest_device *dev, double x, double y) { @@ -1347,8 +1417,11 @@ void litest_setup_tests(void) { struct range axis_range = {ABS_X, ABS_Y + 1}; + struct range compass = {0, 7}; /* cardinal directions */ litest_add("pointer:motion", pointer_motion_relative, LITEST_RELATIVE, LITEST_ANY); + litest_add_for_device("pointer:motion", pointer_motion_relative_zero, LITEST_MOUSE); + litest_add_ranged("pointer:motion", pointer_motion_relative_min_decel, LITEST_RELATIVE, LITEST_ANY, &compass); litest_add("pointer:motion", pointer_motion_absolute, LITEST_ABSOLUTE, LITEST_ANY); litest_add("pointer:motion", pointer_motion_unaccel, LITEST_RELATIVE, LITEST_ANY); litest_add("pointer:button", pointer_button, LITEST_BUTTON, LITEST_CLICKPAD); diff --git a/tools/ptraccel-debug.c b/tools/ptraccel-debug.c index c774e3bf..b2dd1f90 100644 --- a/tools/ptraccel-debug.c +++ b/tools/ptraccel-debug.c @@ -168,6 +168,7 @@ usage(void) "--maxdx= ... in motion mode only. Stop increasing dx at maxdx\n" "--steps= ... in motion and delta modes only. Increase dx by step each round\n" "--speed= ... accel speed [-1, 1], default 0\n" + "--dpi= ... device resolution in DPI (default: 1000)\n" "\n" "If extra arguments are present and mode is not given, mode defaults to 'sequence'\n" "and the arguments are interpreted as sequence of delta x coordinates\n" @@ -191,17 +192,17 @@ main(int argc, char **argv) print_sequence = false; double custom_deltas[1024]; double speed = 0.0; + int dpi = 1000; + enum { OPT_MODE = 1, OPT_NEVENTS, OPT_MAXDX, OPT_STEP, OPT_SPEED, + OPT_DPI, }; - filter = create_pointer_accelerator_filter(pointer_accel_profile_linear); - assert(filter != NULL); - while (1) { int c; int option_index = 0; @@ -211,6 +212,7 @@ main(int argc, char **argv) {"maxdx", 1, 0, OPT_MAXDX }, {"step", 1, 0, OPT_STEP }, {"speed", 1, 0, OPT_SPEED }, + {"dpi", 1, 0, OPT_DPI }, {0, 0, 0, 0} }; @@ -258,6 +260,9 @@ main(int argc, char **argv) case OPT_SPEED: speed = strtod(optarg, NULL); break; + case OPT_DPI: + dpi = strtod(optarg, NULL); + break; default: usage(); exit(1); @@ -265,6 +270,9 @@ main(int argc, char **argv) } } + filter = create_pointer_accelerator_filter(pointer_accel_profile_linear, + dpi); + assert(filter != NULL); filter_set_speed(filter, speed); if (!isatty(STDIN_FILENO)) { diff --git a/udev/90-libinput-model-quirks.rules b/udev/90-libinput-model-quirks.rules index 79b9b36f..43674f55 100644 --- a/udev/90-libinput-model-quirks.rules +++ b/udev/90-libinput-model-quirks.rules @@ -11,6 +11,7 @@ ACTION!="add|change", GOTO="libinput_model_quirks_end" KERNEL!="event*", GOTO="libinput_model_quirks_end" +# Matches below are exclusive, if one matches we skip the rest # hwdb matches: # # libinput:touchpad: diff --git a/udev/libinput-device-group.c b/udev/libinput-device-group.c index adbd6b7f..ab9409bf 100644 --- a/udev/libinput-device-group.c +++ b/udev/libinput-device-group.c @@ -1,3 +1,26 @@ +/* + * Copyright © 2015 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + #include #include #include