AutoHotkey - 根据单击的菜单项执行操作

时间:2015-02-06 02:28:24

标签: variables menu click autohotkey

我环顾了AHK论坛,谷歌,这里堆栈溢出,找不到任何方法来解决这个问题,所以如果你能想出这个,请提前感谢BIG TIME。我在我的示例中使用记事本,但我正在为复杂的销售点程序编写此脚本。

我想做一些几乎与this完全相同的事情,但是使用下面描述的应用程序菜单而不是按钮。

如果单击某个菜单项,我希望有一个执行操作的脚本。无论是由菜单位置,标签还是其他方式确定都无关紧要。但是,光标位置可能不适合我的需要。

一个简单的例子就是在用记事本中的鼠标选择File-Open时打开一个MsgBox。

我已经实现了一些技术,使我能够在左键单击(按钮,下拉菜单等)后从大多数控制对象中提取变量,但是当我使用应用程序菜单时(例如,在记事本中:文件) -save或file-open)返回一个空字符串。例如:

#z::
  MouseGetPos,,,,Ctrl,2
  ControlGetText, Text,,ahk_id %Ctrl%  
  MouseClick, left
  Sleep 2500
  MsgBox, %Text%

(请注意,我使用了windows-z,以便在每次左键单击后都不返回MsgBox。)

如果在记事本的“文件另存为”对话框中按下取消按钮,将返回“取消”,但如果我从应用程序菜单(文件,编辑,格式等)中选择任何内容时激活它,则不返回任何内容

我知道AHK可以访问这些菜单,因为您可以执行以下操作,从记事本菜单中激活“文件保存”:

WinMenuSelectItem, Untitled - Notepad,File,Save

但是当我使用window spy时,我看到菜单后面的对象,而不是菜单中实际存在的字符串。

这些菜单实际上是单独的窗口,我需要切换到活动状态才能读取吗?或者我想做一些不可能的事情?

提前非常感谢,这让我疯狂!

2 个答案:

答案 0 :(得分:2)

菜单并不容易获取信息,至少不能使用autohotkeys内置命令,您需要使用DllCall来获取所需信息。

我在win7 64b上为你做了一个与记事本配合使用的例子

我在示例中所做的是查找记事本如果不在那里运行它然后获取记事本窗口的ID(hWnd)

当您按 ctrl + LButton 时,使用记事本窗口ID的DllCall到GetMenu来获取菜单句柄。

之后,更多的DllCall用于获取GetMenuItemCount,GetSubMenu和GetMenuItemInfo等内容。

这样做是为了让我们逐个遍历菜单项并获取有关它们的信息,在这个例子中我们得到了项目的状态,特别是高亮状态。

当找到具有突出显示状态的项目时,脚本会存储项目的索引并打破循环。

由于这只是一个例子,所以它只显示带有索引号的字符串消息并发送 LButton

实施例

ifWinNotExist, ahk_class Notepad
{
    Run, notepad.exe
    WinWait, ahk_class Notepad
}
WinGet, hWnd, ID, 


^Lbutton::

hMenu :=DllCall("GetMenu", "Uint", hWnd)

loop % (count := DllCall("GetMenuItemCount", "ptr", hMenu))
{
    menu_index := A_index

    ; Note that menu item positions are zero-based.
    hSubMenu := DllCall("GetSubMenu", "Uint", hMenu, "int", (A_index-1))

    ; Set the capacity of mii to sizeof(MENUITEMINFO)
    VarSetCapacity(mii, A_PtrSize=8 ? (Size:=80) : (Size:=48), 0)
    ; Set the cbSize field to sizeof(MENUITEMINFO)
    NumPut(Size, mii, 0)

    ; Set the mask to whatever you want to retrieve.
    ; In this case I set it to MIIM_STATE=1.
    NumPut(1, mii, 4)

    loop % (subCount := DllCall("GetMenuItemCount", "ptr", hSubMenu))
    {
        Sub_index := A_index

        ; Note that menu item positions are zero-based.
        DllCall("GetMenuItemInfo", "UInt", hSubMenu, "UInt", (A_index-1), "UInt", 1, "UInt", &mii)

        ; Get the state field out of the struct.
        fState := NumGet(mii, 12)

        if (fState & 0x80) ; 0x80 MFS_HILITE | 0x8 MFS_CHECKED
        {
            MenuString := "Found in top #" menu_index " Sub pos #" Sub_index
            break 2
        }
    }
}

if (MenuString)
{
    Tooltip % MenuString
}
else
{
    tooltip no menu item highlighted
}
send {Lbutton}
return

我希望这可以帮助您了解做什么需要做什么,其他可能的DllCalls看看是MenuItemFromPoint,GetMenuString。

这可能需要一段时间才能正确,但是在本例中我已经展示了Dllcalls,我希望你能在论坛上找到其他如何使用autohotkey的例子。

答案 1 :(得分:0)

  • 此AutoHotkey脚本应该执行您所需的操作。
  • 它已经在记事本(Windows 7)上进行了测试,并且应该很容易适应其他使用绝大多数软件中仍然使用的标准上下文菜单的程序。虽然许多程序使用自定义菜单栏,但上下文菜单通常仍然是标准的上下文菜单。
  • 我提供了两个脚本,一个将显示工具提示并阻止触发菜单项,只要按下任何菜单项,这对理解和诊断有用。 第二个脚本将显示工具提示并阻止触发任何菜单项,如果其文本字符串以“打开”开头。
  • 注意:记事本菜单项的文本是 Open... Ctrl+OOpen...[tab]Ctrl+O),而不仅仅是“打开”。

-

;==================================================

;tested on Notepad (Windows 7)
;block any clicks on any menu items when notepad is the active window
;note: to bypass this and click an item anyway, use ctrl+click

;note: requires Acc.ahk library in AutoHotkey\Lib folder
;https://github.com/Drugoy/Autohotkey-scripts-.ahk/blob/master/Libraries/Acc.ahk
;on right of screen right-click Raw, Save target as...

#IfWinActive, ahk_class Notepad
;LButton::
CoordMode, Mouse, Screen
MouseGetPos, , , hWnd
WinGetClass, vWinClass, ahk_id %hWnd%

if vWinClass in #32768
{
vCount++ ;your code here
ToolTip blocked %vCount%, 500, 200 ;your code here
Return
}

SendInput {LButton Down}
KeyWait, LButton

MouseGetPos, vPosX, vPosY, hWnd
WinGetClass, vWinClass, ahk_id %hWnd%

if vWinClass in #32768
{
ControlSend, Dummy, {Click, 0, 0}, ahk_class Notepad

vCount++ ;your code here
ToolTip blocked %vCount%, 500, 200 ;your code here
Return
}

SendInput {LButton Up}
Return
#IfWinActive

;==================================================

;tested on Notepad (Windows 7)
;block any clicks on the 'open' menu item when notepad is the active window
;note: to bypass this and click an item anyway, use ctrl+click

;note: requires Acc.ahk library in AutoHotkey\Lib folder
;https://github.com/Drugoy/Autohotkey-scripts-.ahk/blob/master/Libraries/Acc.ahk
;on right of screen right-click Raw, Save target as...

#IfWinActive, ahk_class Notepad
LButton::
CoordMode, Mouse, Screen
MouseGetPos, , , hWnd
WinGetClass, vWinClass, ahk_id %hWnd%

if vWinClass in #32768
{
    vItemText := ""
    oAcc := Acc_Get("Object", "1", 0, "ahk_id " hWnd)
    Loop, % oAcc.accChildCount
    if (oAcc.accState(A_Index) & 0x80) ;MF_HILITE := 0x80
    if (1, vItemText := oAcc.accName(A_Index))
    break

    if (SubStr(vItemText, 1, 4) = "Open")
    {
    vCount++ ;your code here
    ToolTip blocked %vCount%, 500, 200 ;your code here
    Return
    }
}

SendInput {LButton Down}
KeyWait, LButton

MouseGetPos, vPosX, vPosY, hWnd
WinGetClass, vWinClass, ahk_id %hWnd%

if vWinClass in #32768
{
ControlSend, Dummy, {Click, 0, 0}, ahk_class Notepad

    vItemText := ""
    oAcc := Acc_Get("Object", "1", 0, "ahk_id " hWnd)
    Loop, % oAcc.accChildCount
    if (oAcc.accState(A_Index) & 0x80) ;MF_HILITE := 0x80
    if (1, vItemText := oAcc.accName(A_Index))
    break

    if (SubStr(vItemText, 1, 4) = "Open")
    {
    vCount++ ;your code here
    ToolTip blocked %vCount%, 500, 200 ;your code here
    Return
    }
}

SendInput {LButton Up}
Return
#IfWinActive

;==================================================

注意:
在以下两个链接中发布的代码示例,实现了相关目标 Is it possible to catch the close button and minimize the window instead? AutoHotKey
AutoHotKey: Run code on Window Event (Close)

注意:
下面的链接函数JEE_MenuIsActive可用于检查是否 菜单栏/ sysmenu栏处于活动状态 为了区分标题栏菜单和右键单击上下文菜单 GUI命令:完整的RETHINK - AutoHotkey社区
https://autohotkey.com/boards/viewtopic.php?f=5&t=25893