{"id":110554,"date":"2024-11-21T07:00:00","date_gmt":"2024-11-21T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110554"},"modified":"2024-11-20T19:49:43","modified_gmt":"2024-11-21T03:49:43","slug":"20241121-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20241121-00\/?p=110554\/","title":{"rendered":"How can I detect which menu my item was invoked from?"},"content":{"rendered":"<p>A customer had a Win32 program with a menu bar, a context menu that they display on mouse right-click, and the same context menu that they display on a keyboard-initiated context menu (<kbd>Shift<\/kbd>+<kbd>F10<\/kbd> or the dedicated context menu key on some keyboards), and they all have the same menu item, call it <i>Create bookmark<\/i>. For good measure, let&#8217;s say that they also had a keyboard accelerator for <i>Create bookmark<\/i>.<\/p>\n<p>The customer wanted the <i>Create bookmark<\/i> command to work like this:<\/p>\n<ul>\n<li>If invoked from the menu bar, a keyboard-initiated context menu, or a keyboard accelerator, then create a bookmark at the current selected item.<\/li>\n<li>If invoked from a mouse-initiated context menu, then create a bookmark at the position that the user right-clicked.<\/li>\n<\/ul>\n<p>The <code>wParam<\/code> of the <code>WM_<wbr \/>COMMAND<\/code> message indicates whether the message was initiated from a menu (0) or a keyboard accelerator (1). But nothing that lets you distinguish the three menu sources. So what can we do to tell us the source of the message?<\/p>\n<p>This is just a variation of &#8220;<a title=\"If I register the same shell extension as both a context menu extension and a drag\/drop extension, how do I know which one the system is using?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240701-00\/?p=109947\">If I register the same shell extension as both a context menu extension and a drag\/drop extension, how do I know which one the system is using<\/a>?&#8221; Just that you&#8217;re using menu items instead of COM class IDs.<\/p>\n<p>The solution is the same: Since the system doesn&#8217;t tell you the source of the message, you can just give each source a different ID number. The one on the menu bar could be <code>IDM_<wbr \/>CREATE_<wbr \/>BOOKMARK_<wbr \/>MENUBAR<\/code>, the one on the mouse-triggered context menu could be <code>IDM_<wbr \/>CREATE_<wbr \/>BOOKMARK_<wbr \/>MOUSE\u00adMENU<\/code>, the one on the keyboard-triggered context menu could be <code>IDM_<wbr \/>CREATE_<wbr \/>BOOKMARK_<wbr \/>KEYBOARD\u00adMENU<\/code>, and the one from the keyboard accelerator could be <code>IDM_<wbr \/>CREATE_<wbr \/>BOOKMARK_<wbr \/>KEYBOARD\u00adACCELERATOR<\/code>. Now you can use that number to distinguish each of the sources.\u00b9<\/p>\n<p>Now, since you have only two behaviors, you could collapse it to just two IDs:<\/p>\n<ul>\n<li><code>IDM_<wbr \/>CREATE_<wbr \/>BOOKMARK_<wbr \/>AT_<wbr \/>SELECTION<\/code>.<\/li>\n<li><code>IDM_<wbr \/>CREATE_<wbr \/>BOOKMARK_<wbr \/>AT_<wbr \/>MOUSE<\/code>.<\/li>\n<\/ul>\n<p>But wait, this whole problem could be solved in a simpler way: Make right-clicking the mouse select the clicked-on item! This is what Explorer does, it&#8217;s what edit controls do, it&#8217;s what list view controls do, it&#8217;s pretty much standard behavior across most container controls, analogous to the principle that &#8220;double-clicking should be an extension of single-clicking.&#8221;<\/p>\n<p>Once you make right-clicking select the clicked-on item, then the single menu item can simply create a bookmark at the selection. Furthermore, you no longer have to remember the mouse click location somewhere, to refer back to when the user selects the &#8220;create bookmark at mouse&#8221; command.<\/p>\n<p>\u00b9 I called this the &#8220;<a title=\"If I register the same shell extension as both a context menu extension and a drag\/drop extension, how do I know which one the system is using?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240701-00\/?p=109947\">Fred Tire<\/a>&#8221; solution, but you see this often on URLs: If you want to know which advertising campaign sent a potential customer to your Web site, you can give each campaign a slightly different URL, like <code>https:\/\/contoso.com\/?source=1<\/code>, <code>https:\/\/contoso.com\/?source=2<\/code>, and <code>https:\/\/contoso.com\/?source=3<\/code>. All three of the URLs show the same landing page, but you can use the <code>source=<\/code> to figure out which ad campaign the URL came from.\u00b2<\/p>\n<p>\u00b2 I used to work for a very small company that printed slightly different versions of each advertisement they placed. When somebody called the company, the receptionist asked, &#8220;Can you read me the number in the bottom right corner of the advertisement you saw?&#8221; This was surprisingly effective.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Just give them all different IDs. But this might itself by an XY problem.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-110554","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Just give them all different IDs. But this might itself by an XY problem.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110554","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=110554"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110554\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=110554"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110554"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110554"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}