Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Win32 C++ ListView WM_CONTEXTMENU Issue

I have a ListView with which I'd like to use a context menu that changes depending on selection. I'm making sure that I'm first able to display a menu when the right mouse button has been released (as per normal context menu behaviour).

In my ListView WNDPROC I'm using WM_CONTEXTMENU to display the context menu. The menu however is displayed at the location the cursor began the selection, not at the end.

From the MS documentation:

DefWindowProc generates the WM_CONTEXTMENU message when it processes the WM_RBUTTONUP or WM_NCRBUTTONUP message or when the user types SHIFT+F10. The WM_CONTEXTMENU message is also generated when the user presses and releases the VK_APPS key.

When I inspect the call stack, with a breakpoint in WM_CONTEXTMENU, I see that the message sent prior to WM_CONTEXTMENU was 0x0204 or WM_RBUTTONDOWN containing the coordinates of the cursor at this time. This probably explains the menu location issue, but why would this be happening?

When I hold the RMB down outside of the ListView and release it inside, the context menu still appears and I can see from the call stack that the last message was 0x0205 or WM_RBUTTONUP.

Not sure whether I have something wrong in my code, or I'm not understanding something. Any help on this issue would be greatly appreciated, thanks.

like image 243
Synthetic Ascension Avatar asked Dec 05 '25 18:12

Synthetic Ascension


1 Answers

Rather than relying on the WM_RBUTTON(DOWN|UP) messages to determine the mouse coordinates, the WM_CONTEXTMENU's own lParam gives you the mouse's screen coordinates of the message that generated the WM_CONTEXTMENU. If those coordinates are not what you are expecting, you can use GetMessagePos() instead, which will report the screen coordinates at the time WM_CONTEXTMENU was generated. Either way, you can then convert the screen coordinates into ListView client coordinates using ScreenToClient() or MapWindowPoints().

Just be sure you also handle the case where the popup menu is being invoked by the user via keyboard input rather than mouse click. In that case, the lParam of WM_CONTEXTMENU will carry the screen coordinates [x=-1,y=-1], and you can query the ListView for the position of its selected item(s) using LVM_GETITEMPOSITION or LVM_GETITEMRECT as needed, then convert that position to screen coordinates using ClientToScreen() or MapWindowPoints(), and then display the popup menu at that screen location.

like image 56
Remy Lebeau Avatar answered Dec 08 '25 08:12

Remy Lebeau



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!