#include #include #include #include #include #include struct ctx { xcb_connection_t *conn; uint8_t first_xkb_event; }; static void handle_xkb_event(struct ctx *ctx, xcb_generic_event_t *event) { union xkb_event { struct { uint8_t response_type; uint8_t xkbType; uint16_t sequence; xcb_timestamp_t time; uint8_t deviceID; } any; xcb_xkb_map_notify_event_t map_notify; xcb_xkb_state_notify_event_t state_notify; } *xkb_event; xkb_event = (union xkb_event *) event; switch (xkb_event->any.xkbType) { case XCB_XKB_NEW_KEYBOARD_NOTIFY: printf("xkb new keyboard notify\n"); break; case XCB_XKB_MAP_NOTIFY: printf("xkb map notify\n"); break; case XCB_XKB_STATE_NOTIFY: printf("xkb state notify\n"); break; default: break; } } static void loop(struct ctx *ctx) { while (true) { xcb_generic_event_t *event; event = xcb_wait_for_event(ctx->conn); if (!event) errx(1, "couldn't get event"); if (event->response_type == XCB_MAPPING_NOTIFY) { printf("core mapping notify\n"); } if (event->response_type == ctx->first_xkb_event) { handle_xkb_event(ctx, event); } free(event); } } static void setup_xkb(struct ctx *ctx) { { const xcb_query_extension_reply_t *ext; ext = xcb_get_extension_data(ctx->conn, &xcb_xkb_id); if (!ext) errx(1, "no XKB in X server"); ctx->first_xkb_event = ext->first_event; } { xcb_xkb_use_extension_cookie_t use_ext; xcb_xkb_use_extension_reply_t *use_ext_reply; use_ext = xcb_xkb_use_extension(ctx->conn, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION); use_ext_reply = xcb_xkb_use_extension_reply(ctx->conn, use_ext, NULL); if (!use_ext_reply) errx(1, "couldn't use XKB extension"); if (!use_ext_reply->supported) errx(1, "the XKB extension is not supported in X server"); free(use_ext_reply); } { xcb_void_cookie_t select; xcb_generic_error_t *error; static const uint16_t affectWhich = (XCB_XKB_EVENT_TYPE_MAP_NOTIFY | XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | XCB_XKB_EVENT_TYPE_STATE_NOTIFY); static const uint16_t affectMap = (XCB_XKB_MAP_PART_KEY_TYPES | XCB_XKB_MAP_PART_KEY_SYMS | XCB_XKB_MAP_PART_MODIFIER_MAP | XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS | XCB_XKB_MAP_PART_KEY_ACTIONS | XCB_XKB_MAP_PART_KEY_BEHAVIORS | XCB_XKB_MAP_PART_VIRTUAL_MODS | XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP); select = xcb_xkb_select_events_checked(ctx->conn, XCB_XKB_ID_USE_CORE_KBD, affectWhich, 0, affectWhich, affectMap, affectMap, NULL); error = xcb_request_check(ctx->conn, select); if (error) errx(1, "couldn't select XKB events"); } } int main(void) { struct ctx ctx; ctx.conn = xcb_connect(NULL, NULL); if (!ctx.conn) errx(1, "couldn't connect to display"); setup_xkb(&ctx); loop(&ctx); xcb_disconnect(ctx.conn); return 0; }