| View previous topic :: View next topic |
| Author |
Message |
Stefaan Guest
|
Posted: Sun Dec 02, 2007 5:46 pm Post subject: How to detect and close a context menu? |
|
|
I'm trying to make a hotkey that sends ctrl v to paste, when I press the left and right mouse buttons together. Now I have:
| Code: | ~LButton & RButton::Send ^v
~RButton & LButton::Send ^v
|
This works great, except if I press the right button first. Then a context menu is shown on releasing this button. I want to close this menu in my script, but I don't know how to detect the menu. Just sending an escape key wouldn't work, because if no menu is shown, this key could trigger an wrong action, like closing the window.
Another possibility would be to send an {alt} key to the window. This also closes a context menu. But this has the same problem: if no menu is shown, the alt will activate the main menu of the window which will prevent typing in the editor.
So I need to find out if a menu is shown before closing it, to prevent side effects if there isn't a menu. Or I need a solution to close the menu that has no side effects when there is no menu.
Can someone help me further?
Thanks |
|
| Back to top |
|
 |
ahklerner
Joined: 26 Jun 2006 Posts: 1205 Location: USA
|
Posted: Sun Dec 02, 2007 5:52 pm Post subject: |
|
|
use a rbutton::return map in your script too..not tested. _________________
 |
|
| Back to top |
|
 |
Stefaan Guest
|
Posted: Sun Dec 02, 2007 7:28 pm Post subject: |
|
|
No, that doesn't work. I first thought it would block the right mouse button but in fact it doesn't do anything.
However, It's not my intention to block the right mouse button. I just want to close the context menu from the script. |
|
| Back to top |
|
 |
HuBa
Joined: 24 Feb 2007 Posts: 172 Location: Budapest, Hungary
|
Posted: Sun Dec 02, 2007 7:47 pm Post subject: |
|
|
| Code: | KeyWait RButton ; Wait for releasing Right button to show menu
Send {Esc} ; This closes the context menu
Send ^v ; Paste
|
|
|
| Back to top |
|
 |
Stefaan Guest
|
Posted: Mon Dec 03, 2007 3:32 pm Post subject: |
|
|
Thanks for your answer, but it's not quite what I'm looking for.
First should be checked if there actually is a menu shown before sending an escape. Else the escape can have unwanted side effects. For instance, if the hotkey is used in a dialog window and no context menu is shown after releasing the right button, the escape would cancel the dialog. |
|
| Back to top |
|
 |
HuBa
Joined: 24 Feb 2007 Posts: 172 Location: Budapest, Hungary
|
Posted: Mon Dec 03, 2007 3:38 pm Post subject: |
|
|
| Stefaan wrote: | Thanks for your answer, but it's not quite what I'm looking for.
First should be checked if there actually is a menu shown before sending an escape. Else the escape can have unwanted side effects. For instance, if the hotkey is used in a dialog window and no context menu is shown after releasing the right button, the escape would cancel the dialog. |
You can build an ahk group of windows and check for it with IfWinActive |
|
| Back to top |
|
 |
Stefaan Guest
|
Posted: Mon Dec 03, 2007 4:13 pm Post subject: |
|
|
| It depends on where I'm clicking in a window if I get a context menu or not. So I can't know before if a context menu will be shown in a given window. Generally, clicking in an edit will show a menu, but clicking next to an edit will not. In the last case the clipboard will be pasted in the active edit, without showing a menu. So I really need to detect if there's a context menu or not. |
|
| Back to top |
|
 |
HuBa
Joined: 24 Feb 2007 Posts: 172 Location: Budapest, Hungary
|
Posted: Mon Dec 03, 2007 4:30 pm Post subject: |
|
|
| Stefaan wrote: | | It depends on where I'm clicking in a window if I get a context menu or not. So I can't know before if a context menu will be shown in a given window. Generally, clicking in an edit will show a menu, but clicking next to an edit will not. In the last case the clipboard will be pasted in the active edit, without showing a menu. So I really need to detect if there's a context menu or not. |
If focused control's name contains "edit" then context menu will be shown.
Just 2 lines of code. |
|
| Back to top |
|
 |
svi
Joined: 09 Oct 2006 Posts: 124 Location: Finland
|
Posted: Mon Dec 03, 2007 5:25 pm Post subject: Re: How to detect and close a context menu? |
|
|
| Stefaan wrote: | | ... I don't know how to detect the menu. ... So I need to find out if a menu is shown before closing it ... |
Use PixelGetColor to test if a menu is shown. The menu color is (probably EDIT: confirmed) in HKEY_CURRENT_USER\Control Panel\Colors\Menu (decimal values).
If I understood you correctly, you want the action to work for the active window no matter where the cursor is.
So using ControlGetFocus wouldn't work (to detect if the control under mouse contains "Edit"), but MouseGetPos, [OutputVarX, OutputVarY, OutputVarWin, OutputVarControl ...] would.
Clicking on title bar also shows a menu. So also caption should be detected (using WM_NCHITTEST), and at least Taskbar.
So PixelGetColor is perhaps simpliest, unless someone shows a smart way ...
EDIT:
PixelGetColor is not useful because the menu background is by default white (I forgot ), same as window background. Using menu border color (HKEY_CURRENT_USER\Control Panel\Colors\ButtonShadow) even with menu color isn't still reliable enough. _________________ Pekka Vartto
Last edited by svi on Wed Dec 05, 2007 9:19 pm; edited 2 times in total |
|
| Back to top |
|
 |
Stefaan Guest
|
Posted: Mon Dec 03, 2007 9:28 pm Post subject: |
|
|
I have found a solution. The windows api function GetGUIThreadInfo can be used to get information about a window and its thread. If no window is specified, the foreground window is used. The GuiThreadInfo struct contains a variable flags. In this flag bit 4 is set if the thread is showing a menu. Using this information I created the following function:
| Code: | closeContextMenu()
{
GuiThreadInfoSize = 48
VarSetCapacity(GuiThreadInfo, 48)
NumPut(GuiThreadInfoSize, GuiThreadInfo, 0)
if not DllCall("GetGUIThreadInfo", uint, 0, str, GuiThreadInfo)
{
MsgBox GetGUIThreadInfo() indicated a failure.
return
}
; GuiThreadInfo contains a DWORD flags at byte 4
; Bit 4 of this flag is set if the thread is in menu mode. GUI_INMENUMODE = 0x4
if (NumGet(GuiThreadInfo, 4) & 0x4)
send {escape}
} |
And I'm using it like this:
| Code: | ~LButton & RButton::
#MaxThreadsPerHotkey 3
Send ^v
return
~RButton & LButton::
#MaxThreadsPerHotkey 3
Send ^v
if waiting
return
waiting = 1
KeyWait, RButton
waiting = 0
Sleep, 50
closeContextMenu()
return
|
|
|
| Back to top |
|
 |
svi
Joined: 09 Oct 2006 Posts: 124 Location: Finland
|
Posted: Wed Dec 05, 2007 9:10 pm Post subject: |
|
|
You showed a smart way, Stefaan, but I'll show a simple way: just send Ctrl + Alt. I think it has no side effects (unless you've defined the combination to trigger an action).
You may have to define the Control key to be the right one: | Code: | | Send {RCtrl DOWN}{Alt DOWN}{Alt UP}{RCtrl UP} |
I should have found this solution earlier, because I've used AltGr to close a menu after accidental press of Apps key (they are handily next to each other) - and AltGr is almost like Ctrl + Alt - , but I didn't first remember it was AltGr. _________________ Pekka Vartto |
|
| Back to top |
|
 |
HuBa
Joined: 24 Feb 2007 Posts: 172 Location: Budapest, Hungary
|
Posted: Wed Dec 05, 2007 9:15 pm Post subject: |
|
|
| Code: | | Send {RCtrl DOWN}{Alt DOWN}{Alt UP}{RCtrl UP} |
Nice trick, I like it! |
|
| Back to top |
|
 |
|