DEV Community

Cover image for I Thought I Wanted System-Wide Vim. I Actually Wanted Arrow Keys on the Home Row
Naveen
Naveen

Posted on

I Thought I Wanted System-Wide Vim. I Actually Wanted Arrow Keys on the Home Row

Arrow keys are in a terrible place.

I kept noticing this while typing in my browser's address bar. Suppose I typed goo, and the browser showed suggestions such as Google, google.com, and Gmail. The result I wanted was right there, one row below—but selecting it meant moving my right hand away from the home row and reaching for the arrow keys.

That movement is small. It is also repeated constantly.

The arrow-key cluster is too far away to press comfortably with my pinky, so I usually move my whole right hand and use my index finger. Then I have to find the home row again. The same interruption appears in terminal history, autocomplete menus, file pickers, text fields, and dialogs.

My first conclusion was: I need system-wide Vim.

The solution I thought I wanted

I imagined pressing Escape in any application, using J and K to move through results, and then pressing I to return to insert mode.

That sounds attractive if you already use Vim or Neovim, but it solves a much larger problem than the one I had. I did not need text objects, operators, commands, or modes in my browser's address bar. I only wanted to move down one line.

Applications already understand arrow keys. Browsers use them for suggestions. Shells use them for history. Autocomplete widgets use them for selection. Text fields use them for cursor movement.

So instead of teaching every application Vim, I moved the arrow keys.

The smaller solution: a temporary Tab layer

I now hold Tab and use H/J/K/L as arrow keys:

Tab + H  ->  Left
Tab + J  ->  Down
Tab + K  ->  Up
Tab + L  ->  Right
Enter fullscreen mode Exit fullscreen mode

Tapping Tab still produces an ordinary Tab. It becomes a navigation layer only when I hold it with another mapped key.

This is the important part: the layer emits normal arrow-key events. It does not need to know whether I am using a browser, terminal, editor, launcher, or file manager. If something already responds to arrows, it usually works with the layer.

The address-bar example becomes simple:

  1. Type goo.
  2. Hold Tab.
  3. Tap J to move down the suggestions or K to move back up.
  4. Release Tab and continue typing normally.

There is no mode to enter and no mode to escape from. My hand never leaves its normal typing position.

It turned out to be useful everywhere

The browser problem led me to the idea, but the terminal made me fall in love with it.

To recall the previous command, I press Tab + K. To move back down through history, I use Tab + J. When a shell or editor offers an autocomplete suffix that can be accepted with Right, I use Tab + L.

Compare that with entering a shell's Vim normal mode, pressing a navigation key, and returning to insert mode. Modal editing remains excellent when I actually want editing commands. For a single arrow press, the layer is faster and needs less thought.

The rest of my navigation layer follows the same idea:

Shortcut Output
Tab + H/J/K/L Left/Down/Up/Right
Tab + Y Home
Tab + U Page Up
Tab + O End
Tab + M Page Down
Tab + 1 through 0 F1 through F10
Tab + - / Tab + = F11 / F12

I also placed brackets and a few common programming symbols on the layer, but the arrows are the feature that changed how I use the keyboard.

Word movement comes almost for free

Once arrow keys live on the layer, shortcuts built from arrow keys come with them.

For example, many Linux text fields and editors use Ctrl + Left and Ctrl + Right to move by one word. I can produce those without leaving the home row:

Hold Tab first, then press Ctrl + H  ->  Ctrl + Left
Hold Tab first, then press Ctrl + L  ->  Ctrl + Right
Enter fullscreen mode Exit fullscreen mode

That gives me the practical equivalent of Vim's b and w in applications that support Ctrl-arrow word movement. The order matters: I press and hold Tab first, then add Ctrl and H or L.

It is not a perfect reimplementation of Vim semantics. The exact word boundary behavior belongs to the application, and Vim's definition of a word can differ from a GUI text field's definition. But the physical benefit is the same: word movement is available without reaching for the arrow cluster.

The same principle applies to almost anything composed from arrow keys. Add Shift for selection where the application supports Shift+Arrow. Add Ctrl for larger jumps. The remapper does not need a separate feature for every program; it gives me comfortable access to the keyboard events those programs already use.

The simple config and the powerful config

I tried two Linux keyboard remappers for this setup: keyd and Kanata.

Use keyd for the keyboard shortcuts

If all you want is the navigation layer, I recommend keyd. Its configuration is dead simple to read, understand, and edit:

[main]
capslock = overload(control, esc)
tab = overload(tabnav, tab)

[tabnav]
h = left
j = down
k = up
l = right
y = home
u = pageup
o = end
m = pagedown
Enter fullscreen mode Exit fullscreen mode

Even without knowing keyd, the intent is visible. Tap Caps Lock for Escape, hold it for Control; tap Tab for Tab, hold it for the navigation layer.

Use Kanata if you also want keyboard mouse control

I use Kanata for an additional experiment: turning the keyboard into a mouse.

Tapping Right Shift once enters mouse mode. In that mode:

Key Mouse action
H/J/K/L Move left/down/up/right
A Left click
G Middle click
; Right click
U / E Scroll up/down

Tapping Right Shift again—or pressing Escape—returns to the normal keyboard. Holding Right Shift continues to behave like an ordinary Shift key. On my Lenovo IdeaPad, I also use the Fn-lock light as an optional mouse-mode indicator.

Kanata can express this behavior, but its Lisp-like configuration is unusual and much less friendly to read or modify. My recommendation is therefore simple:

  • Want only the keyboard shortcuts? Use keyd.
  • Want the shortcuts plus mouse control from the keyboard? Use Kanata.

Do not run both remappers at the same time. They would both try to transform the same input and could produce confusing results.

Why I prefer this to "Vim everywhere"

I still like modal editing where modal editing makes sense. This setup is not a replacement for Vim, Neovim, editor keybindings, or a browser extension designed for link navigation.

It solves a more basic ergonomic problem: useful keys are physically far away.

By keeping the output ordinary, the layer stays boring in the best possible way. There is no application integration to maintain, no list of supported programs, and no normal-mode state to remember. It works in places where a full Vim layer would be excessive.

The surprising lesson was that I did not need a more sophisticated interaction model. I needed four existing keys in a better location.

Configs and setup

I put both working configurations, shortcut tables, Linux setup instructions, troubleshooting notes, emergency exits, and the optional Lenovo Fn-lock indicator here:

github.com/naveen-010/home-row-navigation

The symbol mappings assume a US QWERTY layout, while the main HJKL navigation idea is much easier to adapt. Before enabling a system-wide remapper, validate the config and remember its emergency exit shortcut.

If you already use a keyboard layer, I would be interested to know which key you use to activate it and what you keep on your home row.


Disclosure: I used AI to help structure and edit this article from my own story and working configuration. The mappings and setup claims were checked against the actual keyd and Kanata config files and their validators.

Top comments (0)