Skip to content
Linux PC i3 window manager configuration specific to my having Parkinson's Disease
Branch: master
Clone or download




Nine months ago (as of 2019-03-16) I posted on reddit, saying that the i3 window manager was very well suited to my needs as someone living with Parkinson’s Disease (PD).

You are currently reading the README for the github repository dopamine, a tidied up direct descendant of i3-parkinson that I’m using and actively working on. I chose the name to be short and memorable. (PD happens when dopamine producing neurons in the brain start dying.) I have made a post on reddit about dopamine and there’s once again an ongoing discussion.

How to run dopamine

Writing INSTALL is on my ToDo list.

Consider evaluating dopamine on a VM so you minimise the risk of breaking your current install, and because dopamine is running on i3 on Xubuntu 16.04 LTS. Symlink the dotfiles and scripts to their runtime locations, use i3-make to install the i3 related files.


i3files directory

The i3files directory contains my i3 configuration files and some i3-related helper scripts. The other directories contain configurations and scripts that I use in conjunction with the aforementioned i3 files. These other files provide context for i3 and my PD; on github they act as my backups. The i3files are discussed in depth in a later section.

dotfiles directory

My PD makes dot-inputrc absolutely essential; combined with a huge bash history size set by dot-bashrc, I can recall, edit and apply commands with minimal typing. I type a few letters to filter what is to be shown, then use up arrow or down arrow to cycle through matching commands. The dot-bashrc has some nice github functions and a prompt that knows about git. The files here are the ones I use. Nothing here is installed by the Makefile in i3files.

dotemacs directory

Emacs and dopamine provide a minimalist voice-assisted editing feature. Spoken sentences are converted to text externally about which more later. The text is inserted into an Emacs buffer as a single line by default, the user can choose to remove said single line. The files here are the ones I use. Nothing here is installed by the Makefile in i3files.

scripts directory

These are scripts have come in handy, for example when making a video. The files here are the ones I use. Nothing here is installed by the Makefile in i3files.



Nine months ago I thought modes would replace modifiers in my way of working. I’ve realised that there are some i3 commands that don’t suit modes, but modifiers don’t suit me. The compromise is to use the numeric keypad, alias the numpad, as found on the far right of full-size keyboards. Separate USB numpads are available for laptop users and left handed users.

The NumLock key toggles between two sets of keys: the KP_0 set for numeric entry and the KP_Insert set for navigation. The arithmetic operators and KP_Enter are unaffected by NumLock. Here’s what currently (2019-04) works for me:

bindsym KP_Left focus left
bindsym KP_Right focus right
bindsym KP_Home focus output $lmon
bindsym KP_Up focus output $cmon
bindsym KP_Prior focus output $rmon
bindsym KP_End move left
bindsym KP_Down move down
bindsym KP_Begin move up
bindsym KP_Next move right
bindsym KP_Delete $defaultnop


Using the numpad for focus hasn’t worked as well as anticipated. Here’s what currently (2019-04) works for me, and yes, it uses modifiers:

bindsym $i3arrowmodifier+Left focus left
bindsym $i3arrowmodifier+Down focus down
bindsym $i3arrowmodifier+Up focus up
bindsym $i3arrowmodifier+Right focus right

i3 modes

There are now only three i3 modes: the default mode, the Primary mode, and the Secondary mode. The Menu key cycles through these modes, the space key returns to default mode from the other two. The screen will dim when in Primary or Secondary mode. If a Primary or Secondary mode binding returns to default mode automatically, the screen will dim momentarily.

  • Primary mode contains my most often used bindings after the numpad ones.

  • Secondary mode contains bindings that are useful but aren’t used often.

  • OK mode is a blatant hack to provide a visual bell for i3-make (q.v.). It can’t be hidden, so it is ignored when we say there are three modes. It may occasionally get confused, pressing the Menu key a few times resets it.


Press Menu followed by Tab to show a dmenu with a "Command:" prompt. There is just enough time to enter two or three characters before the dmenu is automatically dismissed. Whatever has been entered is evaluated as a command. Entering "tt" launches a terminal, for example. Pressing backslash instead of Tab is slightly easier with a UK keyboard.

Pressing KP_Insert shows the same dmenu. The numpad reconfigures to supply the numbers on keys KP_0 KP_1 …​ KP_8 KP_9. Entering 2 or 3 digit commands is easier via the numpad, even with my right hand tremor, probably due to the compact arrangement of the digits.

Commands are a hangover from a past attempt to make a mouse-heavy window manager keyboard-operable. The concept was to either launch a program or switch to a running instance. This is explained in more detail in subsection "Launch or Focus" in section "i3-wrapper".

Numeric Commands

In the past nine months I have experimented with assigning numbers to commands, which sounds promiising (the "teletext argument") but fails in practice. Dopamine is as much about evaluating what doesn’t work as it is about what works!

Hybrid Commands

These are the ten Emacs frame (window) commands e[0-9], and the ten Google Chrome commands g[0-9]. They are discussed in more detail in the section "Launch or Focus".


Numeric Marks

Whenever a terminal, emacs frame, or google chrome window is created, a unique two digit mark is allocated and displayed on the right side of the titlebar. The quick-and-dirty implementation of mark assignment risks failing to terminate when the number of marked containers approaches 100. i3 has a goto-mark function bound to the 2 digit sequence [0-9][0-9] and a swap-container-with-mark function bound to the 3 digit sequence 0[0-9][0-9]. Exchanging marks can make rearranging windows easier than relying upon the conventional incremental movement of focus or windows alone.

Single Letter Marks

In addition to a two character mark matching "[0-9][0-9]", a single letter mark can be added or removed independently. There are ten such marks, which are set in Primary mode by keys 1,2,…​,9,0, and cleared by the same keys in Secondary mode. The ten marks are single capital letters, two groups of three and one group of four, mutually non-adjacent, matching (A,B,C) (R,S,T) (W,X,Y,Z)

For example, a user might edit the source for a program in one window, build the program in another window, and execute the program in yet another window. By marking these A,B,C respectively, the user can cycle though them using just one key, currently Control+Tab. More than one letter can mark a window, hence toggling between two windows marked [R] and {S][T] works as one would want. The bindings density around my left hand is quite high, hence the use of a modifer rather than a mode, plus the homage to Alt-Tab.


The i3files directory contais several files, copies of which must be installed in their run-time locations. Changing the i3 configuration requires that i3 reloads, changing the i3-status script requires that i3 restarts. The repository Makefile is used to automate installation, reloading and restarting. The i3-make script is a wrapper for 'make' calling the Makefile with custom make variables. The example just happens to work for me by default, the user should modify it to suit their system.

Bash scripts


This script is the main one and is described in detail in the section after this one. The other scripts described in this section are the result of refactoring i3-wrapper. The refactoring is still work in progress.


I’m from the UK, but I prefer the US keyboard layout because back in the day there was no choice but the US layout. I have a 105 key UK keyboard, and this script creates my custom US-style keyboard.

Apropos of i3, this is where I invoke xcape to define how modifier keys work when pressed singly.

  • k1='Super_L=Menu'

  • k2='Alt_L=Escape'

  • k3='ISO_Level3_Shift=Escape'


  • Disable the mouse to prevent accidental waking up of the display when the desk is jolted.

  • Disable the mouse when (for example) Emacs has focus, in order to encourage keyboard use.

  • Warp the mouse to follow window focus changes and reduce the overall manual mouse movement distance.

The mouse will automatically disable the mouse inside any Emacs window inside any of the standard Emacs workspaces e[0-9] and em. This is a deliberate decision, to encourage keyboard use and discourage mouse use. To prevent the mouse being disabled for the session, either move the window or rename the workspace. To enable the mouse for just long enough to escape such a mousetrap press Menu at least once, until default mode is reactivated. There is no need to restart the focus watcher.

A recent useful idea from reddit is "mouse follows focus": When the keyboard is used to focus a window, the mouse is warped into the window, to a point offset from the top left corner by one-third of the window width and one-third of the window height. Using the mouse to focus a window with a single click highlights the region between the mouse click point and the keyboard focus point. Using a slow double-click instead leaves no highlight.

These latter two trick modes are mutually exclusive in my opinion, use one or none.


I simply don’t like automatic display blanking, but because my tremor would easily disturb the mouse I can’t allow automatic display unblanking. Keybindings can use this script request that the display sleeps or wakes up.

I have two monitors driven from my PC, and I hope to have three again in future. The left monitor can be driven from other sources, typically the other source is a Raspberry Pi Zero W that streams video. I wish to avoid selecting inputs with buttons on the left monitor. Keybindings can use this script to send commands to both sources such that the left monitor source can be selected programmatically.


This script is a straightforward wrapper round 'i3status'. It adds two things:

  • On/Off control and status for USB webcam microphone and analog stereo microphone. I need both to cover Google Search, Google Chrome Autovoice extension (a mission critical capability in my case), Skype (which actually works when installed as a snap package).

  • A list of the marks that are assigned to terminals, Emacs frames, Chrome windows. The utility is debatable.


I have a tvheadend server on the machine I’m developing dopamine on, so I can watch digital TV when the PD requires that I take a break.

The client is a Raspberry Pi Zero W that makes a surprisingly good attempt at using its Broadcom hardware accelerated media player to render streaming video in high resolution at 25fps (frames not fields).

The i3-headend script provides the client, the i3-wrapper script recognises commands intended for the client and forwards them to i3-tvheadend. There is a command syntax convention for adding subsystems like this, a prefix string between colons.


This script makes explicit how the applications I use should be started and stopped.


File Watcher

The file watcher monitors a file in shared memory, using inotify-hookable. When a command is written to this file, it is forwarded to the i3programs() function in i3-wrapper for evaluation.

Focus Watcher

The focus watcher started out as a joke and programming challenge: to light a keyboard LED when Emacs had focus. The implementation was a hack. Since then, i3 4.16 has provided "i3-msg -t subscribe -m …​" which subscribes to events, in particular the window (changed) event. The implementation is no longer a gimmick. The "Emacs LED" remains, but now this indicates that the mouse is disabled when Emacs has focus. This is done to encourage using the keyboard and discourage using the mouse. This was implemented for my benefit, and since I sometimes find it more than annoying, there is a back door. As described in subsection "i3-mouse", the mouse can be enabled again by a triple press of the Menu key.

Launch or Focus

The i3programs function in i3-wrapper has a bash case statement that accepts commands to launch or focus a program using the aforementioned focus function:

  • If a requested program is not already running, the focus function will launch the requested program in a designated workspace on a designated output.

  • If a requested program is already running, the focus function changes to its workspace and to its output.

The example here launches thunderbird in response to command "tb", launching on the workspace "tb" on the left monitor ${lmon}, unless a Thunderbird window exists, in which case ithe window will receive focus on whatever workspace or output it currently occupies.

focus class Thunderbird 'tb' ${lmon} thunderbird ;;

Not all case statements use the focus function. The ten 'g0 g1 …​ g8 g9' commands launch or focus Google Chrome windows on eponymous workspaces. The "gc" command will launch a Google Chrome window on the current workspace. There are also ten commands 'e0 e1 …​ e8 e9' that launch or focus Emacs frames on eponymous workspaces, and 'em' for the current workspace. These all rely on the 'emgc' function instead of 'focus'. Their names are the "standard" names that other features may expect, as does the focus watcher for example.

Scratchpad Terminal

The popularity of dropdown terminals (Guake, Yakuake …​) has seen i3 users implementing similar functionality using the i3 scratchpad.

A single key binding (Control+Delete) operates the scratchpad terminal. The first two presses perform initialisation, subsequent presses toggle the scratchpad terminal between being visible and being hidden;. There is no dropdown animation. I have locked the terminal to a fixed position on my primary monitor.

My decision to use Control+Delete despite my right hand tremors relies on the space between the two key clusters to the left of the numpad to rest my fingers and steady my hand.

Tiled Terminals

I use tiled terminals laid out in a limited number of different arrangements, which result in bindings to bash functions that perform these operations:

  • 1 terminal opened to the right of an existing container.

  • 1 terminal opened underneath an existing container.

  • 2 terminals opened to the right of an existing container, stacked vertically.

  • Given two terminals stacked one above the other, arrange them side-by-side.

  • Given two terminals stacked side-by-side, arrange them one above the other.

The hardcore i3 user might be able to split but it made my head hurt. These terminal commands combine the splitting and the invoking.


My external speech to text engine is a mobile phone that can write a command or sentence into the file monitored by the file watcher.

The i3programs() function considers a string to be a command if it starts with [a-z0-9], and considers a string to be a sentence if it starts with [A-Z].

The string is injected into an Emacs buffer if it is a sentence. It’s rather cool that this can happen with neither the Emacs frame being focused nor its workspace being active. Injection is unconditional. Mistakes can be removed by saying "cancel". Obviously recognising "cancel" is not 100% accurate.

Nevertheless the draft of an email or drafting a section in a document can be done more or less hands-free using speech input. Even with mistakes it is acceptably fast, and can be faster than my typing one handed.

Apropos of the processing done by the phone. if I say a sentence, it is turned into text. Some common words are Camel Cased or UPPER CASED, and a period (full stop) or question mark is appended. Question detection is partly automated, For example, it looks for sentences that begin with "Who / What / Where / Which / How".

The 'av' command launches or switches to a dedicated AutoVoice workspace that shows the Emacs autovoice buffer.

You can’t perform that action at this time.