diff --git a/Makefile b/Makefile index 36a834b8..f03f55ff 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ CFLAGS += -DI3_VERSION=\"${GIT_VERSION}\" LDFLAGS += -lm LDFLAGS += -lxcb-wm -#LDFLAGS += -lxcb-keysyms +LDFLAGS += -lxcb-keysyms LDFLAGS += -lxcb-xinerama LDFLAGS += -lX11 LDFLAGS += -L/usr/local/lib -L/usr/pkg/lib diff --git a/include/xcb.h b/include/xcb.h index 4302fbcb..7ba80867 100644 --- a/include/xcb.h +++ b/include/xcb.h @@ -22,6 +22,9 @@ #define XCB_CURSOR_SB_H_DOUBLE_ARROW 108 #define XCB_CURSOR_SB_V_DOUBLE_ARROW 116 +/* from X11/keysymdef.h */ +#define XCB_NUM_LOCK 0xff7f + /* The event masks are defined here because we don’t only set them once but we need to set slight variations of them (without XCB_EVENT_MASK_ENTER_WINDOW while rendering the layout) */ /* The XCB_CW_EVENT_MASK for the child (= real window) */ @@ -51,6 +54,8 @@ enum { _NET_SUPPORTED = 0, UTF8_STRING }; +extern unsigned int xcb_numlock_mask; + i3Font *load_font(xcb_connection_t *conn, const char *pattern); uint32_t get_colorpixel(xcb_connection_t *conn, char *hex); xcb_window_t create_window(xcb_connection_t *conn, Rect r, uint16_t window_class, int cursor, @@ -61,5 +66,6 @@ void xcb_draw_line(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext void xcb_draw_rect(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext_t gc, uint32_t colorpixel, uint32_t x, uint32_t y, uint32_t width, uint32_t height); void fake_configure_notify(xcb_connection_t *conn, Rect r, xcb_window_t window); +void xcb_get_numlock_mask(xcb_connection_t *conn); #endif diff --git a/src/handlers.c b/src/handlers.c index c06f4853..7f4b491c 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -107,7 +107,7 @@ int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_ LOG("state %d\n", event->state); /* Remove the numlock bit, all other bits are modifiers we can bind to */ - uint16_t state_filtered = event->state & ~XCB_MOD_MASK_LOCK; + uint16_t state_filtered = event->state & ~(xcb_numlock_mask | XCB_MOD_MASK_LOCK); /* Find the binding */ Binding *bind; diff --git a/src/mainx.c b/src/mainx.c index bbd1efcd..ef71b0fa 100644 --- a/src/mainx.c +++ b/src/mainx.c @@ -503,13 +503,22 @@ int main(int argc, char *argv[], char *env[]) { xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTING_WM_CHECK], WINDOW, 32, 1, &root); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_WM_NAME], atoms[UTF8_STRING], 8, strlen("i3"), "i3"); + xcb_get_numlock_mask(conn); + /* Grab the bound keys */ Binding *bind; TAILQ_FOREACH(bind, &bindings, bindings) { LOG("Grabbing %d\n", bind->keycode); if (bind->mods & BIND_MODE_SWITCH) xcb_grab_key(conn, 0, root, 0, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC); - else xcb_grab_key(conn, 0, root, bind->mods, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); + else { + /* Grab the key in all combinations */ + #define GRAB_KEY(modifier) xcb_grab_key(conn, 0, root, modifier, bind->keycode, \ + XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC) + GRAB_KEY(bind->mods); + GRAB_KEY(bind->mods | xcb_numlock_mask); + GRAB_KEY(bind->mods | xcb_numlock_mask | XCB_MOD_MASK_LOCK); + } } /* check for Xinerama */ diff --git a/src/xcb.c b/src/xcb.c index f7f5c5f1..dc83efa5 100644 --- a/src/xcb.c +++ b/src/xcb.c @@ -16,12 +16,14 @@ #include #include +#include #include "util.h" #include "xcb.h" TAILQ_HEAD(cached_fonts_head, Font) cached_fonts = TAILQ_HEAD_INITIALIZER(cached_fonts); SLIST_HEAD(colorpixel_head, Colorpixel) colorpixels; +unsigned int xcb_numlock_mask; /* * Loads a font for usage, getting its height. This function is used very often, so it @@ -209,3 +211,48 @@ void fake_configure_notify(xcb_connection_t *conn, Rect r, xcb_window_t window) LOG("Told the client it is at %dx%d with %dx%d\n", r.x, r.y, r.width, r.height); } + +/* + * Finds out which modifier mask is the one for numlock, as the user may change this. + * + */ +void xcb_get_numlock_mask(xcb_connection_t *conn) { + xcb_key_symbols_t *keysyms; + xcb_get_modifier_mapping_cookie_t cookie; + xcb_get_modifier_mapping_reply_t *reply; + xcb_keycode_t *modmap, numlock; + int mask, i; + const int masks[8] = { XCB_MOD_MASK_SHIFT, + XCB_MOD_MASK_LOCK, + XCB_MOD_MASK_CONTROL, + XCB_MOD_MASK_1, + XCB_MOD_MASK_2, + XCB_MOD_MASK_3, + XCB_MOD_MASK_4, + XCB_MOD_MASK_5 }; + + /* Request the modifier map */ + cookie = xcb_get_modifier_mapping_unchecked(conn); + + /* Get the keysymbols */ + keysyms = xcb_key_symbols_alloc(conn); + + if ((reply = xcb_get_modifier_mapping_reply(conn, cookie, NULL)) == NULL) { + xcb_key_symbols_free(keysyms); + return; + } + + modmap = xcb_get_modifier_mapping_keycodes(reply); + + /* Get the keycode for numlock */ + numlock = xcb_key_symbols_get_keycode(keysyms, XCB_NUM_LOCK); + + /* Check all modifiers (Mod1-Mod5, Shift, Control, Lock) */ + for (mask = 0; mask < sizeof(masks); mask++) + for (i = 0; i < reply->keycodes_per_modifier; i++) + if (modmap[(mask * reply->keycodes_per_modifier) + i] == numlock) + xcb_numlock_mask = masks[mask]; + + xcb_key_symbols_free(keysyms); + free(reply); +}