#include #include #include #include #include #include #include /* XF86XK_* */ #include "keycodes.h" /* from ui module */ #define X_LIBRARY_NAME "/usr/X11R6/lib/libX11.so.6" #if !DEBUG #define OVERRIDE_KEY(x) \ buf[0] = (char)x; \ buf[1] = '\0'; \ ret = 1; #define OVERRIDE_KEYSYM(x) \ *keysym = x; #else #define OVERRIDE_KEY(x) \ buf[0] = (char)x; \ buf[1] = '\0'; \ ret = 1; \ fprintf(stderr, "\t\tOVERRODE KEY TO: %d\n", x); #define OVERRIDE_KEYSYM(x) \ *keysym = x; \ fprintf(stderr, "\t\tOVERRODE KEYSYM TO: %d\n", x); #endif static void *xlib; typedef int (XLookupString_t)(XKeyEvent *, char *, int, KeySym *, XComposeStatus *); static XLookupString_t *real_XLookupString = NULL; static int key_down[2]; /* pressed state for keys we really mangle */ static int q3keyfix_init(void) __attribute__((constructor)); static void q3keyfix_fini(void) __attribute__((destructor)); static int q3keyfix_init(void) { if ((xlib = dlopen(X_LIBRARY_NAME, RTLD_NOW)) == NULL) { fprintf(stderr, "q3keyfix: failed to open %s: %s\n", X_LIBRARY_NAME, dlerror()); return -1; } if ((real_XLookupString = (XLookupString_t *)dlsym(xlib, "XLookupString")) == NULL) { fprintf(stderr, "q3keyfix: failed to get useful XLookupString symbol: %s\n", dlerror()); return -1; } memset(key_down, 0, sizeof(key_down)); return 0; } static void q3keyfix_fini(void) { if (xlib != NULL) { if (dlclose(xlib) != 0) fprintf(stderr, "q3keyfix: couldn't dlclose() %s!\n", X_LIBRARY_NAME); xlib = NULL; } } int XLookupString(XKeyEvent *xkeyevent, char *buf, int bufsize, KeySym *keysym, XComposeStatus *xcomposestatus) { int ret; if (real_XLookupString == NULL) if (q3keyfix_init() < 0) return 0; ret = real_XLookupString(xkeyevent, buf, bufsize, keysym, xcomposestatus); #if DEBUG fprintf(stderr, "XLookupString(%p, %p, %d, %p, %p) = %d\n", (void *)xkeyevent, (void *)buf, bufsize, (void *)keysym, (void *)xcomposestatus, ret); if (xkeyevent != NULL) { fprintf(stderr, "\txkeyevent:\n"); fprintf(stderr, "\t\ttype: "); switch (xkeyevent->type) { case KeyPress: fprintf(stderr, "KeyPress"); break; case KeyRelease: fprintf(stderr, "KeyRelease"); break; default: fprintf(stderr, "??? (0x%04x)", xkeyevent->type); break; } fprintf(stderr, ", serial: %ld, synthetic: %s, display: %p\n", xkeyevent->serial, xkeyevent->send_event == True ? "yes" : "no", (void *)xkeyevent->display); fprintf(stderr, "\t\twindow: 0x%08lx, root window: 0x%08lx, subwindow: 0x%08lx\n", xkeyevent->window, xkeyevent->root, xkeyevent->subwindow); fprintf(stderr, "\t\ttime: %ld, window pos: +%d+%d, root pos: +%d+%d\n", xkeyevent->time, xkeyevent->x, xkeyevent->y, xkeyevent->x_root, xkeyevent->y_root); fprintf(stderr, "\t\tstate: 0x%02x, raw keycode: %d, same_screen: %s\n", xkeyevent->state, xkeyevent->keycode, xkeyevent->same_screen == True ? "yes" : "no"); } fprintf(stderr, "\tbuffer: %s\n", buf); if (keysym != NULL) fprintf(stderr, "\tkeysym: %s (0x%04lx)\n", XKeysymToString(*keysym), *keysym); #endif /* we can't do anything in these cases */ if (keysym == NULL || xkeyevent == NULL || bufsize < 2) return ret; switch (*keysym) { /* OMISSIONS - These are keys the engine just fails to handle */ case XK_Caps_Lock: OVERRIDE_KEY(K_CAPSLOCK); break; case XK_F13: OVERRIDE_KEY(K_F13); break; case XK_F14: OVERRIDE_KEY(K_F14); break; case XK_F15: OVERRIDE_KEY(K_F15); break; case XK_Num_Lock: OVERRIDE_KEY(K_KP_NUMLOCK); break; case XK_KP_Equal: OVERRIDE_KEY(K_KP_EQUALS); break; /* ADDITIONS - These are keys the engine offers no way to bind */ case XK_Print: OVERRIDE_KEY(K_AUX1); break; case XK_Scroll_Lock: OVERRIDE_KEY(K_AUX2); break; case XK_Hyper_L: case XK_Super_L: OVERRIDE_KEY(K_AUX3); break; case XK_Hyper_R: case XK_Super_R: OVERRIDE_KEY(K_AUX4); break; case XK_Multi_key: case XK_Menu: OVERRIDE_KEY(K_AUX5); break; #ifdef XF86XK_PowerOff case XF86XK_PowerOff: OVERRIDE_KEY(K_AUX6); break; #endif #ifdef XF86XK_Sleep case XF86XK_Sleep: OVERRIDE_KEY(K_AUX7); break; #endif #ifdef XF86XK_WakeUp case XF86XK_WakeUp: OVERRIDE_KEY(K_AUX8); break; #endif /* OVERRIDES - These are cases where the in-game behavior is undesirable */ case XK_grave: /* Control + ` = NUL, but the engine expects ` */ if (!(xkeyevent->state & ControlMask)) break; OVERRIDE_KEY('`'); break; case XK_Meta_L: /* maintain what the game thinks the meta state is */ case XK_Meta_R: case XK_Alt_L: case XK_Alt_R: key_down[0] = xkeyevent->type == KeyPress; break; case XK_Return: /* * Mod1 + Enter = fullscreen toggle, but I hate this; AUX9 so * you can bind it yourself. */ if (!key_down[0] && !key_down[1]) break; OVERRIDE_KEY(K_AUX9); OVERRIDE_KEYSYM(XK_VoidSymbol); key_down[1] = xkeyevent->type == KeyPress; break; default: break; } return ret; }