diff options
Diffstat (limited to 'unsaver.c')
-rw-r--r-- | unsaver.c | 48 |
1 files changed, 40 insertions, 8 deletions
@@ -17,6 +17,7 @@ #include <X11/X.h> #include <X11/Xlib.h> +#include <X11/XKBlib.h> #include <X11/extensions/XTest.h> #include <linux/joystick.h> @@ -661,31 +662,62 @@ void connect_to_x(void) { } } -/* XXX: XKeycodeToKeysym() is deprecated. I must learn XKB. */ +/* XKeycodeToKeysym() is deprecated, hence the pragma fugliness. + Deprecated or not, the xmodmap command still uses it, and it + still works. However, XKB is the new hotness, we'll use that if + it's available. */ +KeySym keycode_is_mapped(XkbDescPtr xkbd, int i) { + if(xkbd) { + return XkbKeyNumGroups(xkbd, i) > 0; + } else { + /* if xkbd is NULL, the caller failed to init XKB. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -KeySym get_keysym(int i) { - return XKeycodeToKeysym(xdisp, i, 0); -} + return XKeycodeToKeysym(xdisp, i, 0) != NoSymbol; #pragma GCC diagnostic pop + } +} -/* the goggles, they do nothing! */ +/* The goggles, they do nothing! + Find an unused keycode in the keymap. From the shell, this would + be something like: xmodmap -pke|grep '= *$'|head -1 */ void find_keycode() { - int i, min_code = 0, max_code = 0; - + int i, ignoreme, min_code = 0, max_code = 0; + int major = XkbMajorVersion, minor = XkbMinorVersion; + XkbDescPtr xkbd = NULL; + + /* not sure any X server still running on planet Earth will lack + the XKB extension, but in case I'm wrong... */ + if(XkbQueryExtension( + xdisp, + &ignoreme, + &ignoreme, + &ignoreme, + &major, + &minor)) + { + xkbd = XkbGetMap(xdisp, XkbAllClientInfoMask, XkbUseCoreKbd); + fprintf(stderr, "using XKB extension major %d, minor %d\n", major, minor); + } else { + fprintf(stderr, "XKB extension not supported, fall back to XKeycodeToKeysym\n"); + } + /* man page doesn't document the return value */ (void)XDisplayKeycodes(xdisp, &min_code, &max_code); if(debug) fprintf(stderr, "XDisplayKeycodes min %d, max %d\n", min_code, max_code); for(i = min_code; i <= max_code; i++) { - if(get_keysym(i) == NoSymbol) { + if(!keycode_is_mapped(xkbd, i)) { keycode = i; if(debug) fprintf(stderr, "using keycode %d\n", keycode); break; } } + if(xkbd) + XkbFreeKeyboard(xkbd, XkbAllClientInfoMask, 1); + if(keycode < 0) { fprintf(stderr, "%s: can't find a free keycode in the keymap, using %d\n", |