neovars: Compose and key-event processing rewritten for clarity

Major changes:
- "Everything is a compose", incl. invididual keystrokes:
  Keys and composes are now on equal footing, their processing unified.
- Key event processing through AllStar and subsequent procedures
  rewritten for clarity.
- Parts of "Wie mit Neo"-Tool rewritten (while adjusting to new compose)

Compose:
- Compose-definitions cannot overwrite (or make unreachable) existing ones,
  so the order of generating composes from files etc. matters
- Reordered Xcompose-files (now base.module is first)
- Compose-definitions in compose.generated.ahk updated
- custom.ahk gets two new initialization event functions so that user can
  declare custom composes before/after others.

Key events:
- Multi-character compose-sequences no longer automatically release the last
  key in the sequence (instead, it will be released once the key which
  triggered the sequence's output is lifted)
- Keyboard-autorepeat no longer sends key-up (release) events

Other changes:
- The reliance on global variables has been reduced, resorting to local
  variables and passing arguments to called functions instead.
- CharProc's receive the keyName of the invoking key as first argument
- Keyhooks must return True (to stop event bubbling) or False
- Keyboard autorepeat is now managed with just two global variables,
  instead of one per individual key.
- Unused arguments (ActKey) removed from functions
This commit is contained in:
ferdinym 2020-10-29 02:48:14 +01:00
parent 52f606b18a
commit 1812ec7a43
18 changed files with 8447 additions and 18231 deletions

View File

@ -10,14 +10,17 @@
[Global]
; Zeichenkette, welche allen Dateinamen in composeFiles vorangestellt wird.
; Alle notwendigen (Back-)Slashes müssen enthalten sein!
; Hinweis: Alle notwendigen (Back-)Slashes müssen enthalten sein!
composeFilesPrefix=..\..\..\Compose\src\
; Komma-separierte Liste der zu ladenden compose-Dateien.
; Nicht-absolute Pfade werden relativ zum "tools"-Verzeichnis ausgewertet.
; In einer vollständigen lokalen Kopie des neo-layout Projektes
; können die Dateien unter "..\..\..\Compose\src" verwendet werden.
composeFiles=en_US.UTF-8, base.module, greek.module, math.module, cyrillic.module, lang.module
; Hinweise:
; - Zuerst gelistete Compose-Definitionen haben vorrang. Spätere Sequenzen werden ignoriert,
; wenn sie bestehende Definitionen verändern noch unerreichbar machen würden.
; - Nicht-absolute Pfade werden relativ zum "tools"-Verzeichnis ausgewertet.
; - In einer vollständigen lokalen Kopie des neo-layout Projektes
; können die Dateien unter "..\..\..\Compose\src" verwendet werden.
composeFiles=base.module, en_US.UTF-8, greek.module, math.module, cyrillic.module, lang.module
; Sollen von den bestehenden Skripten mit früheren Compose-Definitionen
; Sicherheitskopien erstellt werden, bevor diese gelöscht werden?

View File

@ -65,7 +65,7 @@ zeigeModusBox=1
useMod4Light=1
; Soll das Aktivieren des Mod-4-Locks auch über das Caps-Lock-Licht angezeigt werden?
; Hinweis: keine weiteren LEDs vorhanden sind)?
; Hinweis: Diese Funktion ist hilfreich, wenn keine weiteren LEDs vorhanden sind
useMod4LightCaps=0
@ -111,14 +111,17 @@ NumLockOff=0
dynamischesCompose=0
; Zeichenkette, welche allen Dateinamen in dynComposeFiles vorangestellt wird.
; Alle notwendigen (Back-)Slashes müssen enthalten sein!
; Hinweis: Alle notwendigen (Back-)Slashes müssen enthalten sein!
dynComposeFilesPrefix=..\..\..\Compose\src\
; Komma-separierte Liste der bei dynamischem Compose geladenen Dateien.
; Hinweise: Nicht-absolute Pfade werden relativ zum Programmverzeichnis ausgewertet.
; Werden keine Dateien angegeben, werden einige Standarddateien innerhalb
; einer lokalen Kopie des neo-layout Projektverzeichnisses gesucht.
dynComposeFiles=en_US.UTF-8, base.module, greek.module, math.module, cyrillic.module, lang.module, weiter_Definitionen.txt
; Hinweise:
; - Zuerst gelistete Compose-Definitionen haben vorrang. Spätere Sequenzen werden ignoriert,
; wenn sie bestehende Definitionen verändern noch unerreichbar machen würden.
; - Nicht-absolute Dateipfade werden relativ zum Programmverzeichnis ausgewertet.
; - Werden keine Dateien angegeben, werden einige Standarddateien innerhalb einer
; lokalen Kopie des neo-layout Projektverzeichnisses gesucht.
dynComposeFiles=base.module, en_US.UTF-8, greek.module, math.module, cyrillic.module, lang.module
; WEITERE EINSTELLUNGEN --------------

View File

@ -1,114 +1,95 @@
; -*- encoding: utf-8 -*-
;
; Benutzerdefinierte Neovars-Skripte
; Benutzerdefiniertes Neovars-Skript
;
; Damit dieses AHK-Skript beim Programmstart ausgeführt wird, muss es unter
; "%APPDATA%\Neo2\custom.ahk" (bzw. für die portable Version unter
; "<Verzeichnis der Neo2-exe>\Neo2-portable\Neo2.ini") abgelegt werden.
;
; Sind die Funktionen InitializeCustom1() und InitializeCustom2() definiert,
; werden diese zu verschiedenen Zeitpunkten in der Initialisierung aufgerufen
; und können für eigene Komposita-Definitionen genutzt werden.
;
; *Hinweise zu Komposita*
; Einfache statische (XCompose-) Definitionen können per XCompose-Datei beim
; Kompilieren oder dynamisch (per Neo2.ini-Einstellung) geladen werden.
; Sollen Neovars-spezifische Komposita erzeugt werden, können diese hier per
; "makeCompose(sequence, resultChars, fallback)" erzeugt werden.
; Dabei enthält sequence = ["<char1>", "<char2>", ...] die Zeichensequenz,
; welche in die Ausgabe resultChars = "<char1><char2>..." umgewandelt wird.
; Die Zeichen <charN> sind jeweils durch einen hexadezimalen Unicode-Codepoint
; mit vorangestelltem "U" (z.B. "U00266B"), oder durch einen Spezialzeichen-
; Namen zu ersetzen (z.B. "S__Comp" für die <compose>-Taste oder "P___WMN" um
; das "Wie mit Neo" - Werkzeug aufzurufen). In sequence können Unicode-Symbole
; auch direkt eingegeben werden.
; Wird optional fallback = "<char1><char2>..." angegeben, so wird dieses bei
; Fehleingabe des letzten Zeichens der sequenz, gefolgt von dem falsch
; eingegeben Zeichen, gesendet.
; Bereits bestehende Komposita können nicht mehr verändert oder unerreichbar
; gemacht werden.
; Siehe auch compose.ahk.
;
; *Hinweise zu Symbolen auf der Bildschirmtastatur*
; Manchmal ist es sinvoll, Komposita oder Zeichen auf der Bildschirmtastatur
; mit einem Ersatzsymbol darzustellen (insbesondere bei nicht druckbaren
; Zeichen oder langem Text). Dazu kann die Funktion "GUISYM(chars, sym, style)"
; genutzt werden, welche chars = "<char1><char2>..." durch das Unicode-Zeichen
; sym ersetzt. Optional kann die Darstellung per style verändert werden.
; Siehe screenkeyboard.ahk
; Wird nach Initialisierung des Programms aufgerufen
InitializeCustom() {
; Diese Funktion wird während der Programminitialisierung aufgerufen,
; vor Definition der Komposita, Tastenbelegung und Modulinitialisierung.
;
; Hinweise:
; - Hier definierte Komposita überschreiben alle weiteren, einschließlich der
; Originaltastenbelegung.
; - Es sind nicht alle globalen Variablen aus Modulen oder der Tastenbelegung
; verfügbar.
InitializeCustom1() {
global
; ...
; Beispiele für Kompose-Definitionen:
; <compose>-Taste abschalten und durch Tabulator ersetzen
; Hinweis: Alle später definierten über <compose> erreichbaren
; Komposita können diese Definition nicht mehr überschreiben
; und werden daher unerreichbar.
;makeCompose(["S__Comp"], "U000009")
; Werkzeug-Aufrufsequenzen erweitern
;makeCompose(["S__Comp", "U000055", "U000063"], "P__Cal1") ; Uc
;makeCompose(["S__Comp", "U000075", "U000043"], "P__Cal2") ; uC
;makeCompose(["S__Comp", "U000055", "U000077"], "P___WMN") ; Uw
;makeCompose(["S__Comp", "U000075", "U000057"], "P___WMN") ; uW
}
; Modifikationen und Erweiterungen der Compose-Definitionen (Neovars-spezifisch)
; Für projektweite (neo-layout) Definitionen: Compose/src/weiter_Definitionen.txt
; Diese Funktion wird nach Abschluss der Programminitialisierung aufgerufen,
; nach Definition der Komposita, Tastenbelegung und Modulinitialisierung.
;
; Wird nach Initialisierung des Programms und der Compose-Definitionen aufgerufen.
LoadCustomCompose() {
; Hinweise:
; - Hier definierte Komposita können bestehende Komposita, einschließlich der
; Originaltastenbelegung, weder verändern noch unerreichbar machen.
InitializeCustom2() {
global
; *Benutzerdefinierte Komposita*
;
; Kurzreferenz:
; CM<a> := 1
; CM<a><b> := 1
; ...
; CM<a><b>...<n> := 1
; CD<a><b>...<n><m> := "<kompositum>"
; CRC<kompositum> .= " <a><b>...<n><m>"
; Beispiele für Kompose-Definitionen:
; Beispiel: <compose>+<enter> → Tastaturbelegung
; <compose> + <enter> → Tastaturbelegung
; Hinweis: Tastaturbelegung wie zu Programmstart ohne Neovars-Modi
; layoutstringEnc := EncodeUniCompose(layoutstring)
; CDS__CompU00000D := layoutstringEnc
;layoutstringEnc := util_str2UCodes(layoutstring)
;makeCompose(["S__Comp", "U00000D"], layoutstringEnc)
; ...
; verzögert ßß → ſs auslösen
; (nach commit 97f45845332229b0d7a1344157e04b24d856856b)
;makeCompose(["ß", "ß"], "U0000DFFU0000DF", "U0000DF")
; *Benutzerdefinierte Ersatz-Symbole für Bildschirmtastatur*
;
; Kurzreferenz:
; GUISYM("<kompositum>","<symbol>")
; Beispiele für Bildschirmtastatur-Symbole:
; Beispiel: Tastaturbelegung → ⌨ (Tastatur-Emoji)
; Hinweis: Erstes Beispiel muss einkommentiert sein.
; GUISYM(layoutstringEnc,"⌨")
; Tastaturbelegung → ⌨ (Tastatur-Emoji)
; Hinweis: layoutstringEnc aus obigem Beispiel muss definiert sein.
;GUISYM(layoutstringEnc,"⌨")
; ...
; *Zurückfallende Komposita*
;
; Kurzreferenz:
; CF<teilsequenz> := <teilkompositum>
;
; Erläuterung:
;
; Eine typische Compose-Definition mit
; CM<teilsequenz> := 1
; CD<teilsequenz><x> := "<kompositum>"
; wandelt die Eingabesequenz <teilsequenz><x> mit Eingabe des
; Abschlusszeiches <x> in das entsprechende <kompositum> um.
;
; Folgt hingegen auf die <teilsequenz> ein unerwartetes Zeichen <u>,
; dann schlägt die Komposition fehl und die gesamte bisherige Eingabe
; <teilsequenz><u> wird verschluckt.
;
; Alternativ bewirkt die zusätzliche Definition
; CF<teilsequenz> := <teilkompositum>
; die Ausgabe von <teilkompositum><u>, sobald das unerwartete Zeichen <u>
; eingegeben wurde.
;
; Insbesondere wird mit
; CF<teilsequenz> := "<teilsequenz>"
; die gesamte Eingabesequenz so ausgegeben, wie sie eingegeben wurde.
;
; Beispiel:
;
; Setzt man beispielsweise
; CMU0000DF := 1
; CDU0000DFU0000DF := "U00017FU000073"
; dann bewirken die ersten beiden Zeilen, dass ein einzelnes ß erst mal
; „tot“ wirkt, und mit einem zweiten ß wird „ſs“ draus.
;
; Man kann nun folgende Zeile anhängen:
; CFU0000DF := "U0000DF"
; Diese bewirkt nun, dass das erste ß, sobald es von irgend einem anderen
; Zeichen gefolgt wird, mit diesem dann (verzögert) ausgegeben wird, so, als
; gäbe es für alle Compose-Möglichkeiten aus ß und anderem Zeichen eine
; entsprechende Compose-Sequenz, die eben diese beiden Zeichen als Ergebnis
; liefert. Normalerweise würden beide Zeichen verschluckt werden, da es
; keine entsprechende Compose-Sequenz gibt.
;
; Ohne CFU0000DF:
; ßß → ſs
; ßa →
; ßb →
;
; Mit CFU0000DF:
; ßß → ſs
; ßa → ßa
; ßb → ßb
;
; (siehe commit 97f45845332229b0d7a1344157e04b24d856856b)
; Beispiel: verzögert ßß → ſs auslösen
; CMU0000DF := 1
; CDU0000DFU0000DF := "U00017FU000073"
; CRCU00017FU000073 .= " U0000DFU0000DF"
; CFU0000DF := "U0000DF"
; ...
; Unbelegte Tasten als "Nichts-machen"-Werkzeug darstellen
;GUISYM("","❎","t")
}

View File

@ -1,26 +0,0 @@
; -*- encoding:utf-8 -*-
LoadCurrentCompose() {
global ini
; Read compose-input files from ini-file
IniRead, dynComposeFilesPrefix, %ini%, Global, dynComposeFilesPrefix , ""
IniRead, dynComposeFiles, %ini%, Global, dynComposeFiles , ""
; ..or use backwards-compatible defaults
if (not dynComposeFiles) {
MsgBox % dynComposeFiles
dynComposeFilesPrefix := "..\..\..\Compose\src\"
dynComposeFiles := "en_US.UTF-8, base.module, greek.module, math.module, cyrillic.module, lang.module"
}
; Parse and load compose sequences
keySym2KeyIdMap := makeKeySym2KeyIdMap()
Loop, parse, dynComposeFiles, CSV, %A_Space%%A_Tab%
{
f := dynComposeFilesPrefix . A_LoopField
if FileExist(f)
parseComposeFile(f, keySym2KeyIdMap)
}
}

View File

@ -1,41 +1,52 @@
; -*- encoding:utf-8 -*-
; Binds unicode-characters and special keys to compose sequences,
; which can be parsed from files formatted with a subset of the XCompose-
; format for the X-keyboard-extension (xkb, part of Linux X library).
; See also https://www.x.org/releases/X11R7.7/doc/man/man5/Compose.5.xhtml
; Binds unicode-characters and special keys to compose sequences.
; In neovars, everything that can be typed is a compose.
#Include %A_LineFile%\..\util.ahk
; Global settings
COMP_BACK_CHAR := "U000008" ; compose-undo character
; Transform XCompose-format-file into neovars compose-definitions
; Parse XCompose-format-file into neovars compose-definitions
;
; Reads compose-definitions from files formatted with a subset of the XCompose-
; format for the X-keyboard-extension (xkb, part of Linux X library) and
; creates the corresponding compose-definitions for the neovars driver.
; See also https://www.x.org/releases/X11R7.7/doc/man/man5/Compose.5.xhtml
;
; Arguments:
;
; composeFile
; composeFile (in)
; XCompose-File from which compose-definitions are read.
; Only a subset of the XCompose syntax is supported;
; features such as includes and key modifiers are not allowed.
; keySym2KeyIdMap
; keySym2KeyIdMap (in)
; KeySym-lookup-table, see makeKeySym2keyIdMap
; outputFile := ""
; If the argument is absend or an empty string, the parser dynamicall
; creates the compose-definitions in the global namespace.
; Otherwise, a filename of an AHK script, to which the parser
; appends the commands that would create the compose-definitions
; required by neovars when executed at a later time.
; onParseError := ""
; makeComposeFun := "" (in)
; Function object or name of a function that is invoked with each
; compose-result 'resultChars' for the sequence (array of keyIds)
; 'sequence'. Defaults to "makeCompose".
; Call syntax is "success := makeCompose(sequence, resultChars)"
; where success = False indicates an error.
; resDecFun := "" (in)
; Function object or name of a function that transforms each compose-
; result 'resultStr' as read from the input file into the compose-
; result passed to makeComposeFun. Defaults to "util_str2UCodes".
; Call syntax is "resultChars := resDecFun.Call(resultStr)"
; onParseError := "" (in)
; An optional function object that is called whenever the parser
; encounters an error. Called with the arguments (err, errorCount),
; where 'errorCount' is incremented with each such error (starting at 1),
; and 'err' holds further information on the error (see code).
; onProgress := ""
; onProgress := "" (in)
; An optional function object that is called whenever the parser
; made some progress. Called with arguments (line, numLines, errorCount),
; where 'line' is the number of lines parsed of 'numLines' total in the
; composeFile. onProgress is called at least on line=0 and line=numLines.
; progressTicks
; progressLines
; progressTicks (in)
; progressLines (in)
; Control the frequency at which 'onProgress' is called inbetween line=0
; and line=numLines (time in milliseconds and minimal number of lines
; parsed between two callse)
@ -46,9 +57,14 @@
; The composeFile is read with the current default file-encoding, which
; must match the file's encoding unless a BOM is present in UTF-8/16.
;
parseComposeFile(composeFile, keySym2KeyIdMap, outputFile:="", onParseError:="", onProgress:="", progressTicks:=200, progressLines:=100) {
errorCount := 0
parseComposeFile(composeFile, keySym2KeyIdMap, makeComposeFun, resDecFun:="util_str2UCodes"
, onParseError:="", onProgress:="", progressTicks:=200, progressLines:=100) {
; Function objects
makeComposeFun := (IsObject(makeComposeFun) ? makeComposeFun : Func(makeComposeFun))
resDecFun := (IsObject(resDecFun) ? resDecFun : Func(resDecFun))
errorCount := 0
if (onProgress) {
progressNextTick := 0
progressNextLine := 0
@ -59,7 +75,7 @@ parseComposeFile(composeFile, keySym2KeyIdMap, outputFile:="", onParseError:="",
onProgress.Call(0, numLines, errorCount)
}
Loop, Read, % composeFile, % outputFile
Loop, Read, % composeFile
{
; Progress update
if (onProgress and A_TickCount >= progressNextTick and A_Index >= progressNextLine) {
@ -81,20 +97,20 @@ parseComposeFile(composeFile, keySym2KeyIdMap, outputFile:="", onParseError:="",
; Convert sequence of keysyms into neovars keyIds
; E.g. 'keysym1> <keysym1> .. <keysymN> ' -> "S__CompUxxxxxxT__tlde.."
sequence := ""
sequence := []
, keyId := ""
Loop, Parse, linePart1, <, >%A_Space%%A_Tab%
{
keyId := keySym2KeyId(keySym2KeyIdMap, A_LoopField)
if (keyId == "") {
keyId := A_LoopField
, sequence := "" ; invalidate entire line
, sequence := [] ; invalidate entire line
break
}
sequence := sequence . keyId
sequence.Push(keyId)
}
; Handle parsing errors (unknown keysym or empty sequence)
if (sequence == "") {
if (sequence.Length() == 0) {
errorCount++
if (onParseError) {
err := {line: A_LoopReadLine, lineNo: A_Index}
@ -111,17 +127,18 @@ parseComposeFile(composeFile, keySym2KeyIdMap, outputFile:="", onParseError:="",
; Transform resolved symbol 'AAA' into string of codepoints
; 'ABC' -> "UxxxxxxUyyyyyy.."
resolved := util_str2UCodes(util_strUnescape(linePart2))
if (resolved == "") {
resultChars := resDecFun.Call(util_strUnescape(linePart2))
if (resultChars == "") {
onParseError.Call({line: A_LoopReadLine, lineNo: A_Index, type: "result"}, ++errorCount)
continue
}
; Update compose definitions
if (outputFile == "")
makeComposeDef(sequence, resolved)
else
FileAppend, % composeDefCmd(sequence, resolved)
; (even without outputFile, as a "dry-run" to check for conflicts)
success := makeComposeFun.Call(sequence, resultChars)
if (not success)
; error in making compose sequence, compose not updated
onParseError.Call({line: A_LoopReadLine, lineNo: A_Index, type: "make"}, ++errorCount)
}
; Final progress update
@ -131,92 +148,6 @@ parseComposeFile(composeFile, keySym2KeyIdMap, outputFile:="", onParseError:="",
return errorCount
}
; Add new sequence to global neovars compose-definitions
;
; sequence: a sequence of neovars keyIds
; resolved: the character that shall be sent in place of the sequence
makeComposeDef(sequence, resolved) {
global
; Declare composed character
CD%sequence% := resolved
; Generate recall-info for single characters only
if (StrLen(resolved) == 7)
CRC%resolved% .= " " . sequence
; Declare sequence continuations
local incomplSeq
, len := StrLen(sequence) - 7
While (len > 0) {
incomplSeq := SubStr(sequence,1,len)
if (CM%incomplSeq% == 1)
break
CM%incomplSeq% := 1
, len -= 7
}
}
; Write new sequence definition to loadable script file
; See makeComposeDef
composeDefCmd(sequence, resolved) {
global
; Declare composed character
cmdStr := " CD" . sequence . ":=""" . resolved . """"
; Generate recall-info for single characters only
if (StrLen(resolved)==7)
cmdStr .= "`r`n, CRC" . resolved . ".="" " . sequence . """"
; Declare sequence continuations
local incomplSeq
, len := StrLen(sequence) - 7
While (len > 0) {
incomplSeq := SubStr(sequence,1,len)
if (CM%incomplSeq% == 1)
break
CM%incomplSeq% := 1
, cmdStr .= "`r`n, CM" . incomplSeq . ":=1"
, len -= 7
}
; End of command
return cmdStr . "`r`n"
}
; Write new sequence definition to loadable script file
;
; Output format matches previous versions of this script.
;
; Note: Provided for debugging and compatibility with
; previous versions only. Deprecated.
composeDefCmd_LEGACY(sequence, resolved) {
global
cmdStr := ""
; Declare sequence continuations
local incomplSeq
, len := 7
While (len < StrLen(sequence)) {
incomplSeq := SubStr(sequence,1,len)
, len += 7
if (CM%incomplSeq% == 1)
continue
CM%incomplSeq% := 1
, cmdStr .= " CM" . incomplSeq . ":=1`r`n"
}
; Declare composed character
cmdStr .= " CD" . sequence . ":=""" . resolved . """`r`n"
; Generate recall-info for single characters only
if (StrLen(resolved)==7)
cmdStr .= " CRC" . resolved . ".="" " . sequence . """`r`n"
return cmdStr
}
; Lookup keyId from xbk-keySym alias (see makekeySym2KeyIdMap);
; Additionally keySym may be string "Uxx..x" where xx..x is a
; unicode codepoint with up to 6 hexadecimal digits,
@ -241,7 +172,7 @@ keySym2KeyId(keySym2KeyIdMap, keySym) {
return ""
}
; Set up a lookup-table
; Build lookup-table
;
; keySym2KeyIdmap.item(keySym) = keyId
;
@ -952,6 +883,7 @@ makeKeySym2keyIdMap() {
map.item("Arabic_theh") := "U00062B"
map.item("Arabic_jeem") := "U00062C"
map.item("Arabic_hah") := "U00062D"
map.item("Arabic_hah") := "U00062D"
map.item("Arabic_khah") := "U00062E"
map.item("Arabic_dal") := "U00062F"
map.item("Arabic_thal") := "U000630"

View File

@ -0,0 +1,146 @@
; -*- encoding:utf-8 -*-
;
; Global compose definitions
;
; Compose-definitions root object:
; Hosts compose-sequences in a nested structure of associative arrays
; ("compose-planes").
; A child-plane listed under a key "x" corresponds to the character "x"
; to be appended to the compose-sequence (where "x" is a keyId).
; The key that is the special character 'COMP_BACK_CHAR' links back to
; the parent plane. Special keys such as '_result' or '_fallback' hold
; compose-result and fallback characters; a plane with '_result' is
; assumed to be a leaf without child-planes.
composeDict := {} ; first compose-plane
; Reverse-lookup associative array, synchronized to composeDict:
; composeSequences[resultChars] = array of all leaf-planes whose '_result'
; is equal to 'resultChars'.
composeSequences := {}
; Read compose-definitions from XCompose-files ("dynamic compose")
; Appends sequences in provided order to global compose definitions
LoadCurrentCompose() {
global ini
; Read compose-input files from ini-file
IniRead, dynComposeFilesPrefix, %ini%, Global, dynComposeFilesPrefix , ""
IniRead, dynComposeFiles, %ini%, Global, dynComposeFiles , ""
; Backwards-compatible defaults
if (not dynComposeFiles) {
dynComposeFilesPrefix := "..\..\..\Compose\src\"
dynComposeFiles := "base.module, en_US.UTF-8, greek.module, math.module, cyrillic.module, lang.module"
}
; Parse and load compose sequences:
keySym2KeyIdMap := makeKeySym2KeyIdMap()
Loop, parse, dynComposeFiles, CSV, %A_Space%%A_Tab%
{
f := dynComposeFilesPrefix . A_LoopField
if FileExist(f)
parseComposeFile(f, keySym2KeyIdMap, "makeCompose")
}
}
; Add a new compose-sequence to global compose-definitions
;
; Arguments:
;
; sequence (in)
; Array of one or more single characters or neovars keyIds
; (U-code or special key name). If empty, False is returned.
; resultChars (in)
; One or more characters that shall be sent in place of the sequence,
; encoded in a consecutive string of keyIds (e.g. "UxxxxxxUyyyyyyPzzzzzz..").
; If empty, no compose-definition will be created, all conflicts
; with existing sequences will be ignored, and False is returned.
; fallback:="" (in)
; If a non-empty string is provided, it must be a consecutive string
; of U-codes, and becomes the fallback characters sent out when a
; compose-miss on the last character in the provided sequence occurs.
; If an empty string is provided (default), fallback is not enabled.
; Any existing (non-empty) fallback can not be overwritten, and False
; is returned in any attempt to do so (ignoring the provided sequence).
;
; Returns:
; True on success, False otherwise.
;
; Notes:
;
; Updates global dictionaries 'composeDict' and 'composeSequences'
; On entry, 'composeDict' may hold previously defined compose-sequences.
; On successful exit, the provided sequence is added to composeDict
; without overwriting or making inaccessible any existing sequences.
; Similarly, 'composeSequences' is updated with 'sequence' on successful exit.
;
; If the sequence contains any COMP_BACK_CHAR (backspaces by default)
; following any othe character, the COMP_BACK_CHAR acts as "compose-undo"
; and effectively remove the preceding character from the compose sequence
; (if no more such characters exist, the COMP_BACK_CHAR acts litterally)
;
; If the same, a longer, or a shorter sequence already exists, the existing
; sequence will not be overwritten, and False is returned instead.
;
makeCompose(sequence, resultChars, fallback:="") {
global composeDict, composeSequences, COMP_BACK_CHAR
; Quick return: empty result
; (not distinguishable from compose-fail)
if (resultChars == "")
return False
; Quick return: empty sequence
if (sequence.Length() == 0)
return False
; Set up sub-compose planes along the sequence
nextSubDict := composeDict ; current compose-plane
depth := 0
While (depth < sequence.Length())
{
; Enter next compose-plane
subDict := nextSubDict
char := util_char2Ucode(sequence[++depth])
nextSubDict := subDict[char]
if (not nextSubDict) {
; plane does not exist, create it
nextSubDict := {(COMP_BACK_CHAR):subDict, _sequenceChar: char}
subDict[char] := nextSubDict
} else if (nextSubDict._result) {
; error: shorter or equal sequence exists already
return False
} else if (depth == sequence.Length()) {
; error: longer sequence exists already
return False
}
}
; Enable fallback on compose-miss
if (fallback != "") {
if (subDict._fallback)
; error: fallback is already defined
return False
else
subDict._fallback := fallback
}
; Resolve sequence in last plane
nextSubDict._result := resultChars
; Update reverse lookup
; (map result to last plane; sequences can then be rebuild backwards
; from _sequenceChar's, going back step by step through COMP_BACK_CHAR)
compSeqList := composeSequences[resultChars]
if (not compSeqList) {
compSeqList := []
composeSequences[resultChars] := compSeqList
}
compSeqList.push(nextSubDict)
; Successfully updated compose definitions
return True
}

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,21 @@
; -*- encoding: utf-8 -*-
CharProc___EHt() {
CharProc___EHt(keyName) {
global
; Einhandmodus togglen
einHandNeo := !(einHandNeo)
if (einHandNeo) {
CharProc___EH1()
CharProc___EH1(keyName)
if (zeigeModusBox)
TrayTip,NEO-Einhandmodus,Der NEO-Einhand-Modus wurde aktiviert. Zum Deaktivieren Mod3+F10 drücken.,10,1
} else {
CharProc___EH0()
CharProc___EH0(keyName)
if (zeigeModusBox)
TrayTip,NEO-Einhand-Modus,Der Einhandmodus wurde deaktiviert.,10,1
}
}
CharProc___EH1() {
CharProc___EH1(keyName) {
global
; Einhand-NEO aktivieren
; Funktionstasten
@ -60,7 +60,7 @@ CharProc___EH1() {
ED("tab" ,0,"U000009","U000009","S__Comp","U000009","P__M2LT","U000009")
}
CharProc___EH0() {
CharProc___EH0(keyName) {
global
; Einhand-NEO deaktivieren
; Funktionstasten
@ -104,25 +104,26 @@ CharProc___EH0() {
RemoveTransformEinhand() ; make sure we remove trafo
}
CharProc__EHSd() {
CharProc__EHSd(keyName) {
global
; Space im Einhandmodus gedrückt
PRspace := "P__EHSu"
PR%keyName% := "P__EHSu"
InstallTransformEinhand()
}
CharProc__EHSu() {
CharProc__EHSu(keyName) {
global
; Space im Einhandmodus losgelassen
if (!EHKeyPressed) {
AllStar("EHSpace", True, "*EHSpace")
AllStar("EHSpace", False, "*EHSpace up")
AllStar("EHSpace", True)
AllStar("EHSpace", False)
}
EHKeyPressed := 0
RemoveTransformEinhand()
}
CharProc__M2LT() {
CharProc__M2LT(keyName) {
global
; Mod2Lock Toggle
ToggleMod2Lock()
@ -166,7 +167,7 @@ InitializeEinHandNeo() {
global
IniRead,einHandNeo,%ini%,Global,einHandNeo,0
If (einHandNeo)
CharProc___EH1()
CharProc___EH1("")
CP3F10 := "P___EHt"
GUISYM("P__EHSd","EH")

View File

@ -62,6 +62,11 @@ if (inputlocale<>"00000407" and inputlocale<>"00000807" and inputlocale<>"000104
suspend
}
; Run custom initialization (part I)
; (may include compose definitions)
InitializeCustomFun := "InitializeCustom1"
if (IsFunc(InitializeCustomFun))
%InitializeCustomFun%()
wasNonShiftKeyPressed := 0
isShiftRPressed := 0
isShiftLPressed := 0
@ -95,6 +100,13 @@ SetNEOLockStates() {
UpdateNEOLEDS()
}
; Load compose-definitions
; Later definitions cannot modify prior ones.
LoadToolsCompose() ; tool invocation sequences (as documented)
if (dynamischesCompose) ; parse external XCompose
LoadCurrentCompose()
else
LoadDefaultCompose() ; precompiled XCompose
SetOldLockStates() {
global
UpdateOldLEDS()
@ -104,30 +116,24 @@ SetOldLockStates() {
SetCapsLockState,% SavedCapsLockState
}
; Activate driver with default- or custom layout
ActivateLayOut(inputlocale)
TheKeys()
ChangeCustomLayout()
EbeneAktualisieren()
; Zusatzmodule in♫itialisieren
; Initialize auxiliary modules
; (may modify or add keys to the layout)
InitializeLangSTastatur()
InitializeEinHandNeo()
InitializeLernModus()
InitializeQwertz()
InitializeTools()
InitializeCustomFun := "InitializeCustom"
if (IsFunc(LoadCustomComposeFun))
%LoadCustomComposeFun%()
InitializeBST() ; Bildschirmtastatur erst nach Anpassungen laden
; Bildschirmtastatur nach Anpassungen laden
BSTRegister()
; Run custom initialization (part II)
; (may include compose definitions)
InitializeCustomFun := "InitializeCustom2"
if (IsFunc(InitializeCustomFun))
%InitializeCustomFun%()
; Compose definitions
if (dynamischesCompose)
LoadCurrentCompose()
else
LoadDefaultCompose()
LoadToolsCompose()
LoadCustomComposeFun := "LoadCustomCompose"
if (IsFunc(LoadCustomComposeFun))
%LoadCustomComposeFun%()

View File

@ -115,13 +115,22 @@ thekeys() {
SetKeyPos(pos,char) {
global
; Generate lookup table for "Wie mit Neo" tool
current := %pos%
if (current != "")
StringReplace,CRK%current%,CRK%current%,% " " . pos . " ",% " "
if (SubStr(CRK%char%,0) != " ")
CRK%char% .= " "
CRK%char% .= pos . " "
; Map layout-position (CP.VK...SC...) to character
%pos% := char
; Add trivial compose (echo itself)
; (will be ignored if compose exists already,
; e.g. in case of dupliate keys)
makeCompose([char], char)
}
EDR(pos,caps,e1,e2,e3,e4,e5,e6,e7="",e8="") {
@ -277,8 +286,6 @@ EDR1256(pos,caps,e1,e2,e5,e6) {
SetKeyPos("CP6" . pos, e6)
}
Comp := ""
; RegisterAndHookSC
RSC(sc,vk) {
global
@ -306,10 +313,11 @@ RKEYS(keys) {
}
}
; Register hotkeys for up, down key activation events
RKEYN(dnkey, key) {
upkey := dnkey . " up"
upfn := Func("AllStar").Bind(key, False, upkey)
dnfn := Func("AllStar").Bind(key, True, dnkey)
upfn := Func("AllStar").Bind(key, False)
dnfn := Func("AllStar").Bind(key, True)
Hotkey,% dnkey,% dnfn
Hotkey,% upkey,% upfn
}

View File

@ -1,7 +1,8 @@
; -*- encoding: utf-8 -*-
CharProc__LnSt() {
CharProc__LnSt(keyName) {
global
; Nur aktivieren, wenn kein Qwertz aktiv ist
;if (isQwertz) {
; TrayTip,Lang-S-Tastatur,Die Lang-S-Belegungsvariante kann nicht im QWERTZ-Modus aktiviert werden.,10,1
@ -11,17 +12,17 @@ CharProc__LnSt() {
;Lang-s-Tastatur: Toggle
LangSTastatur := !(LangSTastatur)
if (LangSTastatur) {
CharProc__LnS1()
CharProc__LnS1(keyName)
if (zeigeModusBox)
TrayTip,Lang-S-Tastatur,Die Lang-S-Belegungsvariante wurde aktiviert. Zum Deaktivieren`, Mod3+F11 drücken.,10,1
} else {
CharProc__LnS0()
CharProc__LnS0(keyName)
if (zeigeModusBox)
TrayTip,Lang-S-Tastatur,Lang-S-Belegungsvariante wurde deaktiviert.,10,1
}
}
CharProc__LnS1() {
CharProc__LnS1(keyName) {
global
; Lange-s-Tastatur aktivieren
spos := InStr(layoutstring, "s")
@ -40,7 +41,7 @@ CharProc__LnS1() {
SetKeyPos("CP3" . pos, util_char2UCode("ß"))
}
CharProc__LnS0() {
CharProc__LnS0(keyName) {
global
; Lange-s-Tastatur deaktivieren
spos := InStr(layoutstring, "s")
@ -63,7 +64,7 @@ InitializeLangSTastatur() {
global
IniRead,LangSTastatur,%ini%,Global,LangSTastatur,0
If (LangSTastatur)
CharProc__LnS1()
CharProc__LnS1("")
CP3F11 := "P__LnSt"
}

View File

@ -17,22 +17,22 @@ lernModus_std_ZahlenReihe := 0
lernModus_neo_Backspace := 1
lernModus_neo_Entf := 1
CharProc___LMt() {
CharProc___LMt(keyName) {
global
; Lernmodus togglen
lernModus := !(lernModus)
if (lernModus) {
CharProc___LM1()
CharProc___LM1(keyName)
if (zeigeModusBox)
TrayTip,NEO-Lernmodus,NEO-Lernmodus wurde aktiviert. Zum Deaktivieren`, Mod3+F9 drücken.,10,1
} else {
CharProc___LM0()
CharProc___LM0(keyName)
if (zeigeModusBox)
TrayTip,NEO-Lernmodus,Lernmodus wurde deaktiviert.,10,1
}
}
CharProc___LM1() {
CharProc___LM1(keyName) {
global
; Lernmodus aktivieren
if (!lernModus_std_Return)
@ -65,7 +65,7 @@ CharProc___LM1() {
CP4VK52SC013 := "" ; Ebene 4 unter c (QWERTZ: r)
}
CharProc___LM0() {
CharProc___LM0(keyName) {
global
; Lernmodus deaktivieren
ED1("enter" ,"U00000D")
@ -86,8 +86,9 @@ CharProc___LM0() {
InitializeLernModus() {
global
CP3F9 := "P___LMt"
IniRead,lernModus,%ini%,Global,lernModus,0
If (lernModus)
CharProc___LM1()
CharProc___LM1("")
CP3F9 := "P___LMt"
}

View File

@ -16,8 +16,8 @@ SetWorkingDir, %A_ScriptDir%
#include util.ahk
; die Compose-Definitionen
#include compose.ahk
#include compose-parse.ahk
#include compose-gen.ahk
#include *i compose.generated.ahk
#include *i compose-tainted.generated.ahk

View File

@ -2,33 +2,33 @@
; QWERTZ
; (c) 2011 Matthias Wächter
CharProcQwertT() {
CharProcQwertT(keyName) {
global
; Custom Layout togglen
if (isQwertz == 0) {
isQwertz := 1
CharProcQwerT1()
CharProcQwerT1(keyName)
if (zeigeModusBox)
TrayTip,QWERTZ-Belegungsvariante,Die Belegungsvariante QWERTZ wurde aktiviert. Zum Umschalten`, Mod3+F6 drücken.,10,1
} else {
isQwertz := 0
CharProcQwerT0()
CharProcQwerT0(keyName)
if (zeigeModusBox)
TrayTip,Voreingestellte Belegungsvariante,Die voreingestellte Belegungsvariante wurde wieder aktiviert.,10,1
}
}
CharProcQwerT1() {
CharProcQwerT1(keyName) {
; Tastaturbelegungsvariante QWERTZ aktivieren
Change1256Layout("ßqwertzuiopüasdfghjklöäyxcvbnm,.-")
}
CharProcQwerT0() {
CharProcQwerT0(keyName) {
; Ursprüngliche Belegung wieder aktivieren
ChangeCustomLayout()
}
CharProcQwerts() {
CharProcQwerts(keyName) {
global
IniWrite,%isQwertz%,%ini%,Global,isQwertz
if ErrorLevel
@ -39,11 +39,10 @@ CharProcQwerts() {
InitializeQwertz() {
global
IniRead,isQwertz,%ini%,Global,isQwertz,0
if (isQwertz == 1)
CharProcQwerT1("")
CP3F6 := "PQwertt" ; M3+F6: Aktiviere/Deaktiviere QWERTZ
CP4F6 := "PQwerts" ; M4+F6: Speichere QWERTZ
IniRead,isQwertz,%ini%,Global,isQwertz,0
if (isQwertz == 1)
CharProcQwerT1()
}

View File

@ -99,7 +99,7 @@ Check_BSTUpdate() {
if (!BSTactive)
return
; show and update BST display (if out of sync with internal states)
if (useBST or (useDBST and ((Comp != "") or (EbeneC == 5) or (EbeneC == 6)))) {
if (useBST or (useDBST and ((Comp != composeDict) or (EbeneC == 5) or (EbeneC == 6)))) {
if ((Comp != BSTLastComp)
or (EbeneC != BSTLastEbeneC)
or (EbeneNC != BSTLastEbeneNC)
@ -159,66 +159,56 @@ BSTUpdate() {
else
GuiVirtKey := GuiPhysKey
; Make keycap label:
guiCapStyle := guiCapStyleDefault
, guiCP := CP%GuiEb%%GuiVirtKey%
, processStandalone := 0
, guiCP := CP%GuiEb%%GuiVirtKey% ; keyId (U-code or neovars special key name)
, guiComp := Comp[guiCP]
; Label for key following an active compose sequence
if (Comp != "") {
guiComp := Comp . guiCP
; Compose completes; lookup
if (CD%guiComp% != "") {
guiText := CD%guiComp%
; Compose-sequence expands
} else if (CM%guiComp% == 1) {
guiCapStyle := guiCapStyleCompMore
guiText := (guiCapTextCompMore != "" ? guiCapTextCompMore : guiCP)
; Previous compose completes (delayed); lookup + standalone key
} else if (CF%Comp% != "") {
if (SubStr(guiCP,1,1) != "P") ; not a modifier or tool
guiText := CF%Comp%
processStandalone := 1
; Compose fails; label only modifiers
} else {
if (SubStr(guiCP,1,1) == "P") ; is modifier or tool
guiText := guiCP
}
; Replace symbols for screen view
guiSym := BSTSymbols[guiText]
if (guiSym != "") {
guiText := SubStr(guiSym,2)
; Apply special symbol styles unless standalone follows
if (hasCapStyleChanges and processStandalone == 0) {
guiSymStyle := SubStr(guiSym,1,1)
if (guiSymStyle != " ")
guiCapStyle := guiCapStyleSym[guiSymStyle]
}
}
; Compose-miss (fallback)
fallback := (guiComp == "" ? Comp._fallback : "")
if (fallback != "" and SubStr(guiCP,1,1) != "P") {
; Resolve to fallback sequence (except for modifiers or tools),
; then restart from current character
guiSym := BSTSymbols[fallback] ; special keycap symbol?
guiText1 := (guiSym == "" ? fallback : SubStr(guiSym,2))
guiComp := composeDict[guiCP]
} else {
guiText := ""
processStandalone := 1
guiText1 := ""
}
; Label for standalone key (no active compose-sequence)
if (processStandalone) {
; Start compose-sequence (non-delayed)
if (CM%guiCP% == 1 and CF%guiCP% == "")
; Compose-miss (fail)
if (not guiComp) {
; Label only program keys (modifiers, tools)
guiText2 := (SubStr(guiCP,1,1) == "P" ? guiCP : "")
; Compose-hit
} else if (guiComp._result) {
guiText2 := guiComp._result
; Compose-more (append)
} else if (guiComp[COMP_BACK_CHAR] != composeDict) {
guiText2 := (guiCapTextCompMore ? guiCapTextCompMore : guiCP)
guiCapStyle := guiCapStyleCompMore
; Compose-more (start)
} else {
guiText2 := guiCP
if (guiComp._fallback == "")
; Special font except for fallbacks
guiCapStyle := guiCapStyleCompStart
; Replace symbols for screen view
guiSym := BSTSymbols[guiCP]
if (guiSym != "") {
guiText .= SubStr(guiSym,2)
; Apply special symbol styles
if (hasCapStyleChanges) {
guiSymStyle := SubStr(guiSym,1,1)
if (guiSymStyle != " ")
guiCapStyle := guiCapStyleSym[guiSymStyle]
}
} else {
guiText .= guiCP
}
}
; Special keycap symbol / style ?
guiSym := BSTSymbols[guiText2]
if (guiSym != "") {
guiText2 := SubStr(guiSym,2)
guiSymStyle := SubStr(guiSym,1,1)
if (guiSymStyle != " ")
guiCapStyle := guiCapStyleSym[guiSymStyle]
}
guiText := guiText1 . guiText2
; Encode label into UTF-16 null-terminated string for windows API
guiPos := 0
while (guiText != "") {
@ -301,7 +291,7 @@ BSTUpdateDisplayStates() {
; Flag display as being out-of-sync with internal keyboard states
BSTInvalidateDisplayStates() {
global
BSTLastComp := ""
BSTLastComp := composeDict
, BSTLastEbeneC := -1
, BSTLastEbeneNC := -1
, BSTLastTransformBSTProc := ""
@ -328,31 +318,31 @@ GuiAddKey(key,x,y) {
Gui, %BSTGuiHwnd%:Add, Text, x%xPos% y%yPos% w%size% h%size% Center 0x200 0x80 vGuiKey%key% hwndGuiKey%key% BackgroundTrans
}
CharProc__BSTt() {
CharProc__BSTt(keyName) {
global BSTactive, useBST, useDBST
useBST := (not useBST)
if (useBST) {
if (not BSTactive) ; GUI must be created, does not yet exist (DBST off)
CharProc__BST1()
CharProc__BST1(keyName)
} else {
if (BSTactive and not useDBST) ; GUI no longer needed (DBST off)
CharProc__BST0()
CharProc__BST0(keyName)
}
}
CharProc_DBSTt() {
CharProc_DBSTt(keyName) {
global BSTactive, useBST, useDBST, zeigeModusBox
useDBST := (not useDBST)
if (useDBST) {
if (zeigeModusBox)
TrayTip,Dynamische Bildschirmtastatur,Die dynamische Bildschirmtastatur wurde aktiviert. Zum Deaktivieren`, Mod3+F3 drücken.,10,1
if (not BSTactive) ; GUI must be created, does not yet exist (BST off)
CharProc__BST1()
CharProc__BST1(keyName)
} else {
if (zeigeModusBox)
TrayTip,Dynamische Bildschirmtastatur,Die dynamische Bildschirmtastatur wurde deaktiviert.,10,1
if (BSTactive and not useBST) ; GUI no longer needed (BST off)
CharProc__BST0()
CharProc__BST0(keyName)
}
}
@ -362,7 +352,7 @@ BSTOnClose() {
return
useBST := 0 ; external close disables BST + DBST
useDBST := 0
CharProc__BST0()
CharProc__BST0(keyName)
}
BSTOnSize(hwnd, event, width, height) {
@ -451,7 +441,7 @@ BSTEndSuspend() {
DetectHiddenWindows, Off
}
CharProc__BST0() {
CharProc__BST0(keyName) {
global BSTactive, BSTGuiHwnd
BSTactive := False
Gui, %BSTGuiHwnd%:Destroy
@ -741,10 +731,10 @@ BSTisoTKLLayout() {
BSTisoLayout(0)
}
CharProc__BST1() {
CharProc__BST1(keyName) {
global
if (BSTactive)
CharProc__BST0()
CharProc__BST0(keyName)
if InStr(FileExist(ResourceFolder), "D") {
installOverwrite := (isPortable ? 0 : 1)
@ -919,19 +909,19 @@ BSTToggleKeyboardLayout() {
BSTcurrLayout := BSTlayouts[bstLayoutIdx]
IniWrite, % bstLayoutIdx - 1, %ini%, Global, bstLayout
if (BSTactive) {
CharProc__BST0()
CharProc__BST1()
CharProc__BST0("")
CharProc__BST1("")
}
}
CharProc__BSTA() {
CharProc__BSTA(keyName) {
global useBST, useDBST
; Bildschirmtastatur AlwaysOnTop
if (useBST or useDBST)
BSTToggleAlwaysOnTop()
}
CharProc__BSTK() {
CharProc__BSTK(keyName) {
global useBST, useDBST
; Bildschirmtastatur Layout
if (useBST or useDBST)
@ -1171,7 +1161,7 @@ BSTRegister() {
BSTcurrScale := bstBaseScale
if (useBST or useDBST)
CharProc__BST1()
CharProc__BST1("")
CP3F1 := "P__BSTt" ; toggle on screen keyboard
CP4F1 := "P__BSTK" ; toggle keyboard layout

View File

@ -2,22 +2,10 @@
; Römische Zahlen
LoadToolComposeRoman() {
global
CMS__Comp := 1
CMS__CompU000072 := 1
CMS__CompU000052 := 1
CDS__CompU000072U00004F := "P__Rom1"
;CDS__CompU000072U000031 := "P__Rom1"
;CDS__CompU000052U000031 := "P__Rom1"
CDS__CompU000052U00004F := "P__Rom2"
;CDS__CompU000072U000032 := "P__Rom2"
;CDS__CompU000052U000032 := "P__Rom2"
CDS__CompU000072U00006F := "P__Rom3"
;CDS__CompU000072U000033 := "P__Rom3"
;CDS__CompU000052U000033 := "P__Rom3"
CDS__CompU000052U00006F := "P__Rom4"
;CDS__CompU000072U000034 := "P__Rom4"
;CDS__CompU000052U000034 := "P__Rom4"
makeCompose(["S__Comp", "U000072", "U00004F"], "P__Rom1") ; rO
makeCompose(["S__Comp", "U000052", "U00004F"], "P__Rom2") ; RO
makeCompose(["S__Comp", "U000072", "U00006F"], "P__Rom3") ; ro
makeCompose(["S__Comp", "U000052", "U00006F"], "P__Rom4") ; RO
}
InitializeToolRoman() {
@ -28,7 +16,7 @@ InitializeToolRoman() {
GUISYM("P__Rom4","VII","t")
}
CharProc__Rom1() {
CharProc__Rom1(keyName) {
global
; starte klein geschriebene römische Zahlen, verwende U2160++
PressHookProc := "Roman"
@ -36,7 +24,7 @@ CharProc__Rom1() {
RomanSum := 0
}
CharProc__Rom2() {
CharProc__Rom2(keyName) {
global
; starte groß geschriebene römische Zahlen, verwende U2160++
PressHookProc := "Roman"
@ -44,7 +32,7 @@ CharProc__Rom2() {
RomanSum := 0
}
CharProc__Rom3() {
CharProc__Rom3(keyName) {
global
; starte klein geschriebene römische Zahlen, verwende Buchstaben
PressHookProc := "Roman"
@ -52,7 +40,7 @@ CharProc__Rom3() {
RomanSum := 0
}
CharProc__Rom4() {
CharProc__Rom4(keyName) {
global
; starte groß geschriebene römische Zahlen, verwende Buchstaben
PressHookProc := "Roman"
@ -67,10 +55,10 @@ GenRomanDigit(Pos, DigitIs, DigitTest, str0, str1, str2, str3, str4, str5) {
return res
}
PressHookRoman(PhysKey, ActKey, Char) {
PressHookRoman(PhysKey, Char) {
global
if (SubStr(Char,1,1) == "P")
CharStarDown(PhysKey, ActKey, Char)
return True
else if ((Char == "U000030") or (Char == "S__N__0"))
RomanSum := 10*RomanSum
else if ((Char == "U000031") or (Char == "S__N__1"))
@ -172,23 +160,20 @@ PressHookRoman(PhysKey, ActKey, Char) {
PressHookProc := ""
} else
PressHookProc := ""
return False
}
; Unicode <> Hex converter
LoadToolComposeUni() {
global
CMS__CompU000075 := 1
CMS__CompU000055 := 1
CDS__CompU000075U000075 := "P___Uni"
CDS__CompU000075U000055 := "P___Uni"
CDS__CompU000055U000075 := "P___Uni"
CDS__CompU000055U000055 := "P___Uni"
CMS__CompU000064 := 1
CMS__CompU000044 := 1
CDS__CompU000064U000064 := "P__DUni"
CDS__CompU000064U000044 := "P__DUni"
CDS__CompU000044U000064 := "P__DUni"
CDS__CompU000044U000044 := "P__DUni"
makeCompose(["S__Comp", "U000075", "U000075"], "P___Uni")
makeCompose(["S__Comp", "U000075", "U000055"], "P___Uni")
makeCompose(["S__Comp", "U000055", "U000075"], "P___Uni")
makeCompose(["S__Comp", "U000055", "U000055"], "P___Uni")
makeCompose(["S__Comp", "U000064", "U000064"], "P__DUni")
makeCompose(["S__Comp", "U000064", "U000044"], "P__DUni")
makeCompose(["S__Comp", "U000044", "U000064"], "P__DUni")
makeCompose(["S__Comp", "U000044", "U000044"], "P__DUni")
}
InitializeToolUni() {
@ -198,23 +183,23 @@ InitializeToolUni() {
GUISYM("P__DUni","DD","t")
}
CharProc___Uni() {
CharProc___Uni(keyName) {
global
; starte Unicode-Hex-in-Zeichen-Umwandlung
PressHookProc := "Uni"
UniSum := ""
}
CharProc__DUni() {
CharProc__DUni(keyName) {
global
; starte Unicode-Zeichen-in-Hex-Umwandlung
CharOutFilterProc := "DUni"
}
PressHookUni(PhysKey, ActKey, Char) {
PressHookUni(keyName, Char) {
global
if (SubStr(Char,1,1) == "P")
CharStarDown(PhysKey, ActKey, Char)
return True
else if ((Char == "U000030") or (Char == "S__N__0"))
UniSum := UniSum . "0"
else if ((Char == "U000031") or (Char == "S__N__1"))
@ -249,12 +234,14 @@ PressHookUni(PhysKey, ActKey, Char) {
UniSum := UniSum . "F"
else if ((Char == "U00000D") or (Char == "U000020")) {
UniSum := "U" . SubStr("000000" . UniSum, -5)
PP%PhysKey% := UniSum
PR%PhysKey% := UniSum
kbdRepChars := UniSum
kbdRepKey := keyName
PR%keyName% := UniSum
CharOutDown(UniSum)
PressHookProc := ""
} else
PressHookProc := ""
return False
}
CharOutFilterDUni(char,down,up) {
@ -272,10 +259,8 @@ CharOutFilterDUni(char,down,up) {
; Simple calculator
LoadToolComposeCalc() {
global
CDS__CompU000075U000063 := "P__Cal1" ; uc
CDS__CompU000075U000043 := "P__Cal2" ; uC
CDS__CompU000055U000063 := "P__Cal1" ; Uc
CDS__CompU000055U000043 := "P__Cal2" ; UC
makeCompose(["S__Comp", "U000075", "U000063"], "P__Cal1") ; uc
makeCompose(["S__Comp", "U000055", "U000043"], "P__Cal2") ; UC
}
InitializeToolCalc() {
@ -284,7 +269,7 @@ InitializeToolCalc() {
GUISYM("P__Cal2","UC","t")
}
CharProc__Cal1() {
CharProc__Cal1(keyName) {
global
; starte Calculator ohne Echo
PressHookProc := "Calc"
@ -296,7 +281,7 @@ CharProc__Cal1() {
CalcHexOut := 0
}
CharProc__Cal2() {
CharProc__Cal2(keyName) {
global
; starte Calculator mit Echo
PressHookProc := "Calc"
@ -308,10 +293,10 @@ CharProc__Cal2() {
CalcHexOut := 0
}
PressHookCalc(PhysKey, ActKey, Char) {
PressHookCalc(keyName, Char) {
global
if (SubStr(Char,1,1) == "P")
CharStarDown(PhysKey, ActKey, Char)
return True
else if (CalcPhase == 0) {
if ((Char == "U000030") or (Char == "S__N__0"))
CalcVar1 := CalcVar1 . "0"
@ -373,8 +358,9 @@ PressHookCalc(PhysKey, ActKey, Char) {
} else
PressHookProc := ""
if (CalcEcho) {
PP%PhysKey% := Char
PR%PhysKey% := Char
kbdRepChars := Char
kbdRepKey := keyName
PR%keyName% := Char
CharOutDown(Char)
}
} else if (CalcPhase == 1) {
@ -435,50 +421,47 @@ PressHookCalc(PhysKey, ActKey, Char) {
CalcResult := CalcResult + 0
SetFormat,Integer,d
}
tosend := util_char2UCode(CalcResult)
tosend := util_str2UCodes(CalcResult)
if (CalcEcho) {
Char := "U00003D"
PP%PhysKey% := Char
PR%PhysKey% := Char
kbdRepChars := Char
kbdRepKey := keyName
PR%keyName% := Char
CharOutDown(Char)
}
loop {
if (SubStr(tosend,1,1)=="P") {
SubProc := SubStr(tosend,2,6)
CharProc%SubProc%()
} else {
CharOut(SubStr(tosend,1,7))
}
CharOut(SubStr(tosend,1,7))
tosend := SubStr(tosend,8)
if (tosend == "")
break ; erledigt
}
PressHookProc := ""
return ; vermeide, bei CharEcho das aktuelle Zeichen nach dem Ergebnis noch einmal auszugeben
return False ; vermeide, bei CharEcho das aktuelle Zeichen nach dem Ergebnis noch einmal auszugeben
} else
PressHookProc := ""
if (CalcEcho) {
PP%PhysKey% := Char
PR%PhysKey% := Char
CharOutDown(Char)
}
if (CalcEcho) {
kbdRepChars := Char
kbdRepKey := keyName
PR%keyName% := Char
CharOutDown(Char)
}
} else {
PressHookProc := ""
if (CalcEcho) {
PP%PhysKey% := Char
PR%PhysKey% := Char
kbdRepChars := Char
kbdRepKey := keyName
PR%keyName% := Char
CharOutDown(Char)
}
}
return False
}
; "Wie mit Neo?" assistant
LoadToolComposeWMN() {
global
CDS__CompU000075U000077 := "P___WMN" ; uw
CDS__CompU000075U000057 := "P___WMN" ; uW
CDS__CompU000055U000077 := "P___WMN" ; Uw
CDS__CompU000055U000057 := "P___WMN" ; UW
makeCompose(["S__Comp", "U000075", "U000077"], "P___WMN") ; uw
makeCompose(["S__Comp", "U000055", "U000057"], "P___WMN") ; UW
}
InitializeToolWMN() {
@ -486,123 +469,105 @@ InitializeToolWMN() {
GUISYM("P___WMN","UW","t")
}
CharProc___WMN() {
CharProc___WMN(keyName) {
global
ok := DllCall("User32.dll\OpenClipboard", "Ptr", 0)
if (!ok) {
TrayTip,Wie mit NEO,Fehler in OpenClipboard,10,1
; Read first unicode symbol from clipboard-text
clipText := SubStr(clipboard,1,2)
if (not clipText) {
MsgBox, 16, "Wie mit Neo" Tool, Kein Zeichen in der Zwischenablage gefunden!
return
}
uclph:=DllCall("GetClipboardData","uint",CF_UNICODETEXT:=13)
if (uclph == 0) {
DllCall("CloseClipboard")
TrayTip,Wie mit NEO,Fehler in GetClipboardData,10,1
return
}
uclp := DllCall("GlobalLock","uint",uclph)
if (uclp == 0) {
DllCall("CloseClipboard")
TrayTip,Wie mit NEO,Fehler in GlobalLock,10,1
return
}
a := *(uclp+0)
b := *(uclp+1)
resultCharOrd := Ord(clipText) ; unicode codepoint
resultChar := Format("U{:06X}", resultCharOrd) ; keyId (U-code)
a += 256*b
Gui, New, +AlwaysOnTop +HwndWMNGuiHwnd +LabelWMNGuiOn
Gui, %WMNGuiHwnd%:Font, norm
Gui, %WMNGuiHwnd%:Add, Text, ,% Format("Das Zeichen U+{:X} kann wie folgt eingegeben werden:", resultCharOrd)
if ((a >= 0xD800) and (a <= 0xDBFF)) {
c := *(uclp+2)
d := *(uclp+3)
c += 256*d
if ((c >= 0xDC00) and (c <= 0xDFFF)) {
a := (a & 0x3FF) * 1024 + (c & 0x3FF) + 65536
}
}
DllCall("GlobalUnlock","uint",uclph)
DllCall("CloseClipboard")
SetFormat,Integer,h
a += 0
SetFormat,Integer,d
if (a < 0x10000) {
ap := "U" . substr("000000" . substr(a,3),-3)
a := "U" . substr("000000" . substr(a,3),-5)
} else {
ap := "U" . substr("000000" . substr(a,3),-5)
a := ap
}
Gui, New, +AlwaysOnTop +HwndWMNGuiHwnd +LabelWMNOn
Gui, %WMNGuiHwnd%:Font,norm
Gui, %WMNGuiHwnd%:Margin,10,0
Gui, %WMNGuiHwnd%:Add,Text,,% "`r`nDas Zeichen " . ap . " kann wie folgt eingegeben werden:"
loop,parse,CRC%a%,%A_Space%
; List all possible compose-sequences resulting in "resultChar"
hasStandaloneKey := False
for i, trace in composeSequences[resultChar]
{
this_wmn := ""
this_wmnk := ""
nthis := 0
this_wtt := A_LoopField
if (this_wtt == "")
continue ; probably at first or last entry
loop {
if (this_wtt == "")
break
this_char7 := substr(this_wtt,1,7)
this_char := this_char7
this_wtt := substr(this_wtt,8)
if (CB%this_char% != "")
this_char := CB%this_char%
else if (CS%this_char% != "")
this_char := CS%this_char%
; this_char will contain Uxxxx if no shortcut is present. Fix this here.
this_wmn .= " <" . this_char . ">"
if (CRK%this_char7% == "") {
nthis := 1
this_wmnk .= " <" . this_char7 . ">"
} else
this_wmnk .= " " . KeyLong(CRK%this_char7%)
}
if (this_wmn != "")
this_wmn := SubStr(this_wmn,2)
if (this_wmnk != "")
this_wmnk := SubStr(this_wmnk,2)
Gui, %WMNGuiHwnd%:Font,bold
if (nthis == 1)
Gui, %WMNGuiHwnd%:Add,Text,,% "Wegen fehlender Tastenbelegung nicht als Compose:"
else
Gui, %WMNGuiHwnd%:Add,Text,,% "Als Compose:"
Gui, %WMNGuiHwnd%:Font,norm
Gui, %WMNGuiHwnd%:Add,Text,,% this_wmn . "`r`noder`r`n" . this_wmnk
}
this_wmn := "" ; sequence of <symbol names>
this_wmnk := "" ; sequence of <individual keystrokes incl. modifiers>
isSequenceInLayout := True
sequenceLength := 0
; Join characters compose-sequence into a readable string (going backwards)
While (trace != composeDict)
{
; keyId (U-code or special key name) of next key in compose-sequence
sequenceLength++
char := trace._sequenceChar
wmnk := KeyLong(CRK%a%)
Gui, %WMNGuiHwnd%:Font,bold
if (wmnk != "") {
Gui, %WMNGuiHwnd%:Add,Text,,% "Als Tastendruck:"
; resolve keyId to character symbol or name
if (CB%char% != "")
charName := CB%char%
else if (CS%char% != "")
charName := CS%char%
else if (SubStr(char,1,1) == "U") {
; fallback: character from U-code "Uxxxxxx"
charOrd := "0x" . SubStr(char,2,6)
charName := Chr(charOrd)
} else
; fallback: special key name, e.g. "S__Comp"
charName := char
charName := "<" . charName . ">"
; additionally list all alternative ways to create "char",
; each broken down into individual keys incl. modifiers
charNameLong := WMNKeyLong(char)
if (charNameLong == "") {
; key cannot be created on keyboard
isSequenceInLayout := False
if (SubStr(char,1,1) == "U") {
; fallback: character from U-code "Uxxxxxx"
charOrd := "0x" . SubStr(char,2)
charNameLong := Format("<[{:s}=U+{:X}]>", Chr(charOrd), charOrd)
} else
charNameLong := "<" . char . ">"
}
; prepend labels to sequence-string
this_wmn := charName . " " . this_wmn
this_wmnk := charNameLong . " " . this_wmnk
; continue with previous char in compose-sequence
trace := trace[COMP_BACK_CHAR]
}
this_wmn := SubStr(this_wmn,1,-1)
this_wmnk := SubStr(this_wmnk,1,-1)
if (sequenceLength == 0)
continue ; ignore corrupt (zero-length) sequences
if (sequenceLength == 1)
hasStandaloneKey := True
Gui, %WMNGuiHwnd%:Font,bold
Gui, %WMNGuiHwnd%:Add,Text, y+m,% "Als " . (sequenceLength > 1 ? "Compose" : "Tastendruck") . (isSequenceInLayout ? ":" : " (wegen fehlender Tastenbelegung nicht erreichbar!):")
Gui, %WMNGuiHwnd%:Font,norm
Gui, %WMNGuiHwnd%:Add,Text,,% wmnk
} else
Gui, %WMNGuiHwnd%:Add,Text,,% "Als Tastendruck nicht verfuegbar"
btnEventFun := Func("WMNOnClose").Bind(WMNGuiHwnd) ; button closes assocaited GUI
Gui, %WMNGuiHwnd%:Add, Button, Default xp+100 yp+40 vWMNButton, OK
Gui, %WMNGuiHwnd%:Add,Text, y+m,% this_wmn . (this_wmnk != this_wmn ? "`r`noder`r`n" . this_wmnk : "")
}
if (not hasStandaloneKey) {
Gui, %WMNGuiHwnd%:Font,bold
Gui, %WMNGuiHwnd%:Add,Text,,% "Als Tastendruck nicht verfügbar."
Gui, %WMNGuiHwnd%:Font,norm
}
btnEventFun := Func("WMNGuiOnClose").Bind(WMNGuiHwnd) ; button closes assocaited GUI
Gui, %WMNGuiHwnd%:Add, Button, Default xm+100 y+m vWMNButton, OK
GuiControl +g, WMNButton, %btnEventFun%
Gui, %WMNGuiHwnd%:Show
}
WMNOnEscape(hwnd) {
WMNOnClose(hwnd)
WMNGuiOnEscape(hwnd) {
WMNGuiOnClose(hwnd)
}
WMNOnClose(hwnd) {
WMNGuiOnClose(hwnd) {
Gui, %hwnd%:Destroy
}
KeyLong(key) {
WMNKeyLong(char) {
global
num := 0
twmnk := ""
loop,parse,key,%A_Space%
loop,parse,CRK%char%,%A_Space%
{
tis_wmn := ""
tis_wtt := A_LoopField
@ -618,6 +583,11 @@ KeyLong(key) {
base_key := CB%base_key%
else if (CS%base_key% != "")
base_key := CS%base_key%
else if (SubStr(base_key,1,1) == "U") {
; fallback: character from U-code "Uxxxxxx"
base_ord := "0x" . SubStr(base_key,2)
base_key := Format("[{:s}=U+{:X}]", Chr(base_ord), base_ord)
}
twmnk .= "/<" . CBS____M%tis_layer% . base_key . ">"
num := num + 1
@ -630,8 +600,9 @@ KeyLong(key) {
return "(" . SubStr(twmnk,2) . ")"
}
;
; Tools global
;
; Load compose definitions used by tools
; Overwrites existing compose definitions!

View File

@ -1,140 +1,160 @@
; -*- encoding: utf-8 -*-
; -*- encoding: utf-8 -*-
AllStar(KeyId, IsDown, This_HotKey) {
; 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
PhysKey := KeyId
local char, actKeyName
if (TransformProc != "")
ActKey := Transform%TransformProc%(PhysKey)
actKeyName := Transform%TransformProc%(keyName)
else
ActKey := PhysKey
if ((striktesMod2Lock == 0) && (NOC%ActKey% == 1))
Ebene := EbeneNC
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
Ebene := EbeneC
if (Ebene7 and (CP7%ActKey% != ""))
Char := CP7%ActKey%
else if (Ebene8 and (CP8%ActKey% != ""))
Char := CP8%ActKey%
else
Char := CP%Ebene%%ActKey%
if (PressHookProc != "") {
if (IsDown == 1)
PressHook%PressHookProc%(PhysKey, ActKey, Char)
else
CharStarUp(PhysKey)
} else if (IsDown == 1)
CharStarDown(PhysKey, ActKey, Char)
else
CharStarUp(PhysKey)
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)
}
}
CharStarDown(PhysKey, ActKey, char) {
; Key event down
CharStarDown(keyName, char) {
global
if (SubStr(char,1,1)=="P") {
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%()
CharProc%SubProc%(keyName)
return
}
rerun:
wasNonShiftKeyPressed := 1
if (PP%PhysKey% != "")
CompNew := PP%PhysKey% ; Von Tastaturwiederholung
else
CompNew := Comp . char ; Hängen wir mal das neue Zeichen zum Compositum an
if (CD%CompNew% != "") { ; Compose hat getroffen: wird geschickt, Compose gelöscht
tosend := CD%CompNew%
PP%PhysKey% := CompNew
Comp := ""
} else if (CM%CompNew% == 1) { ; Compose muss sich noch was merken: Jetzt noch nichts schicken.
tosend := ""
PP%PhysKey% := ""
Comp := CompNew
} else if (CF%Comp% != "") {
tosend := CF%Comp%
if (PR%PhysKey% != "") { ; Eventuell vergessenen Key-Release aufräumen
CharOutUp(PR%PhysKey%)
PR%PhysKey% := ""
}
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]
loop {
if (SubStr(tosend,1,1)=="P") {
SubProc := SubStr(tosend,2,6)
CharProc%SubProc%()
} else {
CharOut(SubStr(tosend,1,7))
}
tosend := SubStr(tosend,8)
if (tosend == "")
break ; erledigt
}
Comp := ""
PP%PhysKey% := ""
goto rerun
} else if (Comp == "") { ; noch kein Zeichen in der Compose-Queue: Ein einzelnes Zeichen wird geschickt
tosend := char
PP%PhysKey% := char
} else { ; Compose hat verfehlt: nichts schicken, auch aktuelles Zeichen nicht schicken
tosend := ""
PP%PhysKey% := ""
Comp := ""
}
; 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
if (strlen(tosend) > 7) { ; Ausgabe mehrerer Zeichen
if (PR%PhysKey% != "") { ; Eventuell vergessenen Key-Release aufr�umen
CharOutUp(PR%PhysKey%)
PR%PhysKey% := ""
}
loop {
if (SubStr(tosend,1,1)=="P") {
SubProc := SubStr(tosend,2,6)
CharProc%SubProc%()
} else {
CharOut(SubStr(tosend,1,7))
}
tosend := SubStr(tosend,8)
if (tosend == "")
break ; erledigt
}
} else if (tosend != "") {
if (SubStr(tosend,1,1)=="P") {
if (PR%PhysKey% != "") {
CharOutUp(PR%PhysKey%)
PR%PhysKey% := ""
}
SubProc := SubStr(tosend,2,6)
CharProc%SubProc%()
; Compose-more
} else {
if ((PR%PhysKey% != "") and (PR%PhysKey% != tosend))
CharOutUp(PR%PhysKey%)
PR%PhysKey% := tosend
CharOutDown(tosend)
; 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% := ""
}
} else if (PR%PhysKey% != "") {
CharOutUp(PR%PhysKey%)
PR%PhysKey% := ""
}
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()
}
CharStarUp(PhysKey) {
; Key event up
; Send out key-up event with layout-characters memorized in PR%keyname%
; and disable active keyboard repeats
CharStarUp(keyName) {
global
if (PR%PhysKey% != "") {
tosend := PR%PhysKey%
PR%PhysKey% := ""
if (SubStr(tosend,1,1)=="P") {
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%()
CharProc%SubProc%(keyName)
} else
CharOutUp(tosend)
}
PP%PhysKey% := ""
; Stop current key repeat
kbdRepChars := ""
}
;
; Send characters to output
;
; Send out activation event "key down, then up"
CharOut(char) {
global
if (CharOutFilterProc != "") {
@ -150,6 +170,7 @@ CharOut(char) {
SendUnicodeChar("0x" . SubStr(char,2))
}
; Send out activation event "key down"
CharOutDown(char) {
global
if (CharOutFilterProc != "") {
@ -165,6 +186,7 @@ CharOutDown(char) {
SendUnicodeCharDown("0x" . SubStr(char,2))
}
; Send out activation event "key up"
CharOutUp(char) {
global
if (CharOutFilterProc != "") {
@ -220,8 +242,11 @@ CharProc__Rlod() {
reload
}
; Modifier
CharProc__M2LD() {
;
; Modifier procedures
;
CharProc__M2LD(keyName) {
global
if (!isShiftLPressed) {
if (isShiftRPressed and !wasNonShiftKeyPressed)
@ -230,12 +255,12 @@ CharProc__M2LD() {
isShiftPressed := 1
wasNonShiftKeyPressed := 0
EbeneAktualisieren()
PR%PhysKey% := "P__M2LU"
PR%keyName% := "P__M2LU"
}
CharOutDown("S__L_M2")
}
CharProc__M2LU() {
CharProc__M2LU(keyName) {
global
isShiftLPressed := 0
isShiftPressed := isShiftRPressed
@ -243,7 +268,7 @@ CharProc__M2LU() {
CharOutUp("S__L_M2")
}
CharProc__M2RD() {
CharProc__M2RD(keyName) {
global
if (!isShiftRPressed) {
if (isShiftLPressed and !wasNonShiftKeyPressed)
@ -252,12 +277,12 @@ CharProc__M2RD() {
isShiftPressed := 1
wasNonShiftKeyPressed := 0
EbeneAktualisieren()
PR%PhysKey% := "P__M2RU"
PR%keyName% := "P__M2RU"
}
CharOutDown("S__R_M2")
}
CharProc__M2RU() {
CharProc__M2RU(keyName) {
global
isShiftRPressed := 0
isShiftPressed := isShiftLPressed
@ -265,20 +290,20 @@ CharProc__M2RU() {
CharOutUp("S__R_M2")
}
CharProc__M3LD() {
CharProc__M3LD(keyName) {
global
if (!isMod3LPressed) {
if (isMod3RPressed and !wasNonShiftKeyPressed)
CharStarDown("MOD3", "MOD3", "S__Comp")
CharStarDown("MOD3", "S__Comp")
isMod3LPressed := 1
isMod3Pressed := 1
wasNonShiftKeyPressed := 0
EbeneAktualisieren()
PR%PhysKey% := "P__M3LU"
PR%keyName% := "P__M3LU"
}
}
CharProc__M3LU() {
CharProc__M3LU(keyName) {
global
if (isMod3RPressed)
CharStarUp("MOD3")
@ -287,20 +312,20 @@ CharProc__M3LU() {
EbeneAktualisieren()
}
CharProc__M3RD() {
CharProc__M3RD(keyName) {
global
if (!Mod3RPressed) {
if (isMod3LPressed and !wasNonShiftKeyPressed)
CharStarDown("MOD3", "MOD3", "S__Comp")
CharStarDown("MOD3", "S__Comp")
isMod3RPressed := 1
isMod3Pressed := 1
wasNonShiftKeyPressed := 0
EbeneAktualisieren()
PR%PhysKey% := "P__M3RU"
PR%keyName% := "P__M3RU"
}
}
CharProc__M3RU() {
CharProc__M3RU(keyName) {
global
if (isMod3LPressed)
CharStarUp("MOD3")
@ -309,13 +334,13 @@ CharProc__M3RU() {
EbeneAktualisieren()
}
CharProc__M4LD() {
CharProc__M4LD(keyName) {
global
if (!isMod4LPressed) {
isMod4LPressed := 1
isMod4Pressed := 1
EbeneAktualisieren()
PR%PhysKey% := "P__M4LU"
PR%keyName% := "P__M4LU"
if (isMod4RPressed and !wasNonShiftKeyPressed) {
wasNonShiftKeyPressed := 0
ToggleMod4Lock()
@ -324,20 +349,20 @@ CharProc__M4LD() {
}
}
CharProc__M4LU() {
CharProc__M4LU(keyName) {
global
isMod4LPressed := 0
isMod4Pressed := isMod4RPressed
EbeneAktualisieren()
}
CharProc__M4RD() {
CharProc__M4RD(keyName) {
global
if (!isMod4RPressed) {
isMod4RPressed := 1
isMod4Pressed := 1
EbeneAktualisieren()
PR%PhysKey% := "P__M4RU"
PR%keyName% := "P__M4RU"
if (isMod4LPressed and !wasNonShiftKeyPressed) {
wasNonShiftKeyPressed := 0
ToggleMod4Lock()
@ -346,7 +371,7 @@ CharProc__M4RD() {
}
}
CharProc__M4RU() {
CharProc__M4RU(keyName) {
global
isMod4RPressed := 0
isMod4Pressed := isMod4LPressed

View File

@ -28,6 +28,7 @@ SetWorkingDir %A_ScriptDir%
#Include script/logwindow.ahk
#Include script/util.ahk
#include ../src/compose-parse.ahk
#include ../src/compose.ahk ; simulate neovars makeCompose process to find errors
#include ../src/util.ahk
; Paths
@ -127,46 +128,54 @@ logEntry("Set output file to '" . configs["outputFile"] . "'")
; Parse compose-definitions into source script
;
outputFileObj := FileOpen(configs["outputFile"], "w `n", "UTF-8")
if (not IsObject(outputFileObj))
{
logError("Output file cannot be opened for writing at '" . configs["outputFile"] . "'")
logFinal()
}
; Write header
logEntry("Write header information.")
scriptGeneratedBy := A_ScriptName
scriptLineRevision := "compRevision := """ . configs["revision"] . """"
FileAppend,
outputFileObj.WriteLine(
(
; -*- encoding: utf-8 -*-
"; -*- encoding: utf-8 -*-
;
; ** THIS FILE WAS GENERATED BY %scriptGeneratedBy% **
; ** THIS FILE WAS GENERATED BY " . scriptGeneratedBy . " **
; ** DO NOT EDIT BY HAND -- FILE MAY BE OVERWRITTEN ANYTIME **
;
; Revision information
%scriptLineRevision%
" . scriptLineRevision . "
; Make compose-definitions globally available
LoadDefaultCompose() {
global
LoadDefaultCompose() {"
))
), % configs["outputFile"], UTF-8
; Write compose-definitions
; Initialize parsing
makeComposeFun := Func("appendMakeComposeCmd").Bind(outputFileObj)
onParseErrorFun := Func("onParseError")
onProgressFun := Func("onProgress")
keySym2KeyIdMap := makekeySym2KeyIdMap()
; Parse and write out compose-definitions
totalErrorCount := 0
Loop, % numComposeFiles
{
file := configs["composeFilesFull"][A_Index]
logEntry("Parse compose-definitions from '" . file . "'...")
if not FileExist(file)
inputFile := configs["composeFilesFull"][A_Index]
logEntry("Parse compose-definitions from '" . inputFile . "'...")
if not FileExist(inputFile)
{
logError("Compose-file not found at '" . file . "'")
logError("Compose-file not found at '" . inputFile . "'")
continue ; try to complete output with footer etc.
}
try
totalErrorCount += parseComposeFile(file, keySym2KeyIdMap, configs["outputFile"], onParseErrorFun, onProgressFun)
totalErrorCount += parseComposeFile(inputFile, keySym2KeyIdMap, makeComposeFun, , onParseErrorFun, onProgressFun)
catch e
{
logError("Unhandled exception '" . e.What . (e.Message == "" ? "" : "' reports '" . e.Message) . "' while processing '" . file . "'")
logError("Unhandled exception '" . e.What . (e.Message == "" ? "" : "' reports '" . e.Message) . "' while processing '" . inputFile . "'")
continue ; try to complete output with footer etc.
}
}
@ -174,7 +183,8 @@ logEntry(Format("Parsing finished with {:i} parsing-error{:s} in {:i} file{:s}."
; Write footer
logEntry("Write footer information.")
FileAppend, }, % configs["outputFile"], UTF-8
outputFileObj.WriteLine("}")
outputFileObj.Close()
; Exit
logEntry("Compose-update completed.")
@ -185,18 +195,49 @@ logFinal()
; Functions
; -------------------------------------
; Compose-Parser progress handler
; Compose-parser compose-sequence processor
appendMakeComposeCmd(outputFileObj, sequence, resultChars)
{
; Add new compose to global 'composeDict' and 'composeSequences'.
; Simulates the neovars makeCompose process in order to detect problems early, including
; - invalid sequences,
; - attempting to overwrite existing (shorter or equal) sequences, or
; - sequences that would make existing (longer) sequences inaccessible
; However, these checks can not take into account all compose-definitions available at runtime
; (user-defined composes, neovars layout keys and internal composes for tool invocation, etc.)
success := makeCompose(sequence, resultChars)
; Append compose-definition as a AHK-script command to output file
if (success) {
; Make AHK script command that creates the compose definition when interpreted
sequenceLiteral := "["
for i, char in sequence
sequenceLiteral .= """" . char . ""","
sequenceLiteral := SubStr(sequenceLiteral,1,-1) . "]"
cmd := Format(" makeCompose({:s},""{:s}"")", sequenceLiteral, resultChars)
; Append cmd to file
outputFileObj.WriteLine(cmd)
}
return success
}
; Compose-parser progress handler
onParseError(e, errorCount)
{
if (e.type == "key_sym")
logWarning(Format("Ignored unknown <{:s}> on line {:u} '{:s}'", e.keySym, e.lineNo, e.line))
else if (e.type == "result")
logWarning(Format("Ignored empty result on line {:u} '{:s}'", e.lineNo, e.line))
else if (e.type == "make")
logWarning(Format("Ignored invalid or occupied sequence on line {:u} '{:s}'", e.lineNo, e.line))
else
logWarning(Format("Ignored bad line {:u} '{:s}'", e.lineNo, e.line))
}
; Compose-Parser error handler
; Compose-parser error handler
onProgress(count, total, errorCount)
{
progress := 100 * count / total