ListView - WM_NOTIFY Markierung

  • Hi,
    mit WM_NOTIFY kann ja abgefragt werden, wenn sich die markierten Elemente durch einen Mausklick ändern.
    Geht dies auch wenn dies z. B. durch die Tastatur (Pfeiltasten) passiert :?:

    Spoiler anzeigen
    [autoit]

    #region ;************ Includes ************
    #include <GuiListView.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #endregion ;************ Includes ************

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

    $Form1 = GUICreate("Test", 400, 300)
    $ListView = GUICtrlCreateListView("Test|Test", 20, 20, 300, 200, $LVS_SHOWSELALWAYS)

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

    For $i = 1 To 10
    GUICtrlCreateListViewItem("|" & $i & "| aaaaaaaaaaaaaa|" & Random(0, 10, 1), $ListView)
    Next
    GUISetState(@SW_SHOW)

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

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd

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

    Func WM_NOTIFY($hWnd, $MsgID, $wParam, $lParam)
    Local $tagNMHDR, $event, $hwndFrom, $code
    $tagNMHDR = DllStructCreate("int;int;int", $lParam)
    If @error Then Return 0
    $code = DllStructGetData($tagNMHDR, 3)
    If $wParam = $ListView Then
    Switch $code
    Case $NM_CLICK ;klick
    ConsoleWrite(_GUICtrlListView_GetSelectedIndices($ListView) & @CRLF)
    EndSwitch
    EndIf
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

    [/autoit]
    • Offizieller Beitrag

    Die Pfeiltasten mußt du dir über einen Keyhook abfangen. Ich poste mal aus meiner Bsp.-Sammlung, wie ich es für ein Tab gelöst hatte. Auswahl der Tabs per Klick oder Pfeiltaste

    Spoiler anzeigen
    [autoit]

    #include <GuiConstantsEx.au3>
    #include <GuiTab.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>
    #include <StructureConstants.au3>

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

    OnAutoItExitRegister('OnAutoItExit')
    AdlibRegister('_CheckPass', 50)

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

    Global Const $HC_ACTION = 0

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

    Global $hStub_MouseProc = DllCallbackRegister("_MouseProc", "long", "int;wparam;lparam")
    Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
    Global $hmod = _WinAPI_GetModuleHandle(0)
    Global $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hStub_MouseProc), $hmod)
    Global $hHook2 = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)
    Global $hTab, $lastTab = 0, $checkPass = False

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

    Global $Passwort = 'pass', $passItem = 2 ; <== 0-basierter Index des PW-geschützten TabItems

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

    $Form1 = GUICreate("Testfenster", 297, 341, 210, 144)
    $Tab = GUICtrlCreateTab(8, 8, 280, 304)
    GUICtrlSetResizing(-1, $GUI_DOCKWIDTH + $GUI_DOCKHEIGHT)
    $tab1 = GUICtrlCreateTabItem("Tab1")
    $tab2 = GUICtrlCreateTabItem("Tab2")
    $tab3 = GUICtrlCreateTabItem("Tab3")
    $tab4 = GUICtrlCreateTabItem("Tab4")
    GUICtrlCreateTabItem("")
    GUISetState(@SW_SHOW)

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

    Global $hookGUI = $Form1, $hookID = $Tab

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    Case $Tab
    Switch GUICtrlRead($Tab)
    Case 0
    WinSetTitle($Form1, '', ' >> Tab1 aktiviert <<')
    Case 1
    WinSetTitle($Form1, '', ' >> Tab2 aktiviert <<')
    Case 2
    WinSetTitle($Form1, '', ' >> Tab3 aktiviert <<')
    Case 3
    WinSetTitle($Form1, '', ' >> Tab4 aktiviert <<')
    EndSwitch
    Sleep(1000)
    WinSetTitle($Form1, '', 'Testfenster')
    EndSwitch
    WEnd

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

    Func _MouseProc($nCode, $wParam, $lParam)
    Select
    Case $nCode < 0
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    Case Not _MouseOverTabItem($hookGUI, $hookID, $passItem)
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    Case $wParam = $WM_LBUTTONDOWN
    If $nCode = $HC_ACTION Then
    $checkPass = True ; Überprüfung aktivieren
    Return -1 ; Mausklick wird ignoriert ==> TabItem noch nicht aktiviert
    EndIf
    EndSelect
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndFunc ;==>_MouseProc

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

    Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If ControlGetFocus($Form1) <> 'SysTabControl321' Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
    Switch $vkCode
    Case 0x25 ; ==> Pfeil li.
    If GUICtrlRead($hookID) - 1 = $passItem Then
    $checkPass = True ; Überprüfung aktivieren
    Return -1 ; Tastendruck wird ignoriert ==> TabItem noch nicht aktiviert
    EndIf
    Case 0x27 ; ==> Pfeil re.
    If GUICtrlRead($hookID) + 1 = $passItem Then
    $checkPass = True ; Überprüfung aktivieren
    Return -1 ; Tastendruck wird ignoriert ==> TabItem noch nicht aktiviert
    EndIf
    EndSwitch
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndFunc ;==>_KeyProc

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

    Func _CheckPass()
    If Not $checkPass Then Return
    If InputBox('Passwort', 'Bitte Passwort eingeben:') == $Passwort Then
    _GUICtrlTab_SetCurSel(GUICtrlGetHandle($Tab), $passItem)
    Else
    MsgBox(0, 'Fehler', 'Falsches Passwort!')
    EndIf
    $checkPass = 0
    EndFunc ;==>_CheckPass

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

    Func _MouseOverTabItem($GUI, $TabID, $iTabItem)
    If Not BitAND(WinGetState($GUI), 8) Then Return False
    Local $old = Opt('MouseCoordMode', 2)
    Local $posM = MouseGetPos(), $tMouse = DllStructCreate($tagPOINT)
    DllStructSetData($tMouse, 1, $posM[0])
    DllStructSetData($tMouse, 2, $posM[1])
    Opt('MouseCoordMode', $old)
    Local $tTabItem = _GUICtrlTab_GetItemRectRelativ($GUI, $TabID, $iTabItem, 1)
    If _WinAPI_PtInRect($tTabItem, $tMouse) Then
    Return True
    Else
    Return False
    EndIf
    EndFunc ;==>_MouseOverTabItem

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

    ;===============================================================================
    ; Function Name: _GUICtrlTab_GetItemRectRelativ($GUI, $TabID, $iTabItem, $iReturnType=0)
    ; Description: Returns the co-ordinates of a TabItem relatively to the GUI co-ordinates
    ; Parameter(s): $GUI - window handle
    ; $TabID - Tab ID (not handle!)
    ; $iTabItem - TabItem index
    ; $iReturnType - Return type array=0 (default), RECT-structure=1
    ; Return Value(s): Array or structure with co-ordinates of a TabItem (left, top, right, bottom)
    ; Author(s): BugFix ([email='bugfix@autoit.de'][/email])
    ;===============================================================================
    Func _GUICtrlTab_GetItemRectRelativ($GUI, $TabID, $iTabItem, $iReturnType=0)
    Local $hWnd = GUICtrlGetHandle($TabID)
    Local $TabPos = ControlGetPos($GUI, '', $TabID)
    Local $tRECT = DllStructCreate("int Left;int Top;int Right;int Bottom")
    Local $pRect = DllStructGetPtr($tRECT)
    GUICtrlSendMsg($TabID, $TCM_GETITEMRECT, $iTabItem, $pRect)
    Local $posLeft = $TabPos[0]+2, $posTop = $TabPos[1]+2
    Local $width = (DllStructGetData($tRECT,3) - DllStructGetData($tRECT,1))
    Local $height = DllStructGetData($tRECT,4) - DllStructGetData($tRECT,2)
    If $iTabItem > 0 Then
    For $i = 0 To $iTabItem -1
    GUICtrlSendMsg($TabID, $TCM_GETITEMRECT, $iTabItem, $pRect)
    $posLeft += (DllStructGetData($tRECT,3) - DllStructGetData($tRECT,1))
    Next
    EndIf
    If $iReturnType Then
    DllCall("user32", 'long', 'SetRect', 'ptr', $pRECT, 'long', $posLeft, _
    'long', $posTop, 'long', $posLeft+$width, 'long', $posTop +$height)
    Return $tRECT
    Else
    Local $aOut[4] = [$posLeft, $posTop, $posLeft +$width, $posTop +$height]
    Return $aOut
    EndIf
    EndFunc ;==>_GUICtrlTab_GetItemRectRelativ

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

    Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_MouseProc)
    _WinAPI_UnhookWindowsHookEx($hHook2)
    DllCallbackFree($hStub_KeyProc)
    EndFunc ;==>OnAutoItExit

    [/autoit] [autoit][/autoit] [autoit][/autoit]
  • OK, wiedermal wow :thumbup:

    Habs mal für meinen Fall umgebaut

    Spoiler anzeigen
    [autoit]

    #region ;************ Includes ************
    #include <GuiListView.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #endregion ;************ Includes ************

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

    OnAutoItExitRegister('OnAutoItExit')

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

    Global $hStub_MouseProc = DllCallbackRegister("_MouseProc", "long", "int;wparam;lparam")
    Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
    Global $hmod = _WinAPI_GetModuleHandle(0)
    Global $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hStub_MouseProc), $hmod)
    Global $hHook2 = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)

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

    Global $Form1 = GUICreate("Test", 400, 300)
    Global $ListView = GUICtrlCreateListView("Test|Test", 20, 20, 300, 200, $LVS_SHOWSELALWAYS)

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

    For $i = 1 To 10
    GUICtrlCreateListViewItem("|" & $i & "|" & Random(0, 10, 1), $ListView)
    Next
    GUISetState(@SW_SHOW)

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

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd

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

    Func WM_NOTIFY($hWnd, $MsgID, $wParam, $lParam)
    Local $tagNMHDR, $event, $hwndFrom, $code
    $tagNMHDR = DllStructCreate("int;int;int", $lParam)
    If @error Then Return 0
    $code = DllStructGetData($tagNMHDR, 3)
    If $wParam = $ListView Then
    Switch $code
    Case $NM_CLICK ;klick
    ConsoleWrite(_GUICtrlListView_GetSelectedIndices($ListView) & @CRLF)
    EndSwitch
    EndIf
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

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

    Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If ControlGetFocus($Form1) <> 'SysListView321' Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
    Switch $vkCode
    Case 0x26
    ConsoleWrite(_GUICtrlListView_GetSelectedIndices($ListView) & @CRLF)
    Case 0x28
    ConsoleWrite(_GUICtrlListView_GetSelectedIndices($ListView) & @CRLF)
    EndSwitch
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndFunc ;==>_KeyProc

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

    Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_MouseProc)
    _WinAPI_UnhookWindowsHookEx($hHook2)
    DllCallbackFree($hStub_KeyProc)
    EndFunc ;==>OnAutoItExit

    [/autoit]

    Sollte so passen oder?

    Würdest du WM_NOTIFY für die Mausklick weiterverwenden oder stattdessen _MouseProc :?:
    Würdest du diese Methode immer der ständigen Abfrage in der While-Schleife vorziehen :?:

    • Offizieller Beitrag

    Sollte so passen oder?


    Ja, aber z.Zt. verwendest du das Mouse-Hook-Hwnd in deiner Key-Procedure. ;)
    Und die Passagen für den Mouse-Hook kannst du dann entfernen:

    [autoit]


    Global $hStub_MouseProc = DllCallbackRegister("_MouseProc", "long", "int;wparam;lparam")
    Global $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hStub_MouseProc), $hmod)

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

    ; in Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_MouseProc)

    [/autoit]

    Würdest du WM_NOTIFY für die Mausklick weiterverwenden oder stattdessen _MouseProc :?:
    Würdest du diese Methode immer der ständigen Abfrage in der While-Schleife vorziehen :?:


    Wenn du nur auf den Klick reagieren mußt, bist du mit WM_NOTIFY bestens bedient. Wenn du jedoch den Klick unter Umständen nicht zulassen möchtest und auch zusätzliche Infos zur Maus benötigst ist der Mouse-Hook die bessere Wahl.

  • Ok,
    der Vollständigkeithalber nochmal das komplette Skript für alle die sowas auch mal brauchen :P

    Spoiler anzeigen
    [autoit]

    #region ;************ Includes ************
    #include <GuiListView.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #endregion ;************ Includes ************

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

    OnAutoItExitRegister('OnAutoItExit')

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

    Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
    Global $hmod = _WinAPI_GetModuleHandle(0)
    Global $hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)

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

    Global $Form1 = GUICreate("Test", 400, 300)
    Global $ListView = GUICtrlCreateListView("Test", 20, 20, 300, 200, $LVS_SHOWSELALWAYS)

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

    For $i = 1 To 10
    GUICtrlCreateListViewItem($i & "|" & Random(0, 10, 1), $ListView)
    Next
    GUISetState(@SW_SHOW)

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

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd

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

    Func WM_NOTIFY($hWnd, $MsgID, $wParam, $lParam)
    Local $tagNMHDR, $event, $hwndFrom, $code
    $tagNMHDR = DllStructCreate("int;int;int", $lParam)
    If @error Then Return 0
    $code = DllStructGetData($tagNMHDR, 3)
    If $wParam = $ListView Then
    Switch $code
    Case $NM_CLICK ;klick
    ConsoleWrite(_GUICtrlListView_GetSelectedIndices($ListView) & @CRLF)
    EndSwitch
    EndIf
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

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

    Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If ControlGetFocus($Form1) <> 'SysListView321' Then Return
    $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
    Switch $vkCode
    Case 0x26 ;Pfeil hoch
    ConsoleWrite(_GUICtrlListView_GetSelectedIndices($ListView) & @CRLF)
    Case 0x28 ;Pfeil runter
    ConsoleWrite(_GUICtrlListView_GetSelectedIndices($ListView) & @CRLF)
    EndSwitch
    EndIf
    EndFunc ;==>_KeyProc

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

    Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_KeyProc)
    EndFunc ;==>OnAutoItExit

    [/autoit]

    Danke BugFix :thumbup:

    • Offizieller Beitrag

    O_O jetzt hast du aber was vergessen.
    Nur noch mal zum Verständnis: Ein Hook greift auf den Nachrichtenqueue für den gewählten Ereignistyp (hier Keyboard-Event) zu. Es wird nach den gewünschten Tastenanschlägen gesucht und diese werden ausgewertet.
    Dann wird das Event zur "normalen" Weiterverarbeitung an das System weitergereicht oder, wenn diese unterbunden werden soll, wird -1 zurückgegeben.
    Aber auch wenn die Prüfung, ob das Event während der Verwendung eines bestimmten Controls ausgelöst wurde, negativ ist muß zwingend das Event an das System weitergereicht werden.
    D.h.: Immer, wenn das Ereignis NICHT verworfen werden soll, muß die Funktion mit:

    [autoit]

    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)

    [/autoit]

    verlassen werden.

  • Also dann so.

    Allerdings scheint es wohl nicht ganz zu funktionieren.

    Es scheint so zu sein, als ob der Tastendruck immer um einen Befehl verspätet kommt.

    Folgendes mal testen:
    Zahl 1 anklicken >>> Console = 0
    Pfeil runter (2) >>> Console = 0 ;warum???
    Pfeil runter (3) >>> Console = 1 ;warum???

    Weisst du was ich meine BugFix?


    Spoiler anzeigen
    [autoit]

    #region ;************ Includes ************
    #include <GuiListView.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #endregion ;************ Includes ************

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

    OnAutoItExitRegister('OnAutoItExit')

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

    Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
    Global $hmod = _WinAPI_GetModuleHandle(0)
    Global $hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)

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

    Global $Form1 = GUICreate("Test", 400, 300)
    Global $ListView = GUICtrlCreateListView("Test", 20, 20, 300, 200, $LVS_SHOWSELALWAYS)

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

    For $i = 1 To 10
    GUICtrlCreateListViewItem($i & "|" & Random(0, 10, 1), $ListView)
    Next
    GUISetState(@SW_SHOW)

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

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd

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

    Func WM_NOTIFY($hWnd, $MsgID, $wParam, $lParam)
    Local $tagNMHDR, $event, $hwndFrom, $code
    $tagNMHDR = DllStructCreate("int;int;int", $lParam)
    If @error Then Return 0
    $code = DllStructGetData($tagNMHDR, 3)
    If $wParam = $ListView Then
    Switch $code
    Case $NM_CLICK ;klick
    ConsoleWrite(_GUICtrlListView_GetSelectedIndices($ListView) & @CRLF)
    EndSwitch
    EndIf
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

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

    Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If ControlGetFocus($Form1) <> 'SysListView321' Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
    Switch $vkCode
    Case 0x26 ;Pfeil hoch
    ConsoleWrite(_GUICtrlListView_GetSelectedIndices($ListView) & @CRLF)
    Case 0x28 ;Pfeil runter
    ConsoleWrite(_GUICtrlListView_GetSelectedIndices($ListView) & @CRLF)
    EndSwitch
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndFunc ;==>_KeyProc

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

    Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_KeyProc)
    EndFunc ;==>OnAutoItExit

    [/autoit]
    • Offizieller Beitrag

    Folgendes mal testen:
    Zahl 1 anklicken >>> Console = 0
    Pfeil runter (2) >>> Console = 0 ;warum???
    Pfeil runter (3) >>> Console = 1 ;warum???


    Das ist doch korrekt.
    - aktueller Index: 0
    - Pfeil ab -- wird im Hook erkannt ABER das System hat dieses 'Pfeil ab' noch NICHT umgesetzt. In diesem Moment bist du noch immer auf Index 0. Erst NACH Verlassen der Funktion wird 'Pfeil ab' auch ausgeführt und dann ist der Index 1.

  • Achso das ist so gewollt :huh:
    Ändern kann man dies nicht oder?

    Also müsste ich es einfach -1 (wenn Pfeil hoch) bzw. +1 (wenn Pfeil runter) verrechnen :?:
    Wobei ich dann nicht erkenne, wenn mehrere Einträge ausgewählt werden ?(

    • Offizieller Beitrag

    Also müsste ich es einfach -1 (wenn Pfeil hoch) bzw. +1 (wenn Pfeil runter) verrechnen
    Wobei ich dann nicht erkenne, wenn mehrere Einträge ausgewählt werden


    Du mußt Schritt für Schritt denken. Mit der Tastatur kannst du pro Tastatur-Ereignis IMMER nur EINEN Eintrag auswählen. Insofern ist das Verrechnen des nach Verlassen der Funktion stattfindenden Vorgangs legitim und richtig.

  • Puuh, jetzt steht ich total auf dem Schlauch.
    Ich kann doch mit der Shift+Pfeiltasten mehrere Einträg auswählen.
    Muß ich dann die Shift-Taste auch noch abfragen?
    Oder ist das alles dann doch zu aufwendig?

    • Offizieller Beitrag

    Na klar kannst du mit Shift eine Mehrfachauswahl machen. Aber nicht in einem Abwasch.
    Wie gehst du vor?
    - Shift gedrückt halten
    - 1. Klick 'pfeil ab' - erzeugt Key-Event
    - 2. Klick 'pfeil ab' - erzeugt Key-Event
    - 3. Klick 'pfeil ab' - erzeugt Key-Event

    Du markierst drei Einträge, aber das passiert in 3 Schritten. In einem Rutsch geht das nur mit Maus (Klick erster Eintrag, Shift+Klick letzter zu markierender Eintrag).
    Wenn du jetzt tatsächlich die Mehrfachauswahl berücksichtigen möchtest ist das Abfragen von Shift erforderlich - oder auch von Strg, bei selektiver Auswahl.
    DAS ist dann etwas umfangreicher. Ich poste dir zwei Bsp., denen du das nötige entnehmen kannst:

    Auto-Ersetzen
    [autoit]

    #cs
    Bsp. Auto-Ersetzen mit Hook
    Umlaute und ß
    linke Shift ergibt z.B. Ä-Ae, rechte Shift und CapsLock ergibt Ä-AE (RShift wir nicht per Hook gelöst)
    Ä - Ae (AE) ä - ae
    Ö - Oe (OE) ö - oe
    Ü - Ue (UE) ü - ue
    ß - ss

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

    Hook ist nur wirksam für die GUI (Statusabfrage in der Schleife) und das benannte Ctrl.
    #ce

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

    #include <WinAPI.au3>
    #include <WindowsConstants.au3>
    #include <StructureConstants.au3>
    OnAutoItExitRegister('OnAutoItExit')

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

    Opt('MustDeclareVars', 1)
    Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
    Global $hmod = _WinAPI_GetModuleHandle(0)
    Global $hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)
    Global $active = False, $isShift = False

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

    _Main()

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

    Func _Main()
    Local $gui = GUICreate('Auto Ersetzen: Umlaute und "ß"', 400, 300)
    GUICtrlCreateLabel('Im Input keine Ersetzung', 10, 10, 380)
    GUICtrlCreateInput('', 10, 30, 380)
    GUICtrlCreateLabel('Im Edit werden ersetzt: ä ==> ae ö ==> oe ü ==> ue ß ==> ss', 10, 60, 380)
    Local $edit = GUICtrlCreateEdit('', 10, 80, 380, 210)
    GUISetState()

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

    Do
    If BitAND(WinGetState($gui), 8) And _
    _WinAPI_GetDlgCtrlID(ControlGetHandle($gui, '', ControlGetFocus($gui))) = $edit Then
    $active = True
    Else
    $active = False
    EndIf
    Until GUIGetMsg() = -3
    EndFunc

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

    Func _Exit()
    Exit
    EndFunc

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

    ;===========================================================
    ; callback function
    ;===========================================================
    Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode, $ret, $isCapsLock = 0
    $ret = DllCall("user32.dll","long","GetKeyState","long", 0x14)
    If $ret[0] Then $isCapsLock = 1
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If $nCode < 0 Or Not $active Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
    ConsoleWrite('$vkCode ' & $vkCode & @CRLF)
    If $vkCode = 0xA0 Or $vkCode = 0xA1 Then
    $isShift = True
    EndIf
    Switch $vkCode
    Case 0xBA ; ü ==> ue
    _keybd_event(0x55) ; Zeichen 'u'
    If $isShift Then _keybd_event(0xA0, 0x2) ; Flag 0x2=KEYUP (LShift nach Senden Ersatzbuchstaben lösen)
    _keybd_event(0x45) ; Zeichen 'e'
    Return -1
    Case 0xC0 ; ö ==>oe
    _keybd_event(0x4F)
    If $isShift Then _keybd_event(0xA0, 0x2)
    _keybd_event(0x45)
    Return -1
    Case 0xDB ; ß ==> ss - nicht ausführen, wenn Shift/Capslock aktiv
    If $isShift Or $isCapsLock Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    _keybd_event(0x53)
    _keybd_event(0x53)
    Return -1
    Case 0xDE ; ä ==> ae
    _keybd_event(0x41)
    If $isShift Then _keybd_event(0xA0, 0x2)
    _keybd_event(0x45)
    Return -1
    EndSwitch
    Else
    ;~ ConsoleWrite('flags ' & DllStructGetData($tKEYHOOKS, "flags") & @CRLF)
    Switch DllStructGetData($tKEYHOOKS, "flags")
    Case 0x80, 0x81 ; 0x80= UP für 'normale' Tasten u. li. paarige, 0x81= UP für re. paarige
    If $vkCode = 0xA0 Or $vkCode = 0xA1 Then $isShift = False ; LShift, RShift
    EndSwitch
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndFunc

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

    Func _keybd_event($vkCode, $Flag=0)
    DllCall('user32.dll', 'int', 'keybd_event', 'int', $vkCode, 'int', 0, 'int', $Flag, 'ptr', 0)
    EndFunc

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

    Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_KeyProc)
    EndFunc

    [/autoit]
    Hook Enter
    [autoit]

    #cs
    Hook ENTER in einem Edit-Ctrl
    - ENTER für Funktionsaufruf (Auslesen Inhalt Edit-Ctrl)
    - SHIFT + ENTER für Zeilenumbruch im Edit-Ctrl
    #ce
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>
    #include <StructureConstants.au3>
    Opt("GUIOnEventMode", 1)
    OnAutoItExitRegister('OnAutoItExit')

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

    Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
    Global $hmod = _WinAPI_GetModuleHandle(0)
    Global $hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)
    Global $gui, $edit, $active = False ; <== to allow hook only on this gui
    Global $isShift = False

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

    $gui = GUICreate('CRLF = <Shift>+<Enter>', 300, 170)
    GUISetOnEvent(-3, '_end')
    $edit = GUICtrlCreateEdit('', 10, 10, 280, 150)

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

    GUISetState()

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

    While 1
    _checkWinState()
    Sleep(100)
    WEnd

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

    Func _checkWinState()
    If Not $active And BitAND(WinGetState($gui), 8) Then
    $active = True
    ElseIf $active And Not BitAND(WinGetState($gui), 8) Then
    $active = False
    EndIf
    EndFunc

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

    Func _end()
    Exit
    EndFunc

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

    Func _send() ; for example only
    ConsoleWrite('_send(' & @CRLF & _
    GUICtrlRead($edit) & @CRLF & _
    ') was called' & @CRLF)
    EndFunc

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

    ;===========================================================
    ; callback function
    ;===========================================================
    Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode, $ID
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If $nCode < 0 Or Not $active Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
    $ID = _WinAPI_GetDlgCtrlID(ControlGetHandle($gui, '', ControlGetFocus($gui))) ; get focus-ID from your gui
    If $ID <> $edit Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam) ; Edit has not focus
    If $vkCode = 0xA0 Or $vkCode = 0xA1 Then ; left or right shift-button pressed
    $isShift = True
    EndIf
    If ( $vkCode = 13 ) And ( Not $isShift ) Then
    _send()
    Return -1 ; so the system get not the $vkCode 13
    ElseIf ( $vkCode = 13 ) And $isShift Then
    GUICtrlSetData($ID, GUICtrlRead($ID)) ; if not using style $ES_WANTRETURN, use "GUICtrlRead($ID) & @CRLF"
    EndIf
    Else
    Switch DllStructGetData($tKEYHOOKS, "flags")
    Case 0x80, 0x81 ; 0x80= UP for 'normal' keys and left pairs, 0x81= UP for right pairs
    If $vkCode = 0xA0 Or $vkCode = 0xA1 Then $isShift = False ; LShift, RShift
    EndSwitch
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndFunc

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

    Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_KeyProc)
    EndFunc

    [/autoit]


    Aber Vorsicht, falls du mit "_keybd_event()" arbeiten möchtest! Ein Tastendruck besteht aus zwei Phasen: Hit und Release. Du mußt am Ende deines Programmes sicherstellen, dass alle Tasten released sind - sinst hast du ein sehr merkwürdiges Verhalten deines PC. :whistling:
    Läßt sich aber schlimmstenfalls mit Neustart beheben.

  • Genau das seltsame Verhalten hatte ich gerade :D
    Wie gehe ich denn sicher, dass alle released sind?

    • Offizieller Beitrag

    Wie gehe ich denn sicher, dass alle released sind?


    Das Hantieren mit Hooks greift direkt in das System ein. Wenn man damit arbeitet, wird erwartet, dass du weißt, was du tust. :D Ist wie bei ASM, da gibts keine Syntaxfehler Warnung - da gibts den Crash.
    Die beste Methode ist es, den Ablauf in wirklich alle Teilschritte zu zerlegen. Jedes Down, Hold-Down, Up muß vollkommen klar sein. Das ist nicht zu vergleichen mit Send(), wo im Standardfall Hit und Release automatisch erfolgen.
    Also immer sauber mitzählen - Hit - jetzt muß ein Release kommen oder es wird z.B. für eine Kombination noch ein zweiter Hit erwartet. Danach müssen dann eben zwei Release erfolgen (und in der richtigen Reihenfolge!).

  • Also ich lasse dann doch alles bei alten und frage die markierten Elemente in der While Schleife ab.
    Das geht mir dann doch ein wenig zu weit.

    Aber Danke BugFix, vielleicht kann ichs später mal gebrauchen 8o