更改窗口焦点时,AutoHotKey WinActive返回错误的值



在我的AutoHotKey脚本中,我使用#IfWinActive来检测Roblox窗口是否在焦点上,然后每当鼠标左键单击时按下数字1按钮,如下所示:

#IfWinActive, Roblox
LButton::
MouseClick, Left
SendInput, {1}
return
#IfWinActive

它工作得很好,除了当我从Roblox窗口点击回到另一个窗口时。它仍然会在第一次单击时激发此代码,导致它在Notepad(或我将焦点切换到的任何窗口)中键入数字1

我想,当我点击记事本时,焦点仍然在Roblox窗口上,这就是为什么代码仍然会触发的原因。所以我试着把代码改成这样:

#IfWinActive, Roblox
LButton::
Sleep, 100
if WinActive("Roblox")
{
MouseClick, Left
SendInput, {1}
}
return
#IfWinActive

假设到Sleep完成时,焦点将转移到Notepad窗口,If WinActive("Roblox")将返回false,但它仍然返回true,并在Notepad中键入1

我还尝试使用StartTimer和一个标签,认为Sleep可能不是异步的,但也有同样的问题。

有人知道如何绕过这个问题吗?提前感谢!

这种情况下的主要问题是在按下LButton后立即启动热键,并且Roblox窗口仍然处于活动状态。

我看到的唯一解决方案是在释放LButton时使用波浪号前缀(~)启动热键,以防止AHK阻止按键按下/向上事件:

#IfWinActive, Roblox
~LButton Up:: SendInput, 1
#IfWinActive

有几种方法可以实现这一点。TL;DR需要解决方案,请查看此帖子的黄色部分
首先,我将解决您代码中的问题

  1. MouseClick相对于Click的用法。从技术上讲没有错,但据说Click在某些情况下更可靠,更容易使用。看起来也更干净
  2. 不需要将1封装在{}中,这对您没有任何帮助。在某些情况下,这样做甚至可能产生不想要的行为。在send命令中,{}用于转义具有特殊含义的密钥,或定义不能直接键入的密钥。有关详细信息,请参阅文档
  3. 有一个坏的WinTitle,你正在与之匹配。同样,技术上没有错,但现在你可以匹配任何以Roblox开头的窗口。不应该太难意外地匹配错误的窗口
    一个快速而有效的解决方案是与Roblox窗口的进程名称进行匹配
    所以#IfWinActive, ahk_exe Roblox.exe或if语句中的if (WinActive("ahk_exe Roblox.exe"))(假设这是进程的名称,我不知道)
    对于一种绝对愚蠢的方式,可以与Roblox窗口的hwnd匹配。然而,这可能有点过头了,而且您也不能真正将其与#IfWinActive一起使用。我将在下面写的一个例子将使用这个

然而,通过这种巧妙的重新映射密钥的方法,可以完全避免问题1和2(重新映射几乎就是您在这里所做的)
~LButton::1
好的,为什么这样有效
key::key只是一种简单地进行基本重映射的语法,使用~,我们指定热键在触发时不会被使用。


很酷,但现在谈谈你遇到的实际问题
那么睡觉的东西出了什么问题?既然你正在使用热键,你实际上所做的就是启动热键,等待100毫秒,然后检查Roblox是否处于活动状态。是的,它仍然是活动的,因为从来没有做过任何事情来切换焦点。
如果你不使用左键单击操作,它会起作用,这绝对不是一个好主意。您不希望在热键语句中睡眠。AHK没有真正的多线程,除非你为热键指定了更高的#MaxThreadsPerHotkey,否则在那100ms内,所有后续的热键按压都将被完全忽略
因此,是的,通过指定可以为该热键运行的更多线程,这将使该解决方案发挥作用,但这仍然是一种糟糕的做法。我们可以想出更好的办法。

使用定时器,您可以避免在热键语句中睡觉。听起来你已经试过计时器了,但我不能确定它是否正确,因为没有提供代码,所以我会复习一下:

#IfWinActive, ahk_exe Roblox.exe
~LButton::SetTimer, OurTimersCallbackLabel, -100 ;-100 specifies that it runs ONCE after 100ms has passed
#IfWinActive
OurTimersCallbackLabel:
if (WinActive("ahk_exe Roblox.exe"))
SendInput, 1
return

现在进入真正的解决方案,@user3419297似乎击败了我,就在我写这行文字的时候。

使用按下LButton的向上事件作为热键。

#IfWinActive, ahk_exe Roblox.exe
~LButton Up::SendInput, 1
#IfWinActive

通过这种方式,向下事件已经切换了窗口的焦点,我们的热键甚至不会启动
请注意,不幸的是,在这里我们不能使用我上面描述的key::key重新映射方式。


奖金:

如果按键的向上事件不理想,或者活动窗口的窗口切换被延迟,可以使用以下内容。

RobloxHwnd := WinExist("ahk_exe Roblox.exe")
#If, RobloxUnderMouse()
~LButton::1
#If
RobloxUnderMouse()
{
global RobloxHwnd ;specify that we're using the variable defined outside of this function scope
;could've also ran the code to get Roblox's hwnd here every time, but that would be wasteful
MouseGetPos, , , HwndUnderMouse ;we don't need the first two parameters
return RobloxHwnd == HwndUnderMouse ;are they the same hwnd? (return true or false)
}

在这里,我们首先将Roblox的hwnd存储到变量RobloxHwnd
请注意,在运行此脚本之前,Roblox需要运行,如果重新启动robox,也需要重新启动脚本
因此,添加一些动态更新此变量值的方法会很好,可能需要一些热键。

然后,通过使用#If,每当我们试图启动热键时,我们都会评估一个表达式(在我们的例子中,运行一个函数并评估其返回值)。如果表达式的计算结果为true,我们将启动热键
#If的使用实际上是不推荐的,如果可能的话,最好避免使用。然而,在这么小的脚本中您不会遇到任何问题,因此在这里使用#If将非常方便
如果你有一个更大的脚本,其中有很多代码经常运行,你很可能会遇到问题。

最新更新