Something strange happening with xbindkey and keystate_numlock

I’m using xbindkey to launch a few scripts from keyboard shortcuts, it works just fine, but today I wanted to set keystate_numlock=enable inside the xbindkeysrc config file, and that works too, but something strange happens. My ctrl+alt+q keybind does not work, but if I hit the numlock key, my keybind works, if I hit numlock again, that ctrl+alt+q keybind doesn’t work again, I find this to be very strange, what does the numlock key has anything to do with the ctrl+alt+q shortcut?
I just commented out keystate_numlock and everything is back to normal but I’m that kind of guy that’s curious as why something like this happen, maybe someone has at least a vague ideea. Cheers!

When applications grab keys to be watched (binding) it needs to supply a bit mask for what modifiers are associated with that binding, I’ve got a fair bit of knowledge on this after writing the wm.

Numlock is a strange key overall, it can always be present on binds based on whether it was active during the grab, most applications get around this by grabbing a number of different masked binds: one with just the key, with the key and numlock, and with the key; numlock; and other modifiers. The application is also responsible for determining the bit mask that numlock uses on any given computer as they can differ.

I assume what xbindkeys is doing with their numlock state flag is to allow the user to only grab keys with a specific numlock state. In dk I just find out what the numlock bit mask is before grabbing keys and create a bind for every possible state of numlock. This way the binds work regardless if numlock is enabled or not.

From man 1 xbindkeys

  By defaults, xbindkeys does not pay attention to the modifiers NumLock,  CapsLock  and  ScrollLock.   Add  the
  lines below in the configuration file if you want to pay attention to them.

    keystate_numlock = enable
    keystate_capslock = enable
    keystate_scrolllock= enable

It also lists modifiers that would need to be used for bind (note the num/caps/scroll)

  List of modifiers:
     Release, Control, Shift, Mod1 (Alt), Mod2 (NumLock),
     Mod3 (CapsLock), Mod4, Mod5 (Scroll).

So you would need to make seperate binds for when numlock is enabled or not using Mod2

Example of what’s going on under the hood for grabbing keys/buttons

void grabbuttons(Client *c)
{
	xcb_generic_error_t *e;
	xcb_get_modifier_mapping_reply_t *m = NULL;

	/* determine the current numlock bit mask */
	lockmask = 0;
	if ((m = xcb_get_modifier_mapping_reply(con, xcb_get_modifier_mapping(con), &e))) {
		xcb_keycode_t *k, *t = NULL;
		if ((t = xcb_key_symbols_get_keycode(keysyms, 0xff7f))
				&& (k = xcb_get_modifier_mapping_keycodes(m)))
		{
			for (unsigned int i = 0; i < 8; i++)
				for (unsigned int j = 0; j < m->keycodes_per_modifier; j++)
					if (k[i * m->keycodes_per_modifier + j] == *t)
						lockmask = (1 << i); /* shift in the bit */
		}
		free(t);
	} else {
		iferr(0, "unable to get modifier mapping for numlock", e);
	}
	free(m);

	/* free up any previous grabs */
	xcb_ungrab_button(con, XCB_BUTTON_INDEX_ANY, c->win, XCB_BUTTON_MASK_ANY);

	/* grab every button with basic masks for click-to-focus */
	xcb_grab_button(con, 0, c->win, XCB_EVENT_MASK_BUTTON_PRESS,
			XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC, XCB_NONE, XCB_NONE,
			XCB_BUTTON_INDEX_ANY, XCB_BUTTON_MASK_ANY);

	/* create all the bit masks needed for grabbing keys with numlock enabled/disabled */
	unsigned int mods[] = { 0, XCB_MOD_MASK_LOCK, lockmask, lockmask | XCB_MOD_MASK_LOCK };

	/* for each numlock mask grab the buttons with that mask plus our MOD key */
	for (unsigned int i = 0; i < LEN(mods); i++) {
		xcb_grab_button(con, 0, c->win,
				XCB_EVENT_MASK_BUTTON_PRESS,
				XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC, XCB_NONE, XCB_NONE,
				mousemove, mousemod | mods[i]);
		xcb_grab_button(con, 0, c->win,
				XCB_EVENT_MASK_BUTTON_PRESS,
				XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC, XCB_NONE, XCB_NONE,
				mouseresize, mousemod | mods[i]);
	}
}

Perhaps a bit long winded response but I found it a bit difficult to articulate exactly what’s going on. Feel free to ask follow up and I can probably elaborate further.

1 Like

I wasn’t expecting such a detailed answer :grin: There’s nothing much to follow up from my side after such a reply, it is all allot clearer now, for me I’ll just have to leave keystate_numlock commented out and xbindkeys works normally no matter if numlock is manually set on or off.
Btw, I need to find some time this week to try your DK, Openbox is the only wm that I used up to now but I’m all about floating and manual tilling. Can the most common settings be done from the rc file or one needs to get the hands dirty with the .h file and recompiling?

Thanks allot for your time!

Yes, one of the main differences to predecessors like dwm is that everything is configurable through binds, scripts, and the rc file. More advanced configuration and patching is still supported through the config.h suckless style though.

1 Like