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 <ran234@gmail.com> Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
parent
28c8d07109
commit
b5c05dd5f1
@ -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;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user