How to detect hotkeys and enter keys in a listview Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
fliptoback
Posts: 84
Joined: 03 Sep 2016, 01:27

How to detect hotkeys and enter keys in a listview

Post by fliptoback » 21 Nov 2020, 00:58

Hi guys,

I have a listview whereby the user can double click on an item. In addition to double clicking, I also would like to allow the user to simply press enter at that selected row.

I also want to be able to press a function key F2 at a selected row to execute some code - some as editing the cell.

Now I have a switch A_GuiEvent routine as follows:

Code: Select all

Switch A_GuiEvent
{
	Case "RightClick": 
	{		
	        global listviewselected:= A_GuiControl
	        global rowselected:= A_EventInfo
	        Menu, ProjectListViewMenu, Show	
	}
	Case "DoubleClick":
	{
		Gui, 1: Listview, %A_GuiControl%
		LV_GetText(ProjectPath, A_EventInfo, 3)
	        Run, %ProjectPath%			
	}
}
But I am at a loss how to incorporate the F2 key and Enter key.

I can do a F2:: function but that F2 key will then be execute even when the focus is not in the listview which is not what I would like. I would like the Enter and F2 key only be able to be detected when the user has the listview selected.

Some ideas to point me in the right direction is more appreciated.

Thanks in advance.

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: How to detect hotkeys and enter keys in a listview

Post by mikeyww » 21 Nov 2020, 10:02

Code: Select all

Gui, New,, ThisGUI
Gui, Add, Button,, OK1
Gui, Add, Button,, OK2
Gui, Show

~ENTER::MsgBox, 48, Warning, The GUI is not the active window.

#IfWinActive ahk_class AutoHotkeyGUI ahk_exe AutoHotkey.exe
ENTER::
ControlGetFocus, fcontrol, A
If (fcontrol = "Button1")
     MsgBox, 64, Success, Regardless of the mouse, you ARE focused on the first button!
Else MsgBox, 48, Failure, Regardless of the mouse, you are NOT focused on the first button!
Return

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to detect hotkeys and enter keys in a listview

Post by just me » 21 Nov 2020, 10:36

You can catch the F2 key in the ListView's label when the AltSubmit option is set. The Enter key needs some special handling. I included examples in the following code:

Code: Select all

#NoEnv
Gui, Add, ListView, w400 r20 AltSubmit vLV gLabel, 1|2
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)
Gui, Add, Edit, wp, Focus!
Gui, Show, , Test
OnMessage(0x0100, "WM_KEYDOWN")
Return
; ------------------------------------------------------------------------------
GuiClose:
ExitApp
; ------------------------------------------------------------------------------
Label:
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
   MsgBox, You pressed F2 while the ListView had the focus!
Return
; ------------------------------------------------------------------------------
WM_KEYDOWN(VK, L, M, H) {
   ; https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keydown
   If (VK = 13) && (A_GuiControl = "LV") { ; VK_RETURN = 13 (0x0D)
      MsgBox, You pressed the Enter key while the ListView had the focus!
      Return 0
   }
}

User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: How to detect hotkeys and enter keys in a listview

Post by JoeWinograd » 21 Nov 2020, 11:35

just me wrote:I included examples in the following code
Hi just me,

I've always used the following two-step method to detect the Enter key in a ListView:

(1) Add a hidden, default button with this code:

Code: Select all

Gui,Add,Button,Hidden Default,Default
(2) Sample code for that button (getting the value in column 1):

Code: Select all

ButtonDefault:
GuiControlGet,FocusControl,Focus
If (FocusControl!="SysListView321")
  Return
SelectedRow:=LV_GetNext(0,"Focused")
LV_GetText(ListViewName,SelectedRow,1) ; get value in column 1
Return
It has always worked well, but as I consider you to be among the leading experts here on the forum in ListView (I love your LV_Colors class!), I'm wondering if you think that I should switch from the method that I've been using for the Enter key to the one that you posted here. Thanks, Joe

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: How to detect hotkeys and enter keys in a listview

Post by mikeyww » 21 Nov 2020, 11:35

That's much better! Thank you, @just me. I like @JoeWinograd's idea, too.

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to detect hotkeys and enter keys in a listview

Post by just me » 21 Nov 2020, 12:19

@JoeWinograd: Just another 'special' ListView thingy:

Code: Select all

#NoEnv
Gui, Add, ListView, w400 r20 AltSubmit vLV hwndHLV gLabel, 1|2
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)
Gui, Add, Edit, wp, Focus!
Gui, Show, , Test
LV_WantReturn(HLV)
Return
; ------------------------------------------------------------------------------
GuiClose:
ExitApp
; ------------------------------------------------------------------------------
Label:
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
   MsgBox, You pressed F2 while the ListView had the focus!
If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
   MsgBox, You pressed Enter while the ListView had the focus!
Return
; ==================================================================================================================================
; LV_WantReturn
;     'Fakes' Return key processing for ListView controls which otherwise won't process it.
;     If enabled, control's g-label will be triggered with A_GuiEvent = K and A_EventInfo = 13
;     whenever the <Return> key is pressed while the control has the focus.
; Usage:
;     To register a control call the functions once and pass the controls HWND as the first and only parameter.
;     To deregister it, call the function again with the same HWND as the first and only parameter.
; ==================================================================================================================================
LV_WantReturn(wParam, lParam := "", Msg := "", HWND := "") {
   Static Controls := []
        , MsgFunc := Func("LV_WantReturn")
        , OnMsg := False
        , LVN_KEYDOWN := -155
  ; Message handler call -----------------------------------------------------------------------------------------------------------
   If (Msg = 256) { ; WM_KEYDOWM (0x0100)
      If (wParam = 13) && (Ctl := Controls[HWND]) {
         If !(lParam & 0x40000000) { ; don't send notifications for auto-repeated keydown events
            VarSetCapacity(NMKD, (A_PtrSize * 3) + 8, 0) ; NMLVKEYDOWN/NMTVKEYDOWN structure 64-bit
            , NumPut(HWND, NMKD, 0, "Ptr")
            , NumPut(Ctl.CID, NMKD, A_PtrSize, "Ptr")
            , NumPut(LVN_KEYDOWN, NMKD, A_PtrSize * 2, "Int")
            , NumPut(13, NMKD, A_PtrSize * 3, "UShort")
            , DllCall("SendMessage", "Ptr", Ctl.HGUI, "UInt", 0x004E, "Ptr", Ctl.CID, "Ptr", &NMKD)
         }
         Return 0
      }
   }
   ; User call ---------------------------------------------------------------------------------------------------------------------
   Else {
      If (Controls[wParam += 0]) { ; the control is already registered, remove it
         Controls.Delete(wParam)
         If ((Controls.Length() = 0) && OnMsg) {
            OnMessage(0x0100, MsgFunc, 0)
            OnMsg := False
         }
         Return True
      }
      If !DllCall("IsWindow", "Ptr", wParam, "UInt")
         Return False
      WinGetClass, ClassName, ahk_id %wParam%
      If (ClassName <> "SysListView32")
         Return False
      Controls[wParam] := {CID:  DllCall("GetDlgCtrlID", "Ptr", wParam, "Int")
                         , HGUI: DllCall("GetParent", "Ptr", wParam, "UPtr")}
      If !(OnMsg)
         OnMessage(0x0100, MsgFunc, -1)
      Return (OnMsg := True)
   }
}

User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: How to detect hotkeys and enter keys in a listview

Post by JoeWinograd » 21 Nov 2020, 14:50

just me wrote:Just another 'special' ListView thingy
Hi just me,
Very nice! Seems to provide a great way to do something I've been wondering about...detecting a right-click on a ListView row. I added this code to your Label: path:

Code: Select all

If (A_GuiEvent == "RightClick")
   MsgBox, You did a Right-Click on ListView item# %A_EventInfo%
Appears to work well, but am I missing anything? Thanks, Joe

fliptoback
Posts: 84
Joined: 03 Sep 2016, 01:27

Re: How to detect hotkeys and enter keys in a listview

Post by fliptoback » 21 Nov 2020, 23:44

just me wrote:
21 Nov 2020, 12:19
@JoeWinograd: Just another 'special' ListView thingy:

Code: Select all

#NoEnv
Gui, Add, ListView, w400 r20 AltSubmit vLV hwndHLV gLabel, 1|2
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)
Gui, Add, Edit, wp, Focus!
Gui, Show, , Test
LV_WantReturn(HLV)
Return
; ------------------------------------------------------------------------------
GuiClose:
ExitApp
; ------------------------------------------------------------------------------
Label:
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
   MsgBox, You pressed F2 while the ListView had the focus!
If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
   MsgBox, You pressed Enter while the ListView had the focus!
Return
; ==================================================================================================================================
; LV_WantReturn
;     'Fakes' Return key processing for ListView controls which otherwise won't process it.
;     If enabled, control's g-label will be triggered with A_GuiEvent = K and A_EventInfo = 13
;     whenever the <Return> key is pressed while the control has the focus.
; Usage:
;     To register a control call the functions once and pass the controls HWND as the first and only parameter.
;     To deregister it, call the function again with the same HWND as the first and only parameter.
; ==================================================================================================================================
LV_WantReturn(wParam, lParam := "", Msg := "", HWND := "") {
   Static Controls := []
        , MsgFunc := Func("LV_WantReturn")
        , OnMsg := False
        , LVN_KEYDOWN := -155
  ; Message handler call -----------------------------------------------------------------------------------------------------------
   If (Msg = 256) { ; WM_KEYDOWM (0x0100)
      If (wParam = 13) && (Ctl := Controls[HWND]) {
         If !(lParam & 0x40000000) { ; don't send notifications for auto-repeated keydown events
            VarSetCapacity(NMKD, (A_PtrSize * 3) + 8, 0) ; NMLVKEYDOWN/NMTVKEYDOWN structure 64-bit
            , NumPut(HWND, NMKD, 0, "Ptr")
            , NumPut(Ctl.CID, NMKD, A_PtrSize, "Ptr")
            , NumPut(LVN_KEYDOWN, NMKD, A_PtrSize * 2, "Int")
            , NumPut(13, NMKD, A_PtrSize * 3, "UShort")
            , DllCall("SendMessage", "Ptr", Ctl.HGUI, "UInt", 0x004E, "Ptr", Ctl.CID, "Ptr", &NMKD)
         }
         Return 0
      }
   }
   ; User call ---------------------------------------------------------------------------------------------------------------------
   Else {
      If (Controls[wParam += 0]) { ; the control is already registered, remove it
         Controls.Delete(wParam)
         If ((Controls.Length() = 0) && OnMsg) {
            OnMessage(0x0100, MsgFunc, 0)
            OnMsg := False
         }
         Return True
      }
      If !DllCall("IsWindow", "Ptr", wParam, "UInt")
         Return False
      WinGetClass, ClassName, ahk_id %wParam%
      If (ClassName <> "SysListView32")
         Return False
      Controls[wParam] := {CID:  DllCall("GetDlgCtrlID", "Ptr", wParam, "Int")
                         , HGUI: DllCall("GetParent", "Ptr", wParam, "UPtr")}
      If !(OnMsg)
         OnMessage(0x0100, MsgFunc, -1)
      Return (OnMsg := True)
   }
}
Thanks Mikey, Joe and JustMe.

I like this code and I tried to follow as well - whilst it works very well on your example - but the programming is way over my head and I just don't know where to begin to adapt this to my listview with more than 1 tab. Any tips please?

Edit: After much trial and error, Success!!

Just a summary of what I have to do to make this code works in my code:

1) in the Gui add Listview, make sure AltSubmit and hwndHLV is included. So my actual code looks like this:

Code: Select all

Gui, 1: Add, ListView, x50 y140 W900 h450 r20 vProjectsCategory1 AltSubmit hwndHLV gProjectListView, Project|Name|Path
2) copy and paste the LV_WantReturn routines to somewhere in the script. No need to do anything else.

3) Put this line at the end of the declaration of listview tabs. I have 3 tabs includedd at present.

Code: Select all

LV_WantReturn(HLV)
4) Put this code in the routine called by the Listview

Code: Select all

If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
   MsgBox, You pressed F2 while the ListView had the focus!
If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
   MsgBox, You pressed Enter while the ListView had the focus!
and it works!

Thanks Justme!

fliptoback
Posts: 84
Joined: 03 Sep 2016, 01:27

Re: How to detect hotkeys and enter keys in a listview

Post by fliptoback » 22 Nov 2020, 02:14

JoeWinograd wrote:
21 Nov 2020, 14:50
just me wrote:Just another 'special' ListView thingy
Hi just me,
Very nice! Seems to provide a great way to do something I've been wondering about...detecting a right-click on a ListView row. I added this code to your Label: path:

Code: Select all

If (A_GuiEvent == "RightClick")
   MsgBox, You did a Right-Click on ListView item# %A_EventInfo%
Appears to work well, but am I missing anything? Thanks, Joe
I encounter a problem with the coding.

I implemented Justme code and it can detect the keys being pressed.

But before I can detect the row selected in the listview using the A_EventInfo, but now A_EventInfo when i press F2 returns 13 (which I understand is because of this VK_Return = 13 thing) but how do I detect the row then?

Any idea please?

User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: How to detect hotkeys and enter keys in a listview

Post by JoeWinograd » 22 Nov 2020, 04:05

fliptoback wrote:Any idea please?

Code: Select all

Label:
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed F2 while the ListView was on row %RowNum%
}
If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed Enter while the ListView was on row %RowNum%
}
Return

fliptoback
Posts: 84
Joined: 03 Sep 2016, 01:27

Re: How to detect hotkeys and enter keys in a listview

Post by fliptoback » 22 Nov 2020, 04:11

JoeWinograd wrote:
22 Nov 2020, 04:05
fliptoback wrote:Any idea please?

Code: Select all

Label:
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed F2 while the ListView was on row %RowNum%
}
If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed Enter while the ListView was on row %RowNum%
}
Return
Thanks Joe. I tried your code, and RowNum returns 0 all the time....any ideas?

If I do the following code, it gets the row correctly BUT only on listview tab #1 and not any other tabs...

Code: Select all

ControlGet, rownumberselected, list, count Focused, SysListView321
msgbox, row selected = %rownumberselected%

User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: How to detect hotkeys and enter keys in a listview

Post by JoeWinograd » 22 Nov 2020, 04:15

It isn't stand-alone code. It is a replacement for the Label: path code in just me's post.

fliptoback
Posts: 84
Joined: 03 Sep 2016, 01:27

Re: How to detect hotkeys and enter keys in a listview

Post by fliptoback » 22 Nov 2020, 04:17

JoeWinograd wrote:
22 Nov 2020, 04:15
It isn't stand-alone code. It is a replacement for the Label: path code in just me's post.
Hmm...ok. This is what I have the following inside a g routine.


Code: Select all

ProjectListView:
{
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
{
;MsgBox, You pressed F2 while the ListView had the focus!

ControlGet, rownumberselected, list, count Focused, SysListView321
msgbox, row selected = %rownumberselected%

RowNum:= LV_GetNext()
MsgBox, You pressed F2 while Listview was on row %RowNum%

}

If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
MsgBox, You pressed Enter while the ListView had the focus!
}
return     

User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: How to detect hotkeys and enter keys in a listview

Post by JoeWinograd » 22 Nov 2020, 04:24

Maybe this code will make it clearer for you (with all credit to just me):

Code: Select all

#NoEnv
#SingleInstance force
Gui, Add, ListView, w400 r20 AltSubmit vLV hwndHLV gLabel, Column1|Column2
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)
Gui, Add, Edit, wp, Click here to test LV not having focus
Gui, Show, , Test
LV_WantReturn(HLV)
Return
; ------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
; ------------------------------------------------------------------------------
Label:
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed F2 while the ListView was on row %RowNum%
}
If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed Enter while the ListView was on row %RowNum%
}
If (A_GuiEvent == "RightClick")
{
   RowNum:=A_EventInfo
   MsgBox, You did a Right-Click while the ListView was on row %RowNum%
}
Return
; ==================================================================================================================================
; LV_WantReturn
;     'Fakes' Return key processing for ListView controls which otherwise won't process it.
;     If enabled, control's g-label will be triggered with A_GuiEvent = K and A_EventInfo = 13
;     whenever the <Return> key is pressed while the control has the focus.
; Usage:
;     To register a control call the functions once and pass the controls HWND as the first and only parameter.
;     To deregister it, call the function again with the same HWND as the first and only parameter.
; ==================================================================================================================================
LV_WantReturn(wParam, lParam := "", Msg := "", HWND := "") {
   Static Controls := []
        , MsgFunc := Func("LV_WantReturn")
        , OnMsg := False
        , LVN_KEYDOWN := -155
  ; Message handler call -----------------------------------------------------------------------------------------------------------
   If (Msg = 256) { ; WM_KEYDOWM (0x0100)
      If (wParam = 13) && (Ctl := Controls[HWND]) {
         If !(lParam & 0x40000000) { ; don't send notifications for auto-repeated keydown events
            VarSetCapacity(NMKD, (A_PtrSize * 3) + 8, 0) ; NMLVKEYDOWN/NMTVKEYDOWN structure 64-bit
            , NumPut(HWND, NMKD, 0, "Ptr")
            , NumPut(Ctl.CID, NMKD, A_PtrSize, "Ptr")
            , NumPut(LVN_KEYDOWN, NMKD, A_PtrSize * 2, "Int")
            , NumPut(13, NMKD, A_PtrSize * 3, "UShort")
            , DllCall("SendMessage", "Ptr", Ctl.HGUI, "UInt", 0x004E, "Ptr", Ctl.CID, "Ptr", &NMKD)
         }
         Return 0
      }
   }
   ; User call ---------------------------------------------------------------------------------------------------------------------
   Else {
      If (Controls[wParam += 0]) { ; the control is already registered, remove it
         Controls.Delete(wParam)
         If ((Controls.Length() = 0) && OnMsg) {
            OnMessage(0x0100, MsgFunc, 0)
            OnMsg := False
         }
         Return True
      }
      If !DllCall("IsWindow", "Ptr", wParam, "UInt")
         Return False
      WinGetClass, ClassName, ahk_id %wParam%
      If (ClassName <> "SysListView32")
         Return False
      Controls[wParam] := {CID:  DllCall("GetDlgCtrlID", "Ptr", wParam, "Int")
                         , HGUI: DllCall("GetParent", "Ptr", wParam, "UPtr")}
      If !(OnMsg)
         OnMessage(0x0100, MsgFunc, -1)
      Return (OnMsg := True)
   }
}
Works perfectly here! Regards, Joe

User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: How to detect hotkeys and enter keys in a listview

Post by JoeWinograd » 22 Nov 2020, 04:34

Our messages crossed...I did not look at your last posted code and it is 3:30am in my neck of the woods, so I'm packing it in now. Will check back into the thread first thing in my morning (or early afternoon) to see how you're doing. If you don't have it working by then, I suggest posting your entire script. Regards, Joe

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to detect hotkeys and enter keys in a listview

Post by just me » 22 Nov 2020, 04:44

Built-in Functions for ListViews
You might need to set the default ListView (Gui, ListView, ListViewName) within the control's label.

fliptoback
Posts: 84
Joined: 03 Sep 2016, 01:27

Re: How to detect hotkeys and enter keys in a listview

Post by fliptoback » 22 Nov 2020, 04:46

JoeWinograd wrote:
22 Nov 2020, 04:24
Maybe this code will make it clearer for you (with all credit to just me):

Code: Select all

#NoEnv
#SingleInstance force
Gui, Add, ListView, w400 r20 AltSubmit vLV hwndHLV gLabel, Column1|Column2
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)
Gui, Add, Edit, wp, Click here to test LV not having focus
Gui, Show, , Test
LV_WantReturn(HLV)
Return
; ------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
; ------------------------------------------------------------------------------
Label:
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed F2 while the ListView was on row %RowNum%
}
If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed Enter while the ListView was on row %RowNum%
}
If (A_GuiEvent == "RightClick")
{
   RowNum:=A_EventInfo
   MsgBox, You did a Right-Click while the ListView was on row %RowNum%
}
Return
; ==================================================================================================================================
; LV_WantReturn
;     'Fakes' Return key processing for ListView controls which otherwise won't process it.
;     If enabled, control's g-label will be triggered with A_GuiEvent = K and A_EventInfo = 13
;     whenever the <Return> key is pressed while the control has the focus.
; Usage:
;     To register a control call the functions once and pass the controls HWND as the first and only parameter.
;     To deregister it, call the function again with the same HWND as the first and only parameter.
; ==================================================================================================================================
LV_WantReturn(wParam, lParam := "", Msg := "", HWND := "") {
   Static Controls := []
        , MsgFunc := Func("LV_WantReturn")
        , OnMsg := False
        , LVN_KEYDOWN := -155
  ; Message handler call -----------------------------------------------------------------------------------------------------------
   If (Msg = 256) { ; WM_KEYDOWM (0x0100)
      If (wParam = 13) && (Ctl := Controls[HWND]) {
         If !(lParam & 0x40000000) { ; don't send notifications for auto-repeated keydown events
            VarSetCapacity(NMKD, (A_PtrSize * 3) + 8, 0) ; NMLVKEYDOWN/NMTVKEYDOWN structure 64-bit
            , NumPut(HWND, NMKD, 0, "Ptr")
            , NumPut(Ctl.CID, NMKD, A_PtrSize, "Ptr")
            , NumPut(LVN_KEYDOWN, NMKD, A_PtrSize * 2, "Int")
            , NumPut(13, NMKD, A_PtrSize * 3, "UShort")
            , DllCall("SendMessage", "Ptr", Ctl.HGUI, "UInt", 0x004E, "Ptr", Ctl.CID, "Ptr", &NMKD)
         }
         Return 0
      }
   }
   ; User call ---------------------------------------------------------------------------------------------------------------------
   Else {
      If (Controls[wParam += 0]) { ; the control is already registered, remove it
         Controls.Delete(wParam)
         If ((Controls.Length() = 0) && OnMsg) {
            OnMessage(0x0100, MsgFunc, 0)
            OnMsg := False
         }
         Return True
      }
      If !DllCall("IsWindow", "Ptr", wParam, "UInt")
         Return False
      WinGetClass, ClassName, ahk_id %wParam%
      If (ClassName <> "SysListView32")
         Return False
      Controls[wParam] := {CID:  DllCall("GetDlgCtrlID", "Ptr", wParam, "Int")
                         , HGUI: DllCall("GetParent", "Ptr", wParam, "UPtr")}
      If !(OnMsg)
         OnMessage(0x0100, MsgFunc, -1)
      Return (OnMsg := True)
   }
}
Works perfectly here! Regards, Joe
Thanks Joe. Sorry I am not having success with multiple tabs on the listview using the above code.

It doesn't compile. It says that the same variable cannot be used for more than 1 control.

Could you please tell me how to implement multiple tabs using your example above?

This is what I have currently which is obviously no good....

Code: Select all

#NoEnv
#SingleInstance force

Gui, Add, Tab2, vCurrentTab , Tab 1|Tab 2

Gui, Tab, 1
Gui, Listview, Listview1

Gui, Add, ListView, w400 r20 AltSubmit vLV hwndHLV gLabel, Column1|Column2
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)

Gui, Tab, 2
Gui, Listview, Listview2

Gui, Add, ListView, w400 r20 AltSubmit vLV hwndHLV gLabel, Column1|Column2
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)

Gui, Add, Edit, wp, Click here to test LV not having focus
Gui, Show, , Test
LV_WantReturn(HLV)
Return
; ------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
; ------------------------------------------------------------------------------
Label:
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed F2 while the ListView was on row %RowNum%
}
If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed Enter while the ListView was on row %RowNum%
}
If (A_GuiEvent == "RightClick")
{
   RowNum:=A_EventInfo
   MsgBox, You did a Right-Click while the ListView was on row %RowNum%
}
Return
; ==================================================================================================================================
; LV_WantReturn
;     'Fakes' Return key processing for ListView controls which otherwise won't process it.
;     If enabled, control's g-label will be triggered with A_GuiEvent = K and A_EventInfo = 13
;     whenever the <Return> key is pressed while the control has the focus.
; Usage:
;     To register a control call the functions once and pass the controls HWND as the first and only parameter.
;     To deregister it, call the function again with the same HWND as the first and only parameter.
; ==================================================================================================================================
LV_WantReturn(wParam, lParam := "", Msg := "", HWND := "") {
   Static Controls := []
        , MsgFunc := Func("LV_WantReturn")
        , OnMsg := False
        , LVN_KEYDOWN := -155
  ; Message handler call -----------------------------------------------------------------------------------------------------------
   If (Msg = 256) { ; WM_KEYDOWM (0x0100)
      If (wParam = 13) && (Ctl := Controls[HWND]) {
         If !(lParam & 0x40000000) { ; don't send notifications for auto-repeated keydown events
            VarSetCapacity(NMKD, (A_PtrSize * 3) + 8, 0) ; NMLVKEYDOWN/NMTVKEYDOWN structure 64-bit
            , NumPut(HWND, NMKD, 0, "Ptr")
            , NumPut(Ctl.CID, NMKD, A_PtrSize, "Ptr")
            , NumPut(LVN_KEYDOWN, NMKD, A_PtrSize * 2, "Int")
            , NumPut(13, NMKD, A_PtrSize * 3, "UShort")
            , DllCall("SendMessage", "Ptr", Ctl.HGUI, "UInt", 0x004E, "Ptr", Ctl.CID, "Ptr", &NMKD)
         }
         Return 0
      }
   }
   ; User call ---------------------------------------------------------------------------------------------------------------------
   Else {
      If (Controls[wParam += 0]) { ; the control is already registered, remove it
         Controls.Delete(wParam)
         If ((Controls.Length() = 0) && OnMsg) {
            OnMessage(0x0100, MsgFunc, 0)
            OnMsg := False
         }
         Return True
      }
      If !DllCall("IsWindow", "Ptr", wParam, "UInt")
         Return False
      WinGetClass, ClassName, ahk_id %wParam%
      If (ClassName <> "SysListView32")
         Return False
      Controls[wParam] := {CID:  DllCall("GetDlgCtrlID", "Ptr", wParam, "Int")
                         , HGUI: DllCall("GetParent", "Ptr", wParam, "UPtr")}
      If !(OnMsg)
         OnMessage(0x0100, MsgFunc, -1)
      Return (OnMsg := True)
   }
}

just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to detect hotkeys and enter keys in a listview  Topic is solved

Post by just me » 22 Nov 2020, 05:03

Code: Select all

#NoEnv
#SingleInstance force

Gui, Add, Tab2, vCurrentTab , Tab 1|Tab 2
Gui, Tab, 1
; Gui, Listview, Listview1 ; <<< useless here
Gui, Add, ListView, w400 r20 AltSubmit vListview1 hwndHLV gLabel, Column1|Column2 ; <<< changed
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)
LV_WantReturn(HLV) ; <<< added

Gui, Tab, 2
; Gui, Listview, Listview2 ; <<< useless here
Gui, Add, ListView, w400 r20 AltSubmit vListview2 hwndHLV gLabel, Column1|Column2 ; <<< changed
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)
LV_WantReturn(HLV) ; <<< added

Gui, Add, Edit, wp, Click here to test LV not having focus
Gui, Show, , Test
; LV_WantReturn(HLV) ; too late for the first ListView
Return
; ------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
; ------------------------------------------------------------------------------
Label:
Gui, ListView, %A_GuiControl% ; <<< added
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed F2 while the ListView was on row %RowNum%
}
If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed Enter while the ListView was on row %RowNum%
}
If (A_GuiEvent == "RightClick")
{
   RowNum:=A_EventInfo
   MsgBox, You did a Right-Click while the ListView was on row %RowNum%
}
Return
; ==================================================================================================================================
; LV_WantReturn
;     'Fakes' Return key processing for ListView controls which otherwise won't process it.
;     If enabled, control's g-label will be triggered with A_GuiEvent = K and A_EventInfo = 13
;     whenever the <Return> key is pressed while the control has the focus.
; Usage:
;     To register a control call the functions once and pass the controls HWND as the first and only parameter.
;     To deregister it, call the function again with the same HWND as the first and only parameter.
; ==================================================================================================================================
LV_WantReturn(wParam, lParam := "", Msg := "", HWND := "") {
   Static Controls := []
        , MsgFunc := Func("LV_WantReturn")
        , OnMsg := False
        , LVN_KEYDOWN := -155
  ; Message handler call -----------------------------------------------------------------------------------------------------------
   If (Msg = 256) { ; WM_KEYDOWM (0x0100)
      If (wParam = 13) && (Ctl := Controls[HWND]) {
         If !(lParam & 0x40000000) { ; don't send notifications for auto-repeated keydown events
            VarSetCapacity(NMKD, (A_PtrSize * 3) + 8, 0) ; NMLVKEYDOWN/NMTVKEYDOWN structure 64-bit
            , NumPut(HWND, NMKD, 0, "Ptr")
            , NumPut(Ctl.CID, NMKD, A_PtrSize, "Ptr")
            , NumPut(LVN_KEYDOWN, NMKD, A_PtrSize * 2, "Int")
            , NumPut(13, NMKD, A_PtrSize * 3, "UShort")
            , DllCall("SendMessage", "Ptr", Ctl.HGUI, "UInt", 0x004E, "Ptr", Ctl.CID, "Ptr", &NMKD)
         }
         Return 0
      }
   }
   ; User call ---------------------------------------------------------------------------------------------------------------------
   Else {
      If (Controls[wParam += 0]) { ; the control is already registered, remove it
         Controls.Delete(wParam)
         If ((Controls.Length() = 0) && OnMsg) {
            OnMessage(0x0100, MsgFunc, 0)
            OnMsg := False
         }
         Return True
      }
      If !DllCall("IsWindow", "Ptr", wParam, "UInt")
         Return False
      WinGetClass, ClassName, ahk_id %wParam%
      If (ClassName <> "SysListView32")
         Return False
      Controls[wParam] := {CID:  DllCall("GetDlgCtrlID", "Ptr", wParam, "Int")
                         , HGUI: DllCall("GetParent", "Ptr", wParam, "UPtr")}
      If !(OnMsg)
         OnMessage(0x0100, MsgFunc, -1)
      Return (OnMsg := True)
   }
}

fliptoback
Posts: 84
Joined: 03 Sep 2016, 01:27

Re: How to detect hotkeys and enter keys in a listview

Post by fliptoback » 22 Nov 2020, 05:08

just me wrote:
22 Nov 2020, 05:03

Code: Select all

#NoEnv
#SingleInstance force

Gui, Add, Tab2, vCurrentTab , Tab 1|Tab 2
Gui, Tab, 1
; Gui, Listview, Listview1 ; <<< useless here
Gui, Add, ListView, w400 r20 AltSubmit vListview1 hwndHLV gLabel, Column1|Column2 ; <<< changed
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)
LV_WantReturn(HLV) ; <<< added

Gui, Tab, 2
; Gui, Listview, Listview2 ; <<< useless here
Gui, Add, ListView, w400 r20 AltSubmit vListview2 hwndHLV gLabel, Column1|Column2 ; <<< changed
Loop, 10
   LV_Add("", "1" . A_Index, "2" . A_Index)
LV_WantReturn(HLV) ; <<< added

Gui, Add, Edit, wp, Click here to test LV not having focus
Gui, Show, , Test
; LV_WantReturn(HLV) ; too late for the first ListView
Return
; ------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
; ------------------------------------------------------------------------------
Label:
Gui, ListView, %A_GuiControl% ; <<< added
If (A_GuiEvent == "K") && (A_EventInfo = 113) ; VK_F2 = 113 (0x71)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed F2 while the ListView was on row %RowNum%
}
If (A_GuiEvent == "K") && (A_EventInfo = 13) ; VK_RETURN = 13 (0x0D)
{
   RowNum:=LV_GetNext()
   MsgBox, You pressed Enter while the ListView was on row %RowNum%
}
If (A_GuiEvent == "RightClick")
{
   RowNum:=A_EventInfo
   MsgBox, You did a Right-Click while the ListView was on row %RowNum%
}
Return
; ==================================================================================================================================
; LV_WantReturn
;     'Fakes' Return key processing for ListView controls which otherwise won't process it.
;     If enabled, control's g-label will be triggered with A_GuiEvent = K and A_EventInfo = 13
;     whenever the <Return> key is pressed while the control has the focus.
; Usage:
;     To register a control call the functions once and pass the controls HWND as the first and only parameter.
;     To deregister it, call the function again with the same HWND as the first and only parameter.
; ==================================================================================================================================
LV_WantReturn(wParam, lParam := "", Msg := "", HWND := "") {
   Static Controls := []
        , MsgFunc := Func("LV_WantReturn")
        , OnMsg := False
        , LVN_KEYDOWN := -155
  ; Message handler call -----------------------------------------------------------------------------------------------------------
   If (Msg = 256) { ; WM_KEYDOWM (0x0100)
      If (wParam = 13) && (Ctl := Controls[HWND]) {
         If !(lParam & 0x40000000) { ; don't send notifications for auto-repeated keydown events
            VarSetCapacity(NMKD, (A_PtrSize * 3) + 8, 0) ; NMLVKEYDOWN/NMTVKEYDOWN structure 64-bit
            , NumPut(HWND, NMKD, 0, "Ptr")
            , NumPut(Ctl.CID, NMKD, A_PtrSize, "Ptr")
            , NumPut(LVN_KEYDOWN, NMKD, A_PtrSize * 2, "Int")
            , NumPut(13, NMKD, A_PtrSize * 3, "UShort")
            , DllCall("SendMessage", "Ptr", Ctl.HGUI, "UInt", 0x004E, "Ptr", Ctl.CID, "Ptr", &NMKD)
         }
         Return 0
      }
   }
   ; User call ---------------------------------------------------------------------------------------------------------------------
   Else {
      If (Controls[wParam += 0]) { ; the control is already registered, remove it
         Controls.Delete(wParam)
         If ((Controls.Length() = 0) && OnMsg) {
            OnMessage(0x0100, MsgFunc, 0)
            OnMsg := False
         }
         Return True
      }
      If !DllCall("IsWindow", "Ptr", wParam, "UInt")
         Return False
      WinGetClass, ClassName, ahk_id %wParam%
      If (ClassName <> "SysListView32")
         Return False
      Controls[wParam] := {CID:  DllCall("GetDlgCtrlID", "Ptr", wParam, "Int")
                         , HGUI: DllCall("GetParent", "Ptr", wParam, "UPtr")}
      If !(OnMsg)
         OnMessage(0x0100, MsgFunc, -1)
      Return (OnMsg := True)
   }
}
Thanks Just me!!! This is very much appreciated.

Works like a charm and thanks for correcting my incorrect code.

I will incorporate this into my original code.

User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: How to detect hotkeys and enter keys in a listview

Post by JoeWinograd » 22 Nov 2020, 10:58

Hi flip,
I see that just me has you squared away...great news! Regards, Joe

Post Reply

Return to “Ask for Help (v1)”