;-- TIME_STAMP   2021-01-04 13:58:50   v 0.1


#include-once
#include <GuiEdit.au3>
#include <WinAPIConstants.au3>
#include <WinAPISys.au3>
#include <WindowsConstants.au3>

Opt('MustDeclareVars', 1)

#cs
- Es wird eine ganz bestimmte feste Zeiteinheit gewählt.
- Die Länge eines Punktes (Dit) dauert eine Zeiteinheit.
- Die Länge eines Striches (Dah) dauert drei Zeiteinheiten.
- Die Punkte bzw. Striche, die jeweils ein Zeichen darstellen, werden durch eine Pause von einer Zeiteinheit getrennt.
- Die Pause zwischen den Darstellungen zweier verschiedener Zeichen beträgt drei Zeiteinheiten.
- Die Pause zwischen Zeichensequenzen, die zwei verschiedene Wörter darstellen, beträgt 7 Zeiteinheiten.

A    B	    C	   D	E	F	   G	 H	    I	 J	    K	  L	     M
.-	 -...	-.-.   -..	.	..-.   --.   ....   ..   .---   -.-   .-..   --


N	 O	   P	  Q	     R	   S	 T   U	   V	  W	    X	   Y	  Z
-.   ---   .--.   --.-   .-.   ...   -   ..-   ...-   .--   -..-   -.--   --..


Ä      Ö      Ü      ß         ;           Umlaute, "ß" und ";" sind nicht ITU-konform
.-.-   ---.   ..--   ...--..   -.-.-.


1	    2	    3	    4	    5	    6	    7	    8	    9	    0
.----	..---	...--	....-	.....	-....	--...	---..	----.	-----


Full stop (period) ............................................................................. [.] .−.−.−
Comma .......................................................................................... [,] −−..−−
Colon or division sign ......................................................................... [:] −−−...
Question mark (note of interrogation or request for repetition of a transmission not understood) [?] ..−−..
Apostrophe ..................................................................................... [’] .−−−−.
Hyphen or dash or subtraction sign ............................................................. [–] −....−
Fraction bar or division sign .................................................................. [/] −..−.
Left-hand bracket (parenthesis) ................................................................ [(] −.−−.
Right-hand bracket (parenthesis) ............................................................... [)] −.−−.−
Inverted commas (quotation marks) (before and after the words) ................................. ["] .−..−.
Double hyphen .................................................................................. [=] −...−
Understood ..................................................................................... VE  ...−.
Error (eight dots) ............................................................................. HH  ........
Cross or addition sign ......................................................................... [+] .−.−.
Invitation to transmit ......................................................................... K   −.−      (als Wort)
Wait ........................................................................................... AS  .−...
End of work .................................................................................... SK  ...−.−
Starting signal (to precede every transmission)................................................. CT  −.−.−
Multiplication sign ............................................................................ X   −..−     (als Wort)
Commercial at .................................................................................. [@] .––.-.
#ce

OnAutoItExitRegister('OnMorseExit')

Global $g_MorseUnit = 80      ; Dauer einer Einheit in ms
Global $g_MorseBeepUnit = 120 ; Dauer einer Einheit in ms für die Audioausgabe - Langsamer ist nicht sinnvoll, da kommt die Ausgabe nicht hinterher
Global $g_MorseF = 2500       ; Frequenz in Hz (Audioausgabe)
Global $g_MorseCharCB = ' '   ; Symbol für Zeichenpause
Global $g_MorseCharWB = '   ' ; Symbol für Wortpause (darf nicht dasselbe Zeichen, wie Zeichenpause sein!)

Global $g_hKeyProc = Null, $g_hHook
Global $g_bMorseKeyIsDown = False  ; Zustand Morsetaste (Up/Down)
Global $g_MorseKeyUpTimer          ; Timer für Messung: Morsetaste nicht gedrückt
Global $g_MorseKeyDownTimer        ; Timer für Messung: Morsetaste gedrückt
Global $g_MorseKeyTimeUp           ; gemessene Zeit: Morsetaste nicht gedrückt
Global $g_MorseKeyTimeDown         ; gemessene Zeit: Morsetaste gedrückt
Global $g_bMorseIDLE = True        ; Wenn keine neue Eingabe erfolgt, würde jede Pause der Länge 7 als Sequenz "Wortpause" gewertet.
                                   ; Das kann hiermit abgefangen werden. (Es dürfen keine zwei Pausen aufeinander folgen)
								   ; Da beim Start derselbe Zustand, wie bei Mehrfachpause besteht: Vorbelegung mit "True"
Global $g_MorseStr = ''            ; zum Verketten der Sequenzen
Global $g_MorseSeq = ''            ; Sequenz (Dit/Dah)

Global $aMorse[][] = [ _
['A','.-'],['B','-...'],['C','-.-.'],['D','-..'],['E','.'],['F','..-.'],['G','--.'],['H','....'],['I','..'],['J','.---'],['K','-.-'],['L','.-..'],['M','--'], _
['N','-.'],['O','---'],['P','.--.'],['Q','--.-'],['R','.-.'],['S','...'],['T','-'],['U','..-'],['V','...-'],['W','.--'],['X','-..-'],['Y','-.--'],['Z','--..'], _
['1','.----'],['2','..---'],['3','...--'],['4','....-'],['5','.....'],['6','-....'],['7','--...'],['8','---..'],['9','----.'],['0','-----'], _
['Ä','.-.-'],['Ö','---.'],['Ü','..--'],['ß','...--..'],[';','-.-.-.'], _
['.','.-.-.-'],[',','--.--'],[':','---...'],['?','..--..'],["'",'.----.'],['-','-....-'],['/','-..-.'],['(','−.−−.'],[')','−.−−.−'],['"','.-..-.'],['=','-...-'], _
['VE','...-.'],['HH','........'],['+','.-.-.'],['AS','.-...'],['SK','...-.-'],['CT','-.-.-'],['@','.--.-.']]

Global $oMorseSend = ObjCreate("Scripting.Dictionary")
Global $oMorseRecv = ObjCreate("Scripting.Dictionary")
For $i = 0 To UBound($aMorse) -1
	$oMorseSend.Add($aMorse[$i][0],$aMorse[$i][1])
	$oMorseRecv.Add($aMorse[$i][1],$aMorse[$i][0])
Next

Global $g_MorseGui           ; GUI, die die Morsesignale empfängt
Global $g_MorseRawIn = Null  ; [optional] Ctrl, in das die erkannten Morsesymbole eingetragen werden
Global $g_MorseDecIn = Null  ; [optional] Ctrl, in das die aus den erkannten Morsesymbolen dekodierten Textzeichen eingetragen werden
Global $g_MorseLog = Null    ; [optional] Ctrl, in das die Zeiten (DOWN-Time, UP-Time) protokolliert werden
Global $g_MorseRawBreakCount ; [optional] für mehrzeiliges Ctrl, Anzahl der Zeichen, nach denen ein Zeilenumbruch eingefügt wird
Global $g_MorseDecBreakCount ; [optional] für mehrzeiliges Ctrl, Anzahl der Zeichen, nach denen ein Zeilenumbruch eingefügt wird
Global $g_MorseLogCount      ; [optional] für mehrzeiliges Ctrl, Anzahl der Aufrufe, nach denen ein Zeilenumbruch eingefügt wird

Global $g_tKBSettings = _KeyboardSetting() ; aktuelle Keyboardeinstellungen beim Start speichern

Func OnMorseExit()
	If $g_hKeyProc <> Null Then
		_WinAPI_UnhookWindowsHookEx($g_hHook)
		DllCallbackFree($g_hKeyProc)
		_KeyboardSetting($g_tKBSettings.Delay, $g_tKBSettings.Speed) ; nicht zwingend erforderlich
	EndIf
EndFunc  ;==>OnMorseExit



; Gui für Morse-UDF registrieren, Keyboard-Hook aktivieren, Adlib-Funktion zur Morse-Sequenz-Verarbeitung starten
Func _Morse_RegisterGui($_hWnd)
	$g_MorseGui = $_hWnd
	If $g_hKeyProc = Null Then
		_KeyboardSetting(3, 0) ; Delay auf 1s und Wiederholrate auf 2 Zeichen/s (nicht zwingend erforderlich)
		$g_hKeyProc = DllCallbackRegister("_Morse_KeyProc", "long", "int;wparam;lparam")
		$g_hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($g_hKeyProc), _WinAPI_GetModuleHandle(0))
		AdlibRegister('_Morse_BreakTime', 20)
	EndIf
EndFunc  ;==>_Morse_RegisterGui


; GuiCtrl-ID registrieren für Eintragen des Morsecodes
; $_iCharBreak: optional für mehrzeiliges Ctrl, Anzahl der Zeichen, nach denen ein Zeilenumbruch eingefügt wird
Func _Morse_RegisterRawIn($_ID, $_iCharBreak=0)
	$g_MorseRawIn = $_ID
	$g_MorseRawBreakCount = $_iCharBreak
EndFunc  ;==>_Morse_RegisterRawIn


; GuiCtrl-ID registrieren für Eintragen des dekodierten Morsecodes
; $_iCharBreak: optional für mehrzeiliges Ctrl, Anzahl der Zeichen, nach denen ein Zeilenumbruch eingefügt wird
Func _Morse_RegisterDecodeIn($_ID, $_iCharBreak=0)
	$g_MorseDecIn = $_ID
	$g_MorseDecBreakCount = $_iCharBreak
EndFunc  ;==>_Morse_RegisterDecodeIn


; GuiCtrl-ID registrieren für Loggen der UP/DOWN Zeiten, je UP und je DOWN ein Funktionsaufruf
; $_iCallBreak: optional für mehrzeiliges Ctrl, Anzahl der Aufrufe, nach denen ein Zeilenumbruch eingefügt wird
Func _Morse_RegisterLog($_ID, $_iCallBreak=0)
	$g_MorseLog = $_ID
	$g_MorseLogCount = $_iCallBreak
EndFunc  ;==>_Morse_RegisterLog


; Morsefrequenz definieren für Audioausgabe
Func _Morse_SetFrequency($_i=-1) ; Standard(-1): 2500 Hz
	$g_MorseUnit = ($_i < 0 ? 2500 : $_i)
	Return $g_MorseUnit
EndFunc  ;==>_Morse_SetFrequency


; Basislänge der Morseeinheit definieren
Func _Morse_SetUnit($_i=-1) ; Standard(-1): min = 30 ms
	$g_MorseUnit = ($_i < 0 ? 30 : ($_i < 30 ? 30 : $_i))
	Return $g_MorseUnit
EndFunc  ;==>_Morse_SetUnit


; Trennzeichen im Morsecode nach Zeichenende definieren
Func _Morse_SetCharacterCharBreak($_s='') ; Standard(''): ' '
	$g_MorseCharCB = ($_s = '' ? ' ' : $_s)
	Return $g_MorseCharCB
EndFunc  ;==>_Morse_SetCharacterCharBreak


; Trennzeichen im Morsecode nach Wortende definieren
Func _Morse_SetCharacterWordBreak($_s='') ; Standard(''): '  '
	$g_MorseCharWB = ($_s = '' ? '  ' : $_s)
	Return $g_MorseCharWB
EndFunc  ;==>_Morse_SetCharacterWordBreak



; konvertiert einen Text in geschriebene Morsezeichen
; Zeichenende wird mit $g_MorseCharCB und Wortende mit $g_MorseCharWB markiert
Func _Morse_EnCrypt($_s)
	Local $sMorse
	$_s = StringUpper($_s)
	Local $aSplit = StringSplit($_s, '')
	For $i = 1 To $aSplit[0]
		If $aSplit[$i] = ' ' Then ; Wortende
			$sMorse = StringTrimRight($sMorse,1) & $g_MorseCharWB
			ContinueLoop
		EndIf
		If $oMorseSend.Exists($aSplit[$i]) Then
			$sMorse &= $oMorseSend.Item($aSplit[$i]) & $g_MorseCharCB
		Else
			$sMorse &= $aSplit[$i] & $g_MorseCharCB
		EndIf
	Next
	Return StringTrimRight($sMorse, 1)
EndFunc  ;==>_Morse_EnCrypt

; konvertiert einen Satz geschriebener Morsezeichen in Text
Func _Morse_DeCrypt($_p)
	Local $sPhrase
	Local $aWords = StringSplit($_p, $g_MorseCharWB, 1)
	For $i = 1 To $aWords[0]
		$sPhrase &= __Morse_DeCryptWord($aWords[$i]) & ' '
	Next
	Return $sPhrase
EndFunc  ;==>_Morse_DeCrypt

; konvertiert eine Wortsequenz von Morsezeichen in Text
Func __Morse_DeCryptWord($_w)
	Local $sWord, $aChars = StringSplit($_w, $g_MorseCharCB, 1)
	For $i = 1 To $aChars[0]
		$sWord &= __Morse_DeCryptChar($aChars[$i])
	Next
	Return $sWord
EndFunc  ;==>__Morse_DeCryptWord

; konvertiert eine Zeichensequenz von Morsezeichen in Text
Func __Morse_DeCryptChar($_c)
	If $oMorseRecv.Exists($_c) Then
		Return $oMorseRecv.Item($_c)
	Else
		Return '[' & $_c & ']' ; unbekanntes Zeichen, wird wie erkannt zurückgegeben
	EndIf
EndFunc  ;==>__Morse_DeCryptChar

; fügt erkannte Morsesequenz in Ctrl ein (sofern registriert)
Func __Morse_AddRaw($_s)
	If $g_MorseRawIn = Null Then Return
	Local Static $h_RawIn = IsHWnd($g_MorseRawIn) ? $g_MorseRawIn : GUICtrlGetHandle($g_MorseRawIn)
	Local Static $iCount = 0
	If $g_MorseRawBreakCount > 0 Then
		$iCount += 1
		If $iCount = $g_MorseRawBreakCount Then
			$_s &= @CRLF
			$iCount = 0
		EndIf
	EndIf
	_GUICtrlEdit_AppendText($h_RawIn, $_s)
EndFunc  ;==>__Morse_AddRaw

; fügt aus Morsesequenz dekodiertes Zeichen in Ctrl ein (sofern registriert)
Func __Morse_AddDec($_s)
	If $g_MorseDecIn = Null Then Return
	Local Static $h_DecIn = IsHWnd($g_MorseDecIn) ? $g_MorseDecIn : GUICtrlGetHandle($g_MorseDecIn)
	Local Static $iCount = 0
	Local $sCRLF = ''
	If $g_MorseDecBreakCount > 0 Then
		$iCount += 1
		If $iCount = $g_MorseDecBreakCount Then
			$sCRLF = @CRLF
			$iCount = 0
		EndIf
	EndIf
	If ($_s = $g_MorseCharCB) Or ($_s = $g_MorseCharWB) Or ($_s = ' ') Then
		_GUICtrlEdit_AppendText($h_DecIn, $_s & $sCRLF)
	Else
		_GUICtrlEdit_AppendText($h_DecIn, __Morse_DeCryptChar($_s) & $sCRLF)
	EndIf
EndFunc  ;==>__Morse_AddDec

; fügt DOWN/UP-Time in Ctrl ein (sofern registriert)
Func __Morse_AddLog($_s)
	If $g_MorseLog = Null Then Return
	Local Static $iCount = 0
	Local Static $h_Log = IsHWnd($g_MorseLog) ? $g_MorseLog : GUICtrlGetHandle($g_MorseLog)
	If $g_MorseLogCount > 0 Then
		$iCount += 1
		If $iCount = $g_MorseLogCount Then ; $g_MorseLogCount/2 Tastendrücke (Down und Up) nebeneinander, dann neue Zeile
			$_s &= @CRLF
			$iCount = 0
		EndIf
	EndIf
	_GUICtrlEdit_AppendText($h_Log, $_s)
EndFunc  ;==>__Morse_AddLog


; Akustische Wiedergabe eines mit "_Morse_EnCrypt" codierten Textes
Func _Morse_Beep($_sMorse, $_bConsoleOut=False)
	Local Static $oLen = ObjCreate('Scripting.Dictionary')
	Local Static $bAdd = False
	If $bAdd = False Then
		$bAdd = True
		$oLen.Add('.', 1)
		$oLen.Add('-', 3)
		$oLen.Add('°', 3-1) ; Da nach jedem '.' oder '-' IMMER eine Pause von 1 folgt, ...
		$oLen.Add('^', 7-1) ; ... wird dieser Wert bei Zeichen- und Wortende abgezogen.
	EndIf
	$_sMorse = StringReplace($_sMorse, $g_MorseCharWB, '^') ; Zeichen- u. Wortende durch Platzhalter mit 1 Zeichen Länge ersetzen ...
	$_sMorse = StringReplace($_sMorse, $g_MorseCharCB, '°') ; ... um zeichenweises Verarbeiten zu gewährleisten
	Local $aSplit = StringSplit($_sMorse, ''), $sCh = ''
	For $i = 1 To $aSplit[0]
		Switch $aSplit[$i]
			Case '.', '-'
				Beep($g_MorseF, $oLen.Item($aSplit[$i]) * $g_MorseBeepUnit) ; Beep in definierter Frequenz und Länge des Dit/Dah
				Sleep($g_MorseBeepUnit)                                     ; Pause von 1 Einheit, die nach jedem Dit/Dah folgt
				If $_bConsoleOut Then
					$sCh &= $aSplit[$i]
					If $i = $aSplit[0] Then ConsoleWrite($oMorseRecv.Item($sCh) & @CRLF) ; letztes Zeichen erreicht -> Ausgabe erkanntes Zeichen
				EndIf
			Case '°', '^'
				Sleep($oLen.Item($aSplit[$i]) * $g_MorseBeepUnit)   ; Zeichen-/Wortpause in der entsprechenden Länge
				If $_bConsoleOut Then
					ConsoleWrite($oMorseRecv.Item($sCh))        ; bei Zeichen-/Wortpause das zuletzt erkannte Zeichen ausgeben
					$sCh = ''                                   ; Zeichen-Variable zurücksetzen
					If $aSplit[$i] = '^' Then ConsoleWrite(' ') ; Wortpause: Leerzeichen als Worttrenner (Text) ausgeben
				EndIf
		EndSwitch
	Next
EndFunc  ;==>_Morse_Beep


;==============================================================================
; Callback-Function: wird erst gestartet, wenn dafür eine Gui registriert ist
;==============================================================================
Func _Morse_KeyProc($nCode, $wParam, $lParam)
	Local Static $iUnit1_Max = 1.4 * $g_MorseUnit   ; max. Dit-Länge und Pausenlänge zwischen zwei aufeinanderfolgenden Dit oder Dah
	Local Static $iUnit3_Min = 0.6 * 3*$g_MorseUnit ; min. und
	Local Static $iUnit3_Max = 1.4 * 3*$g_MorseUnit ; max Dah-Länge und Pausenlänge zwischen zwei aufeinanderfolgenden Zeichen
	Local Static $bOnce = False

    If ($nCode < 0) Or (Not BitAND(WinGetState($g_MorseGui), 8)) Then _ ; nicht verarbeiten, wenn registrierte Gui inaktiv
		Return _WinAPI_CallNextHookEx($g_hHook, $nCode, $wParam, $lParam)
    Local $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
	Local $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
	If $vkCode <> 163 Then Return _WinAPI_CallNextHookEx($g_hHook, $nCode, $wParam, $lParam) ; nur R-CTRL auswerten

	If $wParam = $WM_KEYDOWN Then
		If Not $bOnce Then ; bei erstmaligem Aufruf der Funktion Ausgabe der aktuellen Parameter in das Log
			$bOnce = True
			__Morse_AddLog(StringFormat('[DIT: <= %i ms, DAH: %i ms bis %i ms, SEQ: < %i ms, CHAR: %i ms bis %i ms]\n', _
			                            $iUnit1_Max, $iUnit3_Min, $iUnit3_Max, $iUnit1_Max, $iUnit3_Min, $iUnit3_Max))
		EndIf
		$g_bMorseKeyIsDown = True
		$g_MorseKeyDownTimer = TimerInit()       ; Timer für DOWN-Time starten
		$g_MorseKeyTimeUp = TimerDiff($g_MorseKeyUpTimer) ; UP-Time (Pausenzeit) messen und auswerten
		__Morse_AddLog($g_bMorseIDLE ? '[UP IDLE]' : (StringFormat('[UP %03i] ', $g_MorseKeyTimeUp)))
		If $g_bMorseIDLE Then  ; IDLE-Mode, beim Start oder wenn Eingabepause > 7 Units
			$g_bMorseIDLE = False                ; IDLE-Mode beendet
			; falls letzte Eingabe noch nicht verarbeitet
			If $g_MorseStr <> '' Then
				__Morse_AddDec($g_MorseStr)      ; erkanntes Zeichen (dekodiert) in Dekodiert-Ctrl ausgeben
				__Morse_AddRaw($g_MorseCharCB)   ; Zeichen für Zeichentrennung in Raw-Ctrl ausgeben
				$g_MorseStr = ''                 ; Stringvariable zurücksetzen
			EndIf
		Else                   ; Eingabemodus, UP-Time < 7 Units
			Select
				Case $g_MorseKeyTimeUp > $iUnit3_Min And _ ; Zeichenpause, Sequenzen des Zeichens ...
					 $g_MorseKeyTimeUp < $iUnit3_Max       ; ... dekodieren und ausgeben
					If $g_MorseStr <> '' Then
						__Morse_AddDec($g_MorseStr)      ; erkanntes Zeichen (dekodiert) in Dekodiert-Ctrl ausgeben
						__Morse_AddRaw($g_MorseCharCB)   ; Zeichen für Zeichentrennung in Raw-Ctrl ausgeben
						$g_MorseStr = ''                 ; Stringvariable zurücksetzen
					EndIf
				Case $g_MorseKeyTimeUp < $iUnit1_Max       ; Sequenzpause
					; keine gesonderte Auswertung erforderlich,
			EndSelect
		EndIf
	ElseIf $wParam = $WM_KEYUP Then
		$g_bMorseKeyIsDown = False
		$g_MorseKeyUpTimer = TimerInit()         ; Timer für UP-Time starten
		$g_MorseKeyTimeDown = TimerDiff($g_MorseKeyDownTimer) ; DOWN-Time (Taste gedrückt Zeit) messen und auswerten
		__Morse_AddLog(StringFormat('[DOWN %03i] ', $g_MorseKeyTimeDown))
		$g_MorseSeq = ''
		Select
			Case $g_MorseKeyTimeDown > $iUnit3_Max
				$g_MorseSeq = '>'      ; Tastendruck länger als max. Zeitraum für längstes Zeichen
			Case $g_MorseKeyTimeDown > $iUnit3_Min And $g_MorseKeyTimeDown < $iUnit3_Max
				$g_MorseSeq = '-'      ; Dah
			Case $g_MorseKeyTimeDown < $iUnit1_Max  ; alles kürzer max. wird immer als Dit gewertet
				$g_MorseSeq = '.'      ; Dit
		EndSelect
		$g_MorseStr &= $g_MorseSeq     ; Sequenz verketten
		__Morse_AddRaw($g_MorseSeq)    ; Sequenz in Raw-Ctrl ausgeben
	EndIf

    Return _WinAPI_CallNextHookEx($g_hHook, $nCode, $wParam, $lParam)
EndFunc  ;==>_Morse_KeyProc


; Auswertung der Pausen zwischen R-CTRL bei aktiver (registrierter) GUI
Func _Morse_BreakTime()
	Local Static $iUnit7_Min = 7*$g_MorseUnit
	If $g_bMorseKeyIsDown Then Return  ; nur UP-Zyklus (Pause) auswerten
	AdlibUnRegister('_Morse_BreakTime')
	If TimerDiff($g_MorseKeyUpTimer) > $iUnit7_Min Then
		If Not $g_bMorseIDLE Then ; Wortpause, kein IDLE
			If $g_MorseStr <> '' Then ; falls letzte Eingabe noch nicht verarbeitet
				__Morse_AddDec($g_MorseStr)      ; erkanntes Zeichen (dekodiert) in Dekodiert-Ctrl ausgeben
				$g_MorseStr = ''
			EndIf
			__Morse_AddRaw($g_MorseCharWB)  ; Zeichen für Worttrennung in Raw-Ctrl ausgeben
			__Morse_AddDec(' ')             ; Leerzeichen für Worttrennung in Dekodiert-Ctrl ausgeben
			$g_bMorseIDLE = True            ; Beginn IDLE
		EndIf
	EndIf
	AdlibRegister('_Morse_BreakTime', 20)
EndFunc  ;==>_Morse_BreakTime



; #FUNCTION# ====================================================================================================================
; Name ..........: _KeyboardSetting
; Description ...: Abfragen (Standard "-1") oder Setzen der Keyboardeinstellungen in der Registry
; Parameters ....: $_iDelay               (Default = -1) Verzögerung bis bei gedrückter Taste die Zeichenwiederholung aktiviert wird
;                                         gültige Werte: 0 = 250ms, 1 = 500ms, 2 = 750ms, 3 = 1s
; ...............: $_iSpeed               (Default = -1) Geschwindigkeit, mit der bei aktivierter Zeichenwiederholung das Zeichen wiederholt wird
;                                         gültige Werte: "0" (2 Zeichen je Sekunde) bis "31" (30 Zeichen je Sekunde)
; ...............: $_iNumlockOnAtStartup  (Default = -1) Numlock-Taste ist beim Start an oder aus
;                                         gültige Werte: "0" = Aus, "2" = An
;                                         Der Wert für Numlock wird beim Abmelden des Users mit dem dann aktuellen Zustand der Taste überschrieben.
; Return values .: Struktur mit den aktuellen Keyboardeinstellungen: ".Delay", ".Speed", ".NumlockOn"
; Author ........: BugFix
; ===============================================================================================================================
Func _KeyboardSetting($_iDelay=-1, $_iSpeed=-1, $_iNumlockOnAtStartup=-1)
	Local $iDelay = RegRead("HKEY_CURRENT_USER\Control Panel\Keyboard", "KeyboardDelay")
	Local $iSpeed = RegRead("HKEY_CURRENT_USER\Control Panel\Keyboard", "KeyboardSpeed")
	Local $iInitIndicator = RegRead("HKEY_CURRENT_USER\Control Panel\Keyboard", "InitialKeyboardIndicators")
	Local $tKeyboard = DllStructCreate("struct;int Delay;int Speed;int NumlockOn;endstruct")
	; alle Parameter "-1" -> nur Auslesen
	If $_iDelay = -1 And $_iSpeed = -1 And $_iNumlockOnAtStartup = -1 Then
		$tKeyboard.Delay = $iDelay
		$tKeyboard.Speed = $iSpeed
		$tKeyboard.NumlockOn = $iInitIndicator
		Return $tKeyboard
	EndIf
	If $_iDelay <> -1 Then
		$_iDelay = ($_iDelay < 0 ? 0 : ($_iDelay > 3 ? 3 : $_iDelay))
		RegWrite("HKEY_CURRENT_USER\Control Panel\Keyboard", "KeyboardDelay", "REG_SZ", $_iDelay)
		$tKeyboard.Delay = RegRead("HKEY_CURRENT_USER\Control Panel\Keyboard", "KeyboardDelay")
	Else
		$tKeyboard.Delay = $iDelay
	EndIf
	If $_iSpeed <> -1 Then
		$_iSpeed = ($_iSpeed < 0 ? 0 : ($_iSpeed > 31 ? 31 : $_iSpeed))
		RegWrite("HKEY_CURRENT_USER\Control Panel\Keyboard", "KeyboardSpeed", "REG_SZ", $_iSpeed)
		$tKeyboard.Speed = RegRead("HKEY_CURRENT_USER\Control Panel\Keyboard", "KeyboardSpeed")
	Else
		$tKeyboard.Speed = $iSpeed
	EndIf
	If $_iNumlockOnAtStartup <> -1 Then
		$_iNumlockOnAtStartup = ($_iNumlockOnAtStartup < 0 ? 0 : ($_iNumlockOnAtStartup = 2 ? 2 : 0))
		RegWrite("HKEY_CURRENT_USER\Control Panel\Keyboard", "InitialKeyboardIndicators", "REG_SZ", $_iNumlockOnAtStartup)
		$tKeyboard.NumlockOn = RegRead("HKEY_CURRENT_USER\Control Panel\Keyboard", "InitialKeyboardIndicators")
	Else
		$tKeyboard.NumlockOn = $iInitIndicator
	EndIf
	Return $tKeyboard
EndFunc  ;==>_KeyboardSetting



