Eventorientiertes IsPressed

  • Hi,

    ich habe - größtenteils aus Langeweile - eine UDF geschrieben, die _IsPressed (GetAsyncKeyState) benutzt, aber wie HotKeySet (Oder sogar besser) zu benutzen ist.
    Vorweg: Mir ist durchaus bewusst, dass durch das AdLibRegister unter Umständen Performanceeinbrüche entstehen können. Dafür ist ja SetCheckInterval da. :P

    Funktionen:

    Code
    _IsPressed_CallBackRegister
    _IsPressed_CallBackUnRegisterOld
    _IsPressed_CallBackUnRegister
    _IsPressed_SetCheckInterval


    Weitere Informationen zu den jeweiligen Funktionen finden sich wie gewohnt in den Funktionsheadern. ;)

    Hier mal kurz eine Liste der Features:

    • Eventorientiert (UP, DOWN, UPDOWN)
    • Erweiterte Unterstützung für Tastenkombinationen (Theoretisch bis zu X Tastendrücke gleichzeitig abfangbar (Rekursionslimit von AutoIt))
    • Callbacks (Ordentlicher als If-Abfragen mit _IsPressed in der Hauptschleife...)

    Die CallBack-Funktionen müssen 2 Parameter akzeptieren: Den Tastencode der gedrückten Taste im Hex-Format und das Event ($IPC_XXX).
    Example ist aber zur Verdeutlichung auch dabei.^^

    Es gibt noch einen wichtigen Bug:
    Wenn mehrere Tasten gleichzeitig gedrückt werden (UPDOWN-Event registriert), und eine losgelassen wird, bekommen alle anderen gedrückten Tasten erst das Event $IPC_UP und direkt danach $IPC_DOWN!

    Ich überlege, ob man evtl. mit der Timer-UDF arbeiten kann. Dann würde u.U. das Skript nicht mehr pausieren, wenn mehrere Tasten gedrückt sind...
    Mal schauen. So funktioniert es jedenfalls erstmal.^^

    IsPressedCallback.au3
    [autoit]


    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $gaCallBacks[1][3]
    Global $ghUser32 = DllOpen("user32.dll")
    Global $giIntervalMS = 100
    Global Enum $IPC_NORMAL, $IPC_DOWN, $IPC_UP, $IPC_DOWNUP
    AdlibRegister("__IsPressed_CallBackHandler", $giIntervalMS)
    OnAutoItExitRegister("__IsPressed_Shutdown")

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name ..........: _IsPressed_CallBackRegister
    ; Description ...: Register a new hotkey.
    ; Syntax ........: _IsPressed_CallBackRegister($sHexKey, $sCallBack, $iMethod)
    ; Parameters ....: $sHexKey - Keycode as hex, see _IsPressed
    ; $sCallBack - Callback function
    ; $iMethod - $IPC_NORMAL: Original _IsPressed
    ; - $IPC_DOWN: Fire event on key down
    ; - $IPC_UP: Fire event on key up
    ; - $IPC_DOWNUP or $IPC_DOWN + $IPC_UP: Fire event on key down and key up
    ; Return values .: An id to use with _IsPressed_CallBackUnRegister
    ; Author ........: chesstiger (AutoIt.de)
    ; Modified ......:
    ; Remarks .......:
    ; Related .......:
    ; Link ..........:
    ; Example .......: See "Example.au3"
    ; ===============================================================================================================================
    Func _IsPressed_CallBackRegister($sHexKey, $sCallBack, $iMethod = 0)
    $gaCallBacks[UBound($gaCallBacks) - 1][0] = $sHexKey
    $gaCallBacks[UBound($gaCallBacks) - 1][1] = $sCallBack
    $gaCallBacks[UBound($gaCallBacks) - 1][2] = $iMethod
    ReDim $gaCallBacks[UBound($gaCallBacks) + 1][3]
    Return UBound($gaCallBacks) - 2
    EndFunc ;==>_IsPressed_CallBackRegister

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name ..........: _IsPressed_CallBackUnRegisterOld
    ; Description ...: Unregisters a hotkey by the hotkey code.
    ; Syntax ........: _IsPressed_CallBackUnRegisterOld($sHexKey)
    ; Parameters ....: $sHexKey - keycode as hex, like _IsPressed.
    ; Return values .: None
    ; Author ........: chesstiger
    ; Modified ......:
    ; Remarks .......: If you have two functions on one hotkey, this function will just remove one of them -> DEPRECATED
    ; Related .......:
    ; Link ..........:
    ; Example .......: No
    ; ===============================================================================================================================
    Func _IsPressed_CallBackUnRegisterOld($sHexKey)
    AdlibUnRegister("__IsPressed_CallBackHandler")
    For $i = 0 To UBound($gaCallBacks) - 1 ;Find Match Index
    If $gaCallBacks[$i][0] = $sHexKey Then
    $iMatchIndex = $i
    ExitLoop
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    For $i = $iMatchIndex To UBound($gaCallBacks) - 2
    $gaCallBacks[$i][0] = $gaCallBacks[$i + 1][0]
    $gaCallBacks[$i][1] = $gaCallBacks[$i + 1][1]
    $gaCallBacks[$i][2] = $gaCallBacks[$i + 1][2]
    Next
    $gaCallBacks[UBound($gaCallBacks) - 2][0] = ""
    $gaCallBacks[UBound($gaCallBacks) - 2][1] = ""
    $gaCallBacks[UBound($gaCallBacks) - 2][2] = ""
    ReDim $gaCallBacks[UBound($gaCallBacks) - 1][3]

    [/autoit] [autoit][/autoit] [autoit]

    AdlibRegister("__IsPressed_CallBackHandler", $giIntervalMS)
    EndFunc ;==>_IsPressed_CallBackUnRegister

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name ..........: _IsPressed_CallBackUnRegister
    ; Description ...: Unregisters a hotkey.
    ; Syntax ........: _IsPressed_CallBackUnRegister($iHotkeyID)
    ; Parameters ....: $iHotkeyID - Return value of _IsPressed_CallBackRegister
    ; Return values .: None
    ; Author ........: chesstiger
    ; Modified ......:
    ; Remarks .......:
    ; Related .......:
    ; Link ..........:
    ; Example .......: No
    ; ===============================================================================================================================
    Func _IsPressed_CallBackUnRegister($iHotkeyID)
    For $i = $iHotkeyID To UBound($gaCallBacks) - 2
    $gaCallBacks[$i][0] = $gaCallBacks[$i + 1][0]
    $gaCallBacks[$i][1] = $gaCallBacks[$i + 1][1]
    $gaCallBacks[$i][2] = $gaCallBacks[$i + 1][2]
    Next
    ReDim $gaCallBacks[UBound($gaCallBacks) - 1][3]
    EndFunc
    ; #FUNCTION# ====================================================================================================================
    ; Name ..........: _IsPressed_SetCheckInterval
    ; Description ...: Set the interval for hotkey checking.
    ; Syntax ........: _IsPressed_SetCheckInterval($iMS)
    ; Parameters ....: $iMS - Check interval time in MS
    ; Return values .: None
    ; Author ........: chesstiger
    ; Modified ......:
    ; Remarks .......: Do not use too small values. This will be CPU intensive.
    ; Related .......:
    ; Link ..........:
    ; Example .......: No
    ; ===============================================================================================================================
    Func _IsPressed_SetCheckInterval($iMS)
    AdlibUnRegister("__IsPressed_CallBackHandler")
    AdlibRegister("__IsPressed_CallBackHandler", $iMS)
    $giIntervalMS = $iMS
    EndFunc ;==>_IsPressed_SetCheckInterval

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;INTERN
    Func __IsPressed_CallBackHandler($aExcpHeader = 0) ;recursive
    If Not IsDeclared("aExcpHeader") Then
    Local $aExceptions[1]
    Else
    $aExceptions = $aExcpHeader
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($gaCallBacks) - 1 ;Last element is always empty
    $bSkip = False
    For $iExcp = 1 To UBound($aExceptions) - 1 ;FEE
    If $i = $aExceptions[$iExcp] Then
    $bSkip = True
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If __IsPressed($gaCallBacks[$i][0], $ghUser32) And Not $bSkip Then
    Switch $gaCallBacks[$i][2]
    Case $IPC_NORMAL ;Normal _IsPressed
    Call($gaCallBacks[$i][1], $gaCallBacks[$i][0], $IPC_NORMAL)
    Case $IPC_DOWN ;DOWN
    Call($gaCallBacks[$i][1], $gaCallBacks[$i][0], $IPC_DOWN)
    Do
    Sleep(10)
    Until Not __IsPressed($gaCallBacks[$i][0], $ghUser32)
    Case $IPC_UP ;UP
    Do
    Sleep(10)
    Until Not __IsPressed($gaCallBacks[$i][0], $ghUser32)
    Call($gaCallBacks[$i][1], $gaCallBacks[$i][0], $IPC_UP)
    Case $IPC_DOWN + $IPC_UP
    $iLastItem = _ArrayAdd($aExceptions, $i)
    Call($gaCallBacks[$i][1], $gaCallBacks[$i][0], $IPC_DOWN)
    $iRemoveCallback = _IsPressed_CallBackRegister($gaCallBacks[$i][0], $gaCallBacks[$i][1], $IPC_UP)
    $iUpItem = _ArrayAdd($aExceptions, UBound($gaCallBacks) - 2)
    While __IsPressed_CallBackHandler($aExceptions) <> 5
    Sleep($giIntervalMS)
    WEnd
    Call($gaCallBacks[$i][1], $gaCallBacks[$i][0], $IPC_UP)
    _ArrayDelete($gaCallBacks, $iRemoveCallback)
    _ArrayDelete($aExceptions, $iUpItem)
    _ArrayDelete($aExceptions, $iLastItem)
    EndSwitch
    EndIf
    If Not __IsPressed($gaCallBacks[$i][0], $ghUser32) And $bSkip Then
    Return 5
    EndIf
    Next
    EndFunc ;==>__IsPressed_CallBackHandler

    [/autoit] [autoit][/autoit] [autoit]

    ;INTERN
    Func __IsPressed_Shutdown()
    DllClose($ghUser32)
    EndFunc ;==>__IsPressed_Shutdown

    [/autoit] [autoit][/autoit] [autoit]

    Func __IsPressed($sHexKey, $vDLL = 'user32.dll')
    ; From Misc.au3 by ezzetabi and Jon
    ; For function header see Misc.au3
    Local $a_R = DllCall($vDLL, "short", "GetAsyncKeyState", "int", '0x' & $sHexKey)
    If @error Then Return SetError(@error, @extended, False)
    Return BitAND($a_R[0], 0x8000) <> 0
    EndFunc ;==>__IsPressed

    [/autoit]
    Example
    [autoit]


    #include "IsPressedCallback.au3"
    #include <GDIPlus.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Local $aKeycodes[6] = ["51", "57", "45", "52", "54", "5A"] ;QWERTZ
    Local $aKeynames[6] = ["Q", "W", "E", "R", "T", "Z"] ;QWERTZ
    Local $iPressColor = 0xff0000ff
    Local $iReleaseColor = 0xffff0000

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()
    Opt("GUIOnEventMode", True)
    Opt("TrayIconDebug", True)

    [/autoit] [autoit][/autoit] [autoit]

    $hGUI = GUICreate("QWERTZ-Keyboard", 50 * 6, 50)
    GUISetOnEvent(-3, "_Exit")
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    ;GDI+ Init
    $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBufferBMP = _GDIPlus_BitmapCreateFromGraphics(50 * 6, 50, $hGraphics)
    $hBuffer = _GDIPlus_ImageGetGraphicsContext($hBufferBMP)

    [/autoit] [autoit][/autoit] [autoit]

    Local $aBrushes[UBound($aKeycodes)]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($aKeycodes) - 1
    $aBrushes[$i] = _GDIPlus_BrushCreateSolid($iReleaseColor)
    _IsPressed_CallbackRegister($aKeycodes[$i], "_ChangeColor", $IPC_DOWN + $IPC_UP)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    While True
    _Draw()
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _ChangeColor($sKey, $iEvent)
    Switch $iEvent
    Case $IPC_DOWN
    $iNewColor = $iPressColor
    Case $IPC_UP
    $iNewColor = $iReleaseColor
    EndSwitch
    For $i = 0 To UBound($aKeycodes) - 1
    If $sKey = $aKeycodes[$i] Then
    _GDIPlus_BrushSetSolidColor($aBrushes[$i], $iNewColor)
    EndIf
    Next
    _Draw()
    EndFunc ;==>_ChangeColor

    [/autoit] [autoit][/autoit] [autoit]

    Func _Draw()
    _GDIPlus_GraphicsClear($hBuffer, 0xffffffff)
    For $i = 0 To UBound($aKeycodes) - 1
    _GDIPlus_GraphicsFillRect($hBuffer, 50 * $i, 0, 50, 50, $aBrushes[$i])
    _GDIPlus_GraphicsDrawString($hBuffer, $aKeynames[$i], 50 * $i, 0, "Arial", 34)
    Next
    _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBufferBMP, 0, 0, 50 * 6, 50)
    EndFunc ;==>_Draw

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    _GDIPlus_DisposeAll()
    _GDIPlus_Shutdown()
    Exit
    EndFunc ;==>_Exit

    [/autoit] [autoit][/autoit] [autoit]

    Func _GDIPlus_DisposeAll()
    ;Common GDI+ Dispose Function created by CleanGDI+.au3
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_BitmapDispose($hBufferBMP)
    _GDIPlus_GraphicsDispose($hBuffer)
    For $i = 0 To UBound($aBrushes) - 1
    _GDIPlus_BrushDispose($aBrushes[$i])
    Next
    EndFunc ;==>_GDIPlus_DisposeAll

    [/autoit]

    lg