mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-01-03 12:40:14 +01:00
tablet: sync tools already in proximity at startup
If a tool is in proximity when we init, send a proximity event immediately. This is only partially reliable due to the current kernel behavior: * if the tool comes into proximity when there is no evdev client, the device won't send any events and must be lifted out-of-proximity first. Patch is in the works, see https://patchwork.kernel.org/patch/5924611/ * before 3.19, if the tool was in proximity (with an evdev client attached), but goes out of proximity and back in with no client connected, we get an immediate proximity out event from the kernel once we connect to the device and no further events after that. See kernel commit b905811a49bcd6e6726ce5bbb591f57aaddfd3be Otherwise, things work as expected. The above should be fixed in the kernel anyway. Note that this changes the order of events during a udev seat init, before we had all DEVICE_ADDED events in a row, now the proximity event may be interspersed. Reported-by: Jason Gerecke <killertofu@gmail.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
parent
bd6d427829
commit
411f95b17f
6 changed files with 136 additions and 1 deletions
|
|
@ -897,6 +897,7 @@ static struct evdev_dispatch_interface tp_interface = {
|
|||
tp_device_removed, /* device_suspended, treat as remove */
|
||||
tp_device_added, /* device_resumed, treat as add */
|
||||
tp_tag_device,
|
||||
NULL, /* post_added */
|
||||
};
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ tablet_update_tool(struct tablet_dispatch *tablet,
|
|||
tablet_set_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
|
||||
tablet_unset_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
|
||||
}
|
||||
else
|
||||
else if (!tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))
|
||||
tablet_set_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
|
||||
}
|
||||
|
||||
|
|
@ -868,6 +868,9 @@ tablet_flush(struct tablet_dispatch *tablet,
|
|||
tablet->current_tool_id,
|
||||
tablet->current_tool_serial);
|
||||
|
||||
if (tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))
|
||||
return;
|
||||
|
||||
if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
|
||||
/* Release all stylus buttons */
|
||||
memset(tablet->button_state.stylus_buttons,
|
||||
|
|
@ -915,7 +918,11 @@ tablet_flush(struct tablet_dispatch *tablet,
|
|||
|
||||
tablet_change_to_left_handed(device);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
tablet_reset_state(struct tablet_dispatch *tablet)
|
||||
{
|
||||
/* Update state */
|
||||
memcpy(&tablet->prev_button_state,
|
||||
&tablet->button_state,
|
||||
|
|
@ -946,6 +953,7 @@ tablet_process(struct evdev_dispatch *dispatch,
|
|||
break;
|
||||
case EV_SYN:
|
||||
tablet_flush(tablet, device, time);
|
||||
tablet_reset_state(tablet);
|
||||
break;
|
||||
default:
|
||||
log_error(device->base.seat->libinput,
|
||||
|
|
@ -970,6 +978,47 @@ tablet_destroy(struct evdev_dispatch *dispatch)
|
|||
free(tablet);
|
||||
}
|
||||
|
||||
static void
|
||||
tablet_check_initial_proximity(struct evdev_device *device,
|
||||
struct evdev_dispatch *dispatch)
|
||||
{
|
||||
bool tool_in_prox = false;
|
||||
int code, state;
|
||||
enum libinput_tool_type tool;
|
||||
struct tablet_dispatch *tablet = (struct tablet_dispatch*)dispatch;
|
||||
|
||||
for (tool = LIBINPUT_TOOL_PEN; tool <= LIBINPUT_TOOL_MAX; tool++) {
|
||||
code = tablet_tool_to_evcode(tool);
|
||||
|
||||
/* we only expect one tool to be in proximity at a time */
|
||||
if (libevdev_fetch_event_value(device->evdev,
|
||||
EV_KEY,
|
||||
code,
|
||||
&state) && state) {
|
||||
tool_in_prox = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tool_in_prox)
|
||||
return;
|
||||
|
||||
tablet_update_tool(tablet, device, tool, state);
|
||||
|
||||
tablet->current_tool_id =
|
||||
libevdev_get_event_value(device->evdev,
|
||||
EV_ABS,
|
||||
ABS_MISC);
|
||||
tablet->current_tool_serial =
|
||||
libevdev_get_event_value(device->evdev,
|
||||
EV_MSC,
|
||||
MSC_SERIAL);
|
||||
|
||||
tablet_flush(tablet,
|
||||
device,
|
||||
libinput_now(device->base.seat->libinput));
|
||||
}
|
||||
|
||||
static struct evdev_dispatch_interface tablet_interface = {
|
||||
tablet_process,
|
||||
NULL, /* remove */
|
||||
|
|
@ -979,6 +1028,7 @@ static struct evdev_dispatch_interface tablet_interface = {
|
|||
NULL, /* device_suspended */
|
||||
NULL, /* device_resumed */
|
||||
NULL, /* tag_device */
|
||||
tablet_check_initial_proximity,
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#define LIBINPUT_TABLET_AXIS_NONE 0
|
||||
#define LIBINPUT_TOOL_NONE 0
|
||||
#define LIBINPUT_TOOL_MAX LIBINPUT_TOOL_LENS
|
||||
|
||||
enum tablet_status {
|
||||
TABLET_NONE = 0,
|
||||
|
|
@ -156,4 +157,24 @@ axis_to_evcode(const enum libinput_tablet_axis axis)
|
|||
return evcode;
|
||||
}
|
||||
|
||||
static inline int
|
||||
tablet_tool_to_evcode(enum libinput_tool_type type)
|
||||
{
|
||||
int code;
|
||||
|
||||
switch (type) {
|
||||
case LIBINPUT_TOOL_PEN: code = BTN_TOOL_PEN; break;
|
||||
case LIBINPUT_TOOL_ERASER: code = BTN_TOOL_RUBBER; break;
|
||||
case LIBINPUT_TOOL_BRUSH: code = BTN_TOOL_BRUSH; break;
|
||||
case LIBINPUT_TOOL_PENCIL: code = BTN_TOOL_PENCIL; break;
|
||||
case LIBINPUT_TOOL_AIRBRUSH: code = BTN_TOOL_AIRBRUSH; break;
|
||||
case LIBINPUT_TOOL_FINGER: code = BTN_TOOL_FINGER; break;
|
||||
case LIBINPUT_TOOL_MOUSE: code = BTN_TOOL_MOUSE; break;
|
||||
case LIBINPUT_TOOL_LENS: code = BTN_TOOL_LENS; break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -803,6 +803,7 @@ struct evdev_dispatch_interface fallback_interface = {
|
|||
NULL, /* device_suspended */
|
||||
NULL, /* device_resumed */
|
||||
fallback_tag_device,
|
||||
NULL, /* post_added */
|
||||
};
|
||||
|
||||
static uint32_t
|
||||
|
|
@ -1592,6 +1593,10 @@ evdev_notify_added_device(struct evdev_device *device)
|
|||
}
|
||||
|
||||
notify_added_device(&device->base);
|
||||
|
||||
if (device->dispatch->interface->post_added)
|
||||
device->dispatch->interface->post_added(device,
|
||||
device->dispatch);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -196,6 +196,11 @@ struct evdev_dispatch_interface {
|
|||
/* Tag device with one of EVDEV_TAG */
|
||||
void (*tag_device)(struct evdev_device *device,
|
||||
struct udev_device *udev_device);
|
||||
|
||||
/* Called immediately after the LIBINPUT_EVENT_DEVICE_ADDED event
|
||||
* was sent */
|
||||
void (*post_added)(struct evdev_device *device,
|
||||
struct evdev_dispatch *dispatch);
|
||||
};
|
||||
|
||||
struct evdev_dispatch {
|
||||
|
|
|
|||
|
|
@ -1157,6 +1157,58 @@ START_TEST(tool_capabilities)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(tool_in_prox_before_start)
|
||||
{
|
||||
struct libinput *li;
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_event *event;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_DISTANCE, 10 },
|
||||
{ ABS_TILT_X, 0 },
|
||||
{ ABS_TILT_Y, 0 },
|
||||
{ -1, -1 }
|
||||
};
|
||||
const char *devnode;
|
||||
|
||||
litest_tablet_proximity_in(dev, 10, 10, axes);
|
||||
|
||||
/* for simplicity, we create a new litest context */
|
||||
devnode = libevdev_uinput_get_devnode(dev->uinput);
|
||||
li = litest_create_context();
|
||||
libinput_path_add_device(li, devnode);
|
||||
|
||||
litest_wait_for_event_of_type(li,
|
||||
LIBINPUT_EVENT_DEVICE_ADDED,
|
||||
-1);
|
||||
event = libinput_get_event(li);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_wait_for_event_of_type(li,
|
||||
LIBINPUT_EVENT_TABLET_PROXIMITY,
|
||||
-1);
|
||||
event = libinput_get_event(li);
|
||||
libinput_event_destroy(event);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_tablet_motion(dev, 10, 20, axes);
|
||||
litest_tablet_motion(dev, 30, 40, axes);
|
||||
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_AXIS);
|
||||
litest_assert_empty_queue(li);
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_BUTTON);
|
||||
litest_tablet_proximity_out(dev);
|
||||
|
||||
litest_wait_for_event_of_type(li,
|
||||
LIBINPUT_EVENT_TABLET_PROXIMITY,
|
||||
-1);
|
||||
libinput_unref(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(mouse_tool)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -1615,6 +1667,7 @@ main(int argc, char **argv)
|
|||
{
|
||||
litest_add("tablet:tool", tool_ref, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
|
||||
litest_add_no_device("tablet:tool", tool_capabilities);
|
||||
litest_add("tablet:tool", tool_in_prox_before_start, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add("tablet:tool_serial", tool_serial, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
|
||||
litest_add("tablet:tool_serial", serial_changes_tool, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
|
||||
litest_add("tablet:tool_serial", invalid_serials, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue