pixelsearch Posted December 9, 2020 Share Posted December 9, 2020 (edited) Hi everybody I don't know if what follows is accurate, but here is what I just tested : 1) WM_CONTEXTMENU is a message that seems always sent by a GUI, as soon as you right-click inside the GUI, no matter you created a contextual menu or not (you should have created one but this is for test purpose) The following script shows this behavior, while displaying in the Console some useful informations : expandcollapse popup#include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> If ProcessExists("SciTE.exe") = 0 Then MsgBox($MB_TOPMOST, "SciTE", _ "Please run from SciTE for ConsoleWrite to display") EndIf $hGUI = GUICreate("", 500, 200) WinSetTitle($hGui, "", "GUI Handle : " & $hGUI & " - right-click inside GUI") $idControl = GUICtrlCreateLabel("", _ 20, 20, 200, 40, BitOr($SS_CENTERIMAGE, $SS_CENTER)) GUICtrlSetBkColor(-1, 0xFFA060) ; orange $hControl = GUICtrlGetHandle($idControl) GUICtrlSetData($idControl, "Label handle : " & $hControl) GUISetState(@SW_SHOW, $hGUI) GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU") While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd GUIDelete($hGUI) ;================================================= Func WM_CONTEXTMENU($hwnd, $iMsg, $wParam, $lParam) #forceref $iMsg Local Static $iCounter = 0 $iCounter += 1 Local $iXPos = BitAND($lParam, 0xFFFF) ; X pos of cursor when right-click (screen coords) Local $iYPos = BitShift($lParam, 16) ; Y pos of the cursor ConsoleWrite("WM_CONTEXTMENU #" & $iCounter & _ " $hwnd = " & $hwnd & " $wParam = " & $wParam & _ " $iXPos = " & $iXPos & " $iYPos = " & $iYPos & @crlf) Return $GUI_RUNDEFMSG EndFunc 2) Be careful if "Case $GUI_EVENT_SECONDARYDOWN" is found in your While... Wend loop, because it seems to always be triggered before WM_CONTEXTMENU Also, it may happen that code within "Case $GUI_EVENT_SECONDARYDOWN" will not be executed completely before WM_CONTEXTMENU is triggered, here is an example : expandcollapse popup#include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <WindowsConstants.au3> If ProcessExists("SciTE.exe") = 0 Then MsgBox($MB_TOPMOST, "SciTE", _ "Please run from SciTE for ConsoleWrite to display") EndIf Global $iFlag = False $hGUI = GUICreate("Right-click inside GUI", 500, 200) GUISetState(@SW_SHOW, $hGUI) GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU") While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_SECONDARYDOWN ConsoleWrite("$GUI_EVENT_SECONDARYDOWN BEGIN" & @crlf) $iFlag = False Sleep(1000) ; <===================================== (change it to 10) $iFlag = True ConsoleWrite("$GUI_EVENT_SECONDARYDOWN END" & @crlf) EndSwitch WEnd GUIDelete($hGUI) ;================================================= Func WM_CONTEXTMENU($hwnd, $iMsg, $wParam, $lParam) #forceref $hwnd, $iMsg, $wParam, $lParam Local Static $iCounter = 0 $iCounter += 1 ConsoleWrite("WM_CONTEXTMENU #" & $iCounter & _ " $iFlag = " & $iFlag & @crlf) Return $GUI_RUNDEFMSG EndFunc Console display with Sleep(1000) in the script above $GUI_EVENT_SECONDARYDOWN BEGIN WM_CONTEXTMENU #1 $iFlag = False $GUI_EVENT_SECONDARYDOWN END If you change the line to Sleep(10), then Console should display : $GUI_EVENT_SECONDARYDOWN BEGIN $GUI_EVENT_SECONDARYDOWN END WM_CONTEXTMENU #1 $iFlag = True Which means that one should always have in mind that (global) variables redefined during "Case $GUI_EVENT_SECONDARYDOWN" may not have the same values inside the WM_CONTEXTMENU() function. Note: this Sleep(1000) or Sleep(10) is just a way of showing that the time (in ms) spent within "Case $GUI_EVENT_SECONDARYDOWN" depends on the code (number of lines, variables definition etc...) found in that part of the script. 3) To prevent this issue, a solution could be to avoid using "Case $GUI_EVENT_SECONDARYDOWN" when WM_CONTEXTMENU is registered in a script, especially if variables are shared between both parts of code. 4) Why do I expose all this ? * Actually my real script has a contextual menu and a "Case $GUI_EVENT_SECONDARYDOWN" * WM_CONTEXTMENU is not registered in the real script, so everything works fine ! But what I would like to do now is to prevent sometimes the context menu to be displayed, when the user right-click duration is more than 250ms (which will be processed differently than displaying a context menu) To do this, I need to register WM_CONTEXTMENU and Return 0 when the user right-click duration is > 250ms (Return 0 means "do not display the context menu") Also, I won't be able to use TimerInit() => TimerDiff() within "Case $GUI_EVENT_SECONDARYDOWN", the reason is explained in 2) So I guess I'll have to choose the solution described in 3) which is : avoid using "Case $GUI_EVENT_SECONDARYDOWN" when WM_CONTEXTMENU is registered in a script. The code moved from "Case $GUI_EVENT_SECONDARYDOWN" to Func WM_CONTEXTMENU() will probably have a different scope. Please comment if you got ideas & remarks, thanks ! Edited December 12, 2020 by pixelsearch Title changed to [Solved] Link to comment Share on other sites More sharing options...
Nine Posted December 9, 2020 Share Posted December 9, 2020 @pixelsearch 1) I think it is quite normal that it is call whenever you right-click, because you may want to create a context-menu on the fly within the WM_CONTEXTMENU proc depending on different conditions (one of my scripts actually is doing so) 2) There should not be any form of Sleep within the GUI loop, especially a large one like 1+ sec. And ideally, you should try to reduce usage of Global as much as possible. Usage of dummy controls can also help synchronizing events, instead of manipulating multiple global variables in the WINPROC. If you could make a snippet of the issue you are having with the 250ms delay, we could try to find a solution. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
pixelsearch Posted December 10, 2020 Author Share Posted December 10, 2020 @Nine: Thanks for your reply 4 hours ago, Nine said: There should not be any form of Sleep within the GUI loop, especially a large one like 1+ sec I did explain the meaning of this "false Sleep", with this sentence, please let me requote it here : 5 hours ago, pixelsearch said: Note: this Sleep(1000) or Sleep(10) is just a way of showing that the time (in ms) spent within "Case $GUI_EVENT_SECONDARYDOWN" depends on the code (number of lines, variables definition etc...) found in that part of the script. As Nine suggested, I'll post now 3 short snippets, without any GDI+ functions, no main GUI, no parent & child GUI etc... just trying to explain the logic of each snippet. 1) First snippet corresponds to an old version of the script, which worked very fine. During the main While... Wend loop, the duration of a right click determines which action will be done : * Short right-click => Save an image * Long right-click ( > 250ms) => Cancel Crop (which was done in a precedent step) No context menu is associated to the GUI, no message registered. This version worked fine during months : #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <WindowsConstants.au3> $hGUI = GUICreate("Test #1 - Right-click (short then long) inside GUI", 500, 200, _ -1, -1, -1, $WS_EX_TOPMOST) GUISetState(@SW_SHOW, $hGUI) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_SECONDARYDOWN Local $aPos = GUIGetCursorInfo($hGUI) If Not IsArray($aPos) Then ContinueLoop Local $hTimer = TimerInit() While $aPos[3] = 1 ; Secondary down (1 if pressed, 0 if not pressed) Sleep(50) ; better than Sleep(100) $aPos = GUIGetCursorInfo($hGUI) Wend Local $fDiff = TimerDiff($hTimer) If $fDiff < 250 Then ConsoleWrite("Right-click < 250ms (save image)" & @crlf) ; code for save image here (after confirmation) Else ConsoleWrite("Right-click >= 250ms (cancel crop)" & @crlf) ; code for cancel crop here EndIf EndSwitch WEnd GUIDelete($hGUI) 2) Second snippet below corresponds to the actual version of the script, which works without any error since November 6th : A context menu is associated to the Gui (in fact it's associated to an image control in the real script, no big deal) A right-click, no matter its duration, displays the context menu where the user can choose to save the image or cancel the crop (plus other context menu options not in this snippet, like Delete, Hide tooltip, Quit preview etc...) No message is registered (i.e no WM_CONTEXTMENU is registered in this actual version) : expandcollapse popup; $iClickStatus discussed here : ; https://www.autoitscript.com/forum/topic/204317-solved-how-to-eat-left-clicks/?do=findComment&comment=1468072 #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <WindowsConstants.au3> $hGUI = GUICreate("Test #2 - Right-click inside GUI", 500, 200, _ -1, -1, -1, $WS_EX_TOPMOST) Local $idContext_Menu = GUICtrlCreateContextMenu() Local $idContext_Save = GUICtrlCreateMenuItem("Save", $idContext_Menu) GUICtrlCreateMenuItem("", $idContext_Menu) Local $idContext_CancelCrop = GUICtrlCreateMenuItem("Cancel Crop", $idContext_Menu) GUISetState(@SW_SHOW, $hGUI) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_SECONDARYDOWN Local $aPos = GUIGetCursorInfo($hGUI) If Not IsArray($aPos) Then ; $iClickStatus = 0 ContinueLoop Else ; $iClickStatus = 2 EndIf Case $idContext_Save ConsoleWrite("Code for Save Image" & @crlf) Case $idContext_CancelCrop ConsoleWrite("Code for Cancel Crop" & @crlf) EndSwitch WEnd GUIDelete($hGUI) 3) Third snippet below is just the bad idea discussed in my 1st post : what would happen if we mix the logic of the 2 scripts above ? * Allow again the user to right-click > 250ms to perform a crop cancel without displaying the context menu * When user right-click < 250ms then the context menu is displayed * Remove the "Crop Cancel" item from the context menu (this last point to be discussed as there's no harm to keep it in) expandcollapse popup#include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <WindowsConstants.au3> Global $bContextDisplay = True $hGUI = GUICreate("Test #3 - Right-click (short then long) inside GUI", 500, 200, _ -1, -1, -1, $WS_EX_TOPMOST) Local $idContext_Menu = GUICtrlCreateContextMenu() Local $idContext_Save = GUICtrlCreateMenuItem("Save", $idContext_Menu) GUISetState(@SW_SHOW, $hGUI) GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU") While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_SECONDARYDOWN $bContextDisplay = True Local $aPos = GUIGetCursorInfo($hGUI) If Not IsArray($aPos) Then ContinueLoop Local $hTimer = TimerInit() While $aPos[3] = 1 ; Secondary down (1 if pressed, 0 if not pressed) Sleep(50) ; better than Sleep(100) $aPos = GUIGetCursorInfo($hGUI) Wend Local $fDiff = TimerDiff($hTimer) If $fDiff > 250 Then ; Cancel crop $bContextDisplay = False ConsoleWrite("Code for Cancel Crop" & @crlf) EndIf Case $idContext_Save ConsoleWrite("Code for Save Image" & @crlf) EndSwitch WEnd GUIDelete($hGUI) ;================================================= Func WM_CONTEXTMENU($hwnd, $iMsg, $wParam, $lParam) #forceref $hwnd, $iMsg, $wParam, $lParam Local Static $iCounter = 0 $iCounter += 1 ConsoleWrite("WM_CONTEXTMENU #" & $iCounter & @crlf) If $bContextDisplay = False Then Return 0 ; prevents the Context menu to appear Return $GUI_RUNDEFMSG EndFunc As you will notice when you run this silly 3rd script, when the user right-clicks > 250ms, the variable $bContextDisplay never equals to False before WM_CONTEXTMENU() is triggered . In fact, no matter how long the user right-click lasts, the context menu is always displayed, very bad scripting ! Tests show that Case $GUI_EVENT_PRIMARYDOWN is immediately triggered by a right-click, but its inside loop While $aPos[3] = 1 ... Wend will be done "in 2 times" : * After about 60-70ms, Autoit will stop executing it and will trigger WM_CONTEXTMENU() while $bContextDisplay is still equal to True, which will display the context menu (while the user is still right-clicking) : everything is going wrong ! * Then, after WM_CONTEXTMENU() has ended, the loop While $aPos[3] = 1 ... Wend will terminate and now only $bContextDisplay = False, which is much too late as WM_CONTEXTMENU() has already been executed. Moving the While $aPos[3] = 1 ... Wend from "Case $GUI_EVENT_PRIMARYDOWN" to "Func WM_CONTEXTMENU" would be a terrible idea too, because we know that a registered message shouldn't contain any "waiting" code, especially the user could right-click during more than 250ms imho there is no need to try to improve anything. Version #2 above is perfect now, let's forget the "long" right-clicks and the registration of WM_CONTEXTMENU() when "Case $GUI_EVENT_PRIMARYDOWN" is present in a script. Canceling the crop in version #2 is just a click away after the context menu is always displayed. I guess I have some strange thoughts sometimes (lol) but I was a bit surprised, when I started this topic, to notice that not only Case $GUI_EVENT_PRIMARYDOWN was triggered first, then followed by the registered WM_CONTEXTMENU (Nine explained why in his answer) but also to notice that after a bunch of ms (60-70), WM_CONTEXTMENU was triggered when "Case $GUI_EVENT_PRIMARYDOWN" hadn't time enough to set the variable $bContextDisplay to False. Thanks for reading Link to comment Share on other sites More sharing options...
Nine Posted December 10, 2020 Share Posted December 10, 2020 That seems to be working fine. As I said there shouldn't be any form of Sleep (even a small loop within the GUI loop can be calculated as a sleep). So by removing the sleep and creating a pseudo-loop outside the Switch, I think I got the result you were looking for : expandcollapse popup#include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <WindowsConstants.au3> Global $bContextDisplay = False $hGUI = GUICreate("Test #3 - Right-click (short then long) inside GUI", 500, 200, _ -1, -1, -1, $WS_EX_TOPMOST) Local $idContext_Menu = GUICtrlCreateContextMenu() Local $idContext_Save = GUICtrlCreateMenuItem("Save", $idContext_Menu) GUISetState(@SW_SHOW, $hGUI) GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU") Local $hTimer, $aPos, $fDiff While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_SECONDARYDOWN ConsoleWrite("secondary" & @CRLF) $bContextDisplay = True $hTimer = TimerInit() Case $GUI_EVENT_SECONDARYUP $bContextDisplay = False Case $idContext_Save ConsoleWrite("Code for Save Image" & @CRLF) EndSwitch If $bContextDisplay Then $aPos = GUIGetCursorInfo($hGUI) If Not IsArray($aPos) Then $bContextDisplay = False ContinueLoop EndIf If $aPos[3] = 1 Then $fDiff = TimerDiff($hTimer) ConsoleWrite("timer diff " & $fDiff & @CRLF) If $fDiff > 250 Then ; Cancel crop $bContextDisplay = False ConsoleWrite("Code for Cancel Crop" & @CRLF) EndIf EndIf EndIf WEnd GUIDelete($hGUI) ;================================================= Func WM_CONTEXTMENU($hwnd, $iMsg, $wParam, $lParam) #forceref $hwnd, $iMsg, $wParam, $lParam Local Static $iCounter = 0 $iCounter += 1 ConsoleWrite("WM_CONTEXTMENU #" & $iCounter & @CRLF) If Not $bContextDisplay Then Return 0 ; prevents the Context menu to appear Return $GUI_RUNDEFMSG EndFunc ;==>WM_CONTEXTMENU pixelsearch 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
pixelsearch Posted December 10, 2020 Author Share Posted December 10, 2020 (edited) Thanks Nine, very interesting ! Especially I spent some time too this morning working on $GUI_EVENT_SECONDARYUP, leading me to nowhere, because I didn't create a pseudo-loop outside the Switch (like you did). I modified below a couple of lines in your script to solve an issue that may happen : expandcollapse popup#include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <WindowsConstants.au3> Global $bContextDisplay = False $hGUI = GUICreate("Test #4 - Right-click (short then long) inside GUI", 500, 200, _ -1, -1, -1, $WS_EX_TOPMOST) Local $idContext_Menu = GUICtrlCreateContextMenu() Local $idContext_Save = GUICtrlCreateMenuItem("Save", $idContext_Menu) GUISetState(@SW_SHOW, $hGUI) GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU") Local $hTimer, $aPos, $fDiff While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_SECONDARYDOWN ConsoleWrite("--------------" & @CRLF & "secondary down" & @CRLF) $bContextDisplay = True $hTimer = TimerInit() Case $GUI_EVENT_SECONDARYUP ConsoleWrite("secondary up" & @CRLF) $bContextDisplay = False Case $idContext_Save ConsoleWrite("Code for Save Image" & @CRLF) EndSwitch If $bContextDisplay Then $aPos = GUIGetCursorInfo($hGUI) If Not IsArray($aPos) Then $bContextDisplay = False ContinueLoop EndIf If $aPos[3] = 1 Then $fDiff = TimerDiff($hTimer) ; ConsoleWrite("timer diff " & $fDiff & @CRLF) ; If $fDiff > 250 Then ; Cancel crop If $fDiff > 250 And $bContextDisplay Then ; Cancel crop <================= $bContextDisplay = False ConsoleWrite("Code for Cancel Crop" & @CRLF) EndIf EndIf EndIf WEnd GUIDelete($hGUI) ;================================================= Func WM_CONTEXTMENU($hwnd, $iMsg, $wParam, $lParam) #forceref $hwnd, $iMsg, $wParam, $lParam Local Static $iCounter = 0 $iCounter += 1 If Not $bContextDisplay Then ConsoleWrite("WM_CONTEXTMENU #" & $iCounter & " (not displayed)" & @CRLF) Return 0 ; prevents the Context menu to appear Else ConsoleWrite("WM_CONTEXTMENU #" & $iCounter & " (visible)" & @CRLF) $bContextDisplay = False ; <================= Return $GUI_RUNDEFMSG EndIf EndFunc ;==>WM_CONTEXTMENU Let's forget the additional informative ConsoleWrite(s), here is what I added/modified : ; If $fDiff > 250 Then ; Cancel crop If $fDiff > 250 And $bContextDisplay Then ; Cancel crop ... $bContextDisplay = False ; added in Func WM_CONTEXTMENU() If we don't do that (i.e running your script "as-is") then a short right-click would correctly display the context menu : -------------- secondary down WM_CONTEXTMENU #1 (visible) Now if the user doesn't choose any option in the menu but right-clicks again (shortly) in the GUI, the context menu will reappear but... -------------- secondary down WM_CONTEXTMENU #1 (visible) Code for Cancel Crop <============= secondary up -------------- secondary down WM_CONTEXTMENU #2 (visible) Code for Cancel Crop was executed when it shouldn't have been at all. Which leads to another question : where should this "Code for Cancel Crop" be placed in the script ? In fact, could it be placed somewhere else ? Because when you run your original script and right-click > 250ms then the Console displays what follows, while the right mouse button is still pressed : -------------- secondary down Code for Cancel Crop And just for the record, when you now release the right mouse button (after 250ms), then it's interesting to see (at last !) the "WM_CONTEXTMENU #1 (not displayed)" in the Console : -------------- secondary down Code for Cancel Crop WM_CONTEXTMENU #1 (not displayed) secondary up Here again, the "Code for Cancel Crop" shouldn't have been executed so soon, it should be executed only after the user releases the right mouse button Though It may not be a major issue for the user to have his "backed up original uncropped" pic reappear while he is still pressing RMB (I hope it will not be an issue), I'm just wondering if we could avoid it and execute the "Code for Cancel Crop" only after RMB is released (as in the 1st snippet in my 2nd post above, which corresponds to the 1st version of the script, when there was no context menu at all) Thanks a lot, Nine, as you already offered a big help teaching me (and probably other users) to "avoid any form of 'Sleep' within the GUI loop". I knew we had to avoid it absolutely within registered messages functions, but I didn't know it had to be avoided too inside the GUI loop Edited December 10, 2020 by pixelsearch typo Link to comment Share on other sites More sharing options...
Nine Posted December 10, 2020 Share Posted December 10, 2020 Glad I could help. And you are absolutely right about negating $bContextDisplay in WM_CONTEXTMENU. I was also able to replicate the issue you found. Good catch. But I don't think it is necessary to confirm $bContextDisplay in this statement as it has already been checked few lines before. If $fDiff > 250 And $bContextDisplay Then ; Cancel crop It would mean that this block on code could be interrupted in some way. Which I do not see how with this script. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
pixelsearch Posted December 10, 2020 Author Share Posted December 10, 2020 My mind was so filled with the script that I forgot the 'like' button So, negating $bContextDisplay in WM_CONTEXTMENU was a good thing. I wonder why I modified the other line you mentioned. I'll let you know... in case I ever remember the reason ! Nine 1 Link to comment Share on other sites More sharing options...
pixelsearch Posted December 11, 2020 Author Share Posted December 11, 2020 Hi Nine Could you please have a look at the following ? Rule #1 - $GUI_EVENT_SECONDARYDOWN doesn't trigger WM_CONTEXTMENU Rule #2 - WM_CONTEXTMENU is triggered as soon as the user physically releases RMB, never before. Rule #3 - $GUI_EVENT_SECONDARYUP is triggered after WM_CONTEXTMENU has ended, never before. Based on these 3 personal rules, I modified the script, trying a new approach : expandcollapse popup#include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <WindowsConstants.au3> Global $hTimer = 0 $hGUI = GUICreate("Test #5 - Right-click (short then long) inside GUI", 500, 200, _ -1, -1, -1, $WS_EX_TOPMOST) Local $idContext_Menu = GUICtrlCreateContextMenu() Local $idContext_Save = GUICtrlCreateMenuItem("Save", $idContext_Menu) GUISetState(@SW_SHOW, $hGUI) GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU") While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_SECONDARYDOWN ConsoleWrite("--------------" & @CRLF & "secondary down" & @CRLF) $hTimer = TimerInit() Case $GUI_EVENT_SECONDARYUP ConsoleWrite("secondary up" & @CRLF) $hTimer = 0 ; peace of mind Case $idContext_Save ConsoleWrite("Code for Save Image" & @CRLF) EndSwitch WEnd GUIDelete($hGUI) ;================================================= Func WM_CONTEXTMENU($hwnd, $iMsg, $wParam, $lParam) #forceref $hwnd, $iMsg, $wParam, $lParam Local Static $iCounter = 0 $iCounter += 1 If $hTimer Then Local $fDiff = TimerDiff($hTimer) $hTimer = 0 If $fDiff > 250 Then ConsoleWrite("WM_CONTEXTMENU #" & $iCounter & " (not displayed)" & @CRLF) Return 0 ; prevents the context menu to appear EndIf EndIf ConsoleWrite("WM_CONTEXTMENU #" & $iCounter & " (visible)" & @CRLF) Return $GUI_RUNDEFMSG EndFunc ;==>WM_CONTEXTMENU The script above simply shows the difference between a quick right-click (which displays a context menu) and a longer one > 250ms (which doesn't display it) expandcollapse popup#include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <WindowsConstants.au3> Global $hTimer = 0, $idDummy_CancelCrop $hGUI = GUICreate("Test #6 - Right-click (short then long) inside GUI", 500, 200, _ -1, -1, -1, $WS_EX_TOPMOST) $idDummy_CancelCrop = GUICtrlCreateDummy() Local $idContext_Menu = GUICtrlCreateContextMenu() Local $idContext_Save = GUICtrlCreateMenuItem("Save", $idContext_Menu) GUISetState(@SW_SHOW, $hGUI) GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU") While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_SECONDARYDOWN ConsoleWrite("--------------" & @CRLF & "secondary down" & @CRLF) $hTimer = TimerInit() Case $GUI_EVENT_SECONDARYUP ConsoleWrite("secondary up" & @CRLF) $hTimer = 0 ; peace of mind Case $idContext_Save ConsoleWrite("Code for Save Image" & @CRLF) Case $idDummy_CancelCrop ConsoleWrite("Code for Cancel Crop" & @CRLF) EndSwitch WEnd GUIDelete($hGUI) ;================================================= Func WM_CONTEXTMENU($hwnd, $iMsg, $wParam, $lParam) #forceref $hwnd, $iMsg, $wParam, $lParam Local Static $iCounter = 0 $iCounter += 1 If $hTimer Then Local $fDiff = TimerDiff($hTimer) $hTimer = 0 If $fDiff > 250 Then ConsoleWrite("WM_CONTEXTMENU #" & $iCounter & " (not displayed)" & @CRLF) GUICtrlSendToDummy($idDummy_CancelCrop) Return 0 ; prevents the context menu to appear EndIf EndIf ConsoleWrite("WM_CONTEXTMENU #" & $iCounter & " (visible)" & @CRLF) Return $GUI_RUNDEFMSG EndFunc ;==>WM_CONTEXTMENU Script above : after a dummy control has been added, we can trigger this dummy control directly from WM_CONTEXTMENU. The goal was to execute the "Code for Cancel Crop" only after the user released RMB, but never while RMB is still pressed. Please advise if you think something is wrong with this logic or could be improved, Thanks ! Link to comment Share on other sites More sharing options...
Nine Posted December 11, 2020 Share Posted December 11, 2020 Good observations. Your latest code seems optimal. Usage of dummy is a good choice. If $hTimer Then is probably not necessary, but it doesn't hurt “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
pixelsearch Posted December 11, 2020 Author Share Posted December 11, 2020 Thanks Nine ! 2 hours ago, Nine said: If $hTimer Then is probably not necessary, but it doesn't hurt This line is related to Rule #4 that I didn't mention in the precedent post because... it's a looong rule, compared to the 3 other short ones Rule #4 - right clicks inside an already displayed context menu (what a strange idea !) will trigger WM_CONTEXTMENU as many times as right clicks were pressed. When finally the user chooses or not an option in the context menu (closing the context menu) then will follow : => 1 $GUI_EVENT_SECONDARYUP (the "regular" one) => many couples of $GUI_EVENT_SECONDARYDOWN / $GUI_EVENT_SECONDARYUP (as many as stacked right clicks) * With line "If $hTimer Then" and 2 additionals right clicks inside the displayed context menu. Result looks correct : -------------- secondary down WM_CONTEXTMENU #1 (visible) WM_CONTEXTMENU #2 (visible) WM_CONTEXTMENU #3 (visible) secondary up -------------- secondary down secondary up -------------- secondary down secondary up Code for Save Image * Without line "If $hTimer Then" , result looks a bit messy : -------------- secondary down WM_CONTEXTMENU #1 (visible) WM_CONTEXTMENU #2 (not displayed) WM_CONTEXTMENU #3 (not displayed) secondary up -------------- secondary down secondary up Code for Cancel Crop -------------- secondary down secondary up Code for Cancel Crop Code for Save Image Anyway, I guess it won't be that simple in the real script, because of right clicks inside Main gui, then into parent & child Gui's etc... When it will happen, then $hwnd, $wParam and $lParam will heavily be used to know where we came from... even if we absolutely don't know where we're going to ! Thanks again for your help & advices. 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