Input¶
Input provides key, mouse, gamepad, and action/axis bindings. It exposes both
raw device state and higher-level actions.
Key States¶
keyDown(key)returns true while held.keyPressed(key)returns true for a single frame on press.keyReleased(key)returns true for a single frame on release.
Actions and Axes¶
bindAction(name, key)maps exactly one key to an action. Binding the same name again replaces its previous key.actionDown(name)reports whether that key is held.actionPressed(name)reports whether that key was pressed this frame.bindAxis(name, negative, positive)maps a pair of keys to a float axis.- Binding an axis name again replaces its previous key pair.
axis(name)returns positive-state minus negative-state:-1,0, or1. Opposing held keys cancel to0.
On desktop, addActionBinding() and addAxisBinding() append keyboard or
mouse-button alternatives, while addGamepadActionBinding() and
addGamepadAxisBinding() add standard gamepad sources. Aggregated axes are
clamped to [-1, 1]. Action edges also describe the aggregate: pressing a
second source while an action is held does not emit another press, and a
release is emitted only after every bound source is up. A complete tap within
one frame still reports both edges. See
Desktop Production for raw queries,
deadzones, connection events, and rebinding methods.
Mouse¶
mousePosition()andmouseDelta()scrollDelta()mouseScale(x, y)to scale coordinates to logical space- Mouse buttons use
KeyCode::MouseLeft,MouseRight, andMouseMiddlewith the samekeyDown,keyPressed, andkeyReleasedqueries as keyboard keys.
Hosts normally set mouseScale() from the surface-to-logical-size ratio.
Changing it resets the mouse baseline and delta; non-positive scale components
fall back to 1.0f.
On web builds, a mouse drag that begins on the game canvas continues to update
mousePosition() until its button is released, even while the pointer is over
another page element or outside the canvas. Outside-canvas positions are not
clamped and may be negative or greater than the logical viewport. A press that
begins outside the canvas is not forwarded to the game. Losing browser focus
or hiding the page releases held mouse buttons so they cannot remain stuck.
Touch (iOS and Android)¶
The iOS and Android hosts feed stable platform pointer IDs through these methods:
onTouchBegan(id, x, y)onTouchMoved(id, x, y)onTouchEnded(id, x, y)onTouchCanceled(id)
Per-frame multi-touch state is queryable via Input::touches(), which returns a std::vector<Touch>. Each Touch carries:
id— stable for the lifetime of the touchposition— already scaled to logical space (same convention asmousePosition())isDown,isPressed,isReleased
The first active touch is treated as the primary pointer: its position is
mirrored onto mousePosition() and its press/release drives
KeyCode::MouseLeft. Scenes and UI written against mouse input therefore work
unchanged on touch platforms. Secondary touches do not change mouse state.
When the primary touch ends or is canceled, MouseLeft is released even if
another touch remains. The next active touch becomes primary for subsequent
position updates, but the engine does not synthesize a replacement
MouseLeft press. An ended or canceled touch remains in touches() for its
release frame with isReleased=true, then is removed at the end of the frame.
Use touches() for true multi-touch and gesture continuity.
auto* input = context()->input();
for (const auto& touch : input->touches()) {
if (touch.isPressed) {
// Begin tracking this pointer.
} else if (touch.isReleased) {
// Finish tracking this pointer.
} else if (touch.isDown) {
// Update this pointer's gesture.
}
}
Platform Notes¶
| Platform | Input source |
|---|---|
| Windows/macOS | GLFW keyboard, mouse, scroll, and standard-layout gamepad input |
| Web | Browser keyboard, mouse/pointer, and wheel events through Emscripten/GLFW |
| iOS | UIKit touch events; the primary touch is mirrored as the left mouse button |
| Android | GameActivity multi-touch and standard hardware keys; primary touch mirrors MouseLeft; Back uses the app Back contract; volume/mute/camera buttons remain system-owned |
The web canvas, iOS view, and Android surface scale pointer coordinates into the engine's logical coordinate space. Use the scene/UI conversion helpers in Runtime when moving positions between world and UI space.
Sample Usage¶
auto* input = context()->input();
input->bindAction("activate", snowpulse::KeyCode::Space);
input->bindAxis("horizontal", snowpulse::KeyCode::A, snowpulse::KeyCode::D);
#if defined(SNOW_PLATFORM_DESKTOP)
input->addGamepadActionBinding(
"activate", snowpulse::Input::kAnyGamepad, snowpulse::GamepadButton::A);
input->addGamepadAxisBinding(
"horizontal", snowpulse::Input::kAnyGamepad, snowpulse::GamepadAxis::LeftX);
#endif
if (input->actionPressed("activate")) {
// Perform the bound action once.
}
const float horizontal = input->axis("horizontal");
if (input->keyPressed(snowpulse::KeyCode::MouseLeft)) {
const glm::vec2 pointer = input->mousePosition();
const glm::vec2 motion = input->mouseDelta();
}