int16_t modfield_from_keysym(xcb_keysym_t keysym) { uint16_t modfield = 0; xcb_keycode_t *keycodes = NULL, *mod_keycodes = NULL; xcb_get_modifier_mapping_reply_t *reply = NULL; xcb_key_symbols_t *symbols = xcb_key_symbols_alloc(dpy); if ((keycodes = xcb_key_symbols_get_keycode(symbols, keysym)) == NULL || (reply = xcb_get_modifier_mapping_reply(dpy, xcb_get_modifier_mapping(dpy), NULL)) == NULL || reply->keycodes_per_modifier < 1 || (mod_keycodes = xcb_get_modifier_mapping_keycodes(reply)) == NULL) { goto end; } unsigned int num_mod = xcb_get_modifier_mapping_keycodes_length(reply) / reply->keycodes_per_modifier; for (unsigned int i = 0; i < num_mod; i++) { for (unsigned int j = 0; j < reply->keycodes_per_modifier; j++) { xcb_keycode_t mk = mod_keycodes[i * reply->keycodes_per_modifier + j]; if (mk == XCB_NO_SYMBOL) { continue; } for (xcb_keycode_t *k = keycodes; *k != XCB_NO_SYMBOL; k++) { if (*k == mk) { modfield |= (1 << i); } } } } end: xcb_key_symbols_free(symbols); free(keycodes); free(reply); return modfield; }
XRecordKeyboardMonitor::XRecordKeyboardMonitor(Display *display) : m_connection(xcb_connect(XDisplayString(display), 0)), m_modifiersPressed(0), m_keysPressed(0) { if (!m_connection) { return; } xcb_get_modifier_mapping_cookie_t modmapCookie = xcb_get_modifier_mapping(m_connection); m_context = xcb_generate_id(m_connection); xcb_record_range_t range; memset(&range, 0, sizeof(range)); range.device_events.first = XCB_KEY_PRESS; range.device_events.last = XCB_KEY_RELEASE; xcb_record_client_spec_t cs = XCB_RECORD_CS_ALL_CLIENTS; xcb_record_create_context(m_connection, m_context, 0, 1, 1, &cs, &range); xcb_flush(m_connection); QScopedPointer<xcb_get_modifier_mapping_reply_t, QScopedPointerPodDeleter> modmap(xcb_get_modifier_mapping_reply(m_connection, modmapCookie, 0)); if (!modmap) { return; } int nModifiers = xcb_get_modifier_mapping_keycodes_length(modmap.data()); xcb_keycode_t *modifiers = xcb_get_modifier_mapping_keycodes(modmap.data()); m_modifier.fill(false, std::numeric_limits<xcb_keycode_t>::max() + 1); for (xcb_keycode_t *i = modifiers; i < modifiers + nModifiers; i++) { m_modifier[*i] = true; } m_ignore.fill(false, std::numeric_limits<xcb_keycode_t>::max() + 1); for (xcb_keycode_t *i = modifiers; i < modifiers + modmap->keycodes_per_modifier; i++) { m_ignore[*i] = true; } m_pressed.fill(false, std::numeric_limits<xcb_keycode_t>::max() + 1); m_cookie = xcb_record_enable_context(m_connection, m_context); xcb_flush(m_connection); m_notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read, this); connect(m_notifier, SIGNAL(activated(int)), SLOT(processNextReply())); m_notifier->setEnabled(true); }