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