Skip to content

Instantly share code, notes, and snippets.

@honboubao
Last active July 31, 2021 10:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save honboubao/9db2827c273ac0d4a296ef1651f99c78 to your computer and use it in GitHub Desktop.
Save honboubao/9db2827c273ac0d4a296ef1651f99c78 to your computer and use it in GitHub Desktop.
#SingleInstance Force
#InstallKeybdHook
TAPPING_TERM := 200
keyboard := ["SC029","SC002","SC003","SC004","SC005","SC006","SC007","SC008","SC009","SC00A","SC00B","SC00C","SC00D","SC00E"
,"SC00F","SC010","SC011","SC012","SC013","SC014","SC015","SC016","SC017","SC018","SC019","SC01A","SC01B","SC01C"
,"SC03A","SC01E","SC01F","SC020","SC021","SC022","SC023","SC024","SC025","SC026","SC027","SC028","SC02B"
,"SC02A","SC02C","SC02D","SC02E","SC02F","SC030","SC031","SC032","SC033","SC034","SC035","SC056","SC136"
,"SC01D","SC15B","SC038","SC039","SC138","SC11D"]
; ^ 1 2 3 4 5 6 7 8 9 0 ß ´ bspc
; tab q w e r t z u i o p ü + enter
; caps a s d f g h j k l ö ä #
; lshift y x c v b n m , . - < rshift
; lctrl lwin lalt space ralt rctrl
scIndexes := {}
shiftMod := { .: "ß", Backspace: "Del", BS: "Del", Enter: "Esc"}
modTaps := [ "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ""
, "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ""
, "" , "+" , 3 , 4 , 2 , "" , "" , 2 , 4 , 3 , "+" , "" , ""
, "" , "^" , "#" , "!" , "" , "" , "" , "" , "!" , "#" , "^" , "^" , ""
, "" , "" , "" , 5 , "" , "" ]
layers := []
layers[1] := [ "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ""
, "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ""
, "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ""
, "" , "" , "" , "" , "" , "" , "" , "" , "ü" , "" , "ä" , "" , ""
, "" , "" , "" , "" , "" , "" ]
layers[2] := [ "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ""
, "" , "1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "0" , "" , "" , ""
, "" , "µ" , "²" , "³" , "=" , "/" , "-" , "4" , "5" , "6" , "," , "" , ""
, "" , "" , "" , "" , "" , "*" , "+" , "1" , "2" , "3" , "." , "" , ""
, "" , "" , "" , "Tab" , "0" , "" ]
layers[3] := [ "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ""
, "" , "^" , "$" , "#" , "%" , "&" , "|" , "{" , "}" , "[" , "]" , "" , "" , ""
, "" , "°" , "´" , "'" , """" , "``" , "?" , "(" , ")" , "<" , ">" , "" , ""
, "" , "§" , "~" , "\" , "€" , "@" , "!" , ";" , "," , ":" , "_" , "" , ""
, "" , "" , "" , "BS" , "" , "" ]
layers[4] := [ "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ""
, "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ""
, "" , "F1" , "F2" , "F3" , "F4" , "F5" , "F6" , "F7" , "F8" , "F9" , "F10" , "" , ""
, "" , "" , "" , "","Click X1", "F11", "F12" ,"Click X2", "" , "" , "" , "" , ""
, "" , "" , "" ,"Enter", "" , "" ]
layers[5] := [ "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ""
, "" , "" , "Home", "Up" , "End" , "PgUp", "^c" , "Home", "Up" , "End" , "" , "" , "" , ""
, "" , "" , "Left", "Down","Right", "PgDn", "^v" , "Left", "Down","Right", "" , "" , ""
, "" , "" , "" , "" , "" , "" , "^x" , "^z" , "" , "" , "" , "" , ""
, "" , "" , "" , "" , "" , "" ]
modTapQueue := []
getCurrentLayer() {
global modTapQueue, layers
currentLayer := 1
for i, state in modTapQueue
if (state.hold and layers[state.targetLayer])
currentLayer := state.targetLayer
return currentLayer
}
getKey(sc) {
global scIndexes, layers
currentLayer := getCurrentLayer()
if (layers[currentLayer][scIndexes[sc]]) {
return layers[currentLayer][scIndexes[sc]]
}
if (currentLayer = 1) {
return GetKeyName(sc)
}
return ""
}
getMods() {
return (GetKeyState("Ctrl") ? "^" : "") . (GetKeyState("Alt") ? "!" : "")
}
class SelfDeletingTimer {
__New(period, fn, prms*) {
this.fn := IsObject(fn) ? fn : Func(fn)
this.prms := prms
SetTimer % this, % period
}
Call() {
this.fn.Call(this.prms*)
this.Stop()
}
Stop() {
SetTimer % this, Delete
}
}
hasUnresolvedModTap() {
global modTapQueue
for i, state in modTapQueue
if (state.targetLayer and not state.hold)
return true
}
getModTapStateIndex(sc) {
global modTapQueue
for i, state in modTapQueue
if (state.sc = sc)
return i
}
getModTapState(sc) {
global modTapQueue
return modTapQueue[getModTapStateIndex(sc)]
}
removeModTapState(sc) {
global modTapQueue
loop {
i := getModTapStateIndex(sc)
if (not i)
break
modTapQueue.removeAt(i)
}
}
modKeyName(mod) {
switch mod {
case "^":
return "Control"
case "!":
return "Alt"
case "+":
return "Shift"
case "#":
return "Win"
}
}
sendModKey(mod, action) {
modKey := modKeyName(mod)
if (modKey)
Send {%modKey% %action%}
}
holdModTap(sc) {
state := getModTapState(sc)
if (state and state.targetLayer and not state.hold) {
state.hold := true
sendModKey(state.targetLayer, "down")
}
}
startModTap(sc, modTapTarget) {
global modTapQueue, TAPPING_TERM
if (getModTapStateIndex(sc)) {
return
}
state := { sc: sc, timer: new SelfDeletingTimer(TAPPING_TERM, "holdModTap", sc), targetLayer: modTapTarget, tick: A_TickCount }
modTapQueue.push(state)
}
finishModTap(sc) {
state := getModTapState(sc)
state.timer.stop()
if (state.hold) {
sendModKey(state.targetLayer, "up")
} else {
resolveModTapQueue(sc)
pressKey(sc)
}
removeModTapState(sc)
}
resolveModTapQueue(sc) {
global modTapQueue
for i, state in modTapQueue {
if (state.sc = sc)
return
if (state.targetLayer and not state.hold)
holdModTap(state.sc)
else if (not state.targetLayer and not state.triggered) {
state.triggered := true
sendKey(state.sc, "down")
}
}
}
startModTapInterrupt(sc) {
global modTapQueue
if (getModTapStateIndex(sc)) {
return
}
state := { sc: sc }
modTapQueue.push(state)
}
finishModTapInterrupt(sc) {
global modTapQueue
state := getModTapState(sc)
if (state) {
resolveModTapQueue(sc)
if (not state.triggered) {
state.triggered := true
sendKey(state.sc, "down")
}
}
sendKey(sc, "up")
removeModTapState(sc)
}
pressKey(sc) {
sendKey(sc, "")
}
sendKey(sc, action) {
global shiftMod
key := getKey(sc)
if (GetKeyState("Shift") and shiftMod[key]) {
mods := getMods()
replacementKey := shiftMod[key]
Send {Shift up}%mods%{%replacementKey% %action%}{Shift down}
return
}
if (StrLen(key) >= 1) {
mods := ""
while (StrLen(key) > 1 and RegExMatch(key, "^[#!^+]")) {
mods .= SubStr(key, 1, 1)
key := SubStr(key, 2)
}
Send {Blind}%mods%{%key% %action%}
}
}
onKey(sc, action) {
global scIndexes, modTaps
modTapTarget := modTaps[scIndexes[sc]]
if (modTapTarget) {
if (action = "down") {
startModTap(sc, modTapTarget)
} else {
finishModTap(sc)
}
return
}
if (action = "down" and hasUnresolvedModTap()) {
startModTapInterrupt(sc)
return
}
if (action = "up" and getModTapState(sc)) {
finishModTapInterrupt(sc)
return
}
sendKey(sc, action)
}
For k, sc in keyboard {
scIndexes[sc] := k
dnfn := Func("onKey").Bind(sc, "down")
upfn := Func("onKey").Bind(sc, "up")
Hotkey, % "*" . sc, % dnfn
Hotkey, % "*" . sc . " up", % upfn
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment