Search code examples
c++winapisendinput

Issues with SendInput()


I was hoping to get some help with this piece of code.

#include <windows.h>
#include <thread>  

void keyPress(WORD keyCode)
{
    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki.wScan = keyCode;
    input.ki.dwFlags = KEYEVENTF_SCANCODE;

    SendInput(1, &input, sizeof(INPUT));
}

void keyRelease(WORD keyCode)
{
    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki.wScan = keyCode;
    input.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;

    SendInput(1, &input, sizeof(INPUT));
}

void CtrlPress() 
{
    while (true)
    {
        if (GetAsyncKeyState(VK_RBUTTON)) {
            Sleep(1000); 
            keyPress(0x1D); 
            Sleep(3000);
            keyRelease(0x1D);
        }
        else {
            keyRelease(0x1D);;
        }
    }
}

int main() {
    CtrlPress();
}

Essentially, what I want it to do is to press Ctrl 1000ms after I press the right mouse button, and then keep it pressed for 3000ms, and then release it, and loop as long as the right mouse button is held down. I also want the loop to immediately stop and Ctrl to be let go if the right mouse button is let go.

However, something is wrong with the code, as it drastically slows down my PC as-is.


Solution

  • Since you want the Ctrl key to be released immediately when the right mouse button is released, you really shouldn't be using Sleep() to pause the entire 1sec/3secs intervals on each loop iteration while the mouse button is down, otherwise you risk delaying up to 4secs after the mouse button is released before you can do anything again.

    I would use a state machine for something like this, eg:

    #include <windows.h>
    
    void keyPress(WORD keyCode)
    {
        INPUT input;
        input.type = INPUT_KEYBOARD;
        input.ki.wScan = keyCode;
        input.ki.dwFlags = KEYEVENTF_SCANCODE;
    
        SendInput(1, &input, sizeof(INPUT));
    }
    
    void keyRelease(WORD keyCode)
    {
        INPUT input;
        input.type = INPUT_KEYBOARD;
        input.ki.wScan = keyCode;
        input.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
    
        SendInput(1, &input, sizeof(INPUT));
    }
    
    enum myKeyState { IsUp, IsDown, WaitingForPress };
    
    void CtrlPress() 
    {
        myKeyState state = IsUp;
        DWORD startTime = 0;
    
        while (true)
        {
            if (GetAsyncKeyState(VK_RBUTTON) < 0) {
                switch (state) {
                    case IsUp:
                        startTime = GetTickCount();
                        state = WaitingForPress;
                        break;
     
                    case IsDown:
                        if ((GetTickCount() - startTime) >= 3000) {
                            keyRelease(0x1D);
                            startTime = GetTickCount();
                            state = WaitingForPress;
                        } 
                        break;
    
                    case WaitingForPress:
                        if ((GetTickCount() - startTime) >= 1000) {
                            keyPress(0x1D); 
                            startTime = GetTickCount();
                            state = IsDown;
                        } 
                        break;
                }
            }
            else {
                if (state == IsDown) {
                    keyRelease(0x1D);
                    state = IsUp;
                }
            }
            Sleep(0); // to avoid CPU throttling
        }
    }
    
    int main() {
        CtrlPress();
    }
    

    That being said, rather than using GetAsyncKeyState() to poll the mouse status at regular intervals, I would instead suggest you ask the OS to notify you when the mouse status changes. In a console app, you can use SetWindowsHookEx() to install a WH_MOUSE or WH_MOUSE_LL hook for that purpose.