Page 1 of 1

Getting the key state in Win32

Posted: Sun Jan 12, 2003 4:38 pm
by jrfritz
I'm programming a key logging program...and I need to get if and what key(s) are pressed. This should be called in the WinProc function....

I don't know how to use GetKeyboardState or GetKeyState....

Re:Getting the key state in Win32

Posted: Sun Jan 12, 2003 5:46 pm
by ark
well, what exactly are you trying to do? if you're trying to figure out what keys are pressed for any window in the entire system, probably the best way would be somewhat difficult (getting it so that your program intercepts keyboard input the way some of those virtual keyboards do). In fact, that's probably the only way that's guaranteed to work for something like that. If you just want to know if a specific key is pressed, then you should use GetAsyncKeyState, not GetKeyState and then test the return value against 0x8000. GetAsyncKeyState and GetKeyState both take an argument which is the virtual key code for the key you want to test (for example, if you want to see if Shift is being pressed at the moment, you use:

if (GetAsyncKeyState(VK_SHIFT) & 0x8000)

The reason for the 0x8000 thing is that GetAsyncKeyState and GetKeyState return a USHORT (16-bit unsigned int), and if the key is pressed then the highest-order bit is set, which is exactly the condition indicated by 0x8000. GetKeyState will tell you whether a given virtual key was pressed when a message was sent to your window, it will not give you the current state of the keyboard. Note that to log generic key presses, you'd have to call GetAsyncKeyState a ridiculous number of times, and by the time they all finish there's no guarantee that you won't miss a key press (I haven't actually tried it, so it might work just fine, but I'd say there's at least some probability that you could miss a key press). Also, your program will have to be a console application or else be multithreaded, otherwise Windows will log it as not responding (you'd have to call GetAsyncKeyState in a basically infinite loop). You could ask Windows to send you timer messages, but the smallest available resolution is something like 52 milliseconds.

You can always test these methods out and see if they work by hitting a key as fast as you possibly can. If you can't make your program miss the keypress after a bunch of tries, then you might assume that it's safe. Of course, there's still no guarantee, but the probability is higher, anyway.

Re:Getting the key state in Win32

Posted: Sun Jan 12, 2003 5:46 pm
by jrfritz
I found some example code that won't work...if I    if (GetAsyncKeyState(VK_F2)) MessageBox("Test","Test", MB_OK, MB_ICONINFORMATION);

I get no message when I press F2.....

Re:Getting the key state in Win32

Posted: Sun Jan 12, 2003 5:49 pm
by jrfritz
That code won't work, Joel....

Re:Getting the key state in Win32

Posted: Sun Jan 12, 2003 6:02 pm
by ark
Apparently, it can't be a console app...this code seems to work fine (I couldn't get it to work as a console app, although I could get it to work as a console app when I tested the left mouse button):

Code: Select all

#include <windows.h>

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uiMsg,
                             WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR pszCmdLine, int nShowCmd)
{
    MSG msg;
    WNDCLASS wndclass;

    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hInstance = hInstance;
    wndclass.lpfnWndProc = MainWndProc;
    wndclass.lpszClassName = "KeyStateTestClass";
    wndclass.lpszMenuName = NULL;
    wndclass.style = 0;

    RegisterClass(&wndclass);

    HWND hwnd = CreateWindow("KeyStateTestClass", "Key Test",
                             WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             NULL, NULL, hInstance, NULL);

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

    return msg.wParam;
}

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uiMsg,
                             WPARAM wParam, LPARAM lParam)
{
    switch(uiMsg)
    {
    case WM_CREATE:
        SetTimer(hwnd, 1, 0, NULL);
        return 0;

    case WM_DESTROY:
        KillTimer(hwnd, 1);
        PostQuitMessage(0);
        return 0;

    case WM_TIMER:
        if (GetAsyncKeyState(VK_F2) & 0x8000)
        {
            MessageBox(hwnd, "Got F2", "Test", MB_OK);
        }

        return 0;
    }

    return ::DefWindowProc(hwnd, uiMsg, wParam, lParam);
}

Re:Getting the key state in Win32

Posted: Sun Jan 12, 2003 6:04 pm
by ark
by the way...I was wrong...GetAsyncKeyState returns a SHORT, not a USHORT

Re:Getting the key state in Win32

Posted: Sun Jan 12, 2003 6:09 pm
by jrfritz
Works...but gives about a ton of Got F2 messages....

Re:Getting the key state in Win32

Posted: Sun Jan 12, 2003 6:10 pm
by jrfritz
And I also need the MessageBox to come up out of the window....like if i'm in another window I need the message box on top of all windows...and need the "Key Test" window hidden....

Re:Getting the key state in Win32

Posted: Sun Jan 12, 2003 6:57 pm
by ark

Code: Select all

#include <windows.h>

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uiMsg,
                             WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR pszCmdLine, int nShowCmd)
{
    MSG msg;
    WNDCLASS wndclass;

    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hInstance = hInstance;
    wndclass.lpfnWndProc = MainWndProc;
    wndclass.lpszClassName = "KeyStateTestClass";
    wndclass.lpszMenuName = NULL;
    wndclass.style = 0;

    RegisterClass(&wndclass);

    HWND hwnd = CreateWindow("KeyStateTestClass", "Key Test",
                             WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             NULL, NULL, hInstance, NULL);

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

    return msg.wParam;
}

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uiMsg,
                             WPARAM wParam, LPARAM lParam)
{
    switch(uiMsg)
    {
    case WM_CREATE:
        SetTimer(hwnd, 1, 0, NULL);
        return 0;

    case WM_DESTROY:
        KillTimer(hwnd, 1);
        PostQuitMessage(0);
        return 0;

    case WM_TIMER:
        if (GetAsyncKeyState(VK_F2) & 0x8000)
        {
            MessageBox(hwnd, "Got F2", "Test", MB_OK | MB_SYSTEMMODAL);
        }

        return 0;
    }

    return ::DefWindowProc(hwnd, uiMsg, wParam, lParam);
}
You'll have to close the program with Ctrl+Alt+Delete. I don't know what to tell you about a bunch of message boxes. If you just want to log the key presses then you may want to simply write to a file every time the condition holds instead of putting up a message box.

Re:Getting the key state in Win32

Posted: Sun Jan 12, 2003 7:08 pm
by jrfritz
Ty....