Andrew Cheong
Andrew Cheong

Reputation: 30273

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

I'm self-answering this question because I've seen it asked all over the Internet, but with few helpful answers, and definitely no resolutions on Stack Overflow that I can find.

Example Code

Consider this code, which simply writes several lines of shell commands:

^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

I'm writing the commands to Notepad to show that it is not an issue limited to terminal applications like PuTTy or xterm. It's easy to think so, since these applications sometimes have laggy behavior.

Example Output

Specifically when using SetKeyDelay, 0, 0 for fast "typing," I get all kinds of weird behavior, like:

It's obvious the issue has something to do with the Shift modifier, as if it's being randomly turned on or off.

Why is this happening, and how do we fix it?

Note that there are no problems when using Send and its variants. The issue specifically arises with ControlSend, which is needed to send inputs to specific controls or to an unfocused window.

Upvotes: 1

Views: 1058

Answers (1)

Andrew Cheong
Andrew Cheong

Reputation: 30273

Solution

Copy this into your script (from user RHCP at AutoHotkey forums):

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
}

And use it like this:

^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

That's it.

Note that edit1 is Notepad's name for its text control. When using this script for PuTTy, I changed it to a blank string. Use AutoHotkey's WindowSpy program to find out the control you wish to write to.

Why

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

Upvotes: 3

Related Questions