From a8cff314204d6893c014dd5ca65322683f1407e9 Mon Sep 17 00:00:00 2001 From: Tony Jansson Date: Sun, 5 Jun 2022 08:27:41 +0300 Subject: [PATCH] (X11) Add LED keyboard driver --- Makefile.common | 4 + led/drivers/led_x11_keyboard.c | 156 +++++++++++++++++++++++++++++++++ led/led_driver.c | 2 +- 3 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 led/drivers/led_x11_keyboard.c diff --git a/Makefile.common b/Makefile.common index 6a07e0c9b0..c0f8d82581 100644 --- a/Makefile.common +++ b/Makefile.common @@ -2434,6 +2434,10 @@ ifneq ($(findstring Win32,$(OS)),) OBJ += led/drivers/led_win32_keyboard.o endif +ifeq ($(HAVE_X11), 1) + OBJ += led/drivers/led_x11_keyboard.o +endif + ifeq ($(HAVE_VITAGLES), 1) DEFINES += -DHAVE_VITAGLES INCLUDE_DIRS += -I$(DEPS_DIR)/Pigs-In-A-Blanket/include diff --git a/led/drivers/led_x11_keyboard.c b/led/drivers/led_x11_keyboard.c new file mode 100644 index 0000000000..a36bed799d --- /dev/null +++ b/led/drivers/led_x11_keyboard.c @@ -0,0 +1,156 @@ +#include +#include "../led_driver.h" +#include "../led_defines.h" + +#include "../../configuration.h" +#include "../../retroarch.h" + +#include +#include + +/* Keys when setting in XKeyboardControl.led */ +#define XK_NUMLOCK 2 +#define XK_CAPSLOCK 1 +#define XK_SCROLLLOCK 3 + +/* Keys when reading from XKeyboardState.led_mask */ +#define XM_NUMLOCK 2 +#define XM_CAPSLOCK 1 +#define XM_SCROLLLOCK 4 + +static void key_translate(int *key) +{ + switch (*key) + { + case 0: + *key = XK_NUMLOCK; + break; + case 1: + *key = XK_CAPSLOCK; + break; + case 2: + *key = XK_SCROLLLOCK; + break; + default: + *key = 0; + break; + } +} + +typedef struct +{ + int setup[MAX_LEDS]; + int state[MAX_LEDS]; + int map[MAX_LEDS]; + bool init; +} keyboard_led_t; + +/* TODO/FIXME - static globals */ +static keyboard_led_t x11kb_curins; +static keyboard_led_t *x11kb_cur = &x11kb_curins; + +static int get_led(int led) +{ + Display *dpy = XOpenDisplay(0); + XKeyboardState state; + XGetKeyboardControl(dpy, &state); + XCloseDisplay(dpy); + + switch (led) + { + case XK_NUMLOCK: + return (state.led_mask & XM_NUMLOCK) ? 1 : 0; + break; + case XK_CAPSLOCK: + return (state.led_mask & XM_CAPSLOCK) ? 1 : 0; + break; + case XK_SCROLLLOCK: + return (state.led_mask & XM_SCROLLLOCK) ? 1 : 0; + break; + default: + break; + } + return 0; +} + +static void set_led(int led, int state) +{ + Display *dpy = XOpenDisplay(0); + XKeyboardControl values; + values.led = led; + values.led_mode = state ? LedModeOn : LedModeOff; + XChangeKeyboardControl(dpy, KBLed | KBLedMode, &values); + XCloseDisplay(dpy); +} + +static int keyboard_led(int led, int state) +{ + int status = 0; + int key = led; + + if ((led < 0) || (led >= MAX_LEDS)) + return -1; + + key_translate(&key); + if (!key) + return -1; + + status = get_led(key); + + if (state == -1) + return status; + + if ((state && !status) || + (!state && status)) + { + set_led(key, state); + x11kb_cur->state[led] = state; + } + return -1; +} + +static void keyboard_init(void) +{ + int i; + settings_t *settings = config_get_ptr(); + + if (!settings || x11kb_cur->init) + return; + + for (i = 0; i < MAX_LEDS; i++) + { + x11kb_cur->setup[i] = keyboard_led(i, -1); + x11kb_cur->state[i] = -1; + x11kb_cur->map[i] = settings->uints.led_map[i]; + if (x11kb_cur->map[i] < 0) + x11kb_cur->map[i] = i; + } + x11kb_cur->init = true; +} + +static void keyboard_free(void) +{ + int i; + + for (i = 0; i < MAX_LEDS; i++) + { + if (x11kb_cur->state[i] != -1 && + x11kb_cur->state[i] != x11kb_cur->setup[i]) + keyboard_led(i, x11kb_cur->setup[i]); + } +} + +static void keyboard_set(int led, int state) +{ + if ((led < 0) || (led >= MAX_LEDS)) + return; + + keyboard_led(x11kb_cur->map[led], state); +} + +const led_driver_t keyboard_led_driver = { + keyboard_init, + keyboard_free, + keyboard_set, + "Keyboard" +}; diff --git a/led/led_driver.c b/led/led_driver.c index d2dfbbe9d5..c7a6987d1c 100644 --- a/led/led_driver.c +++ b/led/led_driver.c @@ -49,7 +49,7 @@ void led_driver_init(const char *led_driver) current_led_driver = &rpi_led_driver; #endif -#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) +#if (defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)) || defined(HAVE_X11) if (string_is_equal("keyboard", drivername)) current_led_driver = &keyboard_led_driver; #endif