0

I am searching for the fastest possible way in C to determine if any key on the keyboard has been pressed.

I am not looking for how to determine if a specific key is pressed (in that case, GetAsyncKeyState() would work).

Also, it needs to work in the background, so without the program window having focus (the program will be running in the background).

EDIT: The program will react on every keypress with a sound output. I want it to output a sound everytime I type something (like in Word and such). That's also why it needs to run in the background. I want it to be fast, so I can minimize the delay between keypress and sound output.

EDIT2: I am searching for something else than Windows Hooks. While it does work for getting key presses in the background, I am looking for something that is faster (least delay possible).

For example: GetAsyncKeyState() works for reacting on specific keypresses, while the program window doesn't have focus. I am looking for something like that, but with the ability to react on any key press, not a specific one.

Ascendise
  • 189
  • 1
  • 10
  • 1
    Sounds like a keylogger... What is the problem you need to solve? Why do you need to get keyboard presses? Why do you need to do it from a background process? And why do you need it to be "fast"? – Some programmer dude Sep 08 '20 at 06:36
  • 1
    @Someprogrammerdude I was afraid someone could think that. I want to react to every keyboard press with a sound (like a click). It was an idea I got after I was missing the clicking from my mechanical keyboard while at school. The process has to run in the background, because I want to have the clicking, while using word and such and not only inside that program. It has to be fast, so I can minimize the delay between keypress and sound output. – Ascendise Sep 08 '20 at 06:42
  • 3
    Please [edit] your question to include that information. And for future questions, please tell us about the actual problem you need to solve, asking directly about it (rather than indirectly) is always better an can even give you some surprise solutions you might not have thought about. – Some programmer dude Sep 08 '20 at 06:44
  • @Someprogrammerdude I edited the question to include that information – Ascendise Sep 08 '20 at 06:47
  • 3
    What kind of "fast" are you looking for? Fast to learn? Fast to implement? What level of "fast" do you need? 1% faster than what you have? 200% faster? Faster by a week? What measurement do you use for determining whether an answer provides fast enough an implementation.? What is your current implementation? – Yunnosch Sep 08 '20 at 06:48
  • 1
    I think you are looking for "low latency", which for many is not necessarily the same as "fast". – Yunnosch Sep 08 '20 at 06:49
  • @Yunnosch With fast I mean, with as less delay between pressing a key on the keyboard and getting that information (a key has been pressed) as possible. I tried to make a window, that would be invisible and react on the message WM_KEYDOWN, but that would only work while having focus on the window and not in the background. Another thing I want to try (I didnt find the time to implement it yet) was to use WindowsHooks, but I was reading that it wasnt the most efficient method. – Ascendise Sep 08 '20 at 06:54
  • 1
    Related: https://stackoverflow.com/a/5024886/4123703 – Louis Go Sep 08 '20 at 06:54
  • @LouisGo I dont think that Windows Hooks are the fastest (minimum delay) way to solve that. For example I was able to react on specific keys with GetAsyncKeyState() without the program having focus. – Ascendise Sep 08 '20 at 07:03
  • 1
    @Ascendise for what you are attempting, you definitely need to use a keyboard hook. Either via `SetWindowsHookEx()`, or `RegisterRawInputDevices()`. – Remy Lebeau Sep 08 '20 at 07:26
  • Does this answer your question? [How to detect KeyPress while program is running in background in Win32 C++](https://stackoverflow.com/questions/5024843/how-to-detect-keypress-while-program-is-running-in-background-in-win32-c) – Mathieu Sep 08 '20 at 07:26
  • @RemyLebeau ``RegisterRawInputDevices()`` sounds promising. I will try that out. – Ascendise Sep 08 '20 at 07:36

1 Answers1

1

As comment, you could use RegisterRawInputDevices as this sample.

  1. Create a Message-Only Window.
  2. Set RAWINPUTDEVICE.hwndTarget to the window create in step 1, so that you don't need to focus on the window.
  3. Call GetRawInputData to get the input data.

Sample(removed the error checking):

#include <windows.h>
#include <iostream>
using namespace std;
LRESULT CALLBACK WindProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    if (Msg == WM_INPUT)
    {
        HRAWINPUT hRawInput = (HRAWINPUT)lParam;
        RAWINPUT input = { 0 };
        UINT size = sizeof(input);
        GetRawInputData(hRawInput, RID_INPUT,&input,&size,sizeof(RAWINPUTHEADER));
        
        printf("vkey: %x, flag: %d\n",input.data.keyboard.VKey, input.data.keyboard.Flags);
    }
    return DefWindowProc(hWnd, Msg, wParam, lParam);
}

int main()
{
    WNDCLASSEX wcx = { 0 };
    wcx.cbSize = sizeof(WNDCLASSEX);
    wcx.lpfnWndProc = WindProc;
    wcx.hInstance = GetModuleHandle(NULL);
    wcx.lpszClassName = TEXT("RawInputClass");
    RegisterClassEx(&wcx);
    HWND hWnd = CreateWindowEx(0, TEXT("RawInputClass"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);

    RAWINPUTDEVICE rid = { 0 };
    rid.usUsagePage = 0x01;
    rid.usUsage = 0x06; //keyboard
    rid.dwFlags = RIDEV_INPUTSINK;
    rid.hwndTarget = hWnd;

    RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE));

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}
Drake Wu
  • 6,927
  • 1
  • 7
  • 30
  • I tried your code, but I am getting one compiler error after the error, stating that many macros are undeclared (like WM_INPUT, HRAWINPUT, etc..) But it is finding other macros which are in the same header. Am I missing anything? I even tried to copy your whole code in (I had to make some changes as I am using C not C++). – Ascendise Sep 09 '20 at 08:37
  • 1
    @Ascendise Found the issue with that. I didnt set WINVER and thats why it didnt create the Macro in the header. – Ascendise Sep 09 '20 at 08:50