Skip to main content

Input Module

The Input module provides an abstract input system that allows handling user actions in a platform-independent way. It maps keyboard keys (on Windows/Web) or GPIO pins (on ESP32) to "actions" that can be queried uniformly.

JARU Input module screenshot for mapping keyboard actions, buttons, and game controls

This approach allows writing portable code that works both on the PC emulator and on ESP32 devices, simply by changing the action mappings.

Usage​

use Input

Key Concepts​

Actions​

The Input module works with actions identified by a number (0-15). An action represents an abstract user input like "jump", "shoot", or "move left".

// Define constants for actions
var ACTION_JUMP = 0
var ACTION_SHOOT = 1
var ACTION_LEFT = 2
var ACTION_RIGHT = 3

Platform Mapping​

On Windows/Web, actions are mapped to keyboard keys. On ESP32, they are mapped to GPIO pins configured with internal pull-up resistors.

// On Windows/Web: SPACE key for jumping
Input.map(ACTION_JUMP, "SPACE")

// On ESP32: GPIO 15 for jumping (button connected to GND)
Input.map(ACTION_JUMP, 15)

Functions​

map​

The map(actionId, key/pin) function associates an action with a keyboard key or GPIO pin.

Parameters​

ParameterTypeDescription
actionIdintegerAction identifier (0-15)
key/pinstring/integerKey name (Windows/Web) or GPIO pin number (ESP32)

Return​

Returns true if the mapping was successful.

// Map keys for a game
Input.map(0, "W") // Up
Input.map(1, "S") // Down
Input.map(2, "A") // Left
Input.map(3, "D") // Right
Input.map(4, "SPACE") // Jump
Input.map(5, "CTRL") // Shoot

Supported Keys (Windows/Web)​

CategoryKeys
LettersA - Z
Numbers0 - 9
ArrowsUP, DOWN, LEFT, RIGHT
SpecialSPACE, ENTER, ESC, TAB
ModifiersSHIFT, CTRL, ALT
GPIO Pins on ESP32

On ESP32, pins are automatically configured as INPUT_PULLUP. Connect the button between the pin and GND. The state is internally inverted, so a pressed button returns true.

pressed​

The pressed(actionId) function checks if an action is currently being pressed.

Parameters​

ParameterTypeDescription
actionIdintegerAction identifier (0-15)

Return​

Returns true while the key/button is pressed, false otherwise.

// Continuous movement while held
if (Input.pressed(2)) then
x = x - speed
end

if (Input.pressed(3)) then
x = x + speed
end

justPressed​

The justPressed(actionId) function detects the exact moment an action is pressed.

Parameters​

ParameterTypeDescription
actionIdintegerAction identifier (0-15)

Return​

Returns true only on the frame when the key/button transitions from not pressed to pressed.

// Single action on press (doesn't repeat while held)
if (Input.justPressed(4)) then
player.jump()
end

if (Input.justPressed(5)) then
player.shoot()
end
Difference between pressed and justPressed
  • pressed(): Returns true on EVERY frame while the key is pressed. Useful for continuous movement.
  • justPressed(): Returns true ONLY on the first frame. Useful for single actions like jumping or shooting.

released​

The released(actionId) function detects the exact moment an action is released.

Parameters​

ParameterTypeDescription
actionIdintegerAction identifier (0-15)

Return​

Returns true only on the frame when the key/button transitions from pressed to not pressed.

// Detect when a button is released
if (Input.released(4)) then
// Cancel jump or reduce height
player.cancelJump()
end

update​

The update() function forces a manual update of the input states.

// Usually not necessary to call manually
// since pressed(), justPressed() and released()
// automatically update the state

Input.update()
Automatic Update

The input system uses a "lazy update" mechanism. The state is automatically updated the first time it's queried in each frame. You only need to call update() if you require forcing an update at a specific moment.

Complete Example​

Character Control​

use Display
use Input

// Define actions
var UP = 0
var DOWN = 1
var LEFT = 2
var RIGHT = 3
var JUMP = 4
var SHOOT = 5

// Configure key mappings
Input.map(UP, "W")
Input.map(DOWN, "S")
Input.map(LEFT, "A")
Input.map(RIGHT, "D")
Input.map(JUMP, "SPACE")
Input.map(SHOOT, "J")

// Player variables
var x = 160
var y = 120
var speed = 2
var jumping = false

Display.open(320, 240)
Display.mode(2)

var draw = Display.draw

while (true)
// Continuous movement
if (Input.pressed(LEFT)) then
x = x - speed
end
if (Input.pressed(RIGHT)) then
x = x + speed
end
if (Input.pressed(UP)) then
y = y - speed
end
if (Input.pressed(DOWN)) then
y = y + speed
end

// Single actions
if (Input.justPressed(JUMP)) then
jumping = true
println("Jumping!")
end

if (Input.justPressed(SHOOT)) then
println("Shot fired!")
end

// Render
draw.clear(0x000000)
draw.rectfill(x - 8, y - 8, x + 8, y + 8, 0x00FF00)
Display.update()

pause(16)
end

Cross-Platform Control​

use Input

// Define actions
var BTN_A = 0
var BTN_B = 1

// Mapping can be done in a configuration file
// or by detecting the platform

// For Windows/Web:
Input.map(BTN_A, "Z")
Input.map(BTN_B, "X")

// For ESP32 (uncomment based on platform):
// Input.map(BTN_A, 15)
// Input.map(BTN_B, 14)

// The rest of the code is identical on both platforms
while (true)
if (Input.justPressed(BTN_A)) then
executeActionA()
end

if (Input.justPressed(BTN_B)) then
executeActionB()
end

pause(16)
end

Considerations​

Action Limit

The system supports a maximum of 16 simultaneous actions (IDs from 0 to 15). If you need more controls, consider using key combinations or a context system where the same actions mean different things depending on the game state.

Debounce on ESP32

On ESP32, physical buttons can generate "bounce" (multiple rapid presses when pressing). The Input module does not include hardware debounce. If you experience issues, consider adding 100nF capacitors between the pin and GND, or implementing software debounce.

Supported Platforms​

PlatformSupportNotes
ESP32✅GPIO pins with INPUT_PULLUP
Windows (SDL2)✅Keyboard keys via SDL
Emscripten (Web)✅Keyboard keys via SDL