That alone would also make the pinky shift keys an even worse torture than before. So, to get shift (and other modifier) keys for the thumbs, I replaced the space bar with a small (single unit wide) key, so the thumbs can freely reach the next row (X/C/V/B/N/M). There's no row for dedicated number keys anymore, but that's a small price to pay IMO. OTOH, function keys closer to the new home row is another advantage.
I'm sharing this script here in QUERTZified form. Personally, I actually relocated the letters, too.
The utility functions here might be useful in other scripts which require a lot of remapping, as they allow configuration via visual keyboard "ASCII art".
Tested with the Windows keyboard layout set to one similar to German default, but without dead keys (in the base layer at least).
"Installation": This script includes and overwrites another script %A_ScriptFullPath%.generated (i.e. called like the name under which you save it with ".generated" appended). You have to initially create it, with encoding UTF-8 with BOM (byte order mark), and write a linefeed in it. (Other contents which Autohotkey accepts should obviously also work, but an empty file somehow does not.)
EDIT: I meant row staggering, not column.
Code: Select all
;Emacs: -*- tab-width: 16 -*-
; Keyboard layout for thumbs on the bottom letter row, no number key row.
; MIT License
;
; Copyright (c) 2018 42td
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in all
; copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
; SOFTWARE.
#SingleInstance force
#Warn, , MsgBox
#NoEnv
SetBatchLines -1
ListLines Off
Process, Priority, , High
SendMode Input
EnvGet, SystemRoot, SystemRoot
Menu Tray, Icon, %SystemRoot%\system32\shell32.dll, 45
aliases := {}
aliases["Spc*" ] := "send {u+00a0}"
aliases["-*" ] := "send {u+2011}" ; non-breaking hyphen
aliases["%" ] := "send {``%}"
aliases["\" ] := "send {u+005c}"
aliases["{" ] := "send {{}"
aliases["}" ] := "send {}}"
aliases["FF" ] := "send {u+240c}"
aliases["FS" ] := "send {u+241c}"
aliases["GS" ] := "send {u+241d}"
aliases["RS" ] := "send {u+241e}"
aliases["US" ] := "send {u+241f}"
aliases["("")" ] := "send {u+0308}" ; dead diaeresis
aliases["(́́´)" ] := "send {u+0301}" ; dead acute
aliases["(́́``)" ] := "send {u+0300}" ; dead grave
aliases["(́́^)" ] := "send {u+0302}" ; dead circumflex
aliases["(~)" ] := "send {u+0303}" ; dead tilde
aliases["(́°)" ] := "send {u+030a}" ; dead circle
aliases["(,)" ] := "send {u+0327}" ; dead cedille
aliases["𝛑" ] := "send {𝛑}"
aliases["╔·" ] := "┌" ; because single-line box drawing characters
aliases["╦·" ] := "┬" ; are used for pretty-printing, these aliases
aliases["╗·" ] := "┐" ; exist to denote those characters when
aliases["╠·" ] := "├" ; mapping them
aliases["╬·" ] := "┼" ;
aliases["╣·" ] := "┤" ;
aliases["╚·" ] := "└" ;
aliases["╩·" ] := "┴" ;
aliases["╝·" ] := "┘" ;
aliases["║·" ] := "│" ;
aliases["═·" ] := "─" ;
; === layers ===
modS := [ "v", "m" ]
modL := [ "b", "n" ]
modR := [ "c", "sc033" ]
modK := [ "LAlt", "Ralt" ]
modM := [ "sc039" ] ;[ "LCtrl" ]
modWN := [ "LCtrl" ]
code := disableKeysCode(modL, modR, modM)
keys := unpretty(["║│", "║"], " ═╔╦╗╚╩╝╠╬╣╤╧"
,"╔═══════╦═══════╦═══════╦═══════╦═══════╦═══════╦═══════╦╤══════╦═══════╦═══════╦═══════╦═══════╦═══════╦═══════════════╗"
,"║ sc029 ║ 1 ║ 2 ║ 3 ║ 4 ║ 5 ║ 6 ║│ 7 ║ 8 ║ 9 ║ 0 ║ sc00c ║ sc00d ║ BS ║"
,"╠═══════╩═══╦═══╩═══╦═══╩═══╦═══╩═══╦═══╩═══╦═══╩═══╦═══╩╧══╦╤══╩═══╦═══╩═══╦═══╩═══╦═══╩═══╦═══╩═══╦═══╩═══╦═══════════╣"
,"║ Tab ║ q ║ w ║ e ║ r ║ t ║ z ║│ u ║ i ║ o ║ p ║ sc01a ║ sc01b ║ Enter ║"
,"╠═══════════╩═╦═════╩═╦═════╩═╦═════╩═╦═════╩═╦═════╩═╦═════╩╧╦╤════╩═╦═════╩═╦═════╩═╦═════╩═╦═════╩═╦═════╩═╗ ║"
,"║ CapsLock ║ a ║ s ║ d ║ f ║ g ║ h ║│ j ║ k ║ l ║ sc027 ║ sc028 ║ sc02b ║ ║"
,"╠═════════╦═══╩═══╦═══╩═══╦═══╩═══╦═══╩═══╦═══╩═══╦═══╩═══╦╤══╩╧══╦═══╩═══╦═══╩═══╦═══╩═══╦═══╩═══╦═══╩═══════╩═════════╣"
,"║ LShift ║ sc056 ║ y ║ x ║ ║ ║ ║│ ║ ║ ║ sc034 ║ sc035 ║ RShift ║"
,"╚═════════╩═══════╩═══════╩═══════╩═══════╩═══════╩═══════╩╧══════╩═══════╩═══════╩═══════╩═══════╩═════════════════════╝")
code .= hotkeysCode([], [], keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ ^ │ / │ q │ w │ e │ r │ t ║ z │ u │ i │ o │ p │ ß │ ≈ │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ LAlt │ LCtrl │ a │ s │ d │ f │ g ║ h │ j │ k │ l │ x │ RCtrl │ LAlt │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ Tab │ Enter │ BS │ Space │ c │ v │ b ║ n │ m │ , │ . │ y │ Tab │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ CapsLock│ - │ + │ `` │ │ │ ║ │ │ │ Ins │ Del │ Esc │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modS, [], keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ ° │ \ │ --- │ --- │ --- │ --- │ --- ║ --- │ --- │ --- │ --- │ --- │ ẞ │ ≉ │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ --- │ --- │ --- │ --- │ --- ║ --- │ --- │ --- │ --- │ --- │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │+Enter │ +BS │+Space │ --- │ --- │ --- ║ --- │ --- │ --- │ --- │ --- │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ _ │ --- │ ʼ │ │ │ ║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modL, [], keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ --- │ --- │ ∃ │ ∀ │ ' │ "" │ --- ║ ☐ │ { │ } │ --- │ ∅ │ ≤ │ ≥ │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ - │ + │ \ │ / │ | ║ * │ ( │ ) │ ~ │ $ │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ < │ > │ & │ --- ║ @ │ [ │ ] │ … │ ! │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ ‒ │ × │ (,) │ │ │ ║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modS, modL, keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ --- │ --- │ ∄ │ --- │ --- │ © │ --- ║ ☒ │ ☑ │ --- │ --- │ ⦰ │ « │ » │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ --- │ ∞ │ ∧ │ --- │ ∨ ║ --- │ ¬ │ --- │ (~) │ ÷ │--- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ ≤ │ ≥ │ --- │ --- ║ • │ --- │ --- │ ‥ │ ‼ │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ -* │ ✕ │ ("") │ │ │ ║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modR, [], keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ (^) │ --- │ --- │ --- │ --- │ _ │ --- ║ --- │ 7 │ 8 │ 9 │ ¿ │ “ │ ” │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ ü │ ö │ ä │ ? │ ‖ ║ # │ 4 │ 5 │ 6 │ . │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ = │ % │ ! │ --- ║ 0 │ 1 │ 2 │ 3 │ , │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ — │ ± │ (``) │ │ │ ║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modS, modR, keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ (°) │ --- │ --- │ --- │ --- │ ¢ │ ¤ ║ --- │ ⁷ │ ⁸ │ ⁹ │ ⁿ │ „ │ --- │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ Ü │ Ö │ Ä │ € │ ¦ ║ ⁽ │ ⁴ │ ⁵ │ ⁶ │ ⁾ │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ ≠ │ £ │ --- │ --- ║ ⁰ │ ¹ │ ² │ ³ │ § │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ – │ ⋆ │ (́́´) │ │ │ ║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modK, [], keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ --- │ --- │ ¼ │ ⅓ │ ½ │ ⅔ │ ¾ ║ ✛ │ ↖ │ ↑ │ ↗ │ ⁈ │ --- │ --- │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ --- │ ∈ │ --- │ --- │ ∖ ║ ∑ │ ← │ ↓ │ → │ ⁄ │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ ≙ │ ¶ │ --- │ ♫ ║ ↕ │ ↙ │ ↔ │ ↘ │ ✓ │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ ⸺ │ ✻ │ --- │ │ │ ║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modS, modK, keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ --- │ --- │ --- │ ♣ │ ♠ │ ♥ │ ♦ ║ ☩ │ ⇖ │ ⇑ │ ⇗ │ ⁉ │ --- │ --- │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ --- │ ∉ │ --- │ --- │ --- ║ --- │ ⇐ │ ⇓ │ ⇒ │ ∕ │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ ≟ │ ‣ │ --- │ ♬ ║ ⇕ │ ⇙ │ ⇔ │ ⇘ │ --- │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ ⸻ │ ★ │ --- │ │ │ ║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modM, [], keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ --- │ --- │ --- │ --- │ --- │ --- │ --- ║ ^Home │ Home │ Up │ End │ ^End │ --- │ --- │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ --- │ --- │ --- │ --- │ --- ║ Ins │ Left │ Down │ Right │ PgUp │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ --- │ --- │ --- │ --- ║ +Ins │ ^Left │ Del │^Right │ PgDn │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ --- │ --- │ --- │ │ │ ║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modK, modL, keys, unpretty(["│", "·║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ --- │ --- │ ⊆ │ ∪ │ --- │ --- │ ⊇ ·║ --- │ ╔· │ ╦· │ ╗· │ --- │ ≪ │ ≫ │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ ⊂ │ --- │ --- │ --- │ ⊃ ·║ ∩ │ ╠· │ ╬· │ ╣· │ ═· │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ Spc* │ --- │ --- │ --- ·║ --- │ ╚· │ ╩· │ ╝· │ ║· │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ --- │ --- │ --- │ │ │ ·║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modK, modR, keys, unpretty(["│", "·║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ --- │ FF │ FS │ GS │ RS │ US │ --- ·║ --- │ ╔ │ ╦ │ ╗ │ --- │ --- │ --- │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ --- │ --- │ --- │ --- │ --- ·║ --- │ ╠ │ ╬ │ ╣ │ ═ │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ --- │ --- │ --- │ --- ·║ --- │ ╚ │ ╩ │ ╝ │ ║ │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ --- │ --- │ --- │ │ │ ·║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modL, modR, keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ --- │ --- │ --- │ --- │ --- │ γ │ --- ║ --- │ ⌂ │ --- │ --- │ --- │ --- │ --- │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ --- │ --- │ α │ ε │ --- ║ --- │ ✗ │ ® │ ™ │ δ │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ --- │ 𝛑 │ --- │ --- ║ β │ µ │ --- │ · │ --- │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ --- │ --- │ --- │ │ │ ║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
code .= hotkeysCode(modWN, [], keys, unpretty(["│", "║"], " ─┌┬┐└┴┘├┼┤╓╥╖╙╨╜╟╫╢"
,"┌───────┬───────┬───────┬───────┬───────┬───────┬───────╥───────┬───────┬───────┬───────┬───────┬───────┬───────────────┐"
,"│ --- │ --- │ --- │ --- │ --- │ --- │ --- ║ --- │ #7 │ #8 │ #9 │ --- │ --- │ --- │"
,"├───────┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───╨───╥───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───────────┤"
,"│ --- │ --- │ --- │ --- │ --- │ --- │ --- ║ --- │ #4 │ #5 │ #6 │ --- │ --- │ --- │"
,"├───────────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────╨─╥─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┬─────┴─┐ │"
,"│ --- │ --- │ --- │ --- │ --- │ --- │ --- ║ #0 │ #1 │ #2 │ #3 │ --- │ --- │ │"
,"├─────────┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───╥───╨───┬───┴───┬───┴───┬───┴───┬───┴───┬───┴───────┴─────────┤"
,"│ --- │ --- │ --- │ --- │ │ │ ║ │ │ │ --- │ --- │ --- │"
,"└─────────┴───────┴───────┴───────┴───────┴───────┴───────╨───────┴───────┴───────┴───────┴───────┴─────────────────────┘"))
; assigns keys to a NOOP
; each parameter may be a single key string or a list thereof
disableKeysCode(keys*) {
local i, e, code := ""
log(A_ThisFunc, A_ThisFunc . "(" . arrayToString(keys) . ")")
for i, e in keys {
code .= isObject(e) ? disableKeysCode(e*) : (e . "::`treturn`n")
}
return code
}
; parameters modifierKeys1, modifierKeys2: list of alternative modifier keys (e.g. left and right kana);
; - both empty to define base layer
; - one of them empty to define a layer reachable with a single modifier
; - both non-empty to define a layer reachable with two modifiers
hotkeysCode(modifierKeys1, modifierKeys2, fromKeys, toKeys) {
; two modifiers: use each in both (#If and prefix) roles, e.g.
; modifierKeys1 == [ "a", "b" ], modifierKeys2 == [ "c", "d" ] =>
; #If (GetKeyState("a", "P") || GetKeyState("b", "P"))
; c & from1:: to1
; c & from2:: to2
; #If (GetKeyState("a", "P") || GetKeyState("b", "P"))
; d & from1:: to1
; d & from2:: to2
; #If (GetKeyState("c", "P") || GetKeyState("d", "P"))
; a & from1:: to1
; a & from2:: to2
; #If (GetKeyState("c", "P") || GetKeyState("d", "P"))
; b & from1:: to1
; b & from2:: to2
; This is required because the former half recognizes a & c & from1 with a pressed before c etc,
; and the latter half recognizes c & a & from1 with a pressed before c etc.
return modifierKeys1.length() > 0 && modifierKeys2.length() > 0 ? (hotkeysCodeImpl(modifierKeys1, modifierKeys2, fromKeys, toKeys) . hotkeysCodeImpl(modifierKeys2, modifierKeys1, fromKeys, toKeys))
; only one modifier: use as #If
: modifierKeys2.length() > 0 ? hotkeysCodeImpl(modifierKeys2, modifierKeys1, fromKeys, toKeys)
; one modifier (already given as #If) or none
: hotkeysCodeImpl(modifierKeys1, modifierKeys2, fromKeys, toKeys)
}
hotkeysCodeImpl(modifierIfKeys, modifierPrefixKeys, fromKeys, toKeys) {
local i, k, code, comment
if (modifierPrefixKeys.length() == 0) {
return hotkeysCodeImplIf(modifierIfKeys) . hotkeysCodeImplHotkeys("", fromKeys, toKeys)
} else {
comment := " && (" . arrayToString(modifierPrefixKeys, " || ", "", 0) . ")"
code := hotkeysCodeImplIf(modifierIfKeys, comment)
for i, k in modifierPrefixKeys {
code .= hotkeysCodeImplHotkeys(k . " & ", fromKeys, toKeys)
}
return code
}
}
; Map e.g. [ "a", "b" ] to `#If (GetKeyState("a", "P") || GetKeyState("b", "P"))'
hotkeysCodeImplIf(modifierKeys, descriptionSuffix = "") {
local i, k
local code := ";`t____________________/ ("
code .= arrayToString(modifierKeys, " || ", "", 0) . ")" . descriptionSuffix
code .= " \____________________"
for i, k in modifierKeys {
code .= (i == modifierKeys.minIndex()) ? "`n#If " : " || "
code .= "GetKeyState(""" . k . """, ""P"")"
}
code .= "`n"
return code
}
; Builds the hotkey definition code, e.g.
; | pk & fk1:: tk1
; | pk & fk2:: tk2
; if prefix == "pk & ", fromKeys == [ "fk1", "fk2" ] and toKeys == [ "tk1", "tk2" ]
; prefix can be empty; otherwise it must include the " & "
hotkeysCodeImplHotkeys(prefix, fromKeys, toKeys) {
local i, k, kt, code := ""
if (fromKeys.length() != toKeys.length()) {
throw "key count mismatch: " . arrayToString(fromKeys) . " / " . arrayToString(toKeys)
}
for i, k in fromKeys {
kt := toKeys[i]
if (neq(kt, "---")) {
kt := eq(aliases[kt], "") ? kt : aliases[kt]
if (eq(prefix, "") && eq(k, kt)) { ; comment out identity mapping
code .= ";;"
}
code .= prefix . k . "::`t" . kt . "`n"
}
}
; log(A_ThisFunc, code)
return code
}
code .= "#If"
log("---------------------------------- generated code ----------------------------------")
log(code)
log("---------------------------------- end of generated code ----------------------------------")
if (fileReplaceInPlace(A_ScriptFullPath . ".generated", ".*", "", code)) {
fileAppend, edited %A_ScriptFullPath%.generated`, re-starting`n, *
sleep 1000
reload
}
; Extracts substrings from a given string, discarding some characters
; (e.g. to extract keys from a pretty-printed keyboard layout).
; This function undoes the pretty-printing by
; 1. discarding all characters in ignoredChars;
; 2. splitting each param at separators (a string or array of strings, see standard function strSplit);
; 3. removing empty split results;
; 4. then joining the split results into one array.
; Example: unpretty("|", " _"
; , "|_q_|_w_|_e_|_r_|"
; , "| |F10| d |")
; == ["q", "w", "e", "r", "F10", "d"]
unpretty(separators, ignoredChars, decoratedKeys*) {
local results := []
local decoratedKey, part
for uu, decoratedKey in decoratedKeys {
local parts := strSplit(decoratedKey, separators, ignoredChars)
for uu, part in parts {
if (neq(part, "")) {
results.push(part)
}
}
}
log(A_ThisFunc, "unpretty(..) == " . arrayToString(results)) ;?
return results
}
arrayToString(array, separator = ", ", elemToStringFunc = "", withIndex = 1) {
local i, e, s
s := ""
for i, e in array {
s .= eq(s, "") ? "" : separator
if (withIndex) {
s .= "[" . i . "] "
}
s .= (elemToStringFunc == "" ? e : elemToStringFunc.call(e))
}
return s
}
log(arg0, arg1 = "") {
local e, arg0nl
if (neq(arg1, "")) {
log(format("{:-22.22s}:{}", arg0, arg1))
} else {
try {
arg0nl := arg0 . "`n"
FileAppend, %arg0nl%, **
} catch e {
OutputDebug %arg0%
}
}
}
; compares values for strict (string) equality
; see https://autohotkey.com/board/topic/28987-compare-two-variables-as-strings/
eq(val1, vals*) {
local i, val2
for i, val2 in vals {
if (("" . val1) != ("" . val2)) {
return 0
}
}
return 1
}
neq(val1, vals*) {
return !eq(val1, vals*)
}
fileReplaceInPlace(fileName, startMarkRegex, endMarkRegex, newLines*) {
local file := fileOpen(fileName, "rw-")
if (!isObject(file)) {
throw "failed to open file " . file . ": " . A_LastError
}
local section := 0 ; 0 / 1 / 2: before / in / after the section to replace
local i, startPos, crlf, oldLines := [], linesAfter := []
while (!file.atEOF) {
local line := file.readLine()
local chompedLine := regexReplace(line, "`r?`n$", "")
crlf := regexMatch(line, "`r`n$")
; outputDebug % "input line:`t" . line
if (section == 0) {
if (regexMatch(chompedLine, startMarkRegex)) {
section := 1
startPos := file.tell()
}
} else if (section == 1) {
if (neq(endMarkRegex, "") && regexMatch(chompedLine, endMarkRegex)) {
section := 2
linesAfter.push(line)
} else {
oldLines.push(chompedLine)
}
} else {
linesAfter.push(line)
}
}
outputDebug % "old lines: " . arrayToString(oldLines)
outputDebug % "new lines: " . arrayToString(newLines)
local sectionChanged := neq(join(oldLines, "`n"), join(newLines, "`n"))
if (section > 0 ; section to replace found
&& sectionChanged) {
; write replacement
local eol := crlf ? "`r`n" : "`n"
file.seek(startPos)
for i, line in newLines {
file.write(line)
file.write(eol)
}
; Write remaining input lines after replacement;
; The end marker is optional; if not found, replace until EOF.
for i, line in linesAfter {
file.write(line)
}
; truncate
file.length := file.tell()
}
file.close()
return section > 0 && sectionChanged
}
join(array, separator = ", ", elemToStringFunc = "") {
return arrayToString(array, separator, elemToStringFunc, 0)
}
; === misc ===
NumLock & Esc:: exitApp
NumLock & F1:: suspend
NumLock & F2:: reload
NumLock:: NumLock
v:: RShift
m:: LShift
LControl:: return
; === sub thumb row ===
; LCtrl:: navigation modifier
; LWin::
; LAlt::
; RAlt::
; AppsKey::
; RWin::
; RCtrl::
; === navigation block, ... ===
; PrintScreen::
; ScrollLock::
; Pause::
;
; Ins::
; Home::
; PgUp::
; Del::
; End::
; PgDn::
;
; Up::
; Left::
; Down::
; Right::
; === number pad ===
; NumLock::
; NumpadDiv::
; NumpadMult::
; NumpadHome::
; NumpadUp::
; NumpadPgUp::
;
; NumpadLeft::
; NumpadClear::
; NumpadRight::
; NumpadEnd::
; NumpadDown::
; NumpadPgDn::
;
; NumpadIns::
; NumpadDel::
; NumpadEnter::
; NumpadAdd::
; NumpadSub::
#Include %A_ScriptFullPath%.generated