doudou Posted March 19, 2010 Share Posted March 19, 2010 (edited) For a while I've been struggling with this problem: when user double clicks an item in a ListView or presses enter key while one is selected, I wanted a certain action to be performed. The normal way to accomplish this would be to respond to LVN_ITEMACTIVATE notification message, sad thing - AutoIt would never send this (or WM_KEYDOWN, WM_KEYUP for that matter) when enter is pressed. An extensive research in these forums and on the Net brought up different proposals how to solve it, ranging from complete meshugge (polling for keys globally) to quite unsatisfactory (catching enter in a window proc), so - after some message spying and process debugging - I forged the following solution. Briefly the core of my method is to subclass the ListView (the mentioned proposals came so far too) and to respond to WM_GETDLGCODE message with DLGC_WANTALLKEYS in the window procedure whereafter the rest is a piece of cake: just define WM_NOTIFY callback and handle LVN_ITEMACTIVATE. Here is the functional example (with some convenience functions for subclassing): expandcollapse popup#include <Constants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPI.au3> #include <GUIListView.au3> Global Const $DLGC_WANTALLKEYS = 0x0004 Global $frmMain = GUICreate("LVN_ITEMACTIVATE", 531, 396, -1, -1, BitOR($WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_CAPTION,$WS_POPUP,$WS_POPUPWINDOW,$WS_GROUP,$WS_VISIBLE,$WS_BORDER,$WS_CLIPSIBLINGS), BitOR($WS_EX_ACCEPTFILES,$WS_EX_WINDOWEDGE)) Global $lvwTest = GUICtrlCreateListView("Items", 1, 1, 529, 394, BitOR($LVS_REPORT,$LVS_SINGLESEL,$LVS_SHOWSELALWAYS,$WS_TABSTOP,$WS_VISIBLE,$WS_CHILD,$WS_CLIPSIBLINGS), BitOR($WS_EX_CLIENTEDGE,$LVS_EX_FULLROWSELECT,$LVS_EX_FLATSB,$LVS_EX_INFOTIP)) For $i = 0 To 9 GUICtrlCreateListViewItem("Item " & $i, $lvwTest) Next Main() Func Main() _GUICtrl_Subclass("lvwTest") GUIRegisterMsg($WM_NOTIFY, "On_WM_NOTIFY") While CheckGUIMsg() ; WEnd _GUICtrl_Unsubclass("lvwTest") EndFunc Func CheckGUIMsg() Local $msg = GUIGetMsg() Select Case $msg = $GUI_EVENT_CLOSE Return False EndSelect Return True EndFunc Func On_WM_NOTIFY($hWnd, $msg, $wParam, $lParam) Local $nmhdr = DllStructCreate($tagNMHDR, $lParam) Local $hWndFrom = HWnd(DllStructGetData($nmhdr, "hWndFrom")) Local $iCode = DllStructGetData($nmhdr, "Code") If _GUICtrl_GetHandle($lvwTest) = $hWndFrom Then Local $i = -1 Switch $iCode Case $LVN_ITEMACTIVATE Local $nmia = DllStructCreate($tagNMITEMACTIVATE, $lParam) $i = DllStructGetData($nmia, "Index") EndSwitch If -1 <> $i Then MsgBox(0, "LVN_ITEMACTIVATE", "Item " & $i) EndIf Return $GUI_RUNDEFMSG EndFunc Func lvwTest_WindowProc($hWnd, $uMsg, $wParam, $lParam) If $WM_GETDLGCODE = $uMsg Then Return $DLGC_WANTALLKEYS EndIf Return _GUICtrl_SubclassedProc("lvwTest", $hWnd, $uMsg, $wParam, $lParam) EndFunc Func _GUICtrl_Subclass($controlName) Local $hlvw = _GUICtrl_GetHandle(Eval($controlName)) If $hlvw Then Local $hProc = DllCallbackRegister($controlName & "_WindowProc", "int", "hwnd;uint;wparam;lparam") If $hProc Then Assign($controlName & "_hProc", $hProc, 2) Assign($controlName & "_hProcOld", _WinAPI_SetWindowLong($hlvw, $GWL_WNDPROC, DllCallbackGetPtr($hProc)), 2) EndIf EndIf EndFunc Func _GUICtrl_Unsubclass($controlName) Local $hProc = Eval($controlName & "_hProc") If $hProc Then _WinAPI_SetWindowLong(_GUICtrl_GetHandle(Eval($controlName)), $GWL_WNDPROC, Eval($controlName & "_hProcOld")) DllCallbackFree($hProc) Assign($controlName & "_hProc", 0) Assign($controlName & "_hProcOld", 0) EndIf EndFunc Func _GUICtrl_SubclassedProc($controlName, $hWnd, $uMsg, $wParam, $lParam) Local $hProc = Eval($controlName & "_hProcOld") If $hProc Then Return _WinAPI_CallWindowProc($hProc, $hWnd, $uMsg, $wParam, $lParam) Return 0 EndFunc Func _GUICtrl_GetHandle($control) If IsHWnd($control) Then Return $control Return GUICtrlGetHandle($control) EndFunc Hopefully this will help somebody else save some time and nerves. Edited March 25, 2010 by doudou UDFS & Apps: Spoiler DDEML.au3 - DDE Client + ServerLocalization.au3 - localize your scriptsTLI.au3 - type information on COM objects (TLBINF emulation)TLBAutoEnum.au3 - auto-import of COM constants (enums)AU3Automation - export AU3 scripts via COM interfacesTypeLibInspector - OleView was yesterday Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ Link to comment Share on other sites More sharing options...
BrettF Posted March 19, 2010 Share Posted March 19, 2010 Very nice! Vist my blog!UDFs: Opens The Default Mail Client | _LoginBox | Convert Reg to AU3 | BASS.au3 (BASS.dll) (Includes various BASS Libraries) | MultiLang.au3 (Multi-Language GUIs!)Example Scripts: Computer Info Telnet Server | "Secure" HTTP Server (Based on Manadar's Server)Software: AAMP- Advanced AutoIt Media Player | WorldCam | AYTU - Youtube Uploader Tutorials: Learning to Script with AutoIt V3Projects (Hardware + AutoIt): ArduinoUseful Links: AutoIt 1-2-3 | The AutoIt Downloads Section: | SciTE4AutoIt3 Full Version! Link to comment Share on other sites More sharing options...
doudou Posted March 21, 2010 Author Share Posted March 21, 2010 Very nice!Thx for the complement. I deserve that! UDFS & Apps: Spoiler DDEML.au3 - DDE Client + ServerLocalization.au3 - localize your scriptsTLI.au3 - type information on COM objects (TLBINF emulation)TLBAutoEnum.au3 - auto-import of COM constants (enums)AU3Automation - export AU3 scripts via COM interfacesTypeLibInspector - OleView was yesterday Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ Link to comment Share on other sites More sharing options...
gaucho14 Posted March 22, 2010 Share Posted March 22, 2010 very cool! thanks you for all your contributes. Link to comment Share on other sites More sharing options...
dmob Posted March 22, 2010 Share Posted March 22, 2010 Very nice. I'll be using this in my projects. Five stars!!!! Thank you for sharing. Link to comment Share on other sites More sharing options...
doudou Posted March 25, 2010 Author Share Posted March 25, 2010 I modified the example a bit: added _GUICtrl_SubclassedProc() to keep blackboxing consistent and verification that DllCallbackRegister() returns a valid handle. UDFS & Apps: Spoiler DDEML.au3 - DDE Client + ServerLocalization.au3 - localize your scriptsTLI.au3 - type information on COM objects (TLBINF emulation)TLBAutoEnum.au3 - auto-import of COM constants (enums)AU3Automation - export AU3 scripts via COM interfacesTypeLibInspector - OleView was yesterday Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ Link to comment Share on other sites More sharing options...
Yashied Posted March 25, 2010 Share Posted March 25, 2010 Nice solution, but maybe easier to use HotKeySet(). My UDFs: iKey | FTP Uploader | Battery Checker | Boot Manager | Font Viewer | UDF Keyword Manager | Run Dialog Replacement | USBProtect | 3D Axis | Calculator | Sleep | iSwitcher | TM | NetHelper | File Types Manager | Control Viewer | SynFolders | DLL Helper Animated Tray Icons UDF Library | Hotkeys UDF Library | Hotkeys Input Control UDF Library | Caret Shape UDF Library | Context Help UDF Library | Most Recently Used List UDF Library | Icons UDF Library | FTP UDF Library | Script Communications UDF Library | Color Chooser UDF Library | Color Picker Control UDF Library | IPHelper (Vista/7) UDF Library | WinAPI Extended UDF Library | WinAPIVhd UDF Library | Icon Chooser UDF Library | Copy UDF Library | Restart UDF Library | Event Log UDF Library | NotifyBox UDF Library | Pop-up Windows UDF Library | TVExplorer UDF Library | GuiHotKey UDF Library | GuiSysLink UDF Library | Package UDF Library | Skin UDF Library | AITray UDF Library | RDC UDF Library Appropriate path | Button text color | Gaussian random numbers | Header's styles (Vista/7) | ICON resource enumeration | Menu & INI | Tabbed string size | Tab's skin | Pop-up circular menu | Progress Bar without animation (Vista/7) | Registry export | Registry path jumping | Unique hardware ID | Windows alignment More... Link to comment Share on other sites More sharing options...
doudou Posted March 25, 2010 Author Share Posted March 25, 2010 Nice solution, but maybe easier to use HotKeySet().Hmm... Easier? Maybe. But HotKeySet() has this effect:When you set a hotkey, AutoIt captures the key-press and does not pass it on to the active applicationThis is exactly what my solution intends to avoid. And after all I didn't title it "The easiest way to catch ENTER..." UDFS & Apps: Spoiler DDEML.au3 - DDE Client + ServerLocalization.au3 - localize your scriptsTLI.au3 - type information on COM objects (TLBINF emulation)TLBAutoEnum.au3 - auto-import of COM constants (enums)AU3Automation - export AU3 scripts via COM interfacesTypeLibInspector - OleView was yesterday Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ Link to comment Share on other sites More sharing options...
Yashied Posted March 26, 2010 Share Posted March 26, 2010 expandcollapse popup#Include <WindowsConstants.au3> #Include <WinAPI.au3> #Include <GUIListView.au3> #Include <GUIConstantsEx.au3> Global $Dummy, $Index, $ListView, $hListView $hForm = GUICreate('MyGUI', 531, 396) $ListView = GUICtrlCreateListView('Items', 1, 1, 529, 394, BitOR($LVS_SINGLESEL, $LVS_SHOWSELALWAYS)) $hListView = GUICtrlGetHandle(-1) $Dummy = GUICtrlCreateDummy() For $i = 0 To 9 GUICtrlCreateListViewItem('Item ' & $i, $ListView) Next HotKeySet('{ENTER}', 'HKEdit') GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY') GUISetState() While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE ExitLoop Case $Dummy $Index = _GUICtrlListView_GetSelectedIndices($hListView) If Not $Index Then ContinueLoop EndIf HotKeySet('{ENTER}') MsgBox(0, '', 'Activate: ' & $Index & @CR) HotKeySet('{ENTER}', 'HKEdit') EndSwitch WEnd Func HKEdit() Switch WinGetHandle('[ACTIVE]') Case 0 Case $hForm If _WinAPI_GetFocus() = $hListView Then GUICtrlSendToDummy($Dummy) Return EndIf EndSwitch HotKeySet('{ENTER}') Send('{ENTER}') HotKeySet('{ENTER}', 'HKEdit') EndFunc ;==>HKEdit Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) Local $tNMITEMACTIVATE = DllStructCreate($tagNMITEMACTIVATE, $lParam) Local $hWndFrom = DllStructGetData($tNMITEMACTIVATE, 'hWndFrom') Local $Index = DllStructGetData($tNMITEMACTIVATE, 'Index') Local $Code = DllStructGetData($tNMITEMACTIVATE, 'Code') Switch $hWndFrom Case $hListView Switch $Code Case $LVN_ITEMACTIVATE GUICtrlSendToDummy($Dummy) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY My UDFs: iKey | FTP Uploader | Battery Checker | Boot Manager | Font Viewer | UDF Keyword Manager | Run Dialog Replacement | USBProtect | 3D Axis | Calculator | Sleep | iSwitcher | TM | NetHelper | File Types Manager | Control Viewer | SynFolders | DLL Helper Animated Tray Icons UDF Library | Hotkeys UDF Library | Hotkeys Input Control UDF Library | Caret Shape UDF Library | Context Help UDF Library | Most Recently Used List UDF Library | Icons UDF Library | FTP UDF Library | Script Communications UDF Library | Color Chooser UDF Library | Color Picker Control UDF Library | IPHelper (Vista/7) UDF Library | WinAPI Extended UDF Library | WinAPIVhd UDF Library | Icon Chooser UDF Library | Copy UDF Library | Restart UDF Library | Event Log UDF Library | NotifyBox UDF Library | Pop-up Windows UDF Library | TVExplorer UDF Library | GuiHotKey UDF Library | GuiSysLink UDF Library | Package UDF Library | Skin UDF Library | AITray UDF Library | RDC UDF Library Appropriate path | Button text color | Gaussian random numbers | Header's styles (Vista/7) | ICON resource enumeration | Menu & INI | Tabbed string size | Tab's skin | Pop-up circular menu | Progress Bar without animation (Vista/7) | Registry export | Registry path jumping | Unique hardware ID | Windows alignment More... Link to comment Share on other sites More sharing options...
doudou Posted March 26, 2010 Author Share Posted March 26, 2010 expandcollapse popup#Include <WindowsConstants.au3> #Include <WinAPI.au3> #Include <GUIListView.au3> #Include <GUIConstantsEx.au3> Global $Dummy, $Index, $ListView, $hListView $hForm = GUICreate('MyGUI', 531, 396) $ListView = GUICtrlCreateListView('Items', 1, 1, 529, 394, BitOR($LVS_SINGLESEL, $LVS_SHOWSELALWAYS)) $hListView = GUICtrlGetHandle(-1) $Dummy = GUICtrlCreateDummy() For $i = 0 To 9 GUICtrlCreateListViewItem('Item ' & $i, $ListView) Next HotKeySet('{ENTER}', 'HKEdit') GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY') GUISetState() While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE ExitLoop Case $Dummy $Index = _GUICtrlListView_GetSelectedIndices($hListView) If Not $Index Then ContinueLoop EndIf HotKeySet('{ENTER}') MsgBox(0, '', 'Activate: ' & $Index & @CR) HotKeySet('{ENTER}', 'HKEdit') EndSwitch WEnd Func HKEdit() Switch WinGetHandle('[ACTIVE]') Case 0 Case $hForm If _WinAPI_GetFocus() = $hListView Then GUICtrlSendToDummy($Dummy) Return EndIf EndSwitch HotKeySet('{ENTER}') Send('{ENTER}') HotKeySet('{ENTER}', 'HKEdit') EndFunc ;==>HKEdit Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) Local $tNMITEMACTIVATE = DllStructCreate($tagNMITEMACTIVATE, $lParam) Local $hWndFrom = DllStructGetData($tNMITEMACTIVATE, 'hWndFrom') Local $Index = DllStructGetData($tNMITEMACTIVATE, 'Index') Local $Code = DllStructGetData($tNMITEMACTIVATE, 'Code') Switch $hWndFrom Case $hListView Switch $Code Case $LVN_ITEMACTIVATE GUICtrlSendToDummy($Dummy) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY Interesting example. I would stick with my proposal nonetheless, if you don't mind. The reasons are: Your solution is even more complex and its complexity increases overproportional with every additional ListView in the project.Dummy controls are needed.You have to deactivate/reactivate the hotkey every now and then in order to process other ENTER events.Potential timing problems: you cannot guarantee HKEdit() is executed atomically, therefore it is possible that the relayed ENTER would hit the wrong target.I would always prefer the way defined by the API publisher (which LVN_ITEMACTIVATE is as documented by MS) over a hack (which your example is strictly spoken). UDFS & Apps: Spoiler DDEML.au3 - DDE Client + ServerLocalization.au3 - localize your scriptsTLI.au3 - type information on COM objects (TLBINF emulation)TLBAutoEnum.au3 - auto-import of COM constants (enums)AU3Automation - export AU3 scripts via COM interfacesTypeLibInspector - OleView was yesterday Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCEĀ Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now