mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 17:20:04 +01:00
evdev: drop relative x/y motion from a device not marked as pointer
A device with REL_X/Y and keys gets marked only as ID_INPUT_KEY, initializes as keyboard and then segfaults when we send x/y coordinates - pointer acceleration never initializes. Ignore the events and log a bug instead. This intentionally only papers over the underlying issue, let's wait for a real device to trigger this and then look at the correct solution. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
parent
5311d76ec1
commit
6953b51b7e
4 changed files with 193 additions and 0 deletions
35
src/evdev.c
35
src/evdev.c
|
|
@ -638,6 +638,36 @@ evdev_notify_axis(struct evdev_device *device,
|
|||
&discrete);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
evdev_reject_relative(struct evdev_device *device,
|
||||
const struct input_event *e,
|
||||
uint64_t time)
|
||||
{
|
||||
struct libinput *libinput = device->base.seat->libinput;
|
||||
|
||||
if ((e->code == REL_X || e->code == REL_Y) &&
|
||||
(device->seat_caps & EVDEV_DEVICE_POINTER) == 0) {
|
||||
switch (ratelimit_test(&device->nonpointer_rel_limit)) {
|
||||
case RATELIMIT_PASS:
|
||||
log_bug_libinput(libinput,
|
||||
"REL_X/Y from device '%s', but this device is not a pointer\n",
|
||||
device->devname);
|
||||
break;
|
||||
case RATELIMIT_THRESHOLD:
|
||||
log_bug_libinput(libinput,
|
||||
"REL_X/Y event flood from '%s'\n",
|
||||
device->devname);
|
||||
break;
|
||||
case RATELIMIT_EXCEEDED:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
evdev_process_relative(struct evdev_device *device,
|
||||
struct input_event *e, uint64_t time)
|
||||
|
|
@ -645,6 +675,9 @@ evdev_process_relative(struct evdev_device *device,
|
|||
struct normalized_coords wheel_degrees = { 0.0, 0.0 };
|
||||
struct discrete_coords discrete = { 0.0, 0.0 };
|
||||
|
||||
if (evdev_reject_relative(device, e, time))
|
||||
return;
|
||||
|
||||
switch (e->code) {
|
||||
case REL_X:
|
||||
if (device->pending_event != EVDEV_RELATIVE_MOTION)
|
||||
|
|
@ -2157,6 +2190,8 @@ evdev_device_create(struct libinput_seat *seat,
|
|||
|
||||
/* at most 5 SYN_DROPPED log-messages per 30s */
|
||||
ratelimit_init(&device->syn_drop_limit, s2us(30), 5);
|
||||
/* at most 5 log-messages per 5s */
|
||||
ratelimit_init(&device->nonpointer_rel_limit, s2us(5), 5);
|
||||
|
||||
matrix_init_identity(&device->abs.calibration);
|
||||
matrix_init_identity(&device->abs.usermatrix);
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ struct evdev_device {
|
|||
|
||||
int dpi; /* HW resolution */
|
||||
struct ratelimit syn_drop_limit; /* ratelimit for SYN_DROPPED logging */
|
||||
struct ratelimit nonpointer_rel_limit; /* ratelimit for REL_* events from non-pointer devices */
|
||||
|
||||
uint32_t model_flags;
|
||||
};
|
||||
|
|
|
|||
155
test/device.c
155
test/device.c
|
|
@ -1030,6 +1030,156 @@ START_TEST(device_udev_tag_synaptics_serial)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_nonpointer_rel)
|
||||
{
|
||||
struct libevdev_uinput *uinput;
|
||||
struct libinput *li;
|
||||
struct libinput_device *device;
|
||||
int i;
|
||||
|
||||
uinput = litest_create_uinput_device("test device",
|
||||
NULL,
|
||||
EV_KEY, KEY_A,
|
||||
EV_KEY, KEY_B,
|
||||
EV_REL, REL_X,
|
||||
EV_REL, REL_Y,
|
||||
-1);
|
||||
li = litest_create_context();
|
||||
device = libinput_path_add_device(li,
|
||||
libevdev_uinput_get_devnode(uinput));
|
||||
ck_assert(device != NULL);
|
||||
|
||||
litest_disable_log_handler(li);
|
||||
for (i = 0; i < 100; i++) {
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1);
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1);
|
||||
libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
litest_restore_log_handler(li);
|
||||
|
||||
libinput_unref(li);
|
||||
libevdev_uinput_destroy(uinput);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_touchpad_rel)
|
||||
{
|
||||
struct libevdev_uinput *uinput;
|
||||
struct libinput *li;
|
||||
struct libinput_device *device;
|
||||
const struct input_absinfo abs[] = {
|
||||
{ ABS_X, 0, 10, 0, 0, 10 },
|
||||
{ ABS_Y, 0, 10, 0, 0, 10 },
|
||||
{ ABS_MT_SLOT, 0, 2, 0, 0, 0 },
|
||||
{ ABS_MT_TRACKING_ID, 0, 255, 0, 0, 0 },
|
||||
{ ABS_MT_POSITION_X, 0, 10, 0, 0, 10 },
|
||||
{ ABS_MT_POSITION_Y, 0, 10, 0, 0, 10 },
|
||||
{ -1, -1, -1, -1, -1, -1 }
|
||||
};
|
||||
int i;
|
||||
|
||||
uinput = litest_create_uinput_abs_device("test device",
|
||||
NULL, abs,
|
||||
EV_KEY, BTN_TOOL_FINGER,
|
||||
EV_KEY, BTN_TOUCH,
|
||||
EV_REL, REL_X,
|
||||
EV_REL, REL_Y,
|
||||
-1);
|
||||
li = litest_create_context();
|
||||
device = libinput_path_add_device(li,
|
||||
libevdev_uinput_get_devnode(uinput));
|
||||
ck_assert(device != NULL);
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1);
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1);
|
||||
libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
|
||||
libinput_unref(li);
|
||||
libevdev_uinput_destroy(uinput);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_touch_rel)
|
||||
{
|
||||
struct libevdev_uinput *uinput;
|
||||
struct libinput *li;
|
||||
struct libinput_device *device;
|
||||
const struct input_absinfo abs[] = {
|
||||
{ ABS_X, 0, 10, 0, 0, 10 },
|
||||
{ ABS_Y, 0, 10, 0, 0, 10 },
|
||||
{ ABS_MT_SLOT, 0, 2, 0, 0, 0 },
|
||||
{ ABS_MT_TRACKING_ID, 0, 255, 0, 0, 0 },
|
||||
{ ABS_MT_POSITION_X, 0, 10, 0, 0, 10 },
|
||||
{ ABS_MT_POSITION_Y, 0, 10, 0, 0, 10 },
|
||||
{ -1, -1, -1, -1, -1, -1 }
|
||||
};
|
||||
int i;
|
||||
|
||||
uinput = litest_create_uinput_abs_device("test device",
|
||||
NULL, abs,
|
||||
EV_KEY, BTN_TOUCH,
|
||||
EV_REL, REL_X,
|
||||
EV_REL, REL_Y,
|
||||
-1);
|
||||
li = litest_create_context();
|
||||
device = libinput_path_add_device(li,
|
||||
libevdev_uinput_get_devnode(uinput));
|
||||
ck_assert(device != NULL);
|
||||
|
||||
litest_disable_log_handler(li);
|
||||
for (i = 0; i < 100; i++) {
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1);
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1);
|
||||
libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
litest_restore_log_handler(li);
|
||||
|
||||
libinput_unref(li);
|
||||
libevdev_uinput_destroy(uinput);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_abs_rel)
|
||||
{
|
||||
struct libevdev_uinput *uinput;
|
||||
struct libinput *li;
|
||||
struct libinput_device *device;
|
||||
const struct input_absinfo abs[] = {
|
||||
{ ABS_X, 0, 10, 0, 0, 10 },
|
||||
{ ABS_Y, 0, 10, 0, 0, 10 },
|
||||
{ -1, -1, -1, -1, -1, -1 }
|
||||
};
|
||||
int i;
|
||||
|
||||
uinput = litest_create_uinput_abs_device("test device",
|
||||
NULL, abs,
|
||||
EV_KEY, BTN_TOUCH,
|
||||
EV_KEY, BTN_LEFT,
|
||||
EV_REL, REL_X,
|
||||
EV_REL, REL_Y,
|
||||
-1);
|
||||
li = litest_create_context();
|
||||
device = libinput_path_add_device(li,
|
||||
libevdev_uinput_get_devnode(uinput));
|
||||
ck_assert(device != NULL);
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1);
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1);
|
||||
libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
|
||||
libinput_unref(li);
|
||||
libevdev_uinput_destroy(uinput);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
litest_setup_tests(void)
|
||||
{
|
||||
|
|
@ -1077,4 +1227,9 @@ litest_setup_tests(void)
|
|||
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);
|
||||
litest_add("device:udev tags", device_udev_tag_synaptics_serial, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
|
||||
litest_add_no_device("device:invalid rel events", device_nonpointer_rel);
|
||||
litest_add_no_device("device:invalid rel events", device_touchpad_rel);
|
||||
litest_add_no_device("device:invalid rel events", device_touch_rel);
|
||||
litest_add_no_device("device:invalid rel events", device_abs_rel);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -778,9 +778,11 @@ litest_log_handler(struct libinput *libinput,
|
|||
fprintf(stderr, "litest %s: ", priority);
|
||||
vfprintf(stderr, format, args);
|
||||
|
||||
#if 0
|
||||
if (strstr(format, "client bug: ") ||
|
||||
strstr(format, "libinput bug: "))
|
||||
litest_abort_msg("libinput bug triggered, aborting.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue