/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* In older X, you can run this and press the "Home" key and see key * events received. In newer X, it gets an X error. */ #include #include #include #include #include #include #include #include static int xkb_opcode; static int xkb_event_base; static int xkb_error_base; static void bind_key_xkb(Display *xdisplay, XkbDescPtr xkb, KeySym keysym, KeyCode keycode) { XkbMapChangesRec changes; XkbMessageAction xma; int types[1]; memset(&changes, 0, sizeof(changes)); printf("Grabbing keysym 0x%lx keycode 0x%x using xkb\n", keysym, keycode); /* keysyms */ if (XkbResizeKeySyms(xkb, keycode, 1) == NULL) { fprintf(stderr, "XkbResizeKeySyms() failed\n"); return; } XkbKeySymEntry(xkb, keycode, 0, 0) = keysym; changes.changed |= XkbKeySymsMask; changes.first_key_sym = keycode; changes.num_key_syms = 1; /* actions */ memset(&xma, 0, sizeof(xma)); xma.type = XkbSA_ActionMessage; xma.flags = XkbSA_MessageOnPress | XkbSA_MessageOnRelease; strcpy((char*)xma.message, "!"); if (XkbResizeKeyActions(xkb, keycode, 1) == NULL) { fprintf(stderr, "XkbResizeKeyActions failed\n"); return; } XkbKeyActionEntry(xkb, keycode, 0, 0)->msg = xma; changes.changed |= XkbKeyActionsMask; changes.first_key_act = keycode; changes.num_key_acts = 1; /* groups */ types[0] = XkbOneLevelIndex; if (XkbChangeTypesOfKey(xkb, keycode, 1, XkbGroup1Mask, types, NULL) != Success) { fprintf(stderr, "XkbChangeTypesOfKey failed\n"); return; } changes.changed |= XkbKeyTypesMask; changes.first_type = XkbKeyKeyTypeIndex(xkb, keycode, 0); changes.num_types = 1; #define XKB_CHANGE_MAP_NONSENSE 1 printf("Sending map changes to server\n"); /* commit to server */ if (!XkbChangeMap(xdisplay, xkb, &changes)) { fprintf(stderr, "XkbChangeMap failed\n"); #if XKB_CHANGE_MAP_NONSENSE } else { /* XkbChangeMap apparently ignores XkbKeyActionsMask (server map) if * used together with XkbKeyTypesMask|XkbKeySymsMask (client map) */ changes.changed = XkbKeyActionsMask; if (!XkbChangeMap(xdisplay, xkb, &changes)) { fprintf(stderr, "XkbChangeMap(XkbKeyActionsMask) failed\n"); } #endif } printf("Bound key OK\n"); } static void bind_keys(Display *xdisplay, XkbDescPtr xkb) { KeySym keysym; KeyCode keycode; keysym = XK_Home; keycode = XKeysymToKeycode(xdisplay, keysym); bind_key_xkb(xdisplay, xkb, keysym, keycode); } int main(int argc, char **argv) { Display *xdisplay; XEvent xevent; XkbDescPtr xkb; xdisplay = XOpenDisplay(NULL); XSynchronize(xdisplay, True); XkbQueryExtension(xdisplay, &xkb_opcode, &xkb_event_base, &xkb_error_base, NULL, NULL); xkb = XkbGetMap(xdisplay, XkbKeySymsMask | XkbKeyTypesMask | XkbKeyActionsMask | XkbModifierMapMask | XkbVirtualModsMask, XkbUseCoreKbd); XkbSelectEvents(xdisplay, XkbUseCoreKbd, XkbMapNotifyMask | XkbActionMessageMask, XkbMapNotifyMask | XkbActionMessageMask); bind_keys(xdisplay, xkb); while (XNextEvent(xdisplay, &xevent) == Success) { if (xevent.type == MappingNotify) { printf("MappingNotify\n"); } else if (xevent.type == KeyPress) { printf("Key press event window 0x%lx root 0x%lx keycode 0x%x\n", xevent.xkey.window, xevent.xkey.root, xevent.xkey.keycode); } else if (xevent.type == (xkb_event_base + XkbEventCode)) { XkbEvent *xkbevent = (XkbEvent*)&xevent; printf("Xkb event received\n"); if (xkbevent->any.xkb_type == XkbMapNotify) { XkbMapNotifyEvent *map = &xkbevent->map; printf("XkbMapNotify\n"); XkbRefreshKeyboardMapping(map); /* Need to redo our xkb keybindings as they may have been lost. * Disable XkbMapNotify events for our own changes to avoid infinite * busy loop. */ XkbSelectEvents(xdisplay, XkbUseCoreKbd, XkbMapNotifyMask, 0); bind_keys(xdisplay, xkb); XkbSelectEvents(xdisplay, XkbUseCoreKbd, XkbMapNotifyMask, XkbMapNotifyMask); } else if (xkbevent->any.xkb_type == XkbActionMessage) { printf("XkbActionMessage %s keycode=0x%x mods=0x%x\n", xkbevent->message.press ? "press" : "release", xkbevent->message.keycode, xkbevent->message.mods); } else { printf("Xkb event xkb_type=%u\n", xkbevent->any.xkb_type); } } else { printf("event type %d\n", xevent.type); } } return 0; }