Tryst::SDL::Gamepad
An SDL3 gamepad: buttons, analog sticks, triggers and rumble.
Wraps SDL's Gamepad API (SDL2's GameController, renamed), which maps physical controls to a fixed Xbox-style layout automatically - higher-level than the raw Joystick API, and what works out of the box for Xbox, PlayStation, Switch Pro and most others.
gp = Tryst::SDL::Gamepad.first
if gp
puts gp.name
puts "A pressed: #{gp.button?(:a)}"
puts "Left stick X: #{gp.axis(:left_x)}"
gp.destroy
end
Tryst::SDL::Gamepad.on_button do |instance_id, button, pressed|
puts "#{button} #{pressed ? "pressed" : "released"}"
end
# In a game loop, or a Tk timer:
Tryst::SDL::Gamepad.poll_events
Constants
Every axis this shard names.
Analog stick axis range: -32768..32767 (centred at 0).
button/axis <-> the raw SDL enum value, both ways - a Hash pair each rather than two long case/when chains matching the same data, which is what these actually are.
Every button this shard names. SDL3 itself has more (paddles, a touchpad click, several vendor-specific "misc" buttons) - this is the portable Xbox-style subset every modern pad maps onto, the same set ruby-tryst's SDL2 port exposed.
Default dead zone threshold for analog sticks.
Trigger axis range: 0..32767 (0 = released, 32767 = fully pressed).
Constructors
Class methods
Zero if value's magnitude is below threshold, otherwise
value unchanged - the small resting drift a real stick reports
at rest is what this is for.
Attaches a virtual gamepad device - no hardware required - so the whole surface above can be exercised in a headless CI container. Returns the instance id (.open takes it, same as any real device). Raises if one is already attached.
Removes the virtual gamepad .attach_virtual created. A no-op if none is attached.
Instance ids of every device SDL currently recognizes as a gamepad - what SDL3 hands #open directly, unlike SDL2's separate device-index/instance-id pair (there is only one id now).
Brings up the gamepad subsystem. Called automatically by every other class method - only useful to call early, e.g. before the first #poll_events so a hot-plug of an already-connected pad at startup is not missed.
Registers a block for a newly connected gamepad, seen through .poll_events. The instance id it is called with is what .open takes.
Registers a block for button press/release events, seen through .poll_events. Replaces any block registered earlier.
Pumps SDL's event queue and dispatches gamepad events to whichever callbacks (#on_button, #on_axis, #on_added, #on_removed) are registered. Returns how many gamepad events were processed.
Call this periodically (e.g. every 16-50ms, from a Tk timer or a game loop) for event-driven input.
SDL_PollEvent pumps the platform event loop, which on macOS is the Cocoa run loop - shared with Tk's own Aqua backend. Use .update_state instead when only fresh #button?/#axis values are needed and event callbacks are not, to avoid contending with Tk for that run loop.
Shuts the gamepad subsystem down on its own, leaving audio/video (if either is up) running. Existing Gamepad objects become unusable.
Refreshes every open gamepad's state WITHOUT pumping the platform event loop - SDL_UpdateGamepads only, none of SDL_PollEvent's SDL_PumpEvents call. After this, #button?/#axis answer with fresh values; event callbacks do not fire - use .poll_events for those.
Instance methods
The current value of axis: AXIS_MIN..AXIS_MAX for a stick,
TRIGGER_MIN..TRIGGER_MAX for a trigger. See AXES for the valid
symbols.
Whether button is currently pressed. See BUTTONS for the valid
symbols.
A GUID string identifying this controller's model - the same model always reports the same GUID, unlike #instance_id which changes across unplug/replug. Useful as a config key for persisting per-controller settings.
Triggers haptic feedback (rumble). low_freq/high_freq are motor intensities (0..65535), duration_ms how long. Returns whether the controller supports it - not every controller does, and that is not an error.
Sets an axis's value on a virtual gamepad (see .attach_virtual). Raises on a real device.