Skip to content

input

This package manages user input across keyboard, mouse and gamepad devices. It supports both raw key polling and an abstract, player-centric binding system that decouples physical inputs from logical game actions.

Features:

  • Action system: Maps physical keys to logical Action enums (digital).
  • Axis system: Maps keys and sticks to logical Axis enums (analog).
  • Multi-User: Supports separate bindings for multiple (default: 5) players via PlayerProfile.
  • Hybrid input: Automatically handles switching between keyboard and gamepad, as well as multiplayer input.
  • Mouse utilities: Helpers for easy usage of the mouse inputs (getMousePosition, getScrollY)
  • Key reading: Direct access to key states via isKeyDown, isKeyPressed and isKeyReleased.
  • Cursor control: Functions to lock or hide the system cursor (setCursorLocked, setCursorVisible) (Desktop only)

Action :: enum u8 {
MenuLeft,
MenuRight,
MenuUp,
MenuDown,
// Add more if needed!
}

Abstract digital actions (on/off) that decouple game logic from specific physical keys.


Axis :: enum u8 {
MoveX,
MoveY,
LookX,
LookY,
}

Abstract analog axes (Float -1.0 to 1.0). Used e.g. for movement.


AxisBind :: struct {
source: BindingSource,
scale: f32,
deadzone: f32,
}

Configuration for a single axis binding (e.g., ‘W’ key contributes -1.0 to MoveY).


BindingSource :: union {
KeyCode,
GamepadButton,
GamepadAxis,
}

Represents a single physical input source.


ButtonPressed :: struct {
index: GamepadIndex,
button: GamepadButton,
}

Event payload when a button is pressed down.


ButtonReleased :: struct {
index: GamepadIndex,
button: GamepadButton,
}

Event payload when a button is released.


DPAD_DOWN :: GamepadButton.LeftFaceDown

Alias for LeftFaceDown gamepad button.


DPAD_LEFT :: GamepadButton.LeftFaceLeft

Alias for LeftFaceLeft gamepad button.


DPAD_RIGHT :: GamepadButton.LeftFaceRight

Alias for LeftFaceRight gamepad button.


DPAD_UP :: GamepadButton.LeftFaceUp

Alias for LeftFaceUp gamepad button.


FACE_DOWN :: GamepadButton.RightFaceDown

Alias for RightFaceDown gamepad button (equivalent of “A” on XBOX controllers and “X” on PS controllers).


FACE_LEFT :: GamepadButton.RightFaceLeft

Alias for RightFaceLeft gamepad button (equivalent of “X” on XBOX controllers and ”□” on PS controllers).


FACE_RIGHT :: GamepadButton.RightFaceRight

Alias for RightFaceRight gamepad button (equivalent of “B” on XBOX controllers and ”○” on PS controllers).


FACE_UP :: GamepadButton.RightFaceUp

Alias for RightFaceUp gamepad button (equivalent of “Y” on XBOX controllers and ”∆” on PS controllers).


GamepadAxis :: enum {
None,
LeftStickX,
LeftStickY,
RightStickX,
RightStickY,
LeftTrigger,
RightTrigger,
}

Standard analog axes for a dual-stick controller.


GamepadButton :: enum {
None,
LeftFaceUp,
LeftFaceDown,
LeftFaceLeft,
LeftFaceRight,
RightFaceUp,
RightFaceDown,
RightFaceLeft,
RightFaceRight,
LeftShoulder,
LeftTrigger,
RightShoulder,
RightTrigger,
LeftStickPress,
RightStickPress,
MiddleFaceLeft,
MiddleFaceMiddle,
MiddleFaceRight,
}

Standard physical buttons for a modern controller.


GamepadEvent :: union {
ButtonPressed,
ButtonReleased,
}

Union representing a state change event for a gamepad.


GamepadIndex :: int

Unique identifier for a connected gamepad.


Input :: struct {
keys: [_KEY_CODE_CAPACITY]bit_set[InputFlag], //bitset of 4 bits (down, pressed, released, repeat)
characterQueue: [dynamic]rune, // for text input
isInputCaptured: bool, // if true, something (e.g. a text box) is consuming the input
mousePosition: gmath.Vector2,
previousMousePosition: gmath.Vector2,
mouseDelta: gmath.Vector2,
mouseScroll: gmath.Vector2,
gamepadKeys: [MAX_GAMEPADS][GamepadButton]bit_set[InputFlag],
touches: [MAX_TOUCHES]Touch,
virtualAxisValues: [MAX_GAMEPADS][GamepadAxis]f32,
}

Main container for the current frame’s input state.


InputFlag :: enum u8 {
down, // Key is currently held down
pressed, // Key was pressed this frame
released, // Key was released this frame
}

Bit flags representing the state of a specific key or button in the current frame.


KeyCode :: enum {
INVALID = 0,
SPACE = 32,
APOSTROPHE = 39,
COMMA = 44,
MINUS = 45,
PERIOD = 46,
SLASH = 47,
_0 = 48,
_1 = 49,
_2 = 50,
_3 = 51,
_4 = 52,
_5 = 53,
_6 = 54,
_7 = 55,
_8 = 56,
_9 = 57,
SEMICOLON = 59,
EQUAL = 61,
A = 65,
B = 66,
C = 67,
D = 68,
E = 69,
F = 70,
G = 71,
H = 72,
I = 73,
J = 74,
K = 75,
L = 76,
M = 77,
N = 78,
O = 79,
P = 80,
Q = 81,
R = 82,
S = 83,
T = 84,
U = 85,
V = 86,
W = 87,
X = 88,
Y = 89,
Z = 90,
LEFT_BRACKET = 91,
BACKSLASH = 92,
RIGHT_BRACKET = 93,
GRAVE_ACCENT = 96,
WORLD_1 = 161,
WORLD_2 = 162,
ESC = 256,
ENTER = 257,
TAB = 258,
BACKSPACE = 259,
INSERT = 260,
DELETE = 261,
RIGHT = 262,
LEFT = 263,
DOWN = 264,
UP = 265,
PAGE_UP = 266,
PAGE_DOWN = 267,
HOME = 268,
END = 269,
CAPS_LOCK = 280,
SCROLL_LOCK = 281,
NUM_LOCK = 282,
PRINT_SCREEN = 283,
PAUSE = 284,
F1 = 290,
F2 = 291,
F3 = 292,
F4 = 293,
F5 = 294,
F6 = 295,
F7 = 296,
F8 = 297,
F9 = 298,
F10 = 299,
F11 = 300,
F12 = 301,
F13 = 302,
F14 = 303,
F15 = 304,
F16 = 305,
F17 = 306,
F18 = 307,
F19 = 308,
F20 = 309,
F21 = 310,
F22 = 311,
F23 = 312,
F24 = 313,
F25 = 314,
KP_0 = 320,
KP_1 = 321,
KP_2 = 322,
KP_3 = 323,
KP_4 = 324,
KP_5 = 325,
KP_6 = 326,
KP_7 = 327,
KP_8 = 328,
KP_9 = 329,
KP_DECIMAL = 330,
KP_DIVIDE = 331,
KP_MULTIPLY = 332,
KP_SUBTRACT = 333,
KP_ADD = 334,
KP_ENTER = 335,
KP_EQUAL = 336,
LEFT_SHIFT = 340,
LEFT_CONTROL = 341,
LEFT_ALT = 342,
LEFT_SUPER = 343,
RIGHT_SHIFT = 344,
RIGHT_CONTROL = 345,
RIGHT_ALT = 346,
RIGHT_SUPER = 347,
MENU = 348,
LEFT_MOUSE = 400,
RIGHT_MOUSE = 401,
MIDDLE_MOUSE = 402,
}

Physical key codes (Stripped from Sokol), but with included mouse buttons.


MAX_GAMEPADS :: 4

The maximum number of supported concurrent gamepads. Default is 4, being in line with the maximum limit for Windows and Web.


MAX_PLAYERS :: MAX_GAMEPADS + 1

Maximum count of logical players that will have their inputs separated.


MOUSE_EMULATE_TOUCH :: true

Configuration constant for touch emulation. If set to true, makes each mouse click emulate a 0-index touch.


PlayerProfile :: struct {
gamepadIndex: GamepadIndex, // -1 for no gamepad
useKeyboard: bool,
bindings: [Action][dynamic]BindingSource,
axes: [Axis][dynamic]AxisBind,
}

Configuration state for a logical player. Contains their assigned device ID and input mappings.


SELECT :: GamepadButton.MiddleFaceLeft

Alias for MiddleFaceLeft gamepad button.


START :: GamepadButton.MiddleFaceRight

Alias for MiddleFaceRight gamepad button.


TOUCH_EMULATE_MOUSE :: false

Configuration constant for touch support. If set to true, makes each touch (0-index) emulate a mouse click.


TouchPhase :: enum {
None, // Slot is empty
Began, // On finger touch
Moved, // Finger is moving
Stationary, // Finger is holding still
Ended, // On finger lift
Cancelled, // System interrupt
}

Defines the lifecycle of a finger.


addVirtualStick :: proc (
position: gmath.Vector2,
radius: f32,
axisX: GamepadAxis,
axisY: GamepadAxis,
playerIndex: uint = 0,
)

Adds a virtual joystick to the touch overlay for a specified player. Default playerIndex is 0. position is the middle point of the thumbstick. :::note(Example) input.addVirtualStick(pos, 20.0, playerIndex = 1) // adds the thumbstick for player 2 :::


assignGamepad :: proc (playerIndex: uint, gamepadIndex: GamepadIndex)

Helper to assign a specific gamepad of index gamepadIndex to a player slot of index playerIndex.


bindAction :: proc (action: Action, source: BindingSource, playerIndex: uint = 0)

Binds a physical input to a logical Action. Default playerIndex is 0.


bindAxis :: proc (
axis: Axis,
source: BindingSource,
scale: f32,
deadzone: f32 = 0.1,
playerIndex: uint = 0,
)

Binds a physical input to an Axis with a specific scale. Default playerIndex is 0.


consumeActionPressed :: proc (action: Action, playerIndex: uint = 0) -> bool

Consumes the press event for a specific action. Returns true if the Action state was changed.


consumeActionReleased :: proc (action: Action, playerIndex: uint = 0) -> bool

Consumes the release event for a specific action. Returns true if the Action state was changed. Default playerIndex is 0.


consumeAnyGamepadPress :: proc (index: GamepadIndex = -1) -> bool

Checks if any button on a specific gamepad (or all gamepads if the argument isn’t provided) was pressed.


consumeAnyKeyPress :: proc () -> bool

Checks if any key is pressed this frame. If found, it consumes that press and returns true.


consumeGamepadPressed :: proc (index: GamepadIndex, button: GamepadButton) -> bool

Manually consumes a pressed event. Returns true if the state was successfully changed.


consumeGamepadReleased :: proc (index: GamepadIndex, button: GamepadButton) -> bool

Manually consumes a released event. Returns true if the state was successfully changed.


consumeKeyPressed :: proc (code: KeyCode) -> bool

Manually consumes a pressed event for a key. Returns true if the state was changed.


consumeKeyReleased :: proc (code: KeyCode) -> bool

Manually consumes a released event for a key. Returns true if the state was changed.


getAxis :: proc (axis: Axis, playerIndex: uint = 0) -> f32

Returns clamped float (-1.0 to 1.0) combining all bound inputs. Default playerIndex is 0.


getCharacterQueue :: proc () -> []rune

Returns a queue of characters triggered this frame. Useful for text input boxes.


getInputState :: proc () -> ^Input

Returns the input state for current frame.


getInputVector :: proc (playerIndex: uint = 0) -> gmath.Vector2

Helper to construct a normalized directional vector from the standard up/down/left/right actions. Default playerIndex is 0. Returns a zero vector if no input, or a normalized vector (length equal to 1.0).


getMouseDelta :: proc () -> gmath.Vector2

Returns the vector by which the mouse moved in the last frame.


getMousePosition :: proc (space: Maybe(InputSpace) = nil) -> gmath.Vector2

Converts the raw screen mouse coordinates into World/UI space coordinates by un-projecting them using the current renderer’s projection matrix. Accepts optional space argument. If set, returns the mouse position in selected space. Otherwise returns the mouse position in currently set space.


getScrollY :: proc () -> f32

Returns the current vertical scroll delta (mouse wheel).


isActionDown :: proc (action: Action, playerIndex: uint = 0) -> bool

Checks if a mapped action is currently held down. Default playerIndex is 0.


isActionPressed :: proc (action: Action, playerIndex: uint = 0) -> bool

Checks if a mapped action (e.g. .MenuLeft, .MenuRight) was pressed this frame. Default playerIndex is 0.


isActionReleased :: proc (action: Action, playerIndex: uint = 0) -> bool

Checks if a mapped action was released this frame. Default playerIndex is 0.


isGamepadDown :: proc (index: GamepadIndex, button: GamepadButton) -> bool

Checks if a GamepadButton is currently held down.


isGamepadPressed :: proc (index: GamepadIndex, button: GamepadButton) -> bool

Checks if a GamepadButton was pressed this frame.


isGamepadReleased :: proc (index: GamepadIndex, button: GamepadButton) -> bool

Checks if a GamepadButton was released this frame.


isKeyDown :: proc (code: KeyCode) -> bool

Checks if a physical key is currently held down. Returns true as long as the key is held.


isKeyPressed :: proc (code: KeyCode) -> bool

Checks if a physical key was pressed this frame. Returns true only on the frame the key went down.


isKeyReleased :: proc (code: KeyCode) -> bool

Checks if a physical key was released this frame. Returns true only on the frame the key went up.


setCaptured :: proc (captured: bool)

Sets whether input is currently captured. If true, isKeyDown/isKeyPressed/isKeyReleased will return false.


setCursorLocked :: proc (isLocked: bool)

Locks the cursor to the window.


setCursorVisible :: proc (isVisible: bool)

Controls the visibility of the system (hardware) cursor. Set to false if you intend to render your own custom cursor sprite.