Sign in to follow this  
Followers 0
Necris

ControlSend, sourcecode?

10 posts in this topic

#1 ·  Posted (edited)

Autoit is a great tool for several diverse tasks. One such task is holding down buttons. I managed to simulate it nicely by changing hold-down time and looping keypresses:
 
 

;;================================================================================
;; Setup and Initialize
;;================================================================================
Opt("SendKeyDelay", 0) ;5 milliseconds - Pause between two consecutive SendKey
Opt("SendKeyDownDelay", 50) ;1 millisecond - The lenght of time the key is down


;;--------------------------------------------------------------------------------
;;  Hotkeys
;;--------------------------------------------------------------------------------
HotKeySet('{END}', 'Quit')


;;--------------------------------------------------------------------------------
;;  Global Variables
;;--------------------------------------------------------------------------------
Global $Exiting = False
Global $ClientHandle


;;================================================================================
;; Main
;;================================================================================

If WinWaitActive("Untitled", "", 10) <> 0 Then
    $ClientHandle = WinGetHandle("")
Else
    MsgBox(4096,"Error","Can't get handle of active window",3)
    Exit 0
EndIf

While WinExists($ClientHandle)
    If $Exiting Then
        Exit 0
    Else
        Sleep(25)
    EndIf
    ControlSend($ClientHandle, "", "", "{F4}")
WEnd
Exit 0

;;--------------------------------------------------------------------------------
;;      Quit()
;;--------------------------------------------------------------------------------
Func Quit()
    $Exiting = Not $Exiting
EndFunc   ;==>Quit

To me, this code should work perfectly, and most of the time it does. After a while though, the mouse cursor starts to flicker, and somehow the shift key is spammed.

I am fairly good at c++ and I have for some time trying to make a program that sends keys to a Direct Input application, I just can't get it right though. The AutoIt Script, however, succedes in doing just that with ControlSend.

 

So, does anyone know how ControlSend does this? Firstly, is AutoIt made in c/c++ or another language? If it is made in any of those, is it known what functions it uses to "ControlSend"?

In C++ I have tried SendInput, SendMessage, SendMessageCallback. For SendInput I tried with both virtual and non-virtual key presses. None of these manages to send keys to the Direct Input application the way ControlSend does it. I would really like to solve this and any input is appriciated.

Edited by Necris

Share this post


Link to post
Share on other sites



Autoit is a great tool for several diverse tasks. One such task is holding down buttons. I managed to simulate it nicely by changing hold-down time and looping keypresses:

 

used send function

https://www.autoitscript.com/autoit3/docs/functions/Send.htm

 

u can used my code

Local $arr[7] = ["{W}", "{D}", "{A}","{S}"] ; keys

While 1
Local $iRandom = Random(0,UBound($arr)-1,1)

Send($arr[$iRandom]) ; keypresses:
Sleep(3000) ; time 3 sec

WEnd

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

That's a lovely story.

 

Not just a story, there are questions too:

"So, does anyone know how ControlSend does this? Firstly, is AutoIt made in c/c++ or another language? If it is made in any of those, is it known what functions it uses to "ControlSend"?"

 

 

The Send function won't work. It has to work on a window without focus.

 

To clarify, I either wan't information that will help me reverse engineer ControlSend in c++, or I would like an UDF similar to ControlSend but where the Shift key don't start spamming. Is there such an UDF? If not, does anyone have any ideas where to start in making one? Why is it that the Shift key starts spamming even though the script I am using don't affect it?

Edited by Necris

Share this post


Link to post
Share on other sites

Not just a story, there are questions too:

There are now, but there were not earlier.

AutoIt is created in C++

I believe SendInput function would be used for AutoIt Send() function but I doubt it for ControlSend(), I believe it would be SendMessage, using both the WM_KEYDOWN and WM_KEYUP messages.

I did make it once while learning C++ but was a couple of years ago and never really used it beyond testing as AutoIt was much simpler.

How is it that you determine the shift key is "spammed"?

1 person likes this

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

There are now, but there were not earlier.

AutoIt is created in C++

I believe SendInput function would be used for AutoIt Send() function but I doubt it for ControlSend(), I believe it would be SendMessage, using both the WM_KEYDOWN and WM_KEYUP messages.

I did make it once while learning C++ but was a couple of years ago and never really used it beyond testing as AutoIt was much simpler.

How is it that you determine the shift key is "spammed"?

 

Yeah, sorry about that. While fiddeling with the code section of my post I somehow accidentaly posted it.

I'm almost sure that ControlSend don't use SendMessage, since earlier today I failed to send input to an application to it, whereas ControlSend succeded. ofcourse, that could have been due to some misstake by me, or simply the application being in another state between the two trials. Just now, I found a post about a simmilar issue as mine, and in that case switching from SendMessage to PostMessage fixed the issue. I'll try that tomorrow.

I know the shift key is affected by my AutoIt script since, after some hours runtime, my typing gets messed up. If I type 50 letters quickly, 35 of them will be capitalized and the rest won't. Sometimes 5 in a row will be in the same state, and sometimes every other will be in a different state than the previous. This only happens when this script have been running for a long time. Also, this is the only script running.

Apparently moddifier keys can be left in a pressed state even while using Send, atleast according to:

'?do=embed' frameborder='0' data-embedContent>>

Alhough, in my case the Shift key "flickers" without even being used in the script.

Edited by Necris

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

It is possible that the shift key is getting stuck some how, not by the script, well partly by the script I suppose.

I imagine during your typing you are using the shift key, say you press shift down and your script sends some text to your target control while it is, or the shift up is missed while script is processing another key send event. I don't know exactly the ins and out of why something like that might happen, it just feels like there might be undefined behaviour while input from multiple locations are being processed simultaneously!

Just a thought.

EDIT:

You might test it, when the problem starts next, open up some window and type only in lower case to see if the problem persists.

Edited by JohnOne

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

It is possible that the shift key is getting stuck some how, not by the script, well partly by the script I suppose.

I imagine during your typing you are using the shift key, say you press shift down and your script sends some text to your target control while it is, or the shift up is missed while script is processing another key send event. I don't know exactly the ins and out of why something like that might happen, it just feels like there might be undefined behaviour while input from multiple locations are being processed simultaneously!

Just a thought.

EDIT:

You might test it, when the problem starts next, open up some window and type only in lower case to see if the problem persists.

 

After having used the computer for some hours with the script running, the shift spamming started again. During those hours I have used the shift key numerous times. It might be that each press of the shift key have a low probability of causing this behaviour, or maybe it was something else. However, typing to notepad, in strictly lowercase, during this "shift spam" session resulted in something simmilar to this;

AAAAAaaAAaAAaaaAAAaAAaaaAAAAaaaAaaAAaaAAAAa

I did not press and hold the "a" key, I made full pressses.

However, that is no longer an issue since I succeded in emulating "ControlSend" in c++, infact, simulating a key being held down worked better than I have ever managed in AutoIt. You were right about SendMessage would work, I had simply forgotten about using administrator rights.

Both SendMessage and PostMessage works for the specific application. It turns out that simulating a held down key is harder than what it seems at first glance. In case someone might need this in the future I'll share it here.

 

Simply sending a key_down event, pausing, and then sending a key_up holds the key down during the pause.

PostMessage(windowHandle, WM_KEYDOWN, VK_F4, 0);
Sleep(2000);                
PostMessage(windowHandle, WM_KEYUP, VK_F4, 0);

// or

SendMessage(windowHandle, WM_KEYDOWN, VK_F4, 0);
Sleep(2000);                
SendMessage(windowHandle, WM_KEYUP, VK_F4, 0);

But that won't cause applications to behave as you would expect them to while holding down a button. Some might, I did not test that many, but none that I tested "repeated" the keypress (like what is seen while typing and holding down a letter".

 

Instead, the key_down event needs to be looped. Here is a working example.

#include <iostream>
#include <windows.h>
using namespace std;

int main()
{
    HWND windowHandle = FindWindow(NULL, "The complete title of the target app");
    while(!(GetAsyncKeyState(VK_ESCAPE)))
    {
        if(windowHandle != NULL)
        {
            int i = 0;
            while (i < 250)
            {
                SendMessage(windowHandle, WM_KEYDOWN, VK_F4, 0);
                Sleep(40);
                i++;
            }
            SendMessage(windowHandle, WM_KEYUP, VK_F4, 0);
        }
        else
        {
            cout << "Failed, cant find hwnd\n";
            Sleep(5000);
        }
    }
    cout << "Complete\n"; 
    cin.get();
    cin.sync();
    return 0;
}

This will emulate {F4} being held down for ten seconds, released and instantly held down again.

 

Thanks alot for the guidance JohnOne, without you I would not have tested SendMessage() again. The Shift spamming is interesting, but I consider this closed and solved now. 

Edited by Necris

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Ace.

Seems odd though that requiring admin rights is needed, unless of course the window you are sending to was started with admin rights.

EDIT:

I think PostMessage and SendMessage are the same, only one is asynchronous posted to the message queue and returns immediately.

Edited by JohnOne

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites

Search internet for autoit-v3.1.0-src.exe

On AutoIt's forum it has been removed some time ago from archive download section.

There is "srcsendkeys.cpp" where is detailed source of Send/ControlSend ...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0