Input System
Implementation status: Input is one of CNA's broadest implemented namespaces. The Keys enum carries the XNA key vocabulary; GamePad provides rumble, trigger rumble, LED control, hot-plug handling and per-device capability probing; and TouchPanel detects all 10 XNA gesture types. Alpha.1 contains 43 input test sources with 490 statically discoverable GoogleTest-family definitions. One known contract bug is documented under TouchPanel.
Overview
All input classes live in the Microsoft::Xna::Framework::Input namespace and follow a polling model that matches XNA 4.0 exactly: you call GetState() once per frame, store the result, and compare it with the previous frame's state to detect transitions. SDL3 handles the underlying OS events and translates them into the state snapshots that CNA exposes.
The typical per-frame pattern for any device is:
// Declare in your Game class
KeyboardState previousKeyboard;
// In Update()
KeyboardState currentKeyboard = Keyboard::GetState();
if (currentKeyboard.IsKeyDown(Keys::Space) && previousKeyboard.IsKeyUp(Keys::Space)) {
// Space was just pressed this frame
}
previousKeyboard = currentKeyboard; // save for next frame
The same pattern applies to MouseState and GamePadState. Because the state objects are plain value types, storing and copying them is cheap.
Keyboard
The Keyboard class provides a snapshot of every key on the physical keyboard. There is no distinction between left and right modifier keys at the KeyboardState level — use Keys::LeftShift / Keys::RightShift etc. when you need that granularity.
| Member | Description |
|---|---|
Keyboard::GetState() |
Returns a KeyboardState snapshot for the current frame. Call once per frame. |
state.IsKeyDown(Keys k) |
Returns true if the specified key is held down. |
state.IsKeyUp(Keys k) |
Returns true if the specified key is not pressed. |
state.GetPressedKeys() |
Returns a collection of all Keys values that are currently down. |
The Keys enum covers the full keyboard: alphanumeric keys, function keys (F1–F24), numpad keys (NumPad0–NumPad9, Multiply, Add, etc.), navigation keys (Home, End, PageUp, PageDown), and modifier keys (LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt).
Detecting a key press (held last frame, pressed this frame) versus a key release:
// Press: key was up last frame and is down this frame
bool justPressed = current.IsKeyDown(k) && previous.IsKeyUp(k);
// Release: key was down last frame and is up this frame
bool justReleased = current.IsKeyUp(k) && previous.IsKeyDown(k);
Example: WASD movement
#include <Microsoft/Xna/Framework/Input/Keyboard.hpp>
using namespace Microsoft::Xna::Framework::Input;
// In Game::Update(GameTime gameTime)
KeyboardState kb = Keyboard::GetState();
Vector2 velocity = Vector2::Zero;
float speed = 200.0f * (float)gameTime.getElapsedGameTimeProperty().getTotalSecondsProperty();
if (kb.IsKeyDown(Keys::W) || kb.IsKeyDown(Keys::Up)) velocity.Y -= speed;
if (kb.IsKeyDown(Keys::S) || kb.IsKeyDown(Keys::Down)) velocity.Y += speed;
if (kb.IsKeyDown(Keys::A) || kb.IsKeyDown(Keys::Left)) velocity.X -= speed;
if (kb.IsKeyDown(Keys::D) || kb.IsKeyDown(Keys::Right)) velocity.X += speed;
playerPosition += velocity;
Mouse
The Mouse class returns a MouseState containing cursor coordinates in screen pixels, scroll wheel accumulation, and the state of all five buttons. Coordinates are relative to the top-left corner of the game window.
| Member | Type | Description |
|---|---|---|
Mouse::GetState() |
MouseState |
Returns the current mouse state snapshot. |
state.X |
int |
Cursor X position in window pixels. |
state.Y |
int |
Cursor Y position in window pixels. |
state.ScrollWheelValue |
int |
Accumulated scroll wheel delta since game start. |
state.LeftButton |
ButtonState |
Pressed or Released. |
state.RightButton |
ButtonState |
Pressed or Released. |
state.MiddleButton |
ButtonState |
Pressed or Released. |
state.XButton1 |
ButtonState |
First extra side button. |
state.XButton2 |
ButtonState |
Second extra side button. |
Mouse::SetPosition(int x, int y) |
void |
Warps the cursor to the given window coordinates. |
Example: mouse click detection
#include <Microsoft/Xna/Framework/Input/Mouse.hpp>
using namespace Microsoft::Xna::Framework::Input;
MouseState previousMouse;
// In Game::Update(GameTime gameTime)
MouseState mouse = Mouse::GetState();
// Single click: button was released this frame
if (mouse.LeftButton == ButtonState::Released &&
previousMouse.LeftButton == ButtonState::Pressed)
{
// Left click at (mouse.X, mouse.Y)
OnLeftClick(mouse.X, mouse.Y);
}
// Track scroll
int scrollDelta = mouse.ScrollWheelValue - previousMouse.ScrollWheelValue;
if (scrollDelta != 0) {
camera.Zoom(scrollDelta * 0.1f);
}
previousMouse = mouse;
GamePad
The GamePad class supports up to four simultaneously connected controllers via the PlayerIndex enum (One through Four). GamePadState exposes analog sticks, triggers, buttons, and the D-pad. Always check IsConnected before reading state to avoid acting on a zeroed-out snapshot for an absent controller.
Behind the XNA surface sits a substantial SDL3 bridge. It is not a thin passthrough: it handles hot-plug (controllers connected and disconnected mid-session), per-device capability probing (so GamePadCapabilities reports what the specific pad actually has rather than a fixed assumption), and the full haptics surface — standard rumble, trigger rumble on pads that support it, and LED control.
| Member | Type | Description |
|---|---|---|
GamePad::GetState(PlayerIndex) |
GamePadState |
Returns the state for the specified player slot. |
state.IsConnected |
bool |
Whether a controller is plugged in for this slot. |
state.ThumbSticks.Left |
Vector2 |
Left stick, X and Y in −1..1. |
state.ThumbSticks.Right |
Vector2 |
Right stick, X and Y in −1..1. |
state.Triggers.Left |
float |
Left trigger, 0..1. |
state.Triggers.Right |
float |
Right trigger, 0..1. |
state.Buttons |
GamePadButtons |
A, B, X, Y, Start, Back, LeftShoulder, RightShoulder, LeftStick, RightStick — each is ButtonState::Pressed or Released. |
state.DPad |
GamePadDPad |
Up, Down, Left, Right — each is ButtonState::Pressed or Released. |
GamePad::SetVibration(PlayerIndex, float left, float right) |
bool |
Sets rumble motor strength, 0.0–1.0 per motor. Returns false if the controller does not support vibration. |
Dead zone handling
Analog sticks rarely rest at exactly (0, 0) due to hardware tolerances. CNA applies a dead zone before returning stick values. The dead zone mode is passed as an optional second argument to GetState():
| Mode | Behaviour |
|---|---|
GamePadDeadZone::IndependentAxes |
Default. X and Y are clamped and rescaled independently. |
GamePadDeadZone::Circular |
The dead zone is a circle; values inside it are zeroed, the remainder is rescaled radially. |
GamePadDeadZone::None |
Raw values; no dead zone applied. Use when you implement your own dead zone logic. |
Example: analog stick movement
#include <Microsoft/Xna/Framework/Input/GamePad.hpp>
using namespace Microsoft::Xna::Framework::Input;
GamePadState previousPad;
// In Game::Update(GameTime gameTime)
GamePadState pad = GamePad::GetState(PlayerIndex::One);
if (pad.IsConnected) {
float speed = 200.0f * (float)gameTime.getElapsedGameTimeProperty().getTotalSecondsProperty();
// Left stick movement
Vector2 move = pad.ThumbSticks.Left;
move.Y = -move.Y; // XNA Y axis: up is positive on stick, down on screen
playerPosition += move * speed;
// Right trigger as an accelerator
speed *= 1.0f + pad.Triggers.Right;
// A button just pressed
if (pad.Buttons.A == ButtonState::Pressed &&
previousPad.Buttons.A == ButtonState::Released)
{
Jump();
}
// Vibrate on damage
if (playerHit) {
GamePad::SetVibration(PlayerIndex::One, 0.8f, 0.4f);
}
}
previousPad = pad;
Beyond XNA: GamePad EXT methods
XNA 4.0 was designed around the Xbox 360 controller, so its GamePad API has no vocabulary for anything a modern pad does. CNA adds roughly 17 CNAEXT-tagged extension methods to cover the gap: device GUID, light bar colour, trigger vibration, gyroscope and accelerometer readings, battery/power info, touchpad finger positions, and the Steam input handle. The extra buttons modern pads expose — back paddles, Misc1, and the touchpad click — are available too, alongside six Keyboard scancode methods, MouseCursor, and TextInputEXT.
These are outside the XNA surface by construction. CNA's compile-time CNAEXT purity check will flag every use, which is what you want if the goal is a codebase that could also build against real XNA.
TouchPanel
The TouchPanel class exposes multi-touch and gesture recognition. All 10 XNA gesture types are genuinely detected — not stubbed, not partially wired — by a 474-line state machine that tracks contacts over time and computes flick velocity with exponential smoothing. Documented deviations: GetState() is event-driven rather than poll-based, MaximumTouchCount reports 4, and GetState() caps at 8 touches, all intentionally matching FNA.
Known contract bug: TouchCollection reports IsReadOnly == true, but its mutator methods mutate the collection instead of throwing. Code that trusts IsReadOnly as a guarantee will be misled. Do not rely on the flag to protect a collection you hand out.
| Member | Type | Description |
|---|---|---|
TouchPanel::GetState() |
TouchCollection |
Returns all active touch points this frame. |
location.Id |
int |
Unique identifier for this touch contact. |
location.State |
TouchLocationState |
Pressed, Moved, or Released. |
location.Position |
Vector2 |
Screen-space position of this touch point. |
TouchPanel::IsGestureAvailable |
bool |
Returns true when at least one gesture is queued. |
TouchPanel::ReadGesture() |
GestureSample |
Dequeues and returns the next gesture sample. |
All 10 GestureType values are detected: Tap, DoubleTap, Hold, HorizontalDrag, VerticalDrag, FreeDrag, Flick, Pinch, PinchComplete, DragComplete.
Example: gesture reading
#include <Microsoft/Xna/Framework/Input/Touch/TouchPanel.hpp>
using namespace Microsoft::Xna::Framework::Input::Touch;
// Configure which gestures you want before your game loop
TouchPanel::EnabledGestures = GestureType::Tap | GestureType::FreeDrag | GestureType::Flick;
// In Game::Update(GameTime gameTime)
while (TouchPanel::IsGestureAvailable) {
GestureSample gesture = TouchPanel::ReadGesture();
switch (gesture.GestureType) {
case GestureType::Tap:
OnTap(gesture.Position);
break;
case GestureType::Flick:
// gesture.Delta holds the flick velocity
playerVelocity += gesture.Delta * 0.01f;
break;
case GestureType::FreeDrag:
cameraOffset -= gesture.Delta;
break;
default:
break;
}
}
TextInputEXT
TextInputEXT is a CNA extension (not in the original XNA 4.0 API) that captures text entry events from the OS input method, including IME composition on platforms that support it. It is the correct way to implement chat boxes, in-game consoles, or any other free-text input — keyboard polling alone will not handle key repeat, modifier combinations, or international characters correctly.
| Member | Type | Description |
|---|---|---|
TextInputEXT::TextInput |
Event | Fires each time the user produces a printable character. The event provides a char32_t Unicode code point. |
#include <Microsoft/Xna/Framework/Input/TextInputEXT.hpp>
using namespace Microsoft::Xna::Framework::Input;
// In Game::Initialize() or wherever you set up input
TextInputEXT::TextInput += [this](char32_t c) {
if (c == U'\b') { // backspace
if (!inputBuffer.empty()) inputBuffer.pop_back();
} else if (c >= U' ') { // printable
inputBuffer += c;
}
};
// To stop receiving events (e.g. when the text field is dismissed)
// TextInputEXT::StopTextInput();
Call TextInputEXT::StartTextInput() to activate text-entry mode (which may show a soft keyboard on mobile) and StopTextInput() when done. On desktop platforms these calls have no visible effect but are still good practice for cross-platform portability.
Accelerometer (Sensors)
The Accelerometer class provides access to the device accelerometer. It is backed by the real SDL3 sensor API on Android, iOS and desktop, with correct m/s²-to-g conversion and substantial concurrency hardening around the sensor callbacks. Its sibling Gyroscope works the same way. See Sensors for the full Microsoft::Devices::Sensors surface, including which sensors are Android-only.
| Member | Type | Description |
|---|---|---|
Accelerometer::GetState() |
AccelerometerState |
Returns the current accelerometer reading. |
state.Acceleration |
Vector3 |
Acceleration in G-force units along X, Y, Z device axes. |
state.IsActive |
bool |
true if the sensor is available and returning data. |
Implementation status
| Class | Namespace | Status | Notes |
|---|---|---|---|
Keyboard |
Input |
Done | All ~145 Keys members; SDL3 scancode mapping complete. |
Mouse |
Input |
Done | All five buttons, scroll wheel, SetPosition. |
GamePad |
Input |
Done | SDL3 bridge: rumble, trigger rumble, LED, hot-plug, per-device capability probing. All three dead zone modes. |
TouchPanel |
Input.Touch |
Done | All 10 XNA gesture types detected by a 474-line state machine. See the TouchCollection::IsReadOnly bug above. |
TextInputEXT |
Input |
Done | CNA extension (CNAEXT). Unicode char32_t events; IME-safe on desktop. |
Accelerometer |
Devices.Sensors |
Done | Real SDL3 sensor API on Android, iOS and desktop; correct m/s²-to-g conversion. |