Monday, March 16, 2015

Reducing reliance on the mouse

The point of this project is to reduce the amount of reliance on the mouse, as I believe it leads to wrist fatigue and other maladies and is just plain slow. Using a Thinkpad T430, I intend to make controlling the laptop as utterly keyboard centric as possible. The T430 only comes with control, windows, and alt keys, but they are distinct keys, such that control_l is different than control_r and same for alt. The only concession I'm willing to make for this keyboard centric approach is the web browser; simply using emacs web browser 'eww' or links/lynx doesn't cut it for me. Conkeror is very useful at helping reduce mouse usage in browsers, but still requires mouse usage. Plus I still need to use chrome and firefox for development and I like to use their dev tools which requires more mouse usage. Firefox though, has the great firemacs add-on which provides emacs bindings for common movements. Chrome stands out as the biggest mouse user.

For what mouse usage I do have perform, I have essentially three options: an external mouse, the touchpad and the trackpoint which is provided on the T430. An external mouse is by far the worst option, requiring moving my hand completely off of the keyboard. Using the touchpad for mouse movements is better but still requires too much reconfiguring of my hands to be acceptable. The T430 has a trackpoint, which requires the least amount of adjusting of my hands. The touchpad can still serve a purpose though, as I still need some sort of scroll wheel. So I'll investigate converting it to one large scroll wheel.

Controllers

The software to control my laptop boils down to the operating system, a window manager, a terminal, and a text editor (aside from the aforementioned browsers). My preferences for these are (Ubuntu/OpenSUSE) Linux, Xmonad, tmux and emacs. What I'm looking for is a way to control these controllers from the keyboard. In particular, I want to be able to easily control iterating through 'windows' in emacs (default is Control-xo), 'windows' in xmonad (default Meta/Alt-tab) and 'panes' in tmux (default Control-bo). Another goal, is to stay as close to default configurations as possible. I don't like being completely lost if I'm on a different machine somewhere in production that doesn't have my configuration scripts. On the other hand, being lost on a different laptop completely is something I'll have to tolerate due to the key reconfiguration.

Conflicts

From the very start, we have conflicts between the modifier keys for emacs xmonad and tmux. Who has priority? Emacs makes extensive use of Control and Meta/Alt, and is my primary operating space, so it takes priority. This leaves the Windows key available, but I have two more programs that need modifier keys. Since my next operating space is the window manager, xmonad gets the Windows key.  We'll have to figure out something for tmux later.

What space iteration key combo to use?

Meta/Alt-tab is a common key chord amongst window managers. For me, it requires moving my pinky, which inevitably moves the rest of my hand as well, with my index finger ending up over the 'd' key on a qwerty keyboard. I like emacs Control-xo, as the 'o' key is comfortable and doesn't move my left hand, but I don't like having to hit three keys to switch window spaces. I can easily change this to just Control-o in .emacs, but Control-o defaults to 'open-line, which I occasionally use. Meta/Alt-o on the other hand enters emac's font system, which, while powerful, is not something I use at all. This also lines up with tmux's Control-bo to 'select-pane'. So some-kind-of-modifier-o is what I'll use.

Control, Super/Win, Alt

On my Thinkpad T430, I have a set of modifier keys on the left of the spacebar (fn, ctrl_l, windows_l, alt_l) and a set on the right of the spacebar (alt_r, PrtSc, ctrl_r). The Fn key is rather important in that it controls other various aspects of the laptop such as screen brightness and toggling the wireless modem. This is not a key I will reconfigure. PrtSc is located in a valuable space, so I should remap that as a second Windows key, for symmetry.

The ctrl_[l|r] keys are extensively used in emacs but the location of both the ctrl keys is not acceptable for me as they require too much pinky distension. So I plan to make a common swap for the valuable capslock location. ctrl_l is more suitable for controlling tmux as interacting with tmux is something I do much less frequently. So I'll have to find some way of making ctrl_l a modifier key for tmux. The Windows key works well as the modifier for xmonad. Tmux is still without a modifier key, but considering that it typically uses Control-b, a chord in itself as a modifier, I would like is to simply have ctrl_[l|r] be the single key needed for tmux.

The Plan

What I would like then is as follows:
  • replace capslock with control
  • replace ctrl_l with a custom tmux modifier
  • make the windows key the modifier key for xmonad
  • make Alt-o the 'window' iteration key for emacs
  • make Windows-o the 'window' iteration key for xmonad
  • make ctrl_l-o the 'pane' iteration key for tmux
  • duplicate the functionality on the right of the space bar (ie, convert PtrSc to a windows key, ctrl_r becomes a second tmux modifer key)
  • make the touchpad one large scrollbar

Key reconfiguring

Here is things get really, really convoluted and confusing. Configuring keys in Linux is done with Xkb and setxkbmap. Xmodmap predates Xbk and is deprecated, so we'll skip that. Researching on the internet for documentation found Extending xkb, x.org's The X Keyboard Extension, and the Archlinux Wiki.

I first need to figure out what keys I have currently. To do this, I have to dump the current layout with the following:
xkbcomp $DISPLAY xkb.dump
This dumps the layout to the file xkb.dump, which I can then inspect. Doing so reveals that I want to edit the keys CAPS, LCTL, PRSC and RCTL. How to do this though, according to the x.org documentation, is that I need a rules file and a symbol file. The rules file references the symbol file in the 'options' field in order to enable the customizations I specified in the symbol file. The two examples I will use for these files are the evdev rule set located in /usr/share/X11/xkb/rules/evdev and the ctrl symbol file located at /usr/share/X11/xkb/symbols/ctrl.

The rule file references various entries in the symbol file via the !option field which specifies all the options such as
ctrl:nocaps = +ctrl(nocaps)
which points to the 'nocaps' entry in the 'symbols/ctrl' file.

Once things are ready to be saved, there is unfortunately no way to save these in a home directory. Custom rules files must exist in /usr/share/X11/xkb/rules/ and symbol files must exist in /usr/share/X11/symbols/. For ease of use, I created my files in ~/.xkb/ and created symlinks with in symbols/ and rules/ to those files. Once those custom files are set up, the rule file can be specified with setxkbmap. Changes in symbol files wont take affect until the cached versions are removed with rm /var/lib/xkb/*.xkm. Then if our symbol file is /usr/share/X11/symbols/test, with symbols defined as
partial modifier_keys
xkb_symbols "nocaps_nolrctrl" {
    replace key <caps>;    { [ Control_L, Control_L ] };
    replace key <lctl>    { [ NoSymbol ] };
    replace key <rctl>    { [ NoSymbol ] };
    modifier_map  Control { <caps> }
};
our option string to use would be 'test:nocaps_nolrctrl'. Test it with setxkbmap -option 'test:nocaps_nolrctrl'. This is also what is needed in the rule file.

Ultimately, I've ended up with a rule file ~/.xkb/window_ctrl that looks like

// Eliminate CapsLock, making it another Ctrl.
partial modifier_keys
xkb_symbols "nocaps_nolrctrl" {
    replace key <caps>  { [ Control_L, Control_L ] };
    replace key <lctl>  { [ NoSymbol ] };
    replace key <rctl>  { [ NoSymbol ] };
    modifier_map  Control { <caps> };
};

// Replace PtrSc
partial modifier_keys
xkb_symbols "prtsc_super" {
    replace key <prsc>  { [ Super_R, Super_R ] };
    modifier_map  Mod4 { <prsc>, <lwin> };
};

// Have [L|R]CTL generate an fkey
partial modifier_keys
xkb_symbols "ctl_fkey" {
    replace key <lctl>  { [ F12 ] };
    replace key <rctl>  { [ F12 ] };
};

For my rules file, I simply copied and pasted the existing evdev and evdev.lst file to ~/.xkb/evdev.mouseless and ~/.xkb/evdev.mouseless.lst then added to the end of the  
! option = symbols section of evdev.mouseless:

  window_ctrl:ctl_fkey        = +window_ctrl(ctl_fkey)
  window_ctrl:nocaps_nolrctrl = +window_ctrl(nocaps_nolrctrl)
  window_ctrl:prtsc_super     = +window_ctrl(prtsc_super)

Then I set my rule file to run with setxkbmap -rules evdev.mouseless -option "window_ctrl:nocaps_nolrctrl,window_ctrl:prtsc_super,window_ctrl:ctl_fkey".

Xmonad config

Configuring xmonad is relatively straightforward. Create a xmonad.hs file in ~/.xmonad starting from a template config, and update
myModMask with mod4Mask (mod4 being the equivalent to the Super/Windows key).

Emacs config

Configuring emacs is just as straighforward. Add

;; Setup move to previous window to mimic tmux bindings
(global-unset-key "\M-o")
(global-set-key "\M-o" 'other-window)
;; Move to next window
(global-set-key "\M-O" (lambda () (interactive) (other-window -1)))

to .emacs.

Tmux config

Configuring tmux simply requires setting the prefix with:
set-option -g prefix F12

Touchpad as one large scrollwheel

In Ubuntu, synaptics handles all touchpad manipulations. Using the synclient, I messed around with setting the RightEdge to various values to indicate where the scroll edge of the touchpad should end. Ultimately I found a value of 1751 covered all of the pad without causing errors. This script needs to be placed in a startup script such as .xinitrc. My own personal set up is using xmonad with bits of gnome thrown in for handling things such as the the panel bar and other various notifications. I'll take advantage of this and gnomes autostart system to place the synclient command in an autostart file in .config/autostart/synclient.desktop

[Desktop Entry]
Name=synclient
GenericName=synclient
Comment=Change trackpad to scrollpad
Exec=synclient RightEdge=1751
Terminal=true
Type=Application
StartupNotify=false

It all works.... but only partial success

All good, except a number of issues. The fragility of my approach is a significant issue.  My customizations wont benefit from any changes to evdev upstream. I'd like to figure out how to get the keyboard configurations working in xorg.conf.d/, but this will have to be a later investigation.

Another issue is that tmux doesn't respond to hyper and no longer responds to fn keys f13-f20 (it instead sees f13 as super-f1 and so on for f14 etc). So I'm stuck having to use a visible key, a key that affects other programs (in particular firefox/chrome) for controlling tmux. Future investigations will be using to send mod4-f12, but that's not straightforward either.

Yet another issue is the intimidatingly complicated nature of getting this all to work. There is supposed to be a simpler way of setting up .conf files in an /etc/X11/xorg.conf.d/ directory, but none of my experiments got this to work successfully.

Finally, tmux doesn't register holding down keys. Holding down my custom lctrl doesn't continue working after entering another key such as lctrl-o. I have to let go of lctrl and hit o again otherwise it simply outputs 'o'. Emacs and xmonad work as expected, so I suppose this could be a terminal issue of sort that I will have to sort out at some later time.

No comments:

Post a Comment