tiramisu/input

Input module - keyboard, mouse, gamepad, and touch input handling.

Input state is automatically updated each frame and passed to your update function via the Context. Query the input state to respond to player actions.

Quick Example

import tiramisu/input

fn update(model, msg, ctx) {
  // Check if player is pressing W to move forward
  let move_forward = case input.is_key_pressed(ctx.input, input.KeyW) {
    True -> 1.0
    False -> 0.0
  }

  // Check mouse button
  let shooting = input.is_left_button_pressed(ctx.input)

  // Update model based on input
  Model(..model, position: move_player(model.position, move_forward))
}

Types

Buffered input for more forgiving gameplay

Buffers action presses for a specified number of frames, allowing players to press inputs slightly before they’re valid (e.g., jump before landing).

Example

// In your model
pub type Model {
  Model(
    buffered_input: input.BufferedInput(Action),
    // ...
  )
}

// In init
fn init(_flags) {
  let buffered = input.with_buffer(buffer_frames: 5)
  Model(buffered_input: buffered, ...)
}

// In update
fn update(model, msg, ctx) {
  // Update buffer each frame
  let buffered = input.update_buffer(
    model.buffered_input,
    ctx.input,
    bindings,
  )

  // Check if action was pressed within buffer window
  let can_jump = input.was_action_pressed_buffered(buffered, bindings, Jump)

  Model(..model, buffered_input: buffered)
}
pub opaque type BufferedInput(action)
pub type ButtonState {
  ButtonState(
    pressed: Bool,
    just_pressed: Bool,
    just_released: Bool,
  )
}

Constructors

  • ButtonState(
      pressed: Bool,
      just_pressed: Bool,
      just_released: Bool,
    )
pub type GamepadAxis {
  LeftStickX
  LeftStickY
  RightStickX
  RightStickY
}

Constructors

  • LeftStickX
  • LeftStickY
  • RightStickX
  • RightStickY

Gamepad button enumeration (standard mapping)

pub type GamepadButton {
  ButtonA
  ButtonB
  ButtonX
  ButtonY
  LeftBumper
  RightBumper
  LeftTrigger
  RightTrigger
  Select
  Start
  LeftStick
  RightStick
  DPadUp
  DPadDown
  DPadLeft
  DPadRight
  HomeButton
}

Constructors

  • ButtonA
  • ButtonB
  • ButtonX
  • ButtonY
  • LeftBumper
  • RightBumper
  • LeftTrigger
  • RightTrigger
  • Select
  • Start
  • LeftStick
  • RightStick
  • DPadUp
  • DPadDown
  • DPadLeft
  • DPadRight
  • HomeButton
pub type GamepadState {
  GamepadState(
    connected: Bool,
    buttons: List(Float),
    axes: List(Float),
  )
}

Constructors

  • GamepadState(
      connected: Bool,
      buttons: List(Float),
      axes: List(Float),
    )

    Arguments

    buttons

    Buttons: Values clamped between 0.0 and 1.0

Input bindings that map inputs to user-defined actions

Generic over action type, so you can define your own action enum:

pub type Action {
  Jump
  MoveForward
  Shoot
}

let bindings = input.new_bindings()
  |> input.bind_key(input.Space, Jump)
  |> input.bind_key(input.KeyW, MoveForward)
  |> input.bind_mouse_button(input.LeftButton, Shoot)
pub opaque type InputBindings(action)

Input state for all input devices (automatically updated each frame).

Access via context.input in your update function.

pub opaque type InputState

Common keyboard codes (standard KeyboardEvent.code values)

pub type Key {
  KeyA
  KeyB
  KeyC
  KeyD
  KeyE
  KeyF
  KeyG
  KeyH
  KeyI
  KeyJ
  KeyK
  KeyL
  KeyM
  KeyN
  KeyO
  KeyP
  KeyQ
  KeyR
  KeyS
  KeyT
  KeyU
  KeyV
  KeyW
  KeyX
  KeyY
  KeyZ
  Digit0
  Digit1
  Digit2
  Digit3
  Digit4
  Digit5
  Digit6
  Digit7
  Digit8
  Digit9
  F1
  F2
  F3
  F4
  F5
  F6
  F7
  F8
  F9
  F10
  F11
  F12
  ArrowUp
  ArrowDown
  ArrowLeft
  ArrowRight
  ShiftLeft
  ShiftRight
  ControlLeft
  ControlRight
  AltLeft
  AltRight
  MetaLeft
  MetaRight
  Space
  Enter
  Escape
  Tab
  Backspace
  Delete
  Insert
  Home
  End
  PageUp
  PageDown
  CapsLock
  Minus
  Equal
  BracketLeft
  BracketRight
  Backslash
  Semicolon
  Quote
  Comma
  Period
  Slash
  Backquote
  Numpad0
  Numpad1
  Numpad2
  Numpad3
  Numpad4
  Numpad5
  Numpad6
  Numpad7
  Numpad8
  Numpad9
  NumpadAdd
  NumpadSubtract
  NumpadMultiply
  NumpadDivide
  NumpadDecimal
  NumpadEnter
  NumLock
  AudioVolumeUp
  AudioVolumeDown
  AudioVolumeMute
  MediaPlayPause
  MediaStop
  MediaTrackNext
  MediaTrackPrevious
  PrintScreen
  ScrollLock
  Pause
  ContextMenu
  Custom(String)
}

Constructors

  • KeyA
  • KeyB
  • KeyC
  • KeyD
  • KeyE
  • KeyF
  • KeyG
  • KeyH
  • KeyI
  • KeyJ
  • KeyK
  • KeyL
  • KeyM
  • KeyN
  • KeyO
  • KeyP
  • KeyQ
  • KeyR
  • KeyS
  • KeyT
  • KeyU
  • KeyV
  • KeyW
  • KeyX
  • KeyY
  • KeyZ
  • Digit0
  • Digit1
  • Digit2
  • Digit3
  • Digit4
  • Digit5
  • Digit6
  • Digit7
  • Digit8
  • Digit9
  • F1
  • F2
  • F3
  • F4
  • F5
  • F6
  • F7
  • F8
  • F9
  • F10
  • F11
  • F12
  • ArrowUp
  • ArrowDown
  • ArrowLeft
  • ArrowRight
  • ShiftLeft
  • ShiftRight
  • ControlLeft
  • ControlRight
  • AltLeft
  • AltRight
  • MetaLeft
  • MetaRight
  • Space
  • Enter
  • Escape
  • Tab
  • Backspace
  • Delete
  • Insert
  • Home
  • End
  • PageUp
  • PageDown
  • CapsLock
  • Minus
  • Equal
  • BracketLeft
  • BracketRight
  • Backslash
  • Semicolon
  • Quote
  • Comma
  • Period
  • Slash
  • Backquote
  • Numpad0
  • Numpad1
  • Numpad2
  • Numpad3
  • Numpad4
  • Numpad5
  • Numpad6
  • Numpad7
  • Numpad8
  • Numpad9
  • NumpadAdd
  • NumpadSubtract
  • NumpadMultiply
  • NumpadDivide
  • NumpadDecimal
  • NumpadEnter
  • NumLock
  • AudioVolumeUp
  • AudioVolumeDown
  • AudioVolumeMute
  • MediaPlayPause
  • MediaStop
  • MediaTrackNext
  • MediaTrackPrevious
  • PrintScreen
  • ScrollLock
  • Pause
  • ContextMenu
  • Custom(String)
pub opaque type KeyboardState

Mouse button enumeration for action mapping

pub type MouseButton {
  LeftButton
  RightButton
  MiddleButton
}

Constructors

  • LeftButton
  • RightButton
  • MiddleButton
pub opaque type MouseState
pub type Touch {
  Touch(id: Int, x: Float, y: Float)
}

Constructors

  • Touch(id: Int, x: Float, y: Float)
pub type TouchState {
  TouchState(
    touches: List(Touch),
    touches_just_started: List(Touch),
    touches_just_ended: List(Touch),
  )
}

Constructors

  • TouchState(
      touches: List(Touch),
      touches_just_started: List(Touch),
      touches_just_ended: List(Touch),
    )

Values

pub fn bind_gamepad_button(
  bindings: InputBindings(action),
  button: GamepadButton,
  action: action,
) -> InputBindings(action)

Bind a gamepad button to an action

pub fn bind_key(
  bindings: InputBindings(action),
  key: Key,
  action: action,
) -> InputBindings(action)

Bind a keyboard key to an action

Example

let bindings = input.new_bindings()
  |> input.bind_key(input.Space, Jump)
  |> input.bind_key(input.KeyW, MoveForward)
pub fn bind_mouse_button(
  bindings: InputBindings(action),
  button: MouseButton,
  action: action,
) -> InputBindings(action)

Bind a mouse button to an action

pub fn clear_buffer(
  buffered: BufferedInput(action),
) -> BufferedInput(action)

Clear all buffered actions

Useful when switching game states or when you want to reset the buffer.

pub fn consume_buffered_action(
  buffered: BufferedInput(action),
  action: action,
) -> BufferedInput(action)

Consume a buffered action (remove it from buffer)

Use this when you’ve acted on a buffered input to prevent it from being used multiple times.

Example

let can_jump = is_grounded
  && input.was_action_pressed_buffered(buffered, Jump)

case can_jump {
  True -> {
    // Perform jump
    let buffered = input.consume_buffered_action(buffered, Jump)
    // ...
  }
  False -> // ...
}
pub fn gamepad_axis(
  input: InputState,
  gamepad_index: Int,
  axis: GamepadAxis,
) -> Float

Get gamepad axis value

pub fn gamepad_button(
  input: InputState,
  gamepad_index: Int,
  button: GamepadButton,
) -> Float

Get gamepad button value

pub fn get_action_value(
  input: InputState,
  bindings: InputBindings(action),
  action: action,
) -> Float

Get the analog value (0.0 to 1.0) for an action

Useful for actions that can have analog input like gamepad triggers. Returns 1.0 for digital inputs (keyboard/mouse) when pressed, 0.0 when not pressed.

pub fn get_axis_with_deadzone(
  input: InputState,
  gamepad_index: Int,
  axis: GamepadAxis,
  deadzone: Float,
) -> Float

Get axis value with dead zone applied

pub fn get_primary_axis(
  input: InputState,
  axis: GamepadAxis,
) -> Float

Convenience: Get axis value on primary gamepad

pub fn get_primary_button(
  input: InputState,
  button: GamepadButton,
) -> Float

Convenience: Get button value on primary gamepad

pub fn is_action_just_pressed(
  input: InputState,
  bindings: InputBindings(action),
  action: action,
) -> Bool

Check if an action was just pressed this frame

Returns True if any input bound to this action was just pressed.

pub fn is_action_just_released(
  input: InputState,
  bindings: InputBindings(action),
  action: action,
) -> Bool

Check if an action was just released this frame

pub fn is_action_pressed(
  input: InputState,
  bindings: InputBindings(action),
  action: action,
) -> Bool

Check if an action is currently pressed

Returns True if any input bound to this action is pressed.

Example

if input.is_action_pressed(ctx.input, bindings, Jump) {
  // Player wants to jump
}
pub fn is_gamepad_button_pressed(
  input: InputState,
  gamepad_index: Int,
  button: GamepadButton,
) -> Bool

Check if gamepad button is pressed

pub fn is_gamepad_connected(
  input: InputState,
  index: Int,
) -> Bool

Check if gamepad at index is connected

pub fn is_key_just_pressed(input: InputState, key: Key) -> Bool

Check if a key was just pressed this frame

pub fn is_key_just_released(input: InputState, key: Key) -> Bool

Check if a key was just released this frame

pub fn is_key_pressed(input: InputState, key: Key) -> Bool

Check if a key is currently pressed

pub fn is_left_button_just_pressed(input: InputState) -> Bool

Check if left mouse button was just pressed

pub fn is_left_button_pressed(input: InputState) -> Bool

Check if left mouse button is pressed

pub fn is_left_stick_active(
  input: InputState,
  gamepad_index: Int,
  threshold: Float,
) -> Bool

Check if left stick is moved in any direction

pub fn is_primary_connected(input: InputState) -> Bool

Convenience: Check if primary gamepad (index 0) is connected

pub fn is_primary_gamepad_button_pressed(
  input: InputState,
  button: GamepadButton,
) -> Bool

Convenience: Check button on primary gamepad

pub fn is_right_button_just_pressed(input: InputState) -> Bool

Check if right mouse button was just pressed

pub fn is_right_button_pressed(input: InputState) -> Bool

Check if right mouse button is pressed

pub fn is_right_stick_active(
  input: InputState,
  gamepad_index: Int,
  threshold: Float,
) -> Bool

Check if right stick is moved in any direction

pub fn mouse_delta(input: InputState) -> #(Float, Float)

Get mouse delta

pub fn mouse_position(input: InputState) -> #(Float, Float)

Get mouse position

pub fn mouse_wheel_delta(input: InputState) -> Float

Get mouse wheel delta

pub fn new() -> InputState
pub fn new_bindings() -> InputBindings(action)

Create a new empty input bindings configuration

pub fn touch_count(input: InputState) -> Int

Get touch count

pub fn touches(input: InputState) -> List(Touch)

Get current touches

pub fn touches_just_ended(input: InputState) -> List(Touch)

Get touches that just ended

pub fn touches_just_started(input: InputState) -> List(Touch)

Get touches that just started

pub fn update_buffer(
  buffered: BufferedInput(action),
  input: InputState,
  bindings: InputBindings(action),
) -> BufferedInput(action)

Update the input buffer each frame

Call this once per frame in your update function to:

  1. Add newly pressed actions to the buffer
  2. Remove expired actions from the buffer

Example

let buffered = input.update_buffer(
  model.buffered_input,
  ctx.input,
  bindings,
)
pub fn was_action_pressed_buffered(
  buffered: BufferedInput(action),
  action: action,
) -> Bool

Check if an action was pressed within the buffer window

Returns True if the action was pressed in the last N frames (where N is buffer_frames). This allows for more forgiving input timing.

Example

// Allow jump input to be buffered - player can press jump slightly
// before landing and it will still work
let can_jump = is_grounded
  && input.was_action_pressed_buffered(buffered, bindings, Jump)
pub fn with_buffer(
  buffer_frames buffer_frames: Int,
) -> BufferedInput(action)

Create a new buffered input system

Search Document