Page 1 of 1

请问怎样获得某程序托盘右键菜单的状态?

Posted: 09 Feb 2018, 05:11
by ZeronoFreya
比如,右键是这种感觉的
Image
我用sendMessage可以设置他的模式,但怎样判断当前的模式呢?

Re: 请问怎样获得某程序托盘右键菜单的状态?

Posted: 12 Oct 2018, 03:26
by tmplinshi
方法1: 使用 acc.ahk

Code: Select all

MsgBox % ss_isPacMode()

ss_isPacMode() {
	TrayIcon_Button("Shadowsocks.exe", "R") ; 点击托盘图标右键
	WinWait, ahk_class #32768 ahk_exe Shadowsocks.exe,, 2
	if ErrorLevel
		throw "没有找到菜单窗口"

	oAcc := Acc_ObjectFromWindow( WinExist() )
	WinClose
	for i, child in Acc_Children(oAcc)
	{
		if ( child.accName(0) ~= "^(系统代理模式|系統代理模式|Mode)$" )
			return !!(child.accChild(1).accState(1) & 0x10) ; 0x10=STATE_SYSTEM_CHECKED
	}
}
获取菜单项及勾选状态:

Code: Select all

SetBatchLines -1

TrayIcon_Button("Shadowsocks.exe", "R") ; 点击托盘图标右键
WinWait, ahk_class #32768 ahk_exe Shadowsocks.exe,, 2

oAcc := Acc_ObjectFromWindow( WinExist() )
for i, child in Acc_Children(oAcc)
{
	if ( child.accName(0) = "系统代理模式" ) {
		Loop, % child.accChild(1).accChildCount
		{
			itemName := child.accChild(1).accName(A_Index)
			itemState := child.accChild(1).accState(A_Index)
			sChecked := (itemState & 0x10) ? " √" : "" ; 0x10=STATE_SYSTEM_CHECKED
			MenuList .= itemName sChecked "`n"
		}
		WinClose ; 关闭菜单
		MsgBox, % MenuList
		ExitApp
	}
}

方法2:

Code: Select all

SetBatchLines -1

TrayIcon_Button("Shadowsocks.exe", "R") ; 点击托盘图标右键
WinWait, ahk_class #32768 ahk_exe Shadowsocks.exe,, 2

SendMessage, 0x1E1, 0, 0 ; MN_GETHMENU
MenuGetAll_sub(ErrorLevel, "", sContents)
MsgBox, % sContents
ExitApp

; https://autohotkey.com/boards/viewtopic.php?f=6&t=8085
MenuGetAll_sub(menu, prefix, ByRef cmds)
{
	Loop % DllCall("GetMenuItemCount", "ptr", menu)
	{
		VarSetCapacity(itemString, 2000)
		if !DllCall("GetMenuString", "ptr", menu, "int", A_Index-1, "str", itemString, "int", 1000, "uint", 0x400)
			continue
		itemString := StrReplace(itemString, "&")
		itemID := DllCall("GetMenuItemID", "ptr", menu, "int", A_Index-1)
		if (itemID = -1)
		if subMenu := DllCall("GetSubMenu", "ptr", menu, "int", A_Index-1, "ptr")
		{
			MenuGetAll_sub(subMenu, prefix itemString " > ", cmds)
			continue
		}
		sChecked := MI_isChecked(menu, A_Index-1) ? " √" : ""
		cmds .= itemID "`t" prefix RegExReplace(itemString, "`t.*") sChecked "`n"
	}
}

MI_isChecked(hMenu, position){
	nState := DllCall("GetMenuState", "ptr", hMenu, "uint", position, "uint", 0x00000400)
	return !!(nState & 0x00000008) ; MF_CHECKED = 0x00000008
}
TrayIcon: https://autohotkey.com/boards/viewtopic.php?t=1229
Acc: https://autohotkey.com/boards/viewtopic.php?t=26201

Re: 请问怎样获得某程序托盘右键菜单的状态?

Posted: 12 Oct 2018, 06:41
by tmplinshi
使用 SetWinEventHook 避免菜单显示出来。

Code: Select all

#NoEnv
SetBatchLines -1

MsgBox % ss_isPacMode()

ss_isPacMode() {
	global g_ss_isPacMode := ""

	; EVENT_SYSTEM_MENUPOPUPSTART := 0x0006
	hook := New WinEventHook(0x0006, 0x0006, "HookProc")

	TrayIcon_Button("Shadowsocks.exe", "R") ; 点击托盘图标右键

	while (g_ss_isPacMode = "")
		Sleep, 10

	return g_ss_isPacMode
}

HookProc(hWinEventHook, event, hWnd, idObject, idChild, dwEventThread, dwmsEventTime) {
	global g_ss_isPacMode

	oAcc := Acc_ObjectFromWindow( hwnd )
	for i, child in Acc_Children(oAcc)
	{
		if ( child.accName(0) ~= "^(系统代理模式|系統代理模式|Mode)$" )
		{
			DllCall("SendMessage", "ptr", hwnd, "uint", WM_CLOSE:=0x10, "ptr", 0, "ptr", 0)
			return g_ss_isPacMode := !!(child.accChild(1).accState(1) & 0x10) ; 0x10=STATE_SYSTEM_CHECKED
		}
	}
}

class WinEventHook
{
	__New(eventMin, eventMax, funcName) {
		this.hWinEventHook := DllCall("SetWinEventHook"
			, "UInt", eventMin
			, "UInt", eventMax
			, "Ptr", 0
			, "Ptr", RegisterCallback(funcName, "F")
			, "UInt", 0
			, "UInt", 0
			, "UInt", 0x0)
	}

	__Delete() {
		DllCall("UnhookWinEvent", "Ptr", this.hWinEventHook)
	}
}

Re: 请问怎样获得某程序托盘右键菜单的状态?

Posted: 03 Nov 2018, 06:07
by nams
这个好,谢谢。。。