From aaaf8f2b5c54a2e61dc4d02805e177ed5307403a Mon Sep 17 00:00:00 2001 From: plague-spreader Date: Sun, 19 May 2024 21:38:07 +0200 Subject: [PATCH] An effort to avoid collision with lock states Does not work in this case: Preconditions: * lock state enabled and associated with the same indicator_led e.g. caps lock * layer enabled with toggle Steps to reproduce: * deactivate the lock state e.g. press caps lock Expected behavior: the lock state LED stays active (because the layer is still enabled) Actual behavior: the lock state LED turns off I think (not 100% sure and I do not have the skills/knowledge to confirm/deny this) the lock state LED turns off because the virtual device driver (or whatever) overrides its state. --- src/daemon.c | 44 ++++++++++++++++++++++++++++++++++++++++---- src/device.c | 1 + 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/daemon.c b/src/daemon.c index 6e396cd..9f0783a 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -1,4 +1,9 @@ +#include "device.h" #include "keyd.h" +#include "log.h" +#include +#include +#include struct config_ent { struct config config; @@ -16,6 +21,14 @@ static int listeners[32]; static size_t nr_listeners = 0; static struct keyboard *active_kbd = NULL; +// num/caps/scroll lock tracking to avoid collisions with LED layer indicator +// since xset supports up to 32 LEDs, a 32bit integer shall be enough to keep +// track of the LED/lock state +static uint32_t lock_state = 0; + +// has a layer been activated? +static int active_layers; + static void free_configs() { struct config_ent *ent = configs; @@ -52,6 +65,22 @@ static void send_key(uint8_t code, uint8_t state) vkbd_send_key(vkbd, code, state); } +static void set_led(const struct device *dev, int led, int new_state) +{ + // Function to handle correctly the LED of the layer indicator + dbg("set_led(%s, %d, %d)", dev->id, led, new_state); + dbg("active_layers = %d", active_layers); + dbg("lock_state = %d", lock_state); + dbg("lock_state & (1 << led) = %d", lock_state & (1 << led)); + if (active_kbd != NULL && led == active_kbd->config.indicator_led) { + // if the num/caps/scroll lock is on or a layer is active then do NOT + // turn off the indicator LED + new_state |= !!((lock_state & (1 << led)) || active_layers); + dbg("new_state = %d", new_state); + } + device_set_led(dev, led, new_state); +} + static void add_listener(int con) { struct timeval tv; @@ -100,7 +129,7 @@ static void on_layer_change(const struct keyboard *kbd, const struct layer *laye size_t n = 0; if (kbd->config.layer_indicator) { - int active_layers = 0; + active_layers = 0; for (i = 1; i < kbd->config.nr_layers; i++) if (kbd->config.layers[i].type != LT_LAYOUT && kbd->layer_state[i].active) { @@ -110,7 +139,7 @@ static void on_layer_change(const struct keyboard *kbd, const struct layer *laye for (i = 0; i < device_table_sz; i++) if (device_table[i].data == kbd) - device_set_led(&device_table[i], kbd->config.indicator_led, active_layers); + set_led(&device_table[i], kbd->config.indicator_led, active_layers); } if (!nr_listeners) @@ -506,11 +535,18 @@ static int event_handler(struct event *ev) * Propagate LED events received by the virtual device from userspace * to all grabbed devices. * - * NOTE/TODO: Account for potential layer_indicator interference + * To account for potential layer_indicator interference, the led status is saved */ + + if (ev->devev->pressed) { + lock_state |= (1 << ev->devev->code); + } else { + lock_state &= 0xffffffff ^ (1 << ev->devev->code); + } + for (i = 0; i < device_table_sz; i++) if (device_table[i].data) - device_set_led(&device_table[i], ev->devev->code, ev->devev->pressed); + set_led(&device_table[i], ev->devev->code, ev->devev->pressed); } break; diff --git a/src/device.c b/src/device.c index c7bc5fb..3034c5b 100644 --- a/src/device.c +++ b/src/device.c @@ -519,6 +519,7 @@ struct device_event *device_read_event(struct device *dev) void device_set_led(const struct device *dev, int led, int state) { + dbg2("device_set_led(%s, %d, %d);", dev->id, led, state); struct input_event ev = { .type = EV_LED, .code = led,