From ec623bc35bcf8f170e30b72903cd7b6edbcf0dd7 Mon Sep 17 00:00:00 2001 From: kikadf Date: Fri, 30 Jan 2026 11:05:59 +0100 Subject: [PATCH 1/2] Handle auto-repeat per device instead of globally --- src/wscons.c | 10 +++++----- src/wscons.h | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/wscons.c b/src/wscons.c index 2120f073..6f984cc9 100644 --- a/src/wscons.c +++ b/src/wscons.c @@ -45,8 +45,6 @@ static void wscons_device_init_pointer_acceleration(struct wscons_device *device, struct motion_filter *filter); -static int old_value = -1; - static int udev_input_enable(struct libinput *libinput) { @@ -128,13 +126,13 @@ wscons_process(struct libinput_device *device, struct wscons_event *wsevent) key = wsevent->value; if (wsevent->type == WSCONS_EVENT_KEY_UP) { kstate = LIBINPUT_KEY_STATE_RELEASED; - old_value = -1; + dev->old_value = -1; } else { kstate = LIBINPUT_KEY_STATE_PRESSED; /* ignore auto-repeat */ - if (key == old_value) + if (key == dev->old_value) return; - old_value = key; + dev->old_value = key; } keyboard_notify_key(device, time, wskey_transcode(wscons_device(device)->scanCodeMap, key), kstate); @@ -517,6 +515,8 @@ wscons_device_init(struct wscons_device *wscons_device) { struct libinput_device *device = &wscons_device->base; + wscons_device->old_value = -1; + if (strncmp(device->devname, "/dev/wsmouse", 12) == 0) { /* XXX handle tablets and touchpanel */ wscons_device->capability = LIBINPUT_DEVICE_CAP_POINTER; diff --git a/src/wscons.h b/src/wscons.h index 636e7487..2124eb21 100644 --- a/src/wscons.h +++ b/src/wscons.h @@ -18,6 +18,7 @@ struct wscons_device { struct libinput_device base; enum libinput_device_capability capability; struct TransMapRec *scanCodeMap; + int old_value; struct { struct libinput_device_config_accel config; struct motion_filter *filter; From 0583d1a79521db9d657fe2dd5348b3f19388df4e Mon Sep 17 00:00:00 2001 From: kikadf Date: Fri, 30 Jan 2026 11:52:08 +0100 Subject: [PATCH 2/2] Handle attached-detached devices with udev monitor --- src/wscons.c | 147 ++++++++++++++++++++++++++++++++++++++++----------- src/wscons.h | 6 +++ 2 files changed, 121 insertions(+), 32 deletions(-) diff --git a/src/wscons.c b/src/wscons.c index 6f984cc9..053cbaea 100644 --- a/src/wscons.c +++ b/src/wscons.c @@ -45,51 +45,121 @@ static void wscons_device_init_pointer_acceleration(struct wscons_device *device, struct motion_filter *filter); -static int -udev_input_enable(struct libinput *libinput) +static void +wscons_udev_handler(void *data) { + struct udev_input *input = data; + struct udev_device *udev_device; struct libinput_seat *seat; struct libinput_device *device; + uint64_t time; + struct timespec ts; + struct libinput_event *event; + const char *action, *devnode, *sysname; - seat = wscons_seat_get(libinput, default_seat, default_seat_name); - list_for_each(device, &seat->devices_list, link) { - device->fd = open_restricted(libinput, device->devname, O_RDWR); - device->source = - libinput_add_fd(libinput, device->fd, - wscons_device_dispatch, device); - if (!device->source) { - return -ENOMEM; + udev_device = udev_monitor_receive_device(input->udev_monitor); + if (!udev_device) + return; + + action = udev_device_get_action(udev_device); + devnode = udev_device_get_devnode(udev_device); + sysname = udev_device_get_sysname(udev_device); + if (!action || !devnode || !sysname) + goto out; + + if (!(strneq(sysname, "wskbd", 5) || strneq(sysname, "wsmouse", 7))) + goto out; + + if (streq(action, "add")) { + device = libinput_path_add_device(&input->base, devnode); + if (!device) + goto out; + clock_gettime(CLOCK_REALTIME, &ts); + time = s2us(ts.tv_sec) + ns2us(ts.tv_nsec); + event = calloc(1, sizeof(*event)); + post_device_event(device, time, LIBINPUT_EVENT_DEVICE_ADDED, event); + } + else if (streq(action, "remove")) { + seat = wscons_seat_get(&input->base, default_seat, default_seat_name); + list_for_each(device, &seat->devices_list, link) { + if (device->devname && strcmp(device->devname, devnode) == 0) { + clock_gettime(CLOCK_REALTIME, &ts); + time = s2us(ts.tv_sec) + ns2us(ts.tv_nsec); + event = calloc(1, sizeof(*event)); + post_device_event(device, time, LIBINPUT_EVENT_DEVICE_REMOVED, event); + libinput_path_remove_device(device); + break; + } } } - return 0; + +out: + udev_device_unref(udev_device); +} + +static int +udev_input_enable(struct libinput *libinput) +{ + struct udev_input *input = (struct udev_input *)libinput; + struct udev *udev = input->udev; + int fd; + + input->udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (!input->udev_monitor) { + log_info(libinput, "udev: failed to create the udev monitor\n"); + return -1; + } + + if (udev_monitor_filter_add_match_subsystem_devtype(input->udev_monitor, "input", NULL)) { + log_info(libinput, "udev: failed to set up filter\n"); + goto err; + } + + if (udev_monitor_enable_receiving(input->udev_monitor)) { + log_info(libinput, "udev: failed to bind the udev monitor\n"); + goto err; + } + + fd = udev_monitor_get_fd(input->udev_monitor); + input->udev_monitor_source = + libinput_add_fd(&input->base, fd, wscons_udev_handler, input); + if (!input->udev_monitor_source) { + goto err; + } + + return 0; + +err: + if (input->udev_monitor) { + udev_monitor_unref(input->udev_monitor); + input->udev_monitor = NULL; + } + return -1; } static void udev_input_disable(struct libinput *libinput) { - struct libinput_seat *seat; - struct libinput_device *device; + struct udev_input *input = (struct udev_input*)libinput; - seat = wscons_seat_get(libinput, default_seat, default_seat_name); - list_for_each(device, &seat->devices_list, link) { - if (device->source) { - libinput_remove_source(libinput, device->source); - device->source = NULL; - } - close_restricted(libinput, device->fd); + if (input->udev_monitor_source) { + libinput_remove_source(&input->base, input->udev_monitor_source); + input->udev_monitor_source = NULL; + } + if (input->udev_monitor) { + udev_monitor_unref(input->udev_monitor); + input->udev_monitor = NULL; } } static void udev_input_destroy(struct libinput *libinput) { - struct libinput_seat *seat; - struct libinput_device *device; + struct udev_input *input = (struct udev_input*)libinput; - fprintf(stderr, "%s", __func__); - seat = wscons_seat_get(libinput, default_seat, default_seat_name); - list_for_each(device, &seat->devices_list, link) { - close_restricted(libinput, device->fd); + if (input->udev) { + udev_unref(input->udev); + input->udev = NULL; } } @@ -283,17 +353,24 @@ libinput_udev_create_context(const struct libinput_interface *interface, void *user_data, struct udev *udev) { - struct libinput *libinput; + struct udev_input *input; - libinput = calloc(1, sizeof(*libinput)); - if (libinput == NULL) + if (!interface || !udev) + return NULL; + + input = calloc(1, sizeof(*input)); + if (!input) return NULL; - if (libinput_init(libinput, interface, &interface_backend, user_data) != 0) { - free(libinput); + if (libinput_init(&input->base, interface, &interface_backend, user_data) != 0) { + libinput_unref(&input->base); + free(input); return NULL; } - return libinput; + + input->udev = udev_ref(udev); + + return &input->base; } LIBINPUT_EXPORT int @@ -305,6 +382,7 @@ libinput_udev_assign_seat(struct libinput *libinput, const char *seat_id) uint64_t time; struct timespec ts; struct libinput_event *event; + struct udev_input *input = (struct udev_input*)libinput; /* Add standard devices */ for (int i = 0; i < 10; i++) { @@ -330,6 +408,10 @@ libinput_udev_assign_seat(struct libinput *libinput, const char *seat_id) post_device_event(device, time, LIBINPUT_EVENT_DEVICE_ADDED, event); } + + if (udev_input_enable(&input->base) < 0) + return -1; + return 0; } @@ -587,6 +669,7 @@ libinput_path_remove_device(struct libinput_device *device) { struct libinput *libinput = device->seat->libinput; + list_remove(&device->link); libinput_remove_source(libinput, device->source); device->source = NULL; diff --git a/src/wscons.h b/src/wscons.h index 2124eb21..3711b54d 100644 --- a/src/wscons.h +++ b/src/wscons.h @@ -25,6 +25,12 @@ struct wscons_device { } pointer; }; +struct udev_input { + struct libinput base; + struct udev *udev; + struct udev_monitor *udev_monitor; + struct libinput_source *udev_monitor_source; +}; static inline struct wscons_device * wscons_device(struct libinput_device *device)