-
Notifications
You must be signed in to change notification settings - Fork 513
Keyboard
DirectXTK | DirectXTK12 |
---|
This is a helper for simplified keyboard state tracking modeled after the XNA Game Studio 4 (Microsoft.Xna.Framework.Input
) Keyboard class.
Related tutorial: Mouse and keyboard input
#include <Keyboard.h>
Keyboard is a singleton.
std::unique_ptr<Keyboard> keyboard;
keyboard = std::make_unique<Keyboard>();
For exception safety, it is recommended you make use of the C++ RAII pattern and use a std::unique_ptr
.
For Windows desktop applications, the application needs to make the appropriate calls during the main WndProc message processing:
#include <Windows.h>
#include "Keyboard.h"
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_ACTIVATE:
case WM_ACTIVATEAPP:
Keyboard::ProcessMessage(message, wParam, lParam);
break;
case WM_SYSKEYDOWN:
if (wParam == VK_RETURN && (lParam & 0x60000000) == 0x20000000)
{
// This is where you'd implement the classic ALT+ENTER hotkey for fullscreen toggle
...
}
Keyboard::ProcessMessage(message, wParam, lParam);
break;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
Keyboard::ProcessMessage(message, wParam, lParam);
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
You also want the following in your WndProc
to avoid getting a 'beep' sound for key inputs assumed to be unsupported menu accelerator keys:
case WM_MENUCHAR:
// A menu is active and the user presses a key that does not correspond
// to any mnemonic or accelerator key. Ignore so we don't produce an error beep.
return MAKELRESULT(0, MNC_CLOSE);
For Universal Windows Platform apps, you need to call SetWindow in the appropriate place.
void ViewProvider::SetWindow(CoreWindow^ window)
{
keyboard->SetWindow(window);
}
void ViewProvider::SetWindow(winrt::Windows::UI::Core::CoreWindow window window)
{
keyboard->SetWindow(window);
}
You only get the C++/WinRT
SetWindow
helper function if you have includedwinrt/Windows.UI.Core.h
before you includeKeyboard.h
. Alternatively, you can always just do what the helper does for you:
keyboard->SetWindow(reinterpret_cast<ABI::Windows::UI::Core::ICoreWindow*>(winrt::get_abi(window)));
For Microsoft GDKX when targeting Gaming.Xbox.*.x64, no additional integration is required.
For the Xbox One XDK, you follow the pattern above for Universal Windows Platform (UWP) apps.
GetState queries the current state of the keyboard.
auto kb = keyboard->GetState();
if (kb.Back)
// Backspace key is down
if (kb.W)
// W key is down
if (kb.A)
// A key is down
if (kb.S)
// S key is down
if (kb.D)
// D key is down
if (kb.LeftShift)
// Left shift key is down
if (kb.RightShift)
// Right shift key is down
if ( kb.IsKeyDown( VK_RETURN ) )
// Return key is down
Since Keyboard is a singleton, you can make use of the static method Get if desired:
auto kb = Keyboard::Get().GetState()
The Keys
enumeration and State
structure is a mapping of the virtual keys rather than alphanumeric values, so the number 0 from the keyboard top-row and the 0 on the 10-key keypad are distinct, as are the left shift vs. right shift, etc.
There is no specific virtual key for lower-case (i.e. a
) vs. upper-case (i.e. A
). You have to determine this from tracking the state of CapsLock and Shift (left/right) when you get the A key down. The same is true for +
vs. =
based on NumLock and Shift (left/right).
Due to limitations of C identifiers, the keyboard's top-row digits 1 through 9 and 0 are D1
through D9
and D0
. The number keypad digits are NumPad0
through NumPad9
.
You can count on OemPlus
(+), OemComma
(,), OemMinus
(-), and OemPeriod
(.) being the same for all layouts. XNA Game Studio and the Keyboard enumeration both use US-layout names for some other Oem keys which will vary based on country/region.
Keyboard State | VirtualKey | US Layout Key |
---|---|---|
OemSemicolon | VK_OEM_1 | ; : |
OemQuestion | VK_OEM_2 | / ? |
OemTilde | VK_OEM_3 | ` ~ |
OemOpenBrackets | VK_OEM_4 | [ { |
OemPipe | VK_OEM_5 | \ | |
OemCloseBrackets | VK_OEM_6 | ] } |
OemQuotes | VK_OEM_7 | ' " |
The Windows logo key is visible in the Keyboard state, but you should avoid using it for your control scheme. Windows logo key is normally a system-wide hotkey for Windows per Microsoft Docs. In particular on Windows 10 or later, Windows+G brings up the Xbox Game Bar, Windows+Alt+B is used to toggle HDR mode, Windows+Alt+PrtScn is used to capture a screenshot, and Windows+Alt+R is used to record a video with Xbox Game Bar.
If accidentally pressing the Windows key or triggering the Windows Accessibility hotkeys is a common problem for your control scheme, see Disabling Shortcut Keys in Games.
For more information on virtual keys, see Microsoft Docs.
A common pattern is to trigger an action when a key is pressed or released, but you don't want to trigger the action every single frame if the key is held down for more than a single frame. This helper class simplifies this.
Keyboard::KeyboardStateTracker tracker;
...
auto state = keyboard->GetState();
tracker.Update( state );
if ( tracker.pressed.Space )
// Space was just pressed down
if ( tracker.IsKeyReleased( VK_F1 ) )
// F1 key was just released
The pressed
member of the state tracker indicates each key that was just pushed down since the previous Update
. The helper IsKeyPressed
can be used to check this state.
The released
member of the state tracker indicates each key that was just went up since the previous Update
. The helper IsKeyReleased
can be used to check this state.
You can determine which keys are 'down' vs. 'up' by looking at the original Keyboard::GetState
to get the equivalent of the Mouse/GamePad HELD
vs. UP
tracker states.
When resuming from a pause or suspend, be sure to call Reset on the tracker object to clear the state history.
The Keyboard class should be thread-safe with the exception of the ProcessMessage which should only be called in your windows message loop.
This helper is intended for game controls tied to the keyboard. For chat input and editable text, you should use the platform-specific methods for text input.
Due to some quirks of the platform, If you press both Left & Right Shift keys at the same time, they will both appear down until both are released.
The IsConnected method can be used to test if a keyboard device is present on the system.
Note that on some systems, support for a virtual keyboard is reported as 'true' even without a physical keyboard.
Keep in mind when designing the keyboard controls for your game the different layouts of standard keyboards. In particularly, note the red keys which are in different locations for international keyboards than the traditional English QWERTY keyboard.
The Keyboard class makes use of virtual keys and not scancodes so your code has to be aware of these layout differences.
QWERTY, QWERTZ, AZERTY, QZERTY
DirectX Tool Kit: Keyboard and Mouse support
Using Keyboard Input
All content and source code for this package are subject to the terms of the MIT License.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
- Universal Windows Platform apps
- Windows desktop apps
- Windows 11
- Windows 10
- Windows 8.1
- Xbox One
- x86
- x64
- ARM64
- Visual Studio 2022
- Visual Studio 2019 (16.11)
- clang/LLVM v12 - v18
- MinGW 12.2, 13.2
- CMake 3.20