Can i detect a right-click on a listbox item?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
wdmodlin
Posts: 150
Joined: 16 Dec 2015, 02:42

Can i detect a right-click on a listbox item?

14 Jan 2016, 01:17

I have several listboxes in a Gui. I would like the user to be able to see additional information about each item in the list by right-clicking the line.

Right-click does not seem to do anything to the selection, and it does not call my gSubroutine.

Is there a way I can get it to do something ?

Also, when I could not find a way to use right-click I thought perhaps I could settle for DoubleClick to ask for the information.

The documentation says that A_GuiEvent will contain "DoubleClick" when this happens.

I can't get that to work either... I've tried sleeping up to 500ms before examining A_GuiEvent, but it never seems to say anything but "Normal".

I've checked the mouse settings in control panel, and have no problem registering double-clicks in the little test window they show to help you adjust the double-click speed.

Any ideas?
just me
Posts: 9504
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Can i detect a right-click on a listbox item?

14 Jan 2016, 02:33

Right-click:
Right-click does not seem to do anything to the selection, and it does not call my gSubroutine.
Right!
Is there a way I can get it to do something ?
In both cases you have use the LB_ITEMFROMPOINT message to get the index of the clicked item (see also LBEX->LBEX_ItemPromPoint()).

Double-click:
A double-click consists of two clicks. So you will always get a "Normal" event first and then the "DoubleClick" event. Sleeping within the label doesn't help, because it blocks the label.
wdmodlin
Posts: 150
Joined: 16 Dec 2015, 02:42

Re: Can i detect a right-click on a listbox item?

14 Jan 2016, 05:36

I'm so glad there are experts around!

Thank you just me. That clarifies it I think.
wdmodlin
Posts: 150
Joined: 16 Dec 2015, 02:42

Re: Can i detect a right-click on a listbox item?

14 Jan 2016, 07:31

Well. Not as clearcut as I thought at first. I'm still very low on the learning curve here, and it will take me some time to absorb what a "message" is and what fuzzy terms like "handle" might refer to or how one acquires such.

I can make it work for the moment by calculating the index of the clicked item from the coordinate A_GuiY which is available to me.
Something like Index := Floor((A_GuiY - 43) / 14) + 1 works for my particular case, though it seems fragile... not sure what determines the pixel height of the items for one.

Anyway, you have given me a starting point for my next learning exercise, and I do have a working (if fragile) script to use now.

Thanks again.

Oh. while you are here, another thing that came up in my browsing was a reference to a more powerful Edit control, HiEdit. But the link doesn't get me to anything useful. Do you know if that happens to be still around?
wdmodlin
Posts: 150
Joined: 16 Dec 2015, 02:42

Re: Can i detect a right-click on a listbox item?

14 Jan 2016, 13:35

Well. I'm not yet able to use the functions you told me about. I'm still missing something... probably a lot of somethings.

EDIT: I may have found a solution... if I am reading it correctly, I can put parens after GuiContextMenu to make it a function, and one of the arguments passed when it is called will be the CtrlHwnd that I need. Makes it very simple, if so. So for now you can ignore this post, but if you have time I would appreciate any comments on what my misconceptions were in the code I show here...

Code: Select all


GuiContextMenu:   ; called by a right click in a listbox, among other things...
;	My 8 listboxes have vNames is1 to is8.  They also have 9 selectable lines each, but line 9 is (none), with no associated info to display

;   First ignore clicks that cannot be relevant to this function:
	If ((SubStr(A_GuiControl,1,2) <> "is") or (A_GuiEvent <> "RightClick") or (A_EventInfo < 1) or (A_EventInfo > 8))
		return

	lOffset := A_GuiY - 43				;As a temporary expedient, I computed the index using empirical numbers I got by right-clicking and MsgBox
	lNum    := Floor(lOffset / 14) + 1		;so long as the actual line height and first offset don't change, this is the index.  It works.

;   Here I am trying to use the functions you showed me... not working yet. 

;  There is probably a proper way to get the handle of the listbox that called me at this point, but I do not know it.
;   So I'm doing something that feels like a "cheat", even if it works.  I put Hwndhb1 through Hwndhb9 in the listbox options...
 
	HandleV := "hb" . A_EventInfo			;the relevant variables have names hb1 to hb8
	HLB := %HandleV%					;I think HLB should now have the content of HandleV, an actual handle?
									;at least, a MsgBox shows HandleV with one of my names, and HLB with some large hex number here
											
	LBindex := LBEX_ItemFromPoint(HLB, A_GuiX, A_GuiY)
	LBstr	:= LBEX_GetText(HLB,LBindex)

	MsgBox, GuiContextMenu called with %A_GuiControl% and %A_EventInfo%, X= %A_GuiX% Y= %A_GuiY% line = %lNum%  Hand = %HandleV% HLB = %HLB% LBindex = %LBindex% LBstr = %LBstr%
	
	;  Oops.  Now I get, for example: HLB=0x1605bc LBindex=65543 LBstr= (nothing, the line ends there.)
	
	;  The other variables are as expected, reporting the listbox variable and line that I actually clicked on.
	;  Guessing that my attempt to cheat at getting a handle didn't work...
	  
	return

wdmodlin
Posts: 150
Joined: 16 Dec 2015, 02:42

Re: Can i detect a right-click on a listbox item?

14 Jan 2016, 14:11

EDIT yet again:
I masked the result from ItemFromPoint with 0xFFFF and now I get a small number related to the vertical position of the click. But it is off... clicking various places inside the first listed item returns 4 or 5, not the 1 that is expected. My ad-hoc calculation seems to always get the right number. I'm back to thinking that the function may be broken... I can't think of anything I could be doing wrong outside to yield this behavior.

EDIT: User Error, as expected. Looking more closely, I missed that the return value from ItemFromPoint has two values in one word.
the upper half contains 1 if the point is outside the "user area". It seems that the X,Y foe GuiContextMenu defines a point outside the user area, but aligned vertically with the item of interest. So my index calculation using Y alone worked, but the returned value has an extra high-word bit which I should mask off. Should all work when I fix that.




Nope. Not fixed yet. Here is the new simpler code:

Code: Select all

GuiContextMenu(GuiHwnd, HLB, EventInfo, IsRightClick, X, Y)   ; called by a right click in a listbox, among other things...
{
	If ((SubStr(A_GuiControl,1,2) <> "is") or (not IsRightClick) or (EventInfo < 1) or (EventInfo > 8))
		return ;  ignore clicks that cannot be relevant

	lOffset := Y - 43						;As a temporary expedient, I computed the index using empirical numbers I got by right-clicking and MsgBox
	lNum    := Floor(lOffset / 14) + 1		;so long as the actual line height and first offset don't change, this is the index.  It works.

				
	LBindex := LBEX_ItemFromPoint(HLB, X, Y)
	LBstr	:= LBEX_GetText(HLB,LBindex)

	MsgBox, GuiContextMenu called with %A_GuiControl% and %A_EventInfo%, X= %A_GuiX% Y= %A_GuiY% line = %lNum%   HLB = %HLB% LBindex = %LBindex% LBstr = %LBstr%
	return
}
I get the same results as before. HLB is some giant number, LBindex is 65544, and LBstr is empty.
No clue as to where to go from here.

EDIT: The problem is with LBEX_ItemFromPoint(). If I use my computed lNum instead of LBindex for calling GetText, , I get the desired string as a result.
just me
Posts: 9504
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Can i detect a right-click on a listbox item?

15 Jan 2016, 04:02

A window handle (HWND) can be used as an unique numeric identifier valid for the whole lifetime of a control (i.e. a child window). You can get it using the HwndOutputVar with Gui, ..., Add, ... or Hwnd sub-command of GuiControlGet, ....

To get it working as you expect you need to pass coordinates relative to the client area of the ListBox to LBEX_ItemFromPoint(). The coordinates provided as A_GuiX and A_GuiY within the GuiContextMenu label/function are relative to the upper-left corner of the window which is the parent GUI in this case.

Here's a modified LBEX_ItemFromCursor() function which will use the current cursor coordinates and do the required conversion internally:

Code: Select all

LBEX_ItemFromCursor(HLB) {
   VarSetCapacity(Point, 8, 0) ; POINT structure -> msdn.microsoft.com/en-us/library/dd162805(v=vs.85).aspx
   DllCall("GetCursorPos", "Ptr", &Point) ; -> msdn.microsoft.com/en-us/library/ms648390(v=vs.85).aspx
   DllCall("ScreenToClient", "Ptr", HLB, "Ptr", &Point) ; -> msdn.microsoft.com/en-us/library/dd162952(v=vs.85).aspx
   X := NumGet(Point, 0, "UShort") ; only 16 bits are used by LB_ITEMFROMPOINT
   Y := NumGet(Point, 4, "UShort") << 16 ; only 16 bits are used by LB_ITEMFROMPOINT
   SendMessage, 0x01A9, 0, % (X + Y), , ahk_id %HLB% ; LB_ITEMFROMPOINT -> msdn.microsoft.com/en-us/library/bb761323(v=vs.85).aspx
   If (ErrorLevel & 0xFFFF0000) ; the HIWORD of the return value is one if the cursor is outside the client area.
      Return 0
   Return (ErrorLevel & 0xFFFF) + 1 ; the return value contains the 0-based index of the item in the LOWORD.
}
BTW: HiEdit is indeed a powerful third-party edit control, but as far as I remember it's 32-bit only.
wdmodlin
Posts: 150
Joined: 16 Dec 2015, 02:42

Re: Can i detect a right-click on a listbox item?

15 Jan 2016, 09:17

I much prefer the change to a single-valued return, with 0 as the failure indicator. That is a good improvement.

The coordinates I am using are the ones supplied as arguments to the GuiContextMenu() subroutine when the control is right clicked. The values automatically generated by the system for that control.

It seems odd for them to supply coordinates that are not in the correct reference frame for other functions related to that control.

Your new version corrects for their design error, and Is more useful. Thank you!

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

Re: Can i detect a right-click on a listbox item?

15 Jan 2016, 11:56

The values automatically generated by the system for that control.
No, they are generated by AHK relative to the whole area of the GUI/window containing the control. It's the window whose ID would be returned in OutputVarWin.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: domingo, haomingchen1998, ntepa and 96 guests