Skip to content

Commit

Permalink
An effort to avoid collision with lock states
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
plague-spreader committed May 19, 2024
1 parent a742a24 commit aaaf8f2
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
44 changes: 40 additions & 4 deletions src/daemon.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
#include "device.h"
#include "keyd.h"
#include "log.h"
#include <linux/input-event-codes.h>
#include <linux/input.h>
#include <stdint.h>

struct config_ent {
struct config config;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit aaaf8f2

Please sign in to comment.