From b5c05dd5f1523fafded15297001b44efebab9914 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Fri, 26 Oct 2012 18:14:32 +0200 Subject: [PATCH] uterm_input_uxkb: update leds to match keyboard state Upon device wakeup or led state changes, we update the keyboard LEDs to match the new xkb state. This means that every kmscon instance retains its own LED state, in the users eyes. In other words, if you had Num Lock set on one kmscon, switched to an X VT where it's off, and come back, then Num Lock will be set as when you left. This is what X server, linux VT, etc. do. Note that since we need to write the LED events to the evdev devices, we need to open them RDWR. But since we don't really care what happens to that write(), that's fine. Also note that this means NumLock is off by default, which might be annoying. We need to think how to get some 'setleds' or 'numlockx' equivalent functionality. Signed-off-by: Ran Benita Signed-off-by: David Herrmann --- src/uterm_input.c | 2 +- src/uterm_input_uxkb.c | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/uterm_input.c b/src/uterm_input.c index 56d017d..0dbbe70 100644 --- a/src/uterm_input.c +++ b/src/uterm_input.c @@ -104,7 +104,7 @@ static int input_wake_up_dev(struct uterm_input_dev *dev) if (dev->rfd >= 0) return 0; - dev->rfd = open(dev->node, O_CLOEXEC | O_NONBLOCK | O_RDONLY); + dev->rfd = open(dev->node, O_CLOEXEC | O_NONBLOCK | O_RDWR); if (dev->rfd < 0) { log_warn("cannot open device %s (%d): %m", dev->node, errno); return -EFAULT; diff --git a/src/uterm_input_uxkb.c b/src/uterm_input_uxkb.c index 9c93b5d..969072d 100644 --- a/src/uterm_input_uxkb.c +++ b/src/uterm_input_uxkb.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "log.h" #include "shl_hook.h" @@ -137,6 +138,35 @@ enum { KEY_REPEATED = 2, }; +static void uxkb_dev_update_keyboard_leds(struct uterm_input_dev *dev) +{ + static const struct { + int evdev_led; + const char *xkb_led; + } leds[] = { + { LED_NUML, XKB_LED_NAME_NUM }, + { LED_CAPSL, XKB_LED_NAME_CAPS }, + { LED_SCROLLL, XKB_LED_NAME_SCROLL }, + }; + struct input_event events[sizeof(leds) / sizeof(*leds)]; + int i; + + if (!(dev->capabilities & UTERM_DEVICE_HAS_LEDS)) + return; + + memset(events, 0, sizeof(events)); + + for (i = 0; i < sizeof(leds) / sizeof(*leds); i++) { + events[i].type = EV_LED; + events[i].code = leds[i].evdev_led; + if (xkb_state_led_name_is_active(dev->state, + leds[i].xkb_led) > 0) + events[i].value = 1; + } + + write(dev->rfd, events, sizeof(events)); +} + static inline int uxkb_dev_resize_event(struct uterm_input_dev *dev, size_t s) { uint32_t *tmp; @@ -269,6 +299,7 @@ int uxkb_dev_process(struct uterm_input_dev *dev, xkb_keycode_t keycode; const xkb_keysym_t *keysyms; int num_keysyms, ret; + enum xkb_state_component changed; if (key_state == KEY_REPEATED) return -ENOKEY; @@ -278,10 +309,14 @@ int uxkb_dev_process(struct uterm_input_dev *dev, num_keysyms = xkb_state_key_get_syms(state, keycode, &keysyms); + changed = 0; if (key_state == KEY_PRESSED) - xkb_state_update_key(state, keycode, XKB_KEY_DOWN); + changed = xkb_state_update_key(state, keycode, XKB_KEY_DOWN); else if (key_state == KEY_RELEASED) - xkb_state_update_key(state, keycode, XKB_KEY_UP); + changed = xkb_state_update_key(state, keycode, XKB_KEY_UP); + + if (changed & XKB_STATE_LEDS) + uxkb_dev_update_keyboard_leds(dev); if (num_keysyms <= 0) return -ENOKEY; @@ -324,4 +359,6 @@ void uxkb_dev_reset(struct uterm_input_dev *dev) } xkb_state_unref(dev->state); dev->state = state; + + uxkb_dev_update_keyboard_leds(dev); } -- 2.7.4