How to Detect Keypress in Windows Using C++

Muhammad Husnain Feb 16, 2024
  1. Keyboard Input in Windows Applications
  2. Use GetKeyState to Detect Keypress in Windows Using C++
  3. Use GetAsyncKeyState to Detect Keypress in Windows Using C++
  4. Use SetWindowsHookEx to Detect Keypress in Windows Using C++
  5. Conclusion
How to Detect Keypress in Windows Using C++

Interacting with keyboard events is a fundamental aspect of many applications, from games to system utilities.

In a Windows environment, C++ provides several methods to detect keypress events. These methods allow developers to create dynamic and interactive programs that respond to user input in real time.

In this guide, we will explore different techniques to detect keypress events using C++ in a Windows environment. Each method offers unique capabilities and is suited for various scenarios.

By understanding and implementing these methods, you’ll have the tools to build applications that dynamically respond to user keyboard input, opening up a wide range of possibilities for your C++ projects. Before moving further, we will look at a brief introduction to keyboard input in Windows applications.

Keyboard Input in Windows Applications

The keyboard is used for a variety of purposes, including:

  • Character Input: Text entered into a document or edit box by the user.
  • Keyboard Shortcuts: Using CTRL+O to open a file is an example of a keystroke that invokes application functions.
  • Commands from the Operating System: Using ALT+TAB to switch windows is an example of a keystroke that invokes system functions.

When catering to the keyboard input, one needs to take care of all the cases of a keypress. For example, if the B key is pressed, there can be: B or b.

Furthermore, if the Ctrl key is pressed, pressing the B key will result in the keyboard shortcut Ctrl+B, which is the shortcut command for making text bold.

Virtual-Key Codes

The operating system generates a scan code for a key when pressed. These scan codes vary from one keyboard to the other.

These codes are unique for all the keyboard keys; for example, key-left and key-right have different scan codes. Since these codes are alphanumeric and difficult to memorize, the keyboard device driver translates these scan codes to virtual-key codes, which are device-independent.

The library file WinUser.h defines the constants for all the virtual-key codes except the characters A-Z and the digits 0-9. Their virtual codes map to their ASCII equivalents:

  • Digits 0-9: codes range from 0x30 to 0x39
  • Alphabets A-Z: codes range from 0x41 to 0x5A

For all the other keys, there are constants defined that map to scan codes of those keys; for example, for the left arrow key, the virtual code is VK_LEFT. As discussed above, no virtual codes are defined for the characters with the corresponding ASCII values.

For instance, there is no virtual code for the character B as VK_B. The list showing some of the commonly used virtual codes is shown below:

Virtual Code Scan Code Description
VK_BACK 0x08 BACKSPACE key
VK_TAB 0x09 TAB key
VK_SHIFT 0x10 SHIFT key
VK_CONTROL 0x11 CTRL key
VK_MENU 0x12 ALT key
VK_PAUSE 0x13 PAUSE key
VK_CAPITAL 0x14 CAPS LOCK key
VK_SPACE 0x20 SPACEBAR
VK_NUMPAD0 to VK_NUMPAD9 0x60 - 0x69 Numpad 0-9 key
VK_F1 to VK_F12 0x70 - 0x7B Function key F1 to F12
VK_NUMLOCK 0x90 NUM LOCK key
VK_SCROLL 0x91 SCROLL LOCK key
VK_LSHIFT 0xA0 Left SHIFT key
VK_RSHIFT 0xA1 Right SHIFT key
VK_LCONTROL 0xA2 Left CONTROL key
VK_RCONTROL 0xA3 Right CONTROL key
VK_LMENU 0xA4 Left MENU key
VK_RMENU 0xA5 Right MENU key
VK_ESCAPE 0x1B ESC key

There are many other codes that you can find in this link.

Use GetKeyState to Detect Keypress in Windows Using C++

A message is generated whenever a key is pressed, and those messages are event-driven.

We can get the state of the key pressed using the function GetKeyState(). This function takes a virtual-key code as an argument and returns a flag telling if that key is pressed or not.

The GetKeyState() method is interesting since it returns the status of the virtual keyboard. This virtual state is changed as messages are removed from the queue and are based on the message queue contents.

GetKeyState provides a snapshot of the keyboard when each message was queued when your program processes window messages. GetKeyState reports the keyboard state when the user pushes the mouse button; for example, if the last message in the queue was WM _BUTTONDOWN.

Syntax:

SHORT GetKeyState(int nVirtKey);
  • GetKeyState: A function from the Windows API that allows you to retrieve the status of a virtual key (e.g., a keyboard key).
  • int nVirtKey: The virtual-key code of the key you want to query. This parameter can take values from 1 to 254, representing various keys on the keyboard. These codes are defined in the Windows API header file <winuser.h>.
  • SHORT: The return type of GetKeyState, which is a 16-bit signed integer. The most significant bit (bit 15) indicates whether the key is currently pressed (1) or not (0). The other bits are reserved and generally not used.

Here is an example usage of GetKeyState:

SHORT keyState = GetKeyState(VK_SPACE);
if(keyState & 0x8000) {
    // The space key is currently pressed.
    // Perform some action...
}

In this example, GetKeyState is used to check the state of the space key.

The result is stored in the variable keyState, and then it’s checked to see if the most significant bit is set, indicating that the key is currently pressed. The bit flag 0x8000 determines if the key is currently pressed.

We will build a C++ program that continuously checks the state of a specific key and responds accordingly.

  • Include Necessary Headers
    #include <iostream>
    #include <Windows.h>
    

    We include the necessary headers: iostream for input/output and Windows.h for access to the Windows API.

  • Implement the Main Function
    int main() {
    	while(true) {
    		SHORT keyState = GetKeyState(VK_SPACE);
    		if(keyState & 0x8000) {
    			std::cout << "Space key is pressed." << std::endl;
    		}
    	}
    	return 0;
    }
    

    Here’s a detailed explanation of the code:

    1. We set up an infinite loop using while(true) to continuously monitor the key state.
    2. GetKeyState(VK_SPACE) is used to check the state of the space key (VK_SPACE).
    3. The return value is stored in keyState, which is a 16-bit value. The most significant bit (bit 15) tells us if the key is pressed (1) or not (0).
    4. We perform a bitwise AND operation with 0x8000 to isolate bit 15 and check if it’s set (indicating that the key is pressed).
    5. If the condition is true, we print a message indicating that the space key is pressed.
  • Compile and Run

    Compile the program using your preferred C++ compiler, and run the executable. You should see a message whenever the space key is pressed.

Output:

Space key is pressed.
Space key is pressed.
Space key is pressed.
Space key is pressed.

Example Use Case: Spacebar Detection in a Game

Imagine you’re developing a game, and you want the player’s character to jump whenever the spacebar is pressed. You can use GetKeyState to continuously monitor the spacebar key state and trigger the jump action when it’s detected as pressed.

int main() {
    while(true) {
        SHORT keyState = GetKeyState(VK_SPACE);
        if(keyState & 0x8000) {
            PerformJumpAction(); // Custom function to make the character jump.
        }
    }
    return 0;
}

In this scenario, PerformJumpAction would be a function that you define to handle the jump action of the character.

Use GetAsyncKeyState to Detect Keypress in Windows Using C++

The GetAsyncKeyState function is a Windows API function that allows us to determine whether a specific key is currently pressed or not. It’s a simple yet powerful tool for responding to user input in real-time.

Syntax:

SHORT GetAsyncKeyState(int vKey);

Here, vKey is the virtual-key code of the key you want to check. The function returns a SHORT value, where the most significant bit (bit 15) indicates whether the key is currently pressed (1) or not (0).

Let’s dive into a practical example to demonstrate how to use GetAsyncKeyState effectively.

#include <iostream>
#include <Windows.h>

int main() {
    while (true) {
        if (GetAsyncKeyState(VK_SPACE) & 0x8000) {
            std::cout << "Space key is pressed." << std::endl;
        }
        if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
            std::cout << "Escape key is pressed." << std::endl;
            break; // Exit the loop if the Escape key is pressed
        }
    }
    return 0;
}

In this example, we include the necessary headers for the Windows API (Windows.h) and standard input/output (iostream).

We then enter an infinite loop to continuously check the state of specific keys. Inside the loop, we use GetAsyncKeyState to check the state of the space key (VK_SPACE) and the escape key (VK_ESCAPE).

If the space key is pressed (GetAsyncKeyState(VK_SPACE) & 0x8000 evaluates to true), we print a message indicating that the space key is pressed.

If the escape key is pressed, we print a message and break out of the loop to exit the program.

Output:

Space key is pressed.
Space key is pressed.
Space key is pressed.
Space key is pressed.
Escape key is pressed.

In the example provided, the while(true) loop ensures that we continuously check for keypress events.

GetAsyncKeyState is used to check the state of the specified keys. In this example, we’re checking the space key (VK_SPACE) and the escape key (VK_ESCAPE).

The function returns a 16-bit value. We use bitwise AND (&) with 0x8000 to isolate bit 15 and check if it’s set (key is pressed).

If a key is pressed, we execute the corresponding code block. If the escape key is pressed, we break out of the loop to exit the program.

Use SetWindowsHookEx to Detect Keypress in Windows Using C++

The SetWindowsHookEx is a function provided by the Windows API that enables us to install a hook procedure into the system. A hook is a mechanism that allows an application to intercept events before they reach the target window procedure.

This can be incredibly useful for tasks such as monitoring input events or modifying behavior in response to specific actions.

Syntax of SetWindowsHookEx:

HHOOK SetWindowsHookEx(
int       idHook,
HOOKPROC  lpfn,
HINSTANCE hMod,
DWORD     dwThreadId
);
  • idHook: Specifies the type of hook procedure to be installed. For keyboard events, we use WH_KEYBOARD_LL, which is a low-level keyboard hook.
  • lpfn: Points to the hook procedure, which is a function that will be called whenever the event occurs.
  • hMod: Handle to the DLL containing the hook procedure. For local hook procedures (like in this case), this parameter should be set to NULL.
  • dwThreadId: Specifies the identifier of the thread with which the hook procedure is to be associated. This can be set to 0 to attach the hook to all existing threads.

Example Code: Detecting Keypress With SetWindowsHookEx in C++

Let’s implement a program that uses SetWindowsHookEx to detect the pressing of the 'A' key.

#include <iostream>
#include <Windows.h>

HHOOK keyboardHook;

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
  if (nCode >= 0 && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) {
	  KBDLLHOOKSTRUCT* pKeyStruct = (KBDLLHOOKSTRUCT*)lParam;
	  if (pKeyStruct->vkCode == 'A') {
		  std::cout << "'A' key is pressed." << std::endl;
	  }
  }
  return CallNextHookEx(keyboardHook, nCode, wParam, lParam);
}

int main() {
  keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
  MSG msg;
  while(GetMessage(&msg, NULL, 0, 0)) {
	  TranslateMessage(&msg);
	  DispatchMessage(&msg);
  }
  UnhookWindowsHookEx(keyboardHook);
  return 0;
}

In the example code, the necessary headers (iostream and Windows.h) are included for input and output operations and Windows API functions. The keyboardHook is used, which is a global variable of type HHOOK that will hold the hook handle.

KeyboardProc is the hook procedure. It will be called whenever a keyboard event occurs.

Inside KeyboardProc, we check if the event is a key press (WM_KEYDOWN or WM_SYSKEYDOWN) and if the pressed key is 'A'. If the 'A' key is detected, a message is printed to the console.

In main, we set up a low-level keyboard hook using SetWindowsHookEx. The hook is installed using WH_KEYBOARD_LL as the hook type.

The program then enters a message loop using GetMessage, which keeps the program running. When the user presses any key, the hook procedure (KeyboardProc) is called.

The hook is uninstalled using UnhookWindowsHookEx before the program terminates.

Output:

'A' key is pressed.

Conclusion

This comprehensive guide explores various methods for detecting keypress events in a Windows environment using C++. The three main techniques discussed are:

  • GetKeyState: Provides a snapshot of the keyboard state, suitable for occasional key state checks.
  • GetAsyncKeyState: Allows continuous monitoring of specific keys, ideal for real-time responsiveness in applications like games.
  • SetWindowsHookEx: Enables the setting of system-wide hooks for intercepting events, useful for tasks like input monitoring or behavior modification.

Each method has distinct strengths and is suited for different use cases. By understanding and implementing these techniques, developers can create dynamic and interactive applications tailored to specific requirements.

Muhammad Husnain avatar Muhammad Husnain avatar

Husnain is a professional Software Engineer and a researcher who loves to learn, build, write, and teach. Having worked various jobs in the IT industry, he especially enjoys finding ways to express complex ideas in simple ways through his content. In his free time, Husnain unwinds by thinking about tech fiction to solve problems around him.

LinkedIn