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
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:
- Type
goo. - Hold
Tab. - Tap
Jto move down the suggestions orKto move back up. - Release
Taband 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
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
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)