Skip to content

Draft: Refactor the gamepad code

Lactozilla requested to merge Lactozilla/SRB2:joystick-changes into next
  • Most notable change: Since the gamepad code now uses SDL's GameController API, button and axis names are now more accurate. On menus, the names will correctly show up depending on the kind of controller that the player is using.
  • In the control configuration menus, you can now set axes to any kind of control. Movement and looking axes are fully analog (they will use the analog deadzone), while other controls are digital (and use the digital deadzone.) The old axis configuration is now unnecessary, but still supported.

srb20131 srb20133

  • Reduced code duplication and moved to a new file (sdl/i_gamepad.c)
  • Game automatically pauses if a controller disconnects (pauseongamepaddisconnect)
  • Allows players to move with the joysticks if the console is open
  • Fixed a bug where the second player mirrored the first player's digital axis choice
  • Adds haptic feedback (rumble), enable with padrumble and padrumble2. See p_haptic.c and p_haptic.h
  • SDL version 2.0.20 is required for this to work

Lua documentation:

gamepad userdata fields:

Field Accepts Returns Description
#gamepad integer This returns the gamepad number. Gamepad numbers are 1-indexed.
gamepad.connected boolean This field returns true if the gamepad is connected, and false otherwise.
gamepad.type string This field returns the type of the gamepad.
gamepad.isXbox boolean true if the gamepad is an Xbox controller; false if otherwise.
gamepad.isPlayStation boolean true if the gamepad is a PlayStation controller; false if otherwise.
gamepad.isNintendoSwitch boolean true if the gamepad is a Nintendo Switch Pro Controller, a Joy-Con L, a Joy-Con R, or Joy-Con in the Joy-Con Grip; false if otherwise.
gamepad.isJoyCon boolean true if the gamepad is a Joy-Con L, or a Joy-Con R; false if otherwise.
gamepad.hasRumble boolean true if the gamepad has haptic feedback capabilities; false if otherwise.
gamepad.isRumbling boolean true if rumble is active in the gamepad; false if otherwise.
gamepad.isRumblePaused boolean boolean This field will return true if the current haptic effect on the gamepad is paused, and false if it isn't. It can be set to pause the effect.
gamepad.largeMotorFrequency fixed point value fixed point value The frequency of the large motor. This is usually physically located on the left side of a gamepad.
gamepad.smallMotorFrequency fixed point value fixed point value The frequency of the small motor. This is usually physically located on the right side of a gamepad.

gamepad userdata functions:

Function Parameters Description Returns
gamepad:isButtonDown string button Checks if a gamepad button is down. boolean
gamepad:getAxis string axis, [fixed_t applyDeadzone] Returns the value of an axis, from -FRACUNIT to FRACUNIT. For triggers, this always returns a value from 0 to FRACUNIT. applyDeadzone is true by default. fixed point value
gamepad:getStick "left" or "right", [fixed_t applyDeadzone] Returns the X and Y values of a stick, from -FRACUNIT to FRACUNIT. applyDeadzone is true by default. two fixed point values
gamepad:getTrigger "left" or "right", [fixed_t applyDeadzone] Returns the value of a stick, from 0 to FRACUNIT. applyDeadzone is true by default. fixed point value
gamepad:getButtonName string button Returns the name of a button. This may vary depending on the gamepad type. This is useful for displaying in e.g. menus. string
gamepad:getAxisName string axis Returns the name of an axis. This may vary depending on the gamepad type. This is useful for displaying in e.g. menus. string
gamepad:getTriggerName "left" or "right" Returns the name of a trigger. This may vary depending on the gamepad type. This is useful for displaying in e.g. menus. string
gamepad:rumble fixed_t large_motor_frequency, [fixed_t small_motor_frequency, [tic_t duration]] Changes the frequency of the gamepad's motors. If the small motor's frequency is nil, it'll be set to the large motor's frequency. If duration is nil or 0, the motors rotate forever, until they're stopped or their frequency changes. true is succeeded, false if not
gamepad:stopRumble Stops the motors on the gamepad from rotating. string

Button names:

Name Description
"a" Bottom face button
"b" Right face button
"x" Left face button
"y" Top face button
"back" Back button
"guide" Guide button
"start" Start
"left-stick" Left stick click
"right-stick" Right stick click
"left-shoulder" Left shoulder
"right-shoulder" Right shoulder
"dpad-up" D-Pad Up
"dpad-down" D-Pad Down
"dpad-left" D-Pad Left
"dpad-right" D-Pad Right
"misc1" Depends on the type of the controller; if you want to know, check the controller type, or try using gamepad:getButtonName("misc1")
"paddle1" P1 Paddle (Xbox Elite controllers)
"paddle2" P2 Paddle (Xbox Elite controllers)
"paddle3" P3 Paddle (Xbox Elite controllers)
"paddle4" P4 Paddle (Xbox Elite controllers)
"touchpad" Touchpad button (PlayStation 4 and 5 controllers)

Axis names:

Name Description
"left-x" Left stick X
"left-y" Left stick Y
"right-x" Right stick X
"right-y" Right stick Y
"trigger-left" Left trigger
"trigger-right" Right trigger

Gamepad types:

Type
"xbox-360"
"xbox-one"
"xbox-series-xs"
"xbox-elite"
"ps3"
"ps4"
"ps5"
"switch-pro"
"switch-joy-con-grip"
"switch-joy-con-left"
"switch-joy-con-right"
"stadia"
"amazon-luna"
"steam-controller"
"virtual"
"unknown"

Functions added:

Function Parameters Description Returns
input.getPlayerGamepad player_t player Returns a gamepad for a specific player. If the specified player isn't "local" to the system running the game, this returns nil. gamepad
P_DoRumble player_t player, fixed_t large_motor_frequency, [fixed_t small_motor_frequency, [tic_t duration]] See gamepad:rumble. This does nothing and always returns false if the specified player isn't "local" to the system running the game. boolean
P_PauseRumble player_t player See gamepad.isRumblePaused. This does nothing if the specified player isn't "local" to the system running the game.
P_UnpauseRumble player_t player See gamepad.isRumblePaused. This does nothing if the specified player isn't "local" to the system running the game.
P_IsRumbleEnabled player_t player Returns true if the player's gamepad supports haptic feedback, and has rumble enabled (console variables padrumble or padrumble2.) This always returns false if the specified player isn't "local" to the system running the game.
P_IsRumblePaused player_t player See gamepad.isRumblePaused. This always returns false if the specified player isn't "local" to the system running the game. boolean
P_StopRumble player_t player See gamepad:stopRumble. This does nothing if the specified player isn't "local" to the system running the game.

Hooks added:

Function Parameters Description
GamepadButtonDown gamepad gamepad, string button Called when a button in the gamepad is pressed. button is the button name. Works just like KeyDown.
GamepadButtonUp gamepad gamepad, string button Called when a button in the gamepad is no longer being pressed. button is the button name. Works just like KeyUp.
GamepadAdded gamepad gamepad Called when a gamepad is added.
GamepadRemoved gamepad gamepad Called when a gamepad is removed.

gamepads library:

Field Description
#gamepads Returns how many gamepads may be connected at once. Always returns 2.
gamepads[n] Returns the n-th gamepad. This is 1-indexed.
gamepads.iterate Iterates through all connected gamepads.

Windows build: joystick-changes-f9c836d1.exe
SDL 2.0.20 dll: SDL2.dll

This branch WILL modify your settings! If you want to preserve your axis names, make a backup of your config file.

Edited by Lactozilla

Merge request reports