WM-agnostic key bindings

I've been trying different desktop environments/window managers. It was mostly fun, but I had the same problem for most of them: dealing with layouts and keybindings.

For example, AwesomeWM key bindings are assigned in rc.lua like this:

awful.key({ modkey, },
function () awful.spawn("firefox --private-window") end,
{description = "'w': run web browser", group = "launcher"}),

This will bind Mod4+e spawn firefox browser in private mode. However, if you'll change layout, then this will not work any more if you keep hitting the same key. As one of the developers pointed out in the GitHub issue, keys are binded to symbols, not keys.

My first solution was to reassign mapping to key codes like this:

awful.key({ modkey, },
function () awful.spawn("firefox --private-window") end,
{description = "'w': run web browser", group = "launcher"}),

Now it worked on both keyboard layouts, but now it's kinda unreadable.

Few weeks ago I decided to give dwm a try. It was fun to configure it and figure out how does it work, but I ended up with the same layout problem.

Instead of parsing symbols, dwm uses X11 key codes like this:

{ MODKEY, XK_e, spawn, {.v = { "firefox --private-window", NULL } },

This looks better when AwesomeWM way, but I failed to remap Caps Lock or Shift+Alt for keyboard layout switch. Then I tried combinations like Shift+S, but it didn't work as well.

I'm still not sure why exactly it's not working, I suspect that X layout may be different for different windows/sessions, so it doesn't affect actual active window. Anyway, after few hours tinkering around with dwm I decided to write my own shell script for layout switching, it looks like this:


us_map=$(setxkbmap -query | grep us,us)
if [ -z "$us_map" ]; then
   setxkbmap us,us -model pc104 -variant alt-int
   setxkbmap ru,us -model pc104 -variant alt-int

Then I put this file to /opt/ and modifed my X11 key bindings like this:


  m:0x2 + c:66

You can add more bindings:


  m:0x40 + c:25
  Mod4 + w

"firefox --private-window"
  m:0x40 + c:26
  Mod4 + e

Bindings begin to work as soon as you run xbindkeys command. If you want to have it on system start-up, add it to ~/.xinitrc (btw it means that those key bindings will work in login manager too!).

But how you figure out those m:0xNN +c:XX codes? Just run xbindkeys -k command in the terminal. It will spawn window. After you press your key combination, it will exit and print required codes.