Jump to content
Sign in to follow this  
Bilgus

Recieve KeyUp/KeyDn Events in a listview

Recommended Posts

Example of Subclassing listviews using setwindowSubclass in order to intercept WM_KEYUP events

Also pops context menu on  Shift + F10

#include <Misc.au3>
#include <ListViewConstants.au3>
#include <GUIConstants.au3>
#include <GuiMenu.au3>

#include <WinAPIShellEx.au3>

Global $g_hCB, $g_pCB, $g_ahProc[2][2] ;Stores the Data for subclassing listview
Global $g_LVKEYUP = 0xFE00, $g_LVKEYDN = 0xFD00 ;Our Own Custom messages (Key Up/Dn)
Global $g_iDummyData

Global $g_hGui = GUICreate("test")

Global $g_hList1 = GUICtrlCreateListView("#|x|y", 5, 24, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL)
GUICtrlCreateListViewItem("text", $g_hList1)
Global $g_hList1_LVN = GUICtrlCreateDummy() ;Recieves Messages from the callback

Global $g_hContext1 = GUICtrlCreateContextMenu($g_hList1)
GUICtrlCreateMenuItem("1", $g_hContext1)
GUICtrlCreateMenuItem("2", $g_hContext1)

Global $g_hList2 = GUICtrlCreateListView("#|x|y", 5, 100, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL)
GUICtrlCreateListViewItem("text", $g_hList2)
Global $g_hList2_LVN = GUICtrlCreateDummy() ;Recieves Messages from the callback

Global $g_hContext2 = GUICtrlCreateContextMenu($g_hList2)
GUICtrlCreateMenuItem("3", $g_hContext2)
GUICtrlCreateMenuItem("4", $g_hContext2)

GUISetState(@SW_SHOW)
SubClassListView() ;Creates our subclass

Func SubClassListView()
    OnAutoItExitRegister("Cleanup") ;to remove our subclass

    $g_hCB = DllCallbackRegister('_SubclassProc', 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
    $g_pCB = DllCallbackGetPtr($g_hCB)

    $g_ahProc[0][0] = $g_hList1 ;Add the Ids of the controls we'd like to subclass
    $g_ahProc[1][0] = $g_hList2

    ;Set up the subclass _WinAPI_SetWindowSubclass ( $hWnd, $pSubclassProc, $idSubClass [, $pData = 0] )
    $g_ahProc[0][1] = _WinAPI_SetWindowSubclass(GUICtrlGetHandle($g_ahProc[0][0]), $g_pCB, $g_ahProc[0][0], $g_hList1_LVN)
    $g_ahProc[1][1] = _WinAPI_SetWindowSubclass(GUICtrlGetHandle($g_ahProc[1][0]), $g_pCB, $g_ahProc[1][0], $g_hList2_LVN)
EndFunc   ;==>SubClassListView

Func _SubclassProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData)
    #forceref $iID

    Local $iRtnMsg = 0
    ;Events we'd like to intercept
    If $iMsg = $WM_KEYUP Or $iMsg = $WM_SYSKEYUP Then
        $iRtnMsg = $g_LVKEYUP
    ElseIf $iMsg = $WM_KEYDOWN Or $iMsg = $WM_SYSKEYDOWN Then
        $iRtnMsg = $g_LVKEYDN
    EndIf

    ;We Recieve the Id of the dummy through $pData and pass our RtnMsg to the dummy control
    If $iRtnMsg Then GUICtrlSendToDummy($pData, BitOR($iRtnMsg, $wParam))

    ;Pass messages on to the default handler
    Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_SubclassProc

Func Cleanup()
    For $i = 0 To UBound($g_ahProc) - 1 ;Remove Our Subclass' by setting it back to the original proc
        _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($g_ahProc[$i][0]), DllCallbackGetPtr($g_ahProc[$i][1]), $g_ahProc[$i][0])
    Next
    
    DllCallbackFree($g_hCB)
EndFunc   ;==>Cleanup

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit

        Case $g_hList1_LVN ;This is just a dummy it only recieves events
            ConsoleWrite("LV1 EVENT 0x" & Hex($g_iDummyData, 4) & @CRLF)
            $g_iDummyData = GUICtrlRead($g_hList1_LVN) ;Retrieve the code that was sent

            Switch BitAND($g_iDummyData, 0xFF00) ;Get the keyup/dn status
                Case $g_LVKEYDN
                    If BitAND($g_iDummyData, 0x00FF) = 0x79 And (_IsPressed("A0") Or _IsPressed("A1")) Then ;Right/ Left Shift & F10
                        ShowMenu($g_hGui, $g_hList1, $g_hContext1)
                    Else
                        ConsoleWrite("Lv1 KeyDn Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
                    EndIf

                Case $g_LVKEYUP
                    ConsoleWrite("Lv1 KeyUp Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode

            EndSwitch

        Case $g_hList2_LVN
            $g_iDummyData = GUICtrlRead($g_hList2_LVN) ;Retrieve the code that was sent
            ConsoleWrite("LV2 EVENT 0x" & Hex($g_iDummyData, 4) & @CRLF)

            Switch BitAND($g_iDummyData, 0xFF00) ;Get the keyup/dn status
                Case $g_LVKEYDN
                    ConsoleWrite("Lv2 KeyDn Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
                Case $g_LVKEYUP
                    ConsoleWrite("Lv2 KeyUp Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
            EndSwitch
    EndSwitch
WEnd

Func ShowMenu($hWnd, $idCtrl, $idContext)
    Local $aPos, $iX, $iY
    Local $hMenu = GUICtrlGetHandle($idContext)

    $aPos = ControlGetPos($hWnd, "", $idCtrl)

    $iX = $aPos[0]
    $iY = $aPos[1] + $aPos[3]

    ClientToScreen($hWnd, $iX, $iY)
    ; Show at the given coordinates (x, y) the popup menu (hMenu) which belongs to a given GUI window (hWnd)
    _GUICtrlMenu_TrackPopupMenu($hMenu, $hWnd, $iX, $iY)
EndFunc   ;==>ShowMenu

; Convert the client (GUI) coordinates to screen (desktop) coordinates
Func ClientToScreen($hWnd, ByRef $iX, ByRef $iY)
    Local $tPoint = DllStructCreate("int;int")

    DllStructSetData($tPoint, 1, $iX)
    DllStructSetData($tPoint, 2, $iY)

    DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "struct*", $tPoint)

    $iX = DllStructGetData($tPoint, 1)
    $iY = DllStructGetData($tPoint, 2)
    ; release Struct not really needed as it is a local
    $tPoint = 0
EndFunc   ;==>ClientToScreen

 

Old Code Using setWindowLong

Spoiler
#include <Misc.au3>
#include <ListViewConstants.au3>
#include <GUIConstants.au3>
#include <GuiMenu.au3>

#include <WinAPISys.au3>

Global $g_hCB, $g_pCB, $g_hProc[2][2] ;Stores the Data for subclassing listview
Global $g_LVKEYUP = 0xFE00, $g_LVKEYDN = 0xFD00 ;Our Own Custom Key Up/Dn messages
Global $g_iDummyData

Global $g_hGui = GUICreate("test")

Global $g_hList1 = GUICtrlCreateListView("#|x|y", 5, 24, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL)
GUICtrlCreateListViewItem("text", $g_hList1)
Global $g_hList1_LVN = GUICtrlCreateDummy() ;Recieves Messages from the callbacks

Global $g_hContext1 = GUICtrlCreateContextMenu($g_hList1)
GUICtrlCreateMenuItem("1", $g_hContext1)
GUICtrlCreateMenuItem("2", $g_hContext1)

Global $g_hList2 = GUICtrlCreateListView("#|x|y", 5, 100, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL)
GUICtrlCreateListViewItem("text", $g_hList2)
Global $g_hList2_LVN = GUICtrlCreateDummy() ;Recieves Messages from the callbacks

Global $g_hContext2 = GUICtrlCreateContextMenu($g_hList2)
GUICtrlCreateMenuItem("3", $g_hContext2)
GUICtrlCreateMenuItem("4", $g_hContext2)

GUISetState()
SubClassListView() ;Creates our subclass

Func SubClassListView()
    OnAutoItExitRegister("Cleanup") ;to remove our subclass
    Local $iPID
    $g_hCB = DllCallbackRegister('_WinProc', 'ptr', 'hwnd;uint;wparam;lparam')
    $g_pCB = DllCallbackGetPtr($g_hCB)
    $g_hProc[0][0] = GUICtrlGetHandle($g_hList1)
    $g_hProc[1][0] = GUICtrlGetHandle($g_hList2)
    $g_hProc[0][1] = _WinAPI_SetWindowLong($g_hProc[0][0], $GWL_WNDPROC, $g_pCB)
    $g_hProc[1][1] = _WinAPI_SetWindowLong($g_hProc[1][0], $GWL_WNDPROC, $g_pCB)
EndFunc   ;==>SubClassWndProc

Func _WinProc($hWnd, $iMsg, $wParam, $lParam)
    Local $iRtnMsg = 0
    If $iMsg = $WM_KEYUP Or $iMsg = $WM_SYSKEYUP Then
        $iRtnMsg = $g_LVKEYUP
    ElseIf $iMsg = $WM_KEYDOWN Or $iMsg = $WM_SYSKEYDOWN Then
        $iRtnMsg = $g_LVKEYDN
    EndIf

    Switch $hWnd
        Case $g_hProc[0][0]
            If $iRtnMsg Then GUICtrlSendToDummy($g_hList1_LVN, BitOR($iRtnMsg, $wParam))

            Return _WinAPI_CallWindowProc($g_hProc[0][1], $hWnd, $iMsg, $wParam, $lParam)

        Case $g_hProc[1][0]
            If $iRtnMsg Then GUICtrlSendToDummy($g_hList2_LVN, BitOR($iRtnMsg, $wParam))

            Return _WinAPI_CallWindowProc($g_hProc[1][1], $hWnd, $iMsg, $wParam, $lParam)
    EndSwitch

EndFunc   ;==>_WinProc

Func Cleanup()
    _WinAPI_SetWindowLong($g_hProc[0][0], $GWL_WNDPROC, $g_hProc[0][1]);Remove our subclass
    _WinAPI_SetWindowLong($g_hProc[1][0], $GWL_WNDPROC, $g_hProc[1][1]);Remove our subclass
    DllCallbackFree($g_hCB)
EndFunc   ;==>Cleanup

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit

        Case $g_hList1_LVN ;This is just a dummy it only recieves events
            ConsoleWrite("LV1 EVENT 0x" & Hex(BitAND($g_iDummyData, 0xFF00), 4) & @CRLF)
            $g_iDummyData = GUICtrlRead($g_hList1_LVN) ;Retrieve the code that was sent
            Switch BitAND($g_iDummyData, 0xFF00) ;Get the keyup/dn status
                Case $g_LVKEYDN
                    If BitAND($g_iDummyData, 0x00FF) = 0x79 And (_IsPressed("A0") Or _IsPressed("A1")) Then ;Right/ Left Shift & F10
                        ShowMenu($g_hGui, $g_hList1, $g_hContext1)
                    Else
                        ConsoleWrite("Lv1 KeyDN Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
                    EndIf
                Case $g_LVKEYUP
                    ConsoleWrite("Lv1 KeyUp Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
            EndSwitch

        Case $g_hList2_LVN
            $g_iDummyData = GUICtrlRead($g_hList2_LVN) ;Retrieve the code that was sent
            ConsoleWrite("LV2 EVENT 0x" & Hex(BitAND($g_iDummyData, 0xFF00), 4) & @CRLF)
            Switch BitAND($g_iDummyData, 0xFF00) ;Get the keyup/dn status
                Case $g_LVKEYDN
                    ConsoleWrite("Lv2 KeyDN Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
                Case $g_LVKEYUP
                    ConsoleWrite("Lv2 KeyUp Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
            EndSwitch
    EndSwitch
WEnd

Func ShowMenu($hWnd, $idCtrl, $idContext)
    Local $aPos, $iX, $iY
    Local $hMenu = GUICtrlGetHandle($idContext)

    $aPos = ControlGetPos($hWnd, "", $idCtrl)

    $iX = $aPos[0]
    $iY = $aPos[1] + $aPos[3]

    ClientToScreen($hWnd, $iX, $iY)
    ; Show at the given coordinates (x, y) the popup menu (hMenu) which belongs to a given GUI window (hWnd)
    _GUICtrlMenu_TrackPopupMenu($hMenu, $hWnd, $iX, $iY)
EndFunc   ;==>ShowMenu

; Convert the client (GUI) coordinates to screen (desktop) coordinates
Func ClientToScreen($hWnd, ByRef $iX, ByRef $iY)
    Local $tPoint = DllStructCreate("int;int")

    DllStructSetData($tPoint, 1, $iX)
    DllStructSetData($tPoint, 2, $iY)

    DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "struct*", $tPoint)

    $iX = DllStructGetData($tPoint, 1)
    $iY = DllStructGetData($tPoint, 2)
    ; release Struct not really needed as it is a local
    $tPoint = 0
EndFunc   ;==>ClientToScreen

 

 

Edited by Bilgus

Share this post


Link to post
Share on other sites
9 hours ago, Bilgus said:

Example of Subclassing listviews using setwindowlong in order to intercept WM_KEYUP events

Also pops context menu on  Shift + F10

#include <Misc.au3>
#include <ListViewConstants.au3>
#include <GUIConstants.au3>
#include <GuiMenu.au3>

#include <WinAPISys.au3>

Global $g_hCB, $g_pCB, $g_hProc[2][2] ;Stores the Data for subclassing listview
Global $g_LVKEYUP = 0xFE00, $g_LVKEYDN = 0xFD00 ;Our Own Custom Key Up/Dn messages
Global $g_iDummyData

Global $g_hGui = GUICreate("test")

Global $g_hList1 = GUICtrlCreateListView("#|x|y", 5, 24, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL)
GUICtrlCreateListViewItem("text", $g_hList1)
Global $g_hList1_LVN = GUICtrlCreateDummy() ;Recieves Messages from the callbacks

Global $g_hContext1 = GUICtrlCreateContextMenu($g_hList1)
GUICtrlCreateMenuItem("1", $g_hContext1)
GUICtrlCreateMenuItem("2", $g_hContext1)

Global $g_hList2 = GUICtrlCreateListView("#|x|y", 5, 100, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL)
GUICtrlCreateListViewItem("text", $g_hList2)
Global $g_hList2_LVN = GUICtrlCreateDummy() ;Recieves Messages from the callbacks

Global $g_hContext2 = GUICtrlCreateContextMenu($g_hList2)
GUICtrlCreateMenuItem("3", $g_hContext2)
GUICtrlCreateMenuItem("4", $g_hContext2)

GUISetState()
SubClassListView() ;Creates our subclass

Func SubClassListView()
    OnAutoItExitRegister("Cleanup") ;to remove our subclass
    Local $iPID
    $g_hCB = DllCallbackRegister('_WinProc', 'ptr', 'hwnd;uint;wparam;lparam')
    $g_pCB = DllCallbackGetPtr($g_hCB)
    $g_hProc[0][0] = GUICtrlGetHandle($g_hList1)
    $g_hProc[1][0] = GUICtrlGetHandle($g_hList2)
    $g_hProc[0][1] = _WinAPI_SetWindowLong($g_hProc[0][0], $GWL_WNDPROC, $g_pCB)
    $g_hProc[1][1] = _WinAPI_SetWindowLong($g_hProc[1][0], $GWL_WNDPROC, $g_pCB)
EndFunc   ;==>SubClassWndProc

Func _WinProc($hWnd, $iMsg, $wParam, $lParam)
    Local $iRtnMsg = 0
    If $iMsg = $WM_KEYUP Or $iMsg = $WM_SYSKEYUP Then
        $iRtnMsg = $g_LVKEYUP
    ElseIf $iMsg = $WM_KEYDOWN Or $iMsg = $WM_SYSKEYDOWN Then
        $iRtnMsg = $g_LVKEYDN
    EndIf

    Switch $hWnd
        Case $g_hProc[0][0]
            If $iRtnMsg Then GUICtrlSendToDummy($g_hList1_LVN, BitOR($iRtnMsg, $wParam))

            Return _WinAPI_CallWindowProc($g_hProc[0][1], $hWnd, $iMsg, $wParam, $lParam)

        Case $g_hProc[1][0]
            If $iRtnMsg Then GUICtrlSendToDummy($g_hList2_LVN, BitOR($iRtnMsg, $wParam))

            Return _WinAPI_CallWindowProc($g_hProc[1][1], $hWnd, $iMsg, $wParam, $lParam)
    EndSwitch

EndFunc   ;==>_WinProc

Func Cleanup()
    _WinAPI_SetWindowLong($g_hProc[0][0], $GWL_WNDPROC, $g_hProc[0][1]);Remove our subclass
    _WinAPI_SetWindowLong($g_hProc[1][0], $GWL_WNDPROC, $g_hProc[1][1]);Remove our subclass
    DllCallbackFree($g_hCB)
EndFunc   ;==>Cleanup

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit

        Case $g_hList1_LVN ;This is just a dummy it only recieves events
            ConsoleWrite("LV1 EVENT 0x" & Hex(BitAND($g_iDummyData, 0xFF00), 4) & @CRLF)
            $g_iDummyData = GUICtrlRead($g_hList1_LVN) ;Retrieve the code that was sent
            Switch BitAND($g_iDummyData, 0xFF00) ;Get the keyup/dn status
                Case $g_LVKEYDN
                    If BitAND($g_iDummyData, 0x00FF) = 0x79 And (_IsPressed("A0") Or _IsPressed("A1")) Then ;Right/ Left Shift & F10
                        ShowMenu($g_hGui, $g_hList1, $g_hContext1)
                    Else
                        ConsoleWrite("Lv1 KeyDN Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
                    EndIf
                Case $g_LVKEYUP
                    ConsoleWrite("Lv1 KeyUp Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
            EndSwitch

        Case $g_hList2_LVN
            $g_iDummyData = GUICtrlRead($g_hList2_LVN) ;Retrieve the code that was sent
            ConsoleWrite("LV2 EVENT 0x" & Hex(BitAND($g_iDummyData, 0xFF00), 4) & @CRLF)
            Switch BitAND($g_iDummyData, 0xFF00) ;Get the keyup/dn status
                Case $g_LVKEYDN
                    ConsoleWrite("Lv2 KeyDN Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
                Case $g_LVKEYUP
                    ConsoleWrite("Lv2 KeyUp Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode
            EndSwitch
    EndSwitch
WEnd

Func ShowMenu($hWnd, $idCtrl, $idContext)
    Local $aPos, $iX, $iY
    Local $hMenu = GUICtrlGetHandle($idContext)

    $aPos = ControlGetPos($hWnd, "", $idCtrl)

    $iX = $aPos[0]
    $iY = $aPos[1] + $aPos[3]

    ClientToScreen($hWnd, $iX, $iY)
    ; Show at the given coordinates (x, y) the popup menu (hMenu) which belongs to a given GUI window (hWnd)
    _GUICtrlMenu_TrackPopupMenu($hMenu, $hWnd, $iX, $iY)
EndFunc   ;==>ShowMenu

; Convert the client (GUI) coordinates to screen (desktop) coordinates
Func ClientToScreen($hWnd, ByRef $iX, ByRef $iY)
    Local $tPoint = DllStructCreate("int;int")

    DllStructSetData($tPoint, 1, $iX)
    DllStructSetData($tPoint, 2, $iY)

    DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "struct*", $tPoint)

    $iX = DllStructGetData($tPoint, 1)
    $iY = DllStructGetData($tPoint, 2)
    ; release Struct not really needed as it is a local
    $tPoint = 0
EndFunc   ;==>ClientToScreen

 

This is very cool code !!Help me a lot
I need some time to study
Thank you again

Share this post


Link to post
Share on other sites

Updated Code to using SetWindowSubclass() instead of setwindowlong

This allows us to pass the ID of the dummy control through the pData Variable which cleans up the subclass procedure a bit

 

Share this post


Link to post
Share on other sites

Neat approach.  I was looking for a way to implement looking for the $WM_CONTEXTMENU notification instead of listening specifically for the Right-Click or Shift+F10 inputs.  That way they (along with the application/menu key) would work without special checks.  My quick implementation was producing two menu pop-ups though and I'm not sure why.


Share this post


Link to post
Share on other sites

@spudw2k If you are just wanting some control over the context menu this example is probably a bit much

since its meant to get KeyUp events before the listview has a chance to eat the message

Instead THIS might be a bit  better

#include <Misc.au3>
#include <ListViewConstants.au3>
#include <GUIConstants.au3>
#include <GuiMenu.au3>

Global $GUI = GUICreate("test")
Global $g_iTemp
Global $g_hList1 = GUICtrlCreateListView("#|x|y", 5, 24, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL)
GUICtrlCreateListViewItem("text", $g_hList1)
Global $g_hList1_LVN = GUICtrlCreateDummy()

Global $context = GUICtrlCreateContextMenu($g_hList1_LVN);Just Associating with dummy so we can have multiple menu
GUICtrlCreateMenuItem("1", $context)
GUICtrlCreateMenuItem("2", $context)

Global $contextH = GUICtrlCreateContextMenu($g_hList1);Only for header since we intercept rightclick on items
GUICtrlCreateMenuItem("1Header", $contextH)
GUICtrlCreateMenuItem("2Header", $contextH)

Global $g_hList2 = GUICtrlCreateListView("#|x|y", 5, 100, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL)
GUICtrlCreateListViewItem("text", $g_hList2)
Global $g_hList2_LVN = GUICtrlCreateDummy()

Global $context2 = GUICtrlCreateContextMenu($g_hList2_LVN) ;Just Associating with dummy so we can have multiple menus
GUICtrlCreateMenuItem("3", $context2)
GUICtrlCreateMenuItem("4", $context2)

Global $context2H = GUICtrlCreateContextMenu($g_hList2)
;Nothing Here

GUISetState()
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
While 1
    Switch GUIGetMsg()
        Case $gui_event_close
            Exit
        Case $g_hList1_LVN ;This is just a dummy it only recieves events
            ConsoleWrite("LV1 EVENT" & @CRLF)
            $g_iTemp = GUICtrlRead($g_hList1_LVN) ;Retrieve the code that WM_NOTIFY SENT
            If $g_iTemp = $LVN_KEYDOWN Then
                If _IsPressed("79") And (_IsPressed("A0") Or _IsPressed("A1")) Then ;Right/ Left Shift & F10
                    ShowMenu($GUI, $g_hList1, $context)
                Else
                    ConsoleWrite("Some Other Keys" & @CRLF)
                EndIf
            ElseIf $g_iTemp = $NM_RCLICK Then
                ShowMenu($GUI, $g_hList1, $context)
            Else
                ConsoleWrite("Some Other Event Lv1" & @CRLF)
            EndIf

        Case $g_hList2_LVN
            ConsoleWrite("LV2 EVENT" & @CRLF)
            $g_iTemp = GUICtrlRead($g_hList2_LVN)
            If $g_iTemp = $LVN_KEYDOWN Then
                If _IsPressed("79") And (_IsPressed("A0") Or _IsPressed("A1")) Then ;Right/ Left Shift & F10
                    ShowMenu($GUI, $g_hList2, $context2)
                EndIf
            ElseIf $g_iTemp = $NM_RCLICK Then
                ShowMenu($GUI, $g_hList2, $context2)
            Else
                ConsoleWrite("Some Other Event Lv2" & @CRLF)
            EndIf
    EndSwitch
WEnd

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Local $tNMHDR, $iCode ;
    Switch $wParam
        Case $g_hList1
            $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
            $iCode = DllStructGetData($tNMHDR, "Code")
            Switch $iCode
                Case $LVN_KEYDOWN, $NM_CLICK
                    GUICtrlSendToDummy($g_hList1_LVN, $iCode) ;send the code back to be processed by the dummy
                Case $NM_RCLICK
                    GUICtrlSendToDummy($g_hList1_LVN, $iCode)
                    Return 1 ;Don't pass message onto default handler
            EndSwitch

        Case $g_hList2
            $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
            $iCode = DllStructGetData($tNMHDR, "Code")
            Switch $iCode
                Case $LVN_KEYDOWN, $NM_CLICK
                    GUICtrlSendToDummy($g_hList2_LVN, $iCode)
                Case $NM_RCLICK
                    GUICtrlSendToDummy($g_hList2_LVN, $iCode)
                    Return 1 ;Don't pass message onto default handler
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func ShowMenu($hWnd, $idCtrl, $idContext)
    ConsoleWrite("POPUP MENU")
    Local $aPos, $x, $y
    Local $hMenu = GUICtrlGetHandle($idContext)

    $aPos = ControlGetPos($hWnd, "", $idCtrl)

    $x = $aPos[0]
    $y = $aPos[1] + $aPos[3]

    ClientToScreen($hWnd, $x, $y)
    TrackPopupMenu($hWnd, $hMenu, $x, $y)
EndFunc   ;==>ShowMenu

; Convert the client (GUI) coordinates to screen (desktop) coordinates
Func ClientToScreen($hWnd, ByRef $x, ByRef $y)
    Local $tPoint = DllStructCreate("int;int")

    DllStructSetData($tPoint, 1, $x)
    DllStructSetData($tPoint, 2, $y)

    DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "struct*", $tPoint)

    $x = DllStructGetData($tPoint, 1)
    $y = DllStructGetData($tPoint, 2)
    ; release Struct not really needed as it is a local
    $tPoint = 0
EndFunc   ;==>ClientToScreen

; Show at the given coordinates (x, y) the popup menu (hMenu) which belongs to a given GUI window (hWnd)
Func TrackPopupMenu($hWnd, $hMenu, $x, $y)
    _GUICtrlMenu_TrackPopupMenu($hMenu, $hWnd, $x, $y)
EndFunc   ;==>TrackPopupMenu

Edit I tried with WM_ContextMenu and while it does recieve Shift+F10 it lags behind on notifications and isn't able to be blocked either so I'd say thats probably the reason for the behavior you saw.. My guess is that the listview implements its own context popup

Spoiler
#include <Misc.au3>
#include <ListViewConstants.au3>
#include <GUIConstants.au3>
#include <GuiMenu.au3>


Global $GUI = GUICreate("test")

Global $g_IdList1 = GUICtrlCreateListView("#|x|y", 5, 24, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL)
Global $g_hList1 = GUICtrlGetHandle ($g_IdList1)
GUICtrlCreateListViewItem("text", $g_IdList1)


Global $context = GUICtrlCreateContextMenu($g_IdList1)
GUICtrlCreateMenuItem("1", $context)
GUICtrlCreateMenuItem("2", $context)


Global $g_IdList2 = GUICtrlCreateListView("#|x|y", 5, 100, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL)
Global $g_hList2 = GUICtrlGetHandle ($g_IdList2)
GUICtrlCreateListViewItem("text", $g_IdList2)

Global $context2 = GUICtrlCreateContextMenu($g_IdList2)
GUICtrlCreateMenuItem("3", $context2)
GUICtrlCreateMenuItem("4", $context2)


GUISetState(@SW_SHOW)

GUIRegisterMsg($WM_CONTEXTMENU, WM_CONTEXTMENU)
GUIRegisterMsg($WM_ENTERMENULOOP, WM_CONTEXTMENU)

While 1
    Switch GUIGetMsg()
        Case $gui_event_close
            Exit

    EndSwitch
WEnd

Func WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam)
    Switch $wParam
        Case $g_hList1
            ConsoleWrite("LV1 " & Hex($hWnd) & @CRLF)
        Case $g_hList2
            ConsoleWrite("LV2 " & Hex($hWnd) & @CRLF)
        Case Else
            If $iMsg = $WM_ENTERMENULOOP Then
                ConsoleWrite("ENTERMENULOOP: " & Hex($hWnd) & " TrackPopup: " & ($wParam ? "True":"False") & @CRLF)
            EndIf
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc

Func ShowMenu($hWnd, $idCtrl, $idContext)
    ConsoleWrite("POPUP MENU")
    Local $aPos, $x, $y
    Local $hMenu = GUICtrlGetHandle($idContext)

    $aPos = ControlGetPos($hWnd, "", $idCtrl)

    $x = $aPos[0]
    $y = $aPos[1] + $aPos[3]

    ClientToScreen($hWnd, $x, $y)
    TrackPopupMenu($hWnd, $hMenu, $x, $y)
EndFunc   ;==>ShowMenu

; Convert the client (GUI) coordinates to screen (desktop) coordinates
Func ClientToScreen($hWnd, ByRef $x, ByRef $y)
    Local $tPoint = DllStructCreate("int;int")

    DllStructSetData($tPoint, 1, $x)
    DllStructSetData($tPoint, 2, $y)

    DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "struct*", $tPoint)

    $x = DllStructGetData($tPoint, 1)
    $y = DllStructGetData($tPoint, 2)
    ; release Struct not really needed as it is a local
    $tPoint = 0
EndFunc   ;==>ClientToScreen

; Show at the given coordinates (x, y) the popup menu (hMenu) which belongs to a given GUI window (hWnd)
Func TrackPopupMenu($hWnd, $hMenu, $x, $y)
    _GUICtrlMenu_TrackPopupMenu($hMenu, $hWnd, $x, $y)
EndFunc   ;==>TrackPopupMenu

 

 

Edited by Bilgus

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By UEZ
      This project has been discontinued!
       
      Here a small tool I wrote to update my Sysinternal tools collection without the need to download always the whole package or visiting the site to check for updates. I know that there are several tools available (also some tools written in AutoIt) but here another one for the collection. It was good exercise for me to code it.
       
       
        
       
       
      Some files from the live web site cannot be downloaded although they are visible!
       
      Here the download link of the source code only: AutoIt Sysinternal Tools Synchronizer v0.99.6 build 2020-09-23 beta.7z  (1557 downloads previously)
      -=> Requires AutoIt version 3.3.13.20 or higher / tested on Win8.1 real machine and some VMs: Win7 / Vista / Win10
       
      Compiled exe only: @MediaFire
       
      Just select the Sysinternal Tools folder or create one and press the synchronize button to download the selected items. Click on AutoIt label (near to left upper corner) to open menu.
       
      Special thanks to LarsJ, Melba23 and mesale0077 for their help. 
       
      I've still some ideas to implement which are more gimmick related, so it is not finished yet...
      If you want to add your language please check out #Region Language. Thanks. 
       
      Please report any bug or if you have any suggestions.
       
      The language of the tool tip from each of the executable in the left list view were automatically created using Google translator and weren't checked for correctness.
       
      Br,
      UEZ
    • By Cengokill
      Hi everyone,
      I have created a ListView that is in a tab, and I want to display an image in that tab, with the ListView on top.
      However, the image still appears on top of my ListView.
      If I remove the tabs everything works. 
      I looked at the autoit documentation and the <GuiListView.au3> documentation , I can't figure out how to display a background image, and put on top a ListView, inside a tab. 😥
      Here is the code:
      Opt("GUIOnEventMode", 1) $Form1 = GUICreate($Titre, 700, 627, $Form1Width, $Form1Height); main window $tabulation = GUICtrlCreateTab(148,0,700,580); creating tabs $tab1=GUICtrlCreateTabItem("Tab 1"); first tab GUICtrlSetState(-1, $GUI_SHOW); this tab is selected by default $Pic1 = GUICtrlCreatePic("image.jpg", 0, 30, 700, 627) GUICtrlSetState(-1, $GUI_DISABLE). $idListview = GUICtrlCreateListView("list 1|list 2|list 3", 200, 50, 390, 200) GUISetState(@SW_SHOW) While 1     Sleep(100) WEnd Thank you in advance.

    • By DrJohn
      Hello all.  It's me again.
      I've got a ListView with an associated ImageList to display icons.  What I seem to be hung up on is how to keep the ImageList updated to match the ListView as the latter changes.  I thought it was the case that the indices of the items in the ListView and those in the ImageList just needed to match.  So, for example, if I:
      Delete an item from the ListView [_GUICtrlListView_DeleteItem()], and also delete the image at the matching index in the ImageList [_GUIImageList_Remove()]. Then add a new item to the end of the ListView [_GUICtrlListView_AddItem()], and correspondingly add an image at the end of the ImageList [_GUIImageList_AddIcon()] Shouldn't everything stay in sync?
      Here's the code I thought would work:
      #include <GUIConstantsEx.au3> #include <GuiListView.au3> #include <FontConstants.au3> #include <WindowsConstants.au3> #include <GuiImageList.au3> Test() func Test() $gui = GUICreate("Test", 400, 300) ; Create ListView $lv = _GUICtrlListView_Create($gui, "", 10, 10, 380, 240, $LVS_DEFAULT) _GUICtrlListView_AddColumn($lv, "Col1", 50) _GUICtrlListView_AddColumn($lv, "Col2", 50) for $i = 0 to 2 $s = StringFormat("%d,1", $i+1) _GUICtrlListView_AddItem($lv, $s, $i) $s = StringFormat("%d,2", $i+1) _GUICtrlListView_AddSubItem($lv, $i, $s, 1) next ; Add ImageList $img_list = _GUIImageList_Create(16, 16, 5, 3) for $i = 0 to 2 $ico = StringFormat("%d.ico", $i+1) _GUIImageList_AddIcon($img_list, $ico) next _GUICtrlListView_SetImageList($lv, $img_list, 1) ; $btn = GUICtrlCreateButton("Test", 10, 260, 60, 30) GUISetState(@SW_SHOW) HotKeySet("^q", Quit) ; Loop until the user exits. while True switch GUIGetMsg() case $GUI_EVENT_CLOSE Exit case $btn ; Remove 2nd list item and image _GUICtrlListView_DeleteItem($lv, 1) _GUIImageList_Remove($img_list, 1) ; Add new item to end of ListView $idx = _GUICtrlListView_AddItem($lv, "foo") _GUICtrlListView_AddSubItem($lv, $idx, "bar", 1) ; Add new image to end of ImageList _GUIImageList_AddIcon($img_list, "5.ico") endswitch wend GUIDelete() endfunc func Quit() Exit endfunc What seems to happen is that when the new item is added to the ListView, its icon is 1.ico (the first item in the ImageList), rather than 5.ico (the newly added item that should be at the end of the ImageList).
      Or do I need to re-create the whole ImageList any time the ListView changes?
      A zip file is attached that contains the script and also the .ico files, for easier testing.
      Thanks!
      /John
      test.zip
    • By Colduction
      Hi AutoIt Programmers!, I just looking for a way to change entered keys in English to Russian keys and reverse, i must clear for you to understand. For example:
       
      I write keys on keyboard and i forgot to change input language and then the result will be: Dkflbvbh (Thing we write in fact) ====> Владимир (Thing we want)
       
      And reverse: Владимир  ====> Dkflbvbh

      Is there any solution without writing constant for each words? for example dlls or WinAPIs.
    • By Dan_555
      Hi.
      I'm using the FreeCommander XE file manager here, and i'v written a script, which will create an empty, new file, after choosing an extension out from the Listbox.
       
      The listview code  is not mine, iv found the scripts somewhere on this forum. I have no credits in it, because it was intended to be only for my personal use.
      But now, i have a lot of free time, so i remembered that i haven't posted anything on this forum, yet, so here is my first script:
      It should be compiled with the Autoit v3.3.14.3 .
      The compiled exe needs a folder passed as a parameter, so that it know where to create the new file.
      A Listbox is opened, with a selection of available extensions.
      After selecting and doubleclicking (or using the ok button), the script creates a filename (if specified in the config file) with increased numbers (up to 9999).
      If the filename exist, the counter is checking the next number, until the maximum is reached.
      This script uses an ini file for configuration, called "NewFile.ini" which should be in the same folder, as the compiled exe.
      NewFile.au3
      #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <GuiListView.au3> #include <String.au3> #include <WinAPIFiles.au3> #include <Array.au3> #include <EditConstants.au3> #include <GuiEdit.au3> #include <ScrollBarsConstants.au3> Global $test[0][2], $hFile, $cmd = "", $cmdtmp, $tmptxt, $tmpinidir, $filesetting, $MouseX, $MouseY, $UseMouseX, $UseMouseY, $Edit1 Global $aArray[1] = [] $cmdtmp = StringReplace($cmdlineraw, Chr(34), "") If StringLen($cmdtmp) = 2 Then     If StringRight($cmdtmp, 1) = ":" Then         $cmd = $cmdtmp & "\"     EndIf Else     If StringRight($cmdtmp, 1) <> "\" Or StringRight($cmdtmp, 1) <> "/" Then         $cmd = $cmdtmp & "\"     EndIf EndIf If Not FileExists($cmd) Then                    ;Check if the folder exists, display an error message if not !     DisplayReadMe(1)     Exit EndIf If StringLen(@ScriptDir) > 3 And StringRight(@ScriptDir, 1) <> "\" Then     $tmpinidir = @ScriptDir & "\" Else     $tmpinidir = @ScriptDir EndIf Local Const $sFilePath = $tmpinidir & "NewFile.ini" $filesetting = IniRead($sFilePath, "setting", "filename", "MyNewFile") $filesetting = StringReplace($filesetting, ">", " ") ;msgbox (0,"",$filesetting)  ;Debugging If FileExists($sFilePath) Then     $aArray = IniReadSectionNames($sFilePath) ; Read the INI section names. This will return a 1 dimensional array. EndIf $UseMouseX = IniRead($sFilePath, "setting", "UseMouseX", "1") $UseMouseY = IniRead($sFilePath, "setting", "UseMouseY", "0") ; Check if an error occurred. If Not @error Then     ; Enumerate through the array displaying the section names.     Local $count = 0     If FileExists($sFilePath) Then         For $i = 1 To $aArray[0]             $tmp1 = IniRead($sFilePath, $aArray[$i], "1", "none")             If $tmp1 <> "none" And StringLeft($tmp1, 1) = "." Then            ;Extension need to have a dot, or it will be ignored !                 $tmptxt = $tmptxt & $tmp1 & "|" & $aArray[$i] & @CRLF                 $count = $count + 1                                            ;Count how many extensions are added !             EndIf         Next     EndIf     If $count = 0 Then $tmptxt = ".au3|AutoIt 3" & @CRLF & ".txt|Text File" & @CRLF     ;MsgBox($MB_SYSTEMMODAL,"",$tmptxt)     _ArrayAdd($test, $tmptxt, 0, "|", @CRLF) Else                                                            ;Reading the ini failed, create a default array for the extensions     $tmptxt = ".au3|AutoIt 3" & @CRLF & ".txt|Text" & @CRLF     _ArrayAdd($test, $tmptxt, 0, "|", @CRLF) EndIf ;Local $test[5][2] = [['.au3', 'AutoIt'], ['.ahk', 'Auto Hotkey'], ['.txt', 'text'], ['.sdlbas', 'Sdl Basic'], ['.html', 'Webpage']] If $UseMouseX = 1 Then     $MouseX = MouseGetPos(0) Else     $MouseX = -1 EndIf If $UseMouseY = 1 Then     $MouseY = MouseGetPos(1) Else     $MouseY = -1 EndIf $Form1 = GUICreate("Create New File", 210, 247, $MouseX, $MouseY, $WS_CAPTION, $WS_EX_TOOLWINDOW) $List = GUICtrlCreateListView("", 5, 5, 200, 200) _GUICtrlListView_InsertColumn($List, 0, "Extension", 65) _GUICtrlListView_InsertColumn($List, 1, "Description", 115) _GUICtrlListView_AddArray($List, $test) GUICtrlCreateLabel("Example:" & $filesetting & "0000.ext", 5, 205) $Button1 = GUICtrlCreateButton("Ok", 16, 224, 45, 22) $Button3 = GUICtrlCreateButton("ReadMe", 80, 224, 55, 22) $Button2 = GUICtrlCreateButton("Cancel", 150, 224, 45, 22) $cDummy = GUICtrlCreateDummy() GUISetState(@SW_SHOW) GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") While 1     $nMsg = GUIGetMsg()     Switch $nMsg         Case $GUI_EVENT_CLOSE, $Button2             Exit         Case $Button3             DisplayReadMe(0)         Case $Button1, $cDummy             Local $tmptxt = StringSplit(_GUICtrlListView_GetItemTextString($List), "|")[1]             If StringLen($tmptxt) > 0 Then                 Local $fnr = 0, $tmpfile = ""                 While $fnr < 10000                     $tmpfile = $cmd & $filesetting & _StringRepeat("0", 4 - StringLen($fnr)) & $fnr & $tmptxt                     ;MsgBox(0,"",$tmpfile) ; for debugging                     If Not (FileExists($tmpfile)) Then                         $hFile = _WinAPI_CreateFile($tmpfile, 0)                         _WinAPI_CloseHandle($hFile)                         Exit                     EndIf                     $fnr = $fnr + 1                 WEnd             EndIf     EndSwitch WEnd ;================================================================================ Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)     Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView     $hWndListView = $List     If Not IsHWnd($List) Then $hWndListView = GUICtrlGetHandle($List)     $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)     $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))     $iCode = DllStructGetData($tNMHDR, "Code")     Switch $hWndFrom         Case $hWndListView             Switch $iCode                 Case $NM_DBLCLK                     ; Fire the dummy if the ListView is double clicked                     GUICtrlSendToDummy($cDummy)             EndSwitch     EndSwitch     Return $GUI_RUNDEFMSG EndFunc   ;==>WM_NOTIFY Func DisplayReadMe($err)     Local $Form1 = GUICreate("Read Me", 550, 400, 10, 10, BitOR($WS_CAPTION, $WS_THICKFRAME ,$WS_MAXIMIZEBOX))     $Edit1 = GUICtrlCreateEdit("", 0, 0, 549, 399)     GUICtrlSetData(-1, "")     GUISetState(@SW_SHOW)     If $err=1 then         local $txttmp01="Error: Path does not exist"         local $txttmp02="Commandline call was: "         AddText ($txttmp01)         Addtext ($txttmp02 & $cmd & @CRLF & @CRLF)     EndIf     AddText("Instructions:" & @CRLF)     AddText("Displays a selection of available extensions and then creates a new file at the Path's location." & @CRLF & @CRLF & "Usage: NewFile Path")     AddText("Example: NewFile c:\myfolder\" & @CRLF)     AddText("Result: A file with a name 'MyFile0000.ext' will be created at the Path's location.")     AddText("If the filename exists, the number counter will increase, until it finds a free number, up to 9999." & @CRLF)     AddText("Uses a configuration file in the .exe folder named NewFile.ini !" & @CRLF)     AddText("Example of a config file:" & @CRLF)     AddText("[setting]" & @CRLF & "filename=MyFile>")     AddText("UseMouseX=0                ;0 or 1 - position the dialog at the mouse x coordinate - usefull for multi monitor settings !")     AddText("UseMouseY=0                ;0 or 1 - Set this and UseMouseX to spawn the dialog at the mouse coordinates !" & @CRLF)     AddText(";Use > in filename as a space char ! (only needed if you want the space char at the beginning or at the end : in between filename and the number)" & @CRLF)     AddText(";Format for this ini file is:" & @CRLF & ";Name              e.g [Auto It]")     AddText(";extension       e.g 1=.au3" & @CRLF & "; p.s. only 1 extension per section ! the number must be 1" & @CRLF)     AddText("[AutoIt3]" & @CRLF & "1=.au3" & @CRLF & @CRLF & "[Text]" & @CRLF & "1=.txt")     _GUICtrlEdit_SetSel($Edit1, 0, 0)     _GUICtrlEdit_Scroll($Edit1, $SB_SCROLLCARET)     If $err=1 Then         _GUICtrlEdit_SetSel($Edit1, 0, StringLen($txttmp01 & $txttmp02 & $cmd)+5)     EndIf     While 1         $nMsg = GUIGetMsg()         Switch $nMsg             Case $GUI_EVENT_CLOSE                 GUIDelete($Form1)                 ExitLoop         EndSwitch     WEnd EndFunc   ;==>DisplayReadMe Func AddText($edittxt)     _GUICtrlEdit_AppendText($Edit1, $edittxt & @CRLF) EndFunc   ;==>AddText  
       NewFile.ini
      [setting] filename=MyNewFile_ UseMouseX=0                ;0 or 1 - position the dialog at the mouse x coordinate - usefull for multi monitor settings ! UseMouseY=0                ;0 or 1 - Set this and UseMouseX to spawn the dialog at the mouse coordinates ! ;Use > in filename as a space char ! (only needed if you want the space char at the beginning or at the end : in between filename and the number) ;Format for this ini file is: ;Name              e.g [Auto It] ;extension       e.g 1=.au3 ; p.s. only 1 extension per section ! the number must be 1 [AutoIt3] 1=.au3 [Auto Hotkey] 1=.ahk [Text] 1=.txt [Sdl Basic] 1=.sdlbas [Webpage] 1=.html [Basic] 1=.bas [Pascal] 1=.pas [Rich Text (RTF)] 1=.rtf [Word Document] 1=.doc [Hex File] 1=.hex
×
×
  • Create New...