forked from neo/neo-layout
481 lines
13 KiB
AutoHotkey
481 lines
13 KiB
AutoHotkey
; -*- encoding: utf-8 -*-
|
|
|
|
; Global neovars objects
|
|
Comp := composeDict ; current compose-plane
|
|
|
|
; Hotkey activation event handler (all modifiers)
|
|
;
|
|
; keyName
|
|
; Activation key-name used by AHK, typically a (combined) vk/sc code-string
|
|
; "VK<vk>SC<sc>" or a key-name such as "space", "backspace" etc.
|
|
; (see https://www.autohotkey.com/docs/KeyList.htm)
|
|
; isDown
|
|
; If True, activation event is key pressed down (including auto-repeats).
|
|
; If False, activation event is a key release.
|
|
; in the correct order.
|
|
AllStar(keyName, isDown) {
|
|
global
|
|
local char, actKeyName
|
|
|
|
if (TransformProc != "")
|
|
actKeyName := Transform%TransformProc%(keyName)
|
|
else
|
|
actKeyName := keyName
|
|
|
|
; Find layout character associated with the key
|
|
; char: U-code (Uxxxxxx) or special key name (7 characters)
|
|
if (Ebene7 and (CP7%actKeyName% != ""))
|
|
char := CP7%actKeyName%
|
|
else if (Ebene8 and (CP8%actKeyName% != ""))
|
|
char := CP8%actKeyName%
|
|
else if ((striktesMod2Lock == 0) && (NOC%actKeyName% == 1))
|
|
char := CP%EbeneNC%%actKeyName%
|
|
else
|
|
char := CP%EbeneC%%actKeyName%
|
|
|
|
; Process activation event through Hook-procedure
|
|
; if installed, or default up/down handler otherwise
|
|
if (isDown) {
|
|
; hook function returns false if event was handled conclusively
|
|
if (PressHookProc == "" or PressHook%PressHookProc%(keyName, char))
|
|
CharStarDown(keyName, char)
|
|
} else {
|
|
CharStarUp(keyName)
|
|
}
|
|
}
|
|
|
|
; Key event down
|
|
CharStarDown(keyName, char) {
|
|
global
|
|
local CompNew, charSend, SubProc, tosend, tosend1, tosend2, i
|
|
|
|
; has special key-procedure
|
|
if (SubStr(char,1,1) == "P") {
|
|
SubProc := SubStr(char,2,6)
|
|
CharProc%SubProc%(keyName)
|
|
return
|
|
}
|
|
wasNonShiftKeyPressed := 1
|
|
|
|
if (kbdRepChars != "" and kbdRepKey == keyName) {
|
|
; Keyboard repeat: replay last characters sent
|
|
tosend1 := ""
|
|
tosend2 := kbdRepChars
|
|
} else {
|
|
; New key is down, append it's character to the compose
|
|
CompNew := Comp[char]
|
|
|
|
; Compose-miss (fallback)
|
|
tosend1 := (CompNew ? "" : Comp._fallback)
|
|
if (tosend1 != "")
|
|
; Send fallback and restart compose
|
|
CompNew := composeDict[char]
|
|
|
|
; Compose-miss (fail)
|
|
if (not CompNew) {
|
|
; Compose hat verfehlt: nichts schicken, auch aktuelles Zeichen nicht schicken
|
|
tosend2 := ""
|
|
Comp := composeDict
|
|
|
|
; Compose-hit
|
|
} else if (CompNew._result) {
|
|
; Compose hat getroffen: wird geschickt, Compose gelöscht
|
|
tosend2 := CompNew._result
|
|
Comp := composeDict
|
|
|
|
; Compose-more
|
|
} else {
|
|
; Compose muss sich noch was merken: Jetzt noch nichts schicken.
|
|
tosend2 := ""
|
|
Comp := CompNew
|
|
}
|
|
|
|
; Enable keyboard repeat (useful to repeat a compose-result)
|
|
kbdRepChars := tosend2
|
|
kbdRepKey := keyName
|
|
|
|
; Clear out forgotten key release
|
|
; (in rare cases, the script window may e.g. go to background and miss events)
|
|
if (PR%keyName% != "") {
|
|
CharOutUp(PR%keyName%)
|
|
PR%keyName% := ""
|
|
}
|
|
}
|
|
tosend := tosend1 . tosend2
|
|
|
|
; Send out and release all characters in tosend1; then
|
|
; send out and release all characters except the last in tosend2
|
|
i := 1
|
|
While (StrLen(tosend) > i) {
|
|
charSend := SubStr(tosend,i,7)
|
|
i += 7
|
|
if (SubStr(charSend,1,1) == "P") {
|
|
; Invoke character-procedure
|
|
SubProc := SubStr(charSend,2,6)
|
|
CharProc%SubProc%(keyName)
|
|
} else if (StrLen(tosend)+1 == i and StrLen(tosend2) > 0) {
|
|
; Send out key down event and set up release cache
|
|
; for last character in tosend2
|
|
CharOutDown(charSend)
|
|
PR%keyName% := charSend
|
|
} else {
|
|
; Send out key down + up event
|
|
CharOut(charSend)
|
|
}
|
|
}
|
|
|
|
; Notify on-screen board to check for updates
|
|
Check_BSTUpdate()
|
|
}
|
|
|
|
; Key event up
|
|
; Send out key-up event with layout-characters memorized in PR%keyname%
|
|
; and disable active keyboard repeats
|
|
CharStarUp(keyName) {
|
|
global
|
|
local SubProc, tosend
|
|
|
|
; Release cached characters from prior down-event
|
|
if (PR%keyName% != "") {
|
|
tosend := PR%keyName%
|
|
PR%keyName% := ""
|
|
if (SubStr(tosend,1,1) == "P") {
|
|
SubProc := SubStr(tosend,2,6)
|
|
CharProc%SubProc%(keyName)
|
|
} else
|
|
CharOutUp(tosend)
|
|
}
|
|
|
|
; Stop current key repeat
|
|
kbdRepChars := ""
|
|
}
|
|
|
|
;
|
|
; Send characters to output
|
|
;
|
|
|
|
; Send out activation event "key down, then up"
|
|
CharOut(char) {
|
|
global
|
|
if (CharOutFilterProc != "") {
|
|
char := CharOutFilter%CharOutFilterProc%(char,1,1)
|
|
if (char == "")
|
|
return
|
|
}
|
|
if (DNCS%char% != "")
|
|
SendBlindShiftFixed(char, DNCS%char% . UPCS%char%)
|
|
else if (CS%char% != "")
|
|
SendBlindShiftFixed(char, "{" . CS%char% . "}")
|
|
else
|
|
SendUnicodeChar("0x" . SubStr(char,2))
|
|
}
|
|
|
|
; Send out activation event "key down"
|
|
CharOutDown(char) {
|
|
global
|
|
if (CharOutFilterProc != "") {
|
|
char := CharOutFilter%CharOutFilterProc%(char,1,0)
|
|
if (char == "")
|
|
return
|
|
}
|
|
if (DNCS%char% != "")
|
|
SendBlindShiftFixed(char, DNCS%char%)
|
|
else if (CS%char% != "")
|
|
SendBlindShiftFixed(char, "{" . CS%char% . " down}")
|
|
else
|
|
SendUnicodeCharDown("0x" . SubStr(char,2))
|
|
}
|
|
|
|
; Send out activation event "key up"
|
|
CharOutUp(char) {
|
|
global
|
|
if (CharOutFilterProc != "") {
|
|
char := CharOutFilter%CharOutFilterProc%(char,0,1)
|
|
if (char == "")
|
|
return
|
|
}
|
|
if (DNCS%char% != "") {
|
|
if (UPCS%char% != "")
|
|
SendBlindShiftFixed(char, UPCS%char%)
|
|
} else if (CS%char% != "")
|
|
SendBlindShiftFixed(char, "{" . CS%char% . " up}")
|
|
else
|
|
SendUnicodeCharUp("0x" . SubStr(char,2))
|
|
}
|
|
|
|
SendBlindShiftFixed(char, theseq) {
|
|
global
|
|
if (UNSH%char%)
|
|
if (isShiftLPressed)
|
|
if (isShiftRPressed)
|
|
send % "{blind}{RShift Up}{Shift Up}" . theseq . "{Shift Down}{RShift Down}"
|
|
else
|
|
send % "{blind}{Shift Up}" . theseq . "{Shift Down}"
|
|
else
|
|
if (isShiftRPressed)
|
|
send % "{blind}{RShift Up}" . theseq . "{RShift Down}"
|
|
else
|
|
send % "{blind}" . theseq
|
|
else if (DOSH%char%)
|
|
if (isShiftLPressed)
|
|
if (isShiftRPressed)
|
|
send % "{blind}" . theseq
|
|
else
|
|
send % "{blind}{RShift Down}" . theseq . "{RShift Up}"
|
|
else
|
|
if (isShiftRPressed)
|
|
send % "{blind}{Shift Down}" . theseq . "{Shift Up}"
|
|
else
|
|
send % "{blind}{Shift Down}" . theseq . "{Shift Up}"
|
|
else
|
|
send % "{blind}" . theseq
|
|
}
|
|
|
|
;
|
|
; Unicode output
|
|
;
|
|
|
|
SendUnicodeChar(charCode){
|
|
static ki := "#"
|
|
if (ki =="#") {
|
|
VarSetCapacity(ki,28*4,0)
|
|
DllCall("RtlFillMemory","uint",&ki+ 0,"uint",1,"uint",1)
|
|
DllCall("RtlFillMemory","uint",&ki+ 28+0,"uint",1,"uint",1)
|
|
DllCall("RtlFillMemory","uint",&ki+2*28+0,"uint",1,"uint",1)
|
|
DllCall("RtlFillMemory","uint",&ki+3*28+0,"uint",1,"uint",1)
|
|
}
|
|
if (charCode < 0x10000) {
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+ 6,"uint",4,"uint",0x40000|charCode) ;KEYEVENTF_UNICODE
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+28+6,"uint",4,"uint",0x60000|charCode) ;KEYEVENTF_KEYUP|KEYEVENTF_UNICODE
|
|
DllCall("SendInput","UInt",2,"UInt",&ki,"Int",28)
|
|
} else {
|
|
hi_surrogate := 0xD800|((charCode-0x10000)/1024)
|
|
lo_surrogate := 0xDC00|((charCode-0x10000)&0x3FF)
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+ 6,"uint",4,"uint",0x40000|hi_surrogate) ;KEYEVENTF_UNICODE
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+ 28+6,"uint",4,"uint",0x40000|lo_surrogate) ;KEYEVENTF_UNICODE
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+2*28+6,"uint",4,"uint",0x60000|hi_surrogate) ;KEYEVENTF_KEYUP|KEYEVENTF_UNICODE
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+3*28+6,"uint",4,"uint",0x60000|lo_surrogate) ;KEYEVENTF_KEYUP|KEYEVENTF_UNICODE
|
|
DllCall("SendInput","UInt",4,"UInt",&ki,"Int",28)
|
|
}
|
|
}
|
|
|
|
SendUnicodeCharDown(charCode){
|
|
static ki := "#"
|
|
if (ki =="#") {
|
|
VarSetCapacity(ki,28*2,0)
|
|
DllCall("RtlFillMemory","uint",&ki+ 0,"uint",1,"uint",1)
|
|
DllCall("RtlFillMemory","uint",&ki+ 28+0,"uint",1,"uint",1)
|
|
}
|
|
if (charCode < 0x10000) {
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+ 6,"uint",4,"uint",0x40000|charCode) ;KEYEVENTF_UNICODE
|
|
DllCall("SendInput","UInt",1,"UInt",&ki,"Int",28)
|
|
} else {
|
|
hi_surrogate := 0xD800|((charCode-0x10000)/1024)
|
|
lo_surrogate := 0xDC00|((charCode-0x10000) & 0x3FF)
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+ 6,"uint",4,"uint",0x40000|hi_surrogate) ;KEYEVENTF_UNICODE
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+ 28+6,"uint",4,"uint",0x40000|lo_surrogate) ;KEYEVENTF_UNICODE
|
|
DllCall("SendInput","UInt",2,"UInt",&ki,"Int",28)
|
|
}
|
|
}
|
|
|
|
SendUnicodeCharUp(charCode){
|
|
static ki := "#"
|
|
if (ki =="#") {
|
|
VarSetCapacity(ki,28*2,0)
|
|
DllCall("RtlFillMemory","uint",&ki+ 0,"uint",1,"uint",1)
|
|
DllCall("RtlFillMemory","uint",&ki+ 28+0,"uint",1,"uint",1)
|
|
}
|
|
if (charCode < 0x10000) {
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+ 6,"uint",4,"uint",0x60000|charCode) ;KEYEVENTF_KEYUP|KEYEVENTF_UNICODE
|
|
DllCall("SendInput","UInt",1,"UInt",&ki,"Int",28)
|
|
} else {
|
|
hi_surrogate := 0xD800|((charCode-0x10000)/1024)
|
|
lo_surrogate := 0xDC00|((charCode-0x10000)&0x3FF)
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+ 6,"uint",4,"uint",0x60000|hi_surrogate) ;KEYEVENTF_KEYUP|KEYEVENTF_UNICODE
|
|
DllCall("ntdll.dll\RtlFillMemoryUlong","uint",&ki+ 28+6,"uint",4,"uint",0x60000|lo_surrogate) ;KEYEVENTF_KEYUP|KEYEVENTF_UNICODE
|
|
DllCall("SendInput","UInt",2,"UInt",&ki,"Int",28)
|
|
}
|
|
}
|
|
|
|
;
|
|
; Modifier procedures
|
|
;
|
|
|
|
CharProc__M2LD(keyName) {
|
|
global
|
|
if (!isShiftLPressed) {
|
|
if (isShiftRPressed and !wasNonShiftKeyPressed)
|
|
ToggleMod2Lock()
|
|
isShiftLPressed := 1
|
|
isShiftPressed := 1
|
|
wasNonShiftKeyPressed := 0
|
|
EbeneAktualisieren()
|
|
PR%keyName% := "P__M2LU"
|
|
}
|
|
CharOutDown("S__L_M2")
|
|
}
|
|
|
|
CharProc__M2LU(keyName) {
|
|
global
|
|
isShiftLPressed := 0
|
|
isShiftPressed := isShiftRPressed
|
|
EbeneAktualisieren()
|
|
CharOutUp("S__L_M2")
|
|
}
|
|
|
|
CharProc__M2RD(keyName) {
|
|
global
|
|
if (!isShiftRPressed) {
|
|
if (isShiftLPressed and !wasNonShiftKeyPressed)
|
|
ToggleMod2Lock()
|
|
isShiftRPressed := 1
|
|
isShiftPressed := 1
|
|
wasNonShiftKeyPressed := 0
|
|
EbeneAktualisieren()
|
|
PR%keyName% := "P__M2RU"
|
|
}
|
|
CharOutDown("S__R_M2")
|
|
}
|
|
|
|
CharProc__M2RU(keyName) {
|
|
global
|
|
isShiftRPressed := 0
|
|
isShiftPressed := isShiftLPressed
|
|
EbeneAktualisieren()
|
|
CharOutUp("S__R_M2")
|
|
}
|
|
|
|
CharProc__M3LD(keyName) {
|
|
global
|
|
if (!isMod3LPressed) {
|
|
if (isMod3RPressed and !wasNonShiftKeyPressed)
|
|
CharStarDown("MOD3", "S__Comp")
|
|
isMod3LPressed := 1
|
|
isMod3Pressed := 1
|
|
wasNonShiftKeyPressed := 0
|
|
EbeneAktualisieren()
|
|
PR%keyName% := "P__M3LU"
|
|
}
|
|
}
|
|
|
|
CharProc__M3LU(keyName) {
|
|
global
|
|
if (isMod3RPressed)
|
|
CharStarUp("MOD3")
|
|
isMod3LPressed := 0
|
|
isMod3Pressed := isMod3RPressed
|
|
EbeneAktualisieren()
|
|
}
|
|
|
|
CharProc__M3RD(keyName) {
|
|
global
|
|
if (!Mod3RPressed) {
|
|
if (isMod3LPressed and !wasNonShiftKeyPressed)
|
|
CharStarDown("MOD3", "S__Comp")
|
|
isMod3RPressed := 1
|
|
isMod3Pressed := 1
|
|
wasNonShiftKeyPressed := 0
|
|
EbeneAktualisieren()
|
|
PR%keyName% := "P__M3RU"
|
|
}
|
|
}
|
|
|
|
CharProc__M3RU(keyName) {
|
|
global
|
|
if (isMod3LPressed)
|
|
CharStarUp("MOD3")
|
|
isMod3RPressed := 0
|
|
isMod3Pressed := isMod3LPressed
|
|
EbeneAktualisieren()
|
|
}
|
|
|
|
CharProc__M4LD(keyName) {
|
|
global
|
|
if (!isMod4LPressed) {
|
|
isMod4LPressed := 1
|
|
isMod4Pressed := 1
|
|
EbeneAktualisieren()
|
|
PR%keyName% := "P__M4LU"
|
|
if (isMod4RPressed and !wasNonShiftKeyPressed) {
|
|
wasNonShiftKeyPressed := 0
|
|
ToggleMod4Lock()
|
|
} else
|
|
wasNonShiftKeyPressed := 0
|
|
}
|
|
}
|
|
|
|
CharProc__M4LU(keyName) {
|
|
global
|
|
isMod4LPressed := 0
|
|
isMod4Pressed := isMod4RPressed
|
|
EbeneAktualisieren()
|
|
}
|
|
|
|
CharProc__M4RD(keyName) {
|
|
global
|
|
if (!isMod4RPressed) {
|
|
isMod4RPressed := 1
|
|
isMod4Pressed := 1
|
|
EbeneAktualisieren()
|
|
PR%keyName% := "P__M4RU"
|
|
if (isMod4LPressed and !wasNonShiftKeyPressed) {
|
|
wasNonShiftKeyPressed := 0
|
|
ToggleMod4Lock()
|
|
} else
|
|
wasNonShiftKeyPressed := 0
|
|
}
|
|
}
|
|
|
|
CharProc__M4RU(keyName) {
|
|
global
|
|
isMod4RPressed := 0
|
|
isMod4Pressed := isMod4LPressed
|
|
EbeneAktualisieren()
|
|
}
|
|
|
|
;
|
|
; Other character procedures
|
|
;
|
|
; See also keyhooks.ahk
|
|
|
|
; Neustart des AHK-Skripts
|
|
CharProc__Rlod(keyName) {
|
|
global
|
|
SetOldLockStates()
|
|
reload
|
|
}
|
|
|
|
;
|
|
; Lock states
|
|
;
|
|
|
|
SetNEOLockStates() {
|
|
global
|
|
SavedNumLockState := GetKeyState("NumLock","T")
|
|
SavedScrollLockState := GetKeyState("ScrollLock","T")
|
|
SavedCapsLockState := GetKeyState("CapsLock","T")
|
|
SwitchIs0 := "Off"
|
|
SwitchIs1 := "On"
|
|
SavedNumLockState := SwitchIs%SavedNumLockState%
|
|
SavedScrollLockState := SwitchIs%SavedScrollLockState%
|
|
SavedCapsLockState := SwitchIs%SavedCapsLockState%
|
|
if (NumLockOff)
|
|
SetNumLockState, Off
|
|
else
|
|
SetNumLockState, On
|
|
SetScrollLockState, Off
|
|
SetCapsLockState, Off
|
|
Sleep,1
|
|
UpdateNEOLEDS()
|
|
}
|
|
|
|
SetOldLockStates() {
|
|
global
|
|
UpdateOldLEDS()
|
|
Sleep,1
|
|
SetNumLockState,% SavedNumLockState
|
|
SetScrollLockState,% SavedScrollLockState
|
|
SetCapsLockState,% SavedCapsLockState
|
|
}
|
|
|