How to make sway act like ratpoison
Sway is an
i3-compatible
Wayland compositor.
Ratpoison is a tiling window
manager for X11 that is largely modeled after GNU
screen. After a lost couple of
years in the WIMPy
land of GNOME, I wanted to go back to a
tiling window manager on my desktop system. I still wanted to stick
to Wayland (X11 is soon becoming
retrocomputing),
which leaves sway as the only option. However, I have no prior love
of i3, and I found the default key shortcuts bad. Specifically, sway
assumes that it can be granted an entire modifier key (say, Alt)
for key shortcuts. As an example, Alt-f
makes a window full
screen. A window manager making such assumptions is intolerable in
the presence of software like GNU
Emacs, which needs all the
modifier keys it can get. Returning to Alt-f
(or
M-f
in Emacs-speak), this
shortcut is usually bound to the common command forward-word
. One
solution is to simply pick a more obscure modifier key, like Super or
Hyper, typically in the form of the Windows- or Menu-keys on a modern
keyboard. Unfortunately, I use a Unicomp reconstruction of a PS/2
Model M keyboard, which has no such
fancy keys.
A much better model of keyboard shortcuts is the one used by programs
such as GNU Screen, tmux
, and
ratpoison, where all commands are hidden behind a prefix key. For
example, in ratpoison you open a new terminal by first pressing
Ctrl-t
and then pressing c
(without holding down Ctrl). Giving up
Ctrl-t
(or Ctrl-b
for tmux
) is a much easier sacrifice than an
entire modifier key. Further, the usual convention is to bind the
non-modified key to send the captured keypress to the current
application (so Ctrl-t t
would send Ctrl-t
).
Sway is quite configurable, but unfortunately does not seem to support
multi-chord keybindings. Fortunately, sway does have a notion of
“modes”, much like vi
, although in the default configuration the
only mode is for resizing windows. With some cleverness, we can use
these modes to emulate a prefix key. We will bind Ctrl-t
to a
command that switches to the prefix mode, where we then bind the
actual keys that we care about. However, there is a wrinkle: in sway,
once you are in a mode, you stay in that mode. This not what we
want: after starting a terminal with Ctrl-t c
, we don’t want every
subsequent c
to start a new terminal! Fortunately, we can bind c
to launch the terminal, and then switch back to the “default” mode.
We will have to do this for every command, which looks a bit clumsy,
but it works well in practice:
mode "prefix" {
# Launch terminal.
bindsym c exec $term; mode "default"
# Send ctrl-t to focused window.
bindsym t exec xdotool key ctrl+t; mode "default"
# Kill focused window.
bindsym k kill; mode "default"
# return to default mode
bindsym Control+g mode "default"
bindsym Return mode "default"
bindsym Escape mode "default"
}
bindsym Control+t mode "prefix"
The main difference compared to ratpoison is that if you are in the prefix mode and hit a key not associated with a command, that key will be passed to the focused window, and you will stay in prefix mode. Ratpoison would beep at you and exit prefix mode (although it’s strictly not a mode in ratpoison). There is no simple way to capture this behaviour in sway, since you cannot define a “default binding” that would exit the mode.
Still, if you are like me, and consider the early/mid-2000s to be the pinnacle of Unix UI design, then the above produces a quite tolerable experience. My full sway configuration has more bits and commands, but you should be able to flesh it out yourself. It is not an exact reproduction of ratpoison, nor is it supposed to be: I can accept some measure of progress, as long as I am allowed to keep decades of muscle memory intact.