April 2006
A Programmer's Keyboard Layout
Preamble
The Dvorak keyboard layout was designed to be easier and faster to type English text with. Other languages require other keyboard layouts, for example french has a much heavier emphasis on "Q" than does English and we would expect "Q" to be in a more convenient location.
This raises two questions: What would the best keyboard layout be for a programmer? Is it much better?
Assumptions
I will compare the general rules I used to the ones Dvorak used
Dvorak |
Programmer Assumptions |
|---|---|
| It is easier to type letters alternating between hands. | Disagree: It is better to keep common digraphs together on the same hand so that the pair can be entered fast with only side of the brain being used. It is faster to tap two adjacent fingers on one hand than it is to tap fingers on alternating hands. |
| For maximum speed and efficiency, the most common letters and digraphs should be the easiest to type. This means that they should be on the home row, which is where the fingers rest. | Agree:
The most common digraphs should be the easiest to type. Disagree: The most common letters should not necessarily be easiest to type: Letters are always typed in the context of other letters, so positioning their digraphs take priority. |
| Likewise, the least common letters should be on the bottom row, which is the hardest row to reach. | Agree: But this is not handled formally by my weighting function. |
| The right hand should do more of the typing, because most people are right-handed. | Disagree: In the age of heavy mouse use the right hand has an extra burden. My weighting function does not prefer a side. |
| It is more difficult to type digraphs with adjacent fingers than non-adjacent fingers. | Disagree: Maybe this was true when pushing a key on a typewriter was very hard, but now it takes little effort to strike adjacent keys on the same row. But, the cost of typing keys on adjacent columns of different rows is proportional to the number of rows traveled. |
| Stroking should generally move from the edges of the board to the middle. An observation of this principle is that when rapping fingers on a table, it is easier going from little finger to index than vice versa. This motion on a keyboard is called inboard stroke flow. | Agree: I assume you can type adjacent, inward, digraphs twice as fast as any other digraph. |
Solution
Because the number of possible digraphs and their positioning lead to a combinatorial explosion, I could not find a deterministic algorithm to find an optimized layout that ran in a reasonable time. Therefore my program explored random permutations on an already known (initially random) design to find better layouts. Despite the random process, the program always settled on the same home-row layout in about a minute. Once the home row was identified, the placement of all other characters on the keyboard contributed little to the overall cost; the last <1% optimization usually took 1/2 an hour.
The Cost Function
- A home row key after another home row key has cost of 1
- An inward adjacent key on the same row has a cost of 0.4
- A key that is one row away and adjacent (or same) column has cost of 2
- A key that is two rows away and adjacent (or same) column has cost of 3
- Keys outside the keyboard have cost of 6
- Shift is assumed to be off-keyboard (thumb or foot). Using the shift key costs an additional 1
Here are some interesting features of the cost function (all descriptions are relative to the last key pressed):
Due to the nature of the cost function, all horizontally and vertically symmetric layouts have identical cost.
It may be instructive to see how the cost function evaluates existing layouts. Notice that the Dvorak keyboard is only slightly better than the Qwerty. I suspect that this difference is small is because the Dvorak home row does not cover programming digraphs any better than Qwerty.
Example: Qwerty Keyboard
| « » |
Q q |
W w |
E e |
R r |
T t |
Y y |
U u |
I i |
O o |
P p |
{ [ |
|
| |
A a |
S s |
D d |
F f |
G g |
H h |
J j |
K k |
L l |
: ; |
" ' |
|
| |
Z z |
X x |
C c |
V v |
B b |
N n |
M m |
< , |
> . |
? / |
|
Cost 2.48 per keystroke
Example: Dvorak Keyboard
| « » |
" ' |
< , |
> . |
P p |
Y y |
F f |
G g |
C c |
R r |
L l |
? / |
|
| |
A a |
O o |
E e |
U u |
I i |
D d |
H h |
T t |
N n |
S s |
_ - |
|
| |
: ; |
Q q |
J j |
K k |
X x |
B b |
M m |
W w |
V v |
Z z |
|
Cost 2.35 per keystroke
Pure Java Keyboard
First we start with what a pure Java keyboard would look like. I used all Java programs I had written as a sample (53K lines ending with semi-colon or have close brace " "). Comments are included, but the licensing comments at the top of each have been removed.
Here are the most common digraphs (per million digraphs):
|
/ / 30902 |
o r 7197 |
p 5709 |
Notice that Java code makes no use of the most common English word, "the", therefore the "th" digraph is relatively rare. I believe the some other pairs can be explained
- "in" mostly from "int" and "String"
- "te" mostly from "System", "private", "iterate", and "temp"
- "nt" mostly from "int", "count" and many others
| K k |
S s |
H h |
C c |
_ . |
G g |
|
W w |
F f |
/ = |
} ] |
* [ |
: | |
| < - |
O o |
R r |
I i |
N n |
D d |
|
V v |
L l |
E e |
T t |
A a |
X x |
| \ ! |
M m |
P p |
U u |
B b |
J j |
|
Y y |
' { |
, ; |
" ) |
+ ( |
> & |
Notice some Java specific features, like the "();" sequence for all those parameterless method calls.
Less-Pure Java Keyboard
Since no one uses a keyboard for pure coding, I also included my sent E-mail (removing original message quotes) and web pages (removed html).
Here are the most common digraphs (per million digraphs):
|
/ / 18341 |
a 7635 |
a r 5863 |
At least the "th" bigraph is registering
| | ] |
\ ( |
" ) |
+ ; |
- { |
Y y |
|
W w |
G g |
H h |
C c |
_ . |
X x |
| K k |
A a |
T t |
E e |
R r |
V v |
|
D d |
O o |
N n |
I i |
S s |
< [ |
| @ > |
» ' |
} , |
/ = |
F f |
* : |
|
M m |
L l |
B b |
U u |
P p |
J j |
Cost 1.97 per keystroke
Very Bad Keyboard
The above layouts are not meant for actual usage, but as design hints. There is an advantage to having a logical layout, but we would like to see how bad it could get. How high a cost can be incurred by a logically designed, but poorly optimized, keyboard?
| H h |
V v |
X x |
J j |
Y y |
M m |
|
> ' |
@ « |
? " |
Q q |
] ^ |
F f |
| = } |
A a |
T t |
E e |
R r |
& * |
|
| ` |
O o |
N n |
I i |
S s |
: - |
| P p |
W w |
Z z |
K k |
B b |
G g |
|
+ # |
< \ |
{ $ |
[ ! |
~ % |
, _ |
Cost 3.04 per keystroke
- Taking common letters (like D, C and L) off the keyboard entirely
- Forcing the user to use the shift key for the next most common symbols
- Leaving the uncommon symbols easily acessable
Once the eight home keys are determined, it seems about 65% (= minCost / maxCost = 1.97 / 3.04) of the keystrokes are covered. No matter how badly placed the rest of the keys are, the amortized per-digraph cost does not exceed 3.04. This includes crazy things like:
Programmer's Keyboard
Since the satellite keys count for little (35%) of the overall cost, we can order them logically to facilitate a shallower learning curve. The home keys and the pink keys have been selected by me, the rest have been optimally placed. I am still not certain about the shift-values for the bottom right.
| K k |
D d |
< ( |
> ) |
: ; |
` » |
' « |
L l |
U u |
P p |
M m |
B b |
|
| G g |
A a |
T t |
E e |
R r |
C c |
H h |
O o |
N n |
I i |
S s |
V v |
|
| W w |
Y y |
F f |
[ { |
] } |
" / |
_ \ |
- = |
* + |
| , |
? . |
X x |
Cost 2.07 per keystroke
This layout saves about 16% of the cost of a Qwerty layout. This is a small savings given that the keyboard is totally rearranged; it may not be worth switching.
Conclusion
This was a humongous waste of time. The program to do the analysis is about 700 lines of code, and went though about 3 iterations. I am most disappointed by the lack of benefit offered by a more efficient layout; even when considering a purely optimized layout you only get 21% savings over Qwerty.
Despite the waste of time, I am happy that I did the analysis. This issue has plagued my imagination for a few years now, and quantifying the (meager) gains that can be achieved helps me put this issue to rest.
There is still the possibility I could vary the cost function, but I see no glaring error in it's logic. It is my feeling that small changes to the cost function will still result in the same conclusion: Rearraging a keyboard for efficiency will not get you enough to justify switching.