Autohotkey:每当我释放按钮时,都会在特定点过早结束长循环。 (如果不寻找循环以外的其他命令)

Autohotkey: Ending a long loop at specific point prematurely whenever I release a button. (if not looking for other command than loop)

问题

你好,我是一般编码的新手,想知道我是否可以过早地结束 autohotkey 中的循环功能。例如在下面的代码中,如果我按下按钮 x 并释放它,它会以一秒的间隔键入 b、s、c、y 和 u。我想要的是,如果我按下 x 一秒钟然后释放 x,它会发送 b 然后终止循环。如果我按 x 两秒钟,它会发送 b 和 s 然后终止,等等。现在的问题是无论我点击 x一两秒等,它完成循环,发送 b、s、c、y 和 u。

*$x::
While(GetKeyState("x", "P"))
{
send b
Sleep 1000
send s
Sleep 1000
send c
Sleep 1000
send y
Sleep 1000
send u
Sleep 1000
}
Return

寻找解决方案

因为我对 autohotkey 和一般编码不熟悉,所以我能想到的就是使用循环,但我认为在这种情况下使用是错误的。我正在寻找解决方案,上面的代码不必是循环(重复)。我想要的只是如果我按下按钮 x 一定秒数,它会相应地发送上面的字母。感谢您阅读这篇相当长的文章 post。

我可以看到一些可能的方法。

1) 第一个也是最糟糕的是在每次发送后有一个 if... 来测试键状态和退出。这是非常重复的,但如果你把它放在一个函数中并只是调用它就不会太糟糕,比如:

*$x::
while (GetKeyState("x", "P")) {
    sendStuff('b')
    sendStuff('s')
    sendStuff('c')
...
}

sendStuff(str) {
    Send str
    if (!GetKeyState("x", "P")) {
        exit
    }
    sleep 1000
}

2) 接下来是继续按原样操作,使用一系列链接命令,并有一个外部的、单独的脚本在 运行 时终止该系列命令,然后重新 Run() 你的脚本,当你想重新启动。常见问题解答中介绍了杀死外部脚本,此处:http://www.autohotkey.com/docs/FAQ.htm#close

那里有三个相关部分,粘贴在这里有点长,但总而言之,您可能对以下命令感兴趣:

; Allow script's hidden main window to be detected.
DetectHiddenWindows On
; Avoid need to specify full path of file.
SetTitleMatchMode 2
; Kill another script: Update params to the script's case sensitive name.
WinClose Script Filemame.ahk - AutoHotkey
; Suspend other script.
PostMessage, 0x111, 65305,,, Script Filename.ahk - AutoHotkey
; Pause other script.
PostMessage, 0x111, 65306,,, Script Filename.ahk - AutoHotkey
; Pause/resume current script on Ctrl+Alt+P
^!p::Pause

3) 下面还有一个更长的代码示例,它描述了取消循环,我相信这是解决这个问题的正确方法,因为虽然它最初可能比较繁琐,但它的可扩展性要高得多,减少代码重复,并允许您在一个地方处理多个循环 entry/exit 条件。

简而言之,就编程风格而言,它是最好的。

将您希望发送的条目 (b, s, c, y, u) 放入字符串、数组或其他可迭代数据结构中,并对其进行迭代,以便您的 while 循环仅发送一个项目并且每次迭代暂停一次。然后,下次您按下热键时,您可以从中断的地方继续循环,也可以重新开始,具体取决于您是否保留指向结构中当前位置的指针。

例如,使用上面的 sendStuff 函数,循环将为您提供非常强大且易于扩展的功能:

*$x::
{
    letters = b,s,c,y,u
    Loop, parse, letters, `,
        sendStuff(%A_LoopField%)
    return
}
x::
  index:="i"
  letters:="l"
  output:="o"
  l:="bscyu"
  i:=(i<o0?++i:1)
  StringSplit,o,l
  send % o%i%
  sleep,1000
return

x Up::i:=0

这个post这么老了,就是忍不住

sendChars := "bscyu"
$x::
i := 1 ; (!i ? 1 : i) ; permits starting where left off.
While (getKeyState("x", "P")) {
    Send % subStr(sendChars, i, 1)
    i := ((i==strLen(sendChars)) ? 1 : (i+1))
    if (getKeyState("x", "P")) { ; why wait if you don't have to.
        Sleep 1000
    }
}

文档指出 While 循环仅在每次迭代开始时进行评估,因此在循环中列出所有键只会发送所有键,然后再次在顶部跳出循环并查看不再按下“x”。