使用 SetKeyDelay, 0, 0 时 ControlSend 随机发送错误字符(修改和未修改)

ControlSend randomly sending wrong characters (modified and unmodified) when using SetKeyDelay, 0, 0

我正在自己回答这个问题,因为我在整个 Internet 上都看到过这个问题,但几乎没有有用的答案,而且我在 Stack Overflow 上绝对找不到任何解决方案。

示例代码

考虑这段代码,它只写了几行 shell 命令:

^0::
    SetKeyDelay, 0, 0
    myWindow = ahk_exe Notepad.exe
    ControlSend, , set c=".cshrc-andrew.cheong"`n, %myWindow%
    ControlSend, , set v=".vimrc-andrew.cheong"`n, %myWindow%
    ControlSend, , foreach d ( /userhome/andrew.cheong /home/$USER /data/$USER )`n, %myWindow%
    ControlSend, , if ( -e $d/$c ) source $d/$c`n, %myWindow%
    ControlSend, , if ( -e $d/$v ) alias vim "vim -N -u $d/$v"`n, %myWindow%
    ControlSend, , end`n, %myWindow%
    Return

我正在将命令写入记事本以表明它不是仅限于 PuTTy 或 xterm 等终端应用程序的问题。很容易这么想,因为这些应用程序有时会出现滞后行为。

示例输出

特别是在使用 SetKeyDelay, 0, 0 快速 "typing," 时,我会遇到各种奇怪的行为,例如:

很明显这个问题与 Shift 修饰符有关,好像它是随机打开或关闭的。

为什么会发生这种情况,我们该如何解决?

请注意,使用 Send 及其变体时没有问题。该问题特别出现在 ControlSend 中,需要将输入发送到特定控件或未聚焦的 window。

解决方案

将此复制到您的脚本中(来自 AutoHotkey 论坛的用户 RHCP):

pSendChars(string, control := "", WinTitle := "", WinText := "", ExcludeTitle := "", ExcludeText := "")
{
    for k, char in StrSplit(string)
        postmessage, WM_CHAR := 0x102, Asc(char),, %Control%, %WinTitle%, %WinText%, %ExcludeTitle%, %ExcludeText%
    return
}

并像这样使用它:

^0::
    myWindow = ahk_exe Notepad.exe
    line .= "set c="".cshrc-acheong""`n"
    line .= "set v="".vimrc-acheong""`n"
    line .= "foreach d ( /userhome/andrew.cheong /home/cama /home/$USER )`n"
    line .= "    if ( -e $d/$c ) source $d/$c`n"
    line .= "    if ( -e $d/$v ) alias vim ""vim -N -u $d/$v""`n"
    line .= "end`n"
    pSendChars(line, "edit1", myWindow)
    Return

就是这样。

请注意,edit1 是记事本文本控件的名称。将此脚本用于 PuTTy 时,我将其更改为空字符串。使用 AutoHotkey 的 WindowSpy 程序找出您要写入的控件。

为什么

This has come up a few times before. Just to add to what Lexikos wrote, the issue is due to the fact that controlSend uses both post message and sendInput/sendEvent to send keystrokes. This is required as some programs will not correctly interpret the keystrokes unless the sent modifier keys are logically down (sent via sendInput/Event).

Modifier keys (unless explicitly stated e.g. {shitft down}) are sent via sendInput while non-modifers are sent via postMessage. Keys sent via postmessage are sent directly to the window and so have less delay than the other keys/messages. Consequently it's possible for keystroke messages to arrive out of synch resulting in unexpected characters. In your case the capitalised letters require the shift key to be sent via sendInput/Event.

In addition to using keyDelays, you can try controlSetText and posting WM_Char messages. If you're working with a text control i would recommend using controlSetText.

- RHCP on 30 Sep 2013