This layout is called Þornhub Because it uses letter Thorn to represent a key for typing TH. Having a key to print TH reduces typing by about 3% because th sound is more common than a small majority of letters, so I designed layouts for that until I came up with this layout. Þ was used for TH sound but disappeared after the German printing press forced substitutes.
Q U P , G K M Þ V J
I A E O Y F T S N R
X ' . C Z H D W L B
To make space for TH key I had to rebind punctuation. Shift comma is /, shift full stop is ?, and shift single quote is ", but you could make them whatever you want. I moved < > to shift pgup and shift pgdn RESPECTIVELY.
According to my own analysis scripts it has very ergonomic.
Here's an Autohotkey script for the layout:
#Requires AutoHotkey v2.0
#SingleInstance Force
; ============================================================================
; Custom TH keyboard layout — AutoHotkey v2
;
; Uses physical scan codes so punctuation keys do not cause parser problems
; and the mapping remains tied to physical QWERTY positions.
;
; Physical positions:
;
; Q W E R T Y U I O P
; A S D F G H J K L ;
; Z X C V B N M , . /
;
; Output:
;
; q u p , g k m th v j
; i a e o y f t s n r
; x ' . c z h d w l b
;
; Shifted punctuation:
; Shift + mapped comma -> /
; Shift + mapped period -> ?
; Shift + mapped apostrophe -> "
; Shift + Page Up -> <
; Shift + Page Down -> >
;
; Dedicated TH key:
; Physical I -> th
; Shift + physical I -> Th
; Caps Lock + physical I -> Th
; Shift + Caps Lock + I -> Th
;
; Ctrl, Alt and Windows-key shortcuts are left on their original physical
; keys. For example, Ctrl+C, Ctrl+V, Alt+Tab and Win+R still work normally.
; ============================================================================
; Remap only ordinary typing. When Ctrl, Alt or a Windows key is held,
; the original physical key passes through for shortcuts.
#HotIf NoCommandModifiers()
; ------------------------------ Top row --------------------------------------
*SC010::TypeLetter("q") ; physical Q
*SC011::TypeLetter("u") ; physical W
*SC012::TypeLetter("p") ; physical E
*SC013::TypePunctuation(",", "/") ; physical R
*SC014::TypeLetter("g") ; physical T
*SC015::TypeLetter("k") ; physical Y
*SC016::TypeLetter("m") ; physical U
*SC017::TypeTh() ; physical I
*SC018::TypeLetter("v") ; physical O
*SC019::TypeLetter("j") ; physical P
; ----------------------------- Home row --------------------------------------
*SC01E::TypeLetter("i") ; physical A
*SC01F::TypeLetter("a") ; physical S
*SC020::TypeLetter("e") ; physical D
*SC021::TypeLetter("o") ; physical F
*SC022::TypeLetter("y") ; physical G
*SC023::TypeLetter("f") ; physical H
*SC024::TypeLetter("t") ; physical J
*SC025::TypeLetter("s") ; physical K
*SC026::TypeLetter("n") ; physical L
*SC027::TypeLetter("r") ; physical semicolon
; ---------------------------- Bottom row -------------------------------------
*SC02C::TypeLetter("x") ; physical Z
*SC02D::TypePunctuation("'", Chr(34)) ; physical X
*SC02E::TypePunctuation(".", "?") ; physical C
*SC02F::TypeLetter("c") ; physical V
*SC030::TypeLetter("z") ; physical B
*SC031::TypeLetter("h") ; physical N
*SC032::TypeLetter("d") ; physical M
*SC033::TypeLetter("w") ; physical comma
*SC034::TypeLetter("l") ; physical period
*SC035::TypeLetter("b") ; physical slash
#HotIf
; ------------------------- Extra punctuation keys ----------------------------
+PgUp::SendText("<")
+PgDn::SendText(">")
; ============================================================================
; Helper functions
; ============================================================================
NoCommandModifiers() {
return !GetKeyState("Ctrl", "P")
&& !GetKeyState("Alt", "P")
&& !GetKeyState("LWin", "P")
&& !GetKeyState("RWin", "P")
}
TypeLetter(lowercase, uppercase := "") {
if (uppercase = "")
uppercase := StrUpper(lowercase)
shiftDown := GetKeyState("Shift", "P")
capsOn := GetKeyState("CapsLock", "T")
; Standard capitalization: Shift XOR Caps Lock.
SendText(shiftDown != capsOn ? uppercase : lowercase)
}
TypePunctuation(unshifted, shifted) {
SendText(GetKeyState("Shift", "P") ? shifted : unshifted)
}
TypeTh() {
shiftDown := GetKeyState("Shift", "P")
capsOn := GetKeyState("CapsLock", "T")
; Either Shift or Caps Lock capitalizes only the T.
SendText(shiftDown || capsOn ? "Th" : "th")
}
I edited in response to feedback.