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)
mousePosition: 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 :: true

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. :::note(Example)

bindAxis(.MoveY, .W, 1.0)
bindAxis(.MoveY, .S, -1.0)
bindAxis(.MoveX, .A, -1.0)
bindAxis(.MoveX, .D, 1.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.


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).


getMousePosition :: proc () -> gmath.Vector2

Converts the raw screen mouse coordinates into World/UI space coordinates by un-projecting them using the current renderer’s projection matrix.


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.


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.