Search code examples
c++winapisendinput

SendInput to Ctrl+C text Doesn't Work When Launched from Hotkey


Currently using this code to Copy selected text in currently open Window in Windows 10. This code is working fine if I run it on its own by when my target program (Notepad) has focus. The selected text in notepad is copied into data variable OK.

wchar_t title[MAX_PATH];
HWND target_window = GetForegroundWindow();
GetWindowText(target_window, title, MAX_PATH);
std::wcout << "Target window is '" << title << "'" << std::endl;

// Send Control + C
int key_count = 4;

INPUT* input = new INPUT[key_count];
for (int i = 0; i < key_count; i++)
{
    input[i].ki.dwFlags = 0;
    input[i].type = INPUT_KEYBOARD;
}

input[0].ki.wVk = VK_CONTROL;
input[0].ki.wScan = MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC);
input[1].ki.wVk = 0x43; // Virtual key code for 'c'
input[1].ki.wScan = MapVirtualKey(0x43, MAPVK_VK_TO_VSC);
input[2].ki.dwFlags = KEYEVENTF_KEYUP;
input[2].ki.wVk = input[0].ki.wVk;
input[2].ki.wScan = input[0].ki.wScan;

input[3].ki.dwFlags = KEYEVENTF_KEYUP;
input[3].ki.wVk = input[1].ki.wVk;
input[3].ki.wScan = input[1].ki.wScan;

if (!SendInput(key_count, (LPINPUT)input, sizeof(INPUT)))
{
    // TODO: error handling
}
else
{
    // not ideal but not sure of another way to wait for SendInput to complete
    Sleep(100); 
    if (OpenClipboard(NULL))
    {
        HGLOBAL hglb = GetClipboardData(CF_UNICODETEXT);
        LPWSTR lpwstr = (LPWSTR)(GlobalLock(hglb));
        std::wstring data(lpwstr);
        GlobalUnlock(hglb);
        CloseClipboard();
        // do something with selected text in data
    }
    else
    {
        // TODO: error handling
    }
}

However, if I launch the exact same code via Hotkey, it doesn't work:

if (RegisterHotKey(
    NULL,
    1,
    MOD_CONTROL | MOD_ALT | MOD_NOREPEAT,
    VK_OEM_2))  // back slash question mark key
{
    std::cout << "Hotkey 'Ctrl+Alt+/' registered, using MOD_NOREPEAT flag\n";
}

MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
    if (msg.message == WM_HOTKEY)
    {
        std::cout << "WM_HOTKEY received\n";

        // Call function to COPY TEXT here

        if (RegisterHotKey(
            NULL,
            1,
            MOD_CONTROL | MOD_ALT | MOD_NOREPEAT,
            VK_OEM_2))  // back slash question mark key
        {
            std::cout << "Hotkey 'Ctrl+Alt+/' registered, using MOD_NOREPEAT flag\n";
        }
    }
}

Now, in both cases, GetWindowText() is showing the title of the program I want to copy text from.

In addition, I wrote a simple test utility to check Ctrl+C is being passed to Window, which it is. It seems like Ctrl+C is being passed, but the copy is not occurring.


Solution

  • Is it possible that Alt is still down because of the hotkey and you are actually sending Ctrl+Alt+C? SendInput inserts the input directly into the global input queue.

    You could try setting a timer in response to the hotkey and call GetAsyncKeyState in the timer handler until all modifier keys are up before generating input.

    A better alternative would be to use UI Automation instead of a hack like this.