我希望每次切换到特定程序时激活声音配置文件,并在每次离开时更改回默认配置文件。 通过单选按钮在GUI中打开此操作。
我创建的解决方法是:
Auto_Ftsps:
gui, Submit, NoHide
While (Rad3==1)
{
Previous_window:= WinActive("A")
Sleep,1000
Current_window:= WinActive("A")
If (Previous_window =Current_window)
{}
Else If (Previous_window !=Current_window)
{
If(WinActive("Fortnite"))
Run_Peace_Profile("Ftsps")
Else
Run_Peace_Profile("Graphic EQ")
}
Sleep,2000
}
return
有更好的方法吗?我查看论坛和教程没有成功。
答案 0 :(得分:2)
OnWin.ahk有点类似于你的方法;它使用SetTimer
来定期检查您向其注册的事件,因此与您的方法不同,它在AHK线程方面是异步的。不要引用我这个,但我认为内部WinWaitActive
也是相似的。
然而,有另一种方法不涉及我们自己定期检查活动窗口,而是允许我们对Windows的“活动窗口更改”事件做出反应 - 一个shell挂钩。通常SetWindowsHookEx
WH_SHELL
将用于此,但我认为甚至不可能单独使用AHK(你必须制作一个DLL),并且它有点复杂以获得一切对。幸运的是有RegisterShellHookWindow
,它允许我们接收shell事件作为Windows消息,而不是将DLL注入其他线程。然后我们可以使用AHK的OnMessage
来对这些消息做出反应,在您的情况下,这意味着有一个函数可以测试wParam
为HSHELL_WINDOWACTIVATED
或HSHELL_RUDEAPPACTIVATED
(即,位3设置)并相应地改变声音配置文件。至于打开/关闭此功能,我们可以让单选按钮的g-label包含用于控制我们是否希望通过(De)RegisterShellHookWindow
接收shell消息的逻辑。
#SingleInstance Force
Gui +AlwaysOnTop +HwndhWnd
Gui Add, Text,, Automatic sound profile change
Gui Add, Radio, gHookRadioHandler Checked, On
Gui Add, Radio, gHookRadioHandler X+, Off
Gui Font,, Consolas
Gui Add, Edit, HwndhLog xm w800 r30 ReadOnly -Wrap -WantReturn
ftspsActive := false
; Get the dynamic identifier for shell messages and assign our callback to handle these messages
SHELL_MSG := DllCall("RegisterWindowMessage", "Str", "SHELLHOOK", "UInt")
OnMessage(SHELL_MSG, Func("ShellCallback"))
if (!SetHook(true)) {
GuiControl,, Off, 1
}
Gui Show
GuiClose() {
ExitApp
}
; Dummy implementation that logs the changes to an edit control for demonstration purposes
Run_Peace_Profile(profile) {
Println("Switched to " profile)
}
; Sets whether the shell hook is registered
SetHook(state) {
global hWnd
static shellHookInstalled := false
if (!shellHookInstalled and state) {
if (!DllCall("RegisterShellHookWindow", "Ptr", hWnd)) {
Println("Failed to register shell hook")
return false
}
Println("Registered shell hook")
shellHookInstalled := true
}
else if (shellHookInstalled and !state) {
if (!DllCall("DeregisterShellHookWindow", "Ptr", hWnd)) {
Println("Failed to deregister shell hook")
return false
}
Println("Deregistered shell hook")
shellHookInstalled := false
}
return true
}
; Radio button handler that controls registration of the sound profile hook
HookRadioHandler() {
state := A_GuiControl == "On"
if (!SetHook(state)) {
GuiControl,, % (state ? "Off" : "On"), 1
}
}
; Shell messages callback
ShellCallback(wParam, lParam) {
; HSHELL_WINDOWACTIVATED = 4, HSHELL_RUDEAPPACTIVATED = 0x8004
if (wParam & 4) {
; lParam = hWnd of activated window
global ftspsActive
WinGet fnHWnd, ID, Fortnite
WinGetTitle t, ahk_id %lParam%
Println("active window: " t)
if (!ftspsActive and fnHWnd = lParam) {
Run_Peace_Profile("Ftsps")
ftspsActive := true
}
else if (ftspsActive and fnHWnd != lParam) {
Run_Peace_Profile("Graphic EQ")
ftspsActive := false
}
}
}
; Prints a line to the logging edit box
Println(s) {
global hLog
static MAX_LINES := 1000, LINE_ADJUST := 200, nLines := 0
; EM_SETSEL = 0xB1, EM_REPLACESEL = 0xC2, EM_LINEINDEX = 0xBB
if (nLines = MAX_LINES) {
; Delete the oldest LINE_ADJUST lines
SendMessage 0xBB, LINE_ADJUST,,, ahk_id %hLog%
SendMessage 0xB1, 0, ErrorLevel,, ahk_id %hLog%
SendMessage 0xC2, 0, 0,, ahk_id %hLog%
nLines -= LINE_ADJUST
}
++nLines
; Move to the end by selecting all and deselecting
SendMessage 0xB1, 0, -1,, ahk_id %hLog%
SendMessage 0xB1, -1, -1,, ahk_id %hLog%
; Add the line
str := "[" A_Hour ":" A_Min "] " s "`r`n"
SendMessage 0xC2, 0, &str,, ahk_id %hLog%
}
请注意,我以编辑控件的形式添加了一些反馈消息,因此这个脚本可以作为一个小型的独立演示。
这种方法的一个可能的缺点来自RegisterShellHookWindow
文档的顶部:
此功能不适用于一般用途。在后续版本的Windows中,它可能会被更改或不可用。
此外,我不知道什么是“粗鲁的应用程序”或为什么他们有自己的常量。 This question表示它与全屏应用程序有关,但问及我看似每个程序HSHELL_RUDEAPPACTIVATED
。
作为替代方案,还有SetWinEventHook
,可以使用EVENT_SYSTEM_FOREGROUND
和WINEVENT_OUTOFCONTEXT
调用来安装AHK的回调,每次前景窗口更改时都会调用该回调。请注意,与RegisterShellHookWindow
方法不同,这将调用到前台的子窗口。
#SingleInstance Force
Gui +AlwaysOnTop
Gui Add, Text,, Automatic sound profile change
Gui Add, Radio, gHookRadioHandler Checked, On
Gui Add, Radio, gHookRadioHandler X+, Off
Gui Font,, Consolas
Gui Add, Edit, HwndhLog xm w800 r30 ReadOnly -Wrap -WantReturn
ftspsActive := false
fcAddr := RegisterCallback(Func("FgCallback"))
if (!SetHook(true)) {
GuiControl,, Off, 1
}
Gui Show
GuiClose() {
ExitApp
}
; Dummy implementation that logs the changes to an edit control for demonstration purposes
Run_Peace_Profile(profile) {
Println("Switched to " profile)
}
; Sets whether the foreground hook is installed
SetHook(state) {
global fcAddr
static hook, fgHookInstalled := false
if (!fgHookInstalled and state) {
; EVENT_SYSTEM_FOREGROUND = 3, WINEVENT_OUTOFCONTEXT = 0
hook := DllCall("SetWinEventHook", "UInt", 3, "UInt", 3, "Ptr", 0, "Ptr", fcAddr, "Int", 0, "Int", 0, "UInt", 0, "Ptr")
if (!hook) {
Println("Failed to set foreground hook")
return false
}
Println("Set foreground hook")
fgHookInstalled := true
}
else if (fgHookInstalled and !state) {
if (!DllCall("UnhookWinEvent", "Ptr", hook)) {
Println("Failed to unset foreground hook")
return false
}
Println("Unset foreground hook")
fgHookInstalled := false
}
return true
}
; Radio button handler that controls installation of the sound profile hook
HookRadioHandler() {
state := A_GuiControl == "On"
if (!SetHook(state)) {
GuiControl,, % (state ? "Off" : "On"), 1
}
}
; Foreground window change callback
FgCallback(hWinEventHook, event, hWnd, idObject, idChild, dwEventThread, dwmsEventTime) {
global ftspsActive
WinGet fnHWnd, ID, Fortnite
WinGetTitle t, ahk_id %hWnd%
Println("fg window: " t)
if (!ftspsActive and fnHWnd = hWnd) {
Run_Peace_Profile("Ftsps")
ftspsActive := true
}
else if (ftspsActive and fnHWnd != hWnd) {
Run_Peace_Profile("Graphic EQ")
ftspsActive := false
}
}
; Prints a line to the logging edit box
Println(s) {
global hLog
static MAX_LINES := 1000, LINE_ADJUST := 200, nLines := 0
; EM_SETSEL = 0xB1, EM_REPLACESEL = 0xC2, EM_LINEINDEX = 0xBB
if (nLines = MAX_LINES) {
; Delete the oldest LINE_ADJUST lines
SendMessage 0xBB, LINE_ADJUST,,, ahk_id %hLog%
SendMessage 0xB1, 0, ErrorLevel,, ahk_id %hLog%
SendMessage 0xC2, 0, 0,, ahk_id %hLog%
nLines -= LINE_ADJUST
}
++nLines
; Move to the end by selecting all and deselecting
SendMessage 0xB1, 0, -1,, ahk_id %hLog%
SendMessage 0xB1, -1, -1,, ahk_id %hLog%
; Add the line
str := "[" A_Hour ":" A_Min "] " s "`r`n"
SendMessage 0xC2, 0, &str,, ahk_id %hLog%
}