Install Asset
Install via Godot
To maintain one source of truth, Godot Asset Library is just a mirror of the old asset library so you can download directly on Godot via the integrated asset library browser
Quick Information
Play Solana Gen 1 Input key mappingRead docs:https://github.com/mira4sol/psg1_input_binding
PSG1Input Library Documentation A plug-and-play controller library for PSG1 hardware in Godot. No setup required, just start using it.
Quick Start gdscript extends CharacterBody2D
func _process(delta): # Get analog stick input var movement = PSG1Input.get_left_stick() velocity = movement * 300
# Check button presses
if PSG1Input.is_action_just_pressed("psg1_south"):
jump()
That's it. No initialization, no configuration files, no extra steps.
Installation Download PSG1Input.gd Put it anywhere in your project folder (example: res://addons/PSG1Input.gd) Start using it immediately in any script That's it. Because PSG1Input uses static functions, you don't need to add it as an AutoLoad or create an instance. Just call the functions directly.
Button Names The PSG1 controller has these buttons:
Face Buttons:
psg1_south - Bottom button (A on Xbox, Cross on PlayStation) psg1_east - Right button (B on Xbox, Circle on PlayStation) psg1_west - Left button (X on Xbox, Square on PlayStation) psg1_north - Top button (Y on Xbox, Triangle on PlayStation) Shoulder Buttons:
psg1_l1 - Left shoulder button psg1_r1 - Right shoulder button psg1_l3 - Left stick click psg1_r3 - Right stick click System Buttons:
psg1_start - Start/Menu button psg1_select - Select/Back button D-Pad:
psg1_dpad_up psg1_dpad_down psg1_dpad_left psg1_dpad_right Analog Inputs:
psg1_left_stick_x - Left stick horizontal psg1_left_stick_y - Left stick vertical psg1_right_stick_x - Right stick horizontal psg1_right_stick_y - Right stick vertical psg1_l2 - Left trigger psg1_r2 - Right trigger Core Functions Button Checks is_action_pressed(action: StringName) -> bool Returns true while a button is held down.
gdscript func _process(delta): if PSG1Input.is_action_pressed("psg1_south"): print("South button is being held") is_action_just_pressed(action: StringName) -> bool Returns true only on the frame when a button is first pressed.
gdscript func _process(delta): if PSG1Input.is_action_just_pressed("psg1_south"): jump() # Jumps once per button press is_action_just_released(action: StringName) -> bool Returns true only on the frame when a button is released.
gdscript func _process(delta): if PSG1Input.is_action_just_released("psg1_south"): stop_charging_attack() Analog Stick Functions get_left_stick(deadzone: float = 0.2) -> Vector2 Gets the left analog stick position as a Vector2. Returns zero if the stick is within the deadzone.
gdscript func _process(delta): var stick = PSG1Input.get_left_stick() # stick.x ranges from -1.0 (left) to 1.0 (right) # stick.y ranges from -1.0 (up) to 1.0 (down)
velocity = stick * move_speed
move_and_slide()
Custom deadzone:
gdscript
More sensitive (smaller deadzone)
var stick = PSG1Input.get_left_stick(0.1)
Less sensitive (larger deadzone)
var stick = PSG1Input.get_left_stick(0.3) get_right_stick(deadzone: float = 0.2) -> Vector2 Gets the right analog stick position. Works exactly like get_left_stick().
gdscript func _process(delta): var aim = PSG1Input.get_right_stick() if aim.length() > 0: player.look_at(player.position + aim) Trigger Functions get_triggers() -> Vector2 Gets both trigger values at once. Returns Vector2 where x is the left trigger and y is the right trigger. Values range from 0.0 (not pressed) to 1.0 (fully pressed).
gdscript func _process(delta): var triggers = PSG1Input.get_triggers() var brake = triggers.x # Left trigger (0.0 to 1.0) var gas = triggers.y # Right trigger (0.0 to 1.0)
car_speed += gas * acceleration
car_speed -= brake * brake_power
get_action_strength(action: StringName) -> float Gets the pressure of a single trigger. Returns 0.0 to 1.0.
gdscript func _process(delta): var shoot_power = PSG1Input.get_action_strength("psg1_r2") if shoot_power > 0.5: fire_weapon(shoot_power) D-Pad Functions get_dpad_vector() -> Vector2 Gets D-pad input as a Vector2. Perfect for 8-directional movement.
gdscript func _process(delta): var dpad = PSG1Input.get_dpad_vector() # dpad.x is -1 (left), 0 (none), or 1 (right) # dpad.y is -1 (up), 0 (none), or 1 (down)
grid_position += dpad
Advanced Functions get_axis(negative_action: StringName, positive_action: StringName) -> float Combines two button actions into a single axis. Returns -1.0 when the negative action is pressed, 1.0 when positive is pressed, and 0.0 when neither or both are pressed.
gdscript func _process(delta): # Get horizontal input from D-pad var horizontal = PSG1Input.get_axis("psg1_dpad_left", "psg1_dpad_right")
# Get vertical input from D-pad
var vertical = PSG1Input.get_axis("psg1_dpad_up", "psg1_dpad_down")
velocity.x = horizontal * speed
velocity.y = vertical * speed
get_axis_raw(action: StringName) -> float Gets the raw value of a single analog axis. Returns -1.0 to 1.0. Use this for individual stick axes.
gdscript func _process(delta): var horizontal = PSG1Input.get_axis_raw("psg1_left_stick_x") var vertical = PSG1Input.get_axis_raw("psg1_left_stick_y") get_vector(negative_x, positive_x, negative_y, positive_y, deadzone) -> Vector2 Combines four actions into a Vector2. Works with both buttons and analog inputs.
gdscript
Using D-pad buttons
var movement = PSG1Input.get_vector( "psg1_dpad_left", "psg1_dpad_right", "psg1_dpad_up", "psg1_dpad_down" )
Using analog sticks
var movement = PSG1Input.get_vector( "psg1_left_stick_x", "psg1_left_stick_x", "psg1_left_stick_y", "psg1_left_stick_y", 0.2 # deadzone ) Device Management set_device(device_id: int) -> void Changes which controller to read from. Use this for multiplayer games.
gdscript
Player 1 uses first controller
PSG1Input.set_device(0)
Player 2 uses second controller
PSG1Input.set_device(1) refresh_actions() -> void Forces the library to re-register all input actions. Call this after changing the device ID.
gdscript func switch_to_player_2(): PSG1Input.set_device(1) PSG1Input.refresh_actions() unregister_input_actions() -> void Removes all PSG1 actions from Godot's InputMap. Only use this if you need to clean up before your game exits.
gdscript func _exit_tree(): PSG1Input.unregister_input_actions() Debugging debug_print_state() -> void Prints all current button and stick states to the console. Helpful when testing controller input.
gdscript func _ready(): PSG1Input.debug_print_state() Output example:
=== PSG1 Controller State === Device: 0 Buttons: psg1_south: PRESSED Axes: Left Stick: (0.75, -0.32) Right Stick: (0, 0) Triggers: (0, 0.8) D-pad: (1, 0) Common Patterns Basic Movement gdscript extends CharacterBody2D
@export var speed = 200.0
func _process(delta): var movement = PSG1Input.get_left_stick() velocity = movement * speed move_and_slide() Jump and Run gdscript extends CharacterBody2D
@export var speed = 300.0 @export var jump_force = 500.0
func _process(delta): # Horizontal movement var horizontal = PSG1Input.get_axis("psg1_dpad_left", "psg1_dpad_right") velocity.x = horizontal * speed
# Jump
if PSG1Input.is_action_just_pressed("psg1_south") and is_on_floor():
velocity.y = -jump_force
# Gravity
velocity.y += 980 * delta
move_and_slide()
Twin-Stick Shooter gdscript extends CharacterBody2D
func _process(delta): # Move with left stick var movement = PSG1Input.get_left_stick() velocity = movement * 200 move_and_slide()
# Aim with right stick
var aim = PSG1Input.get_right_stick()
if aim.length() > 0.2:
rotation = aim.angle()
# Shoot with right trigger
if PSG1Input.get_action_strength("psg1_r2") > 0.5:
shoot()
Racing Game gdscript extends VehicleBody3D
func _process(delta): var triggers = PSG1Input.get_triggers() var steering = PSG1Input.get_axis_raw("psg1_left_stick_x")
# Gas and brake
engine_force = triggers.y * 400 # Right trigger
brake = triggers.x * 100 # Left trigger
# Steering
steering = steering * 0.5
Menu Navigation gdscript extends Control
func _process(delta): # Navigate menu with D-pad if PSG1Input.is_action_just_pressed("psg1_dpad_down"): select_next_item()
if PSG1Input.is_action_just_pressed("psg1_dpad_up"):
select_previous_item()
# Confirm with south button
if PSG1Input.is_action_just_pressed("psg1_south"):
activate_selected_item()
# Cancel with east button
if PSG1Input.is_action_just_pressed("psg1_east"):
go_back()
Combining Keyboard and Controller gdscript
In Project Settings > Input Map, create an action called "jump"
Add these inputs to it:
- Space key
- psg1_south button
func _process(delta): # This works for both keyboard and controller if Input.is_action_just_pressed("jump"): player.jump()
# Mix keyboard WASD with controller stick
var keyboard = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
var controller = PSG1Input.get_left_stick()
# Use whichever has input
var movement = controller if controller.length() > 0 else keyboard
velocity = movement * speed
Multiplayer (Local) gdscript extends Node2D
var player1_input var player2_input
func _ready(): # Player 1 gets device 0 player1_input = PSG1Input.duplicate() player1_input.set_device(0)
# Player 2 gets device 1
player2_input = PSG1Input.duplicate()
player2_input.set_device(1)
func _process(delta): # Player 1 controls var p1_move = PSG1Input.get_left_stick() # Device 0 by default player1.velocity = p1_move * 200
# Player 2 controls
PSG1Input.set_device(1)
var p2_move = PSG1Input.get_left_stick()
player2.velocity = p2_move * 200
# Reset to player 1
PSG1Input.set_device(0)
InputMap Integration PSG1Input automatically registers all actions in Godot's InputMap. This means you can use standard Input functions:
gdscript
These are equivalent:
PSG1Input.is_action_just_pressed("psg1_south") Input.is_action_just_pressed("psg1_south")
You can even view PSG1 actions in Project Settings > Input Map
Adding custom mappings:
Go to Project Settings > Input Map Create a new action (like "jump") Click the + button Select "Joy Buttons" Choose "Button 0" (which is psg1_south) Now you can use Input.is_action_just_pressed("jump") Tips and Best Practices Use deadzones for analog sticks: Analog sticks can drift slightly even when not touched. A deadzone of 0.2 prevents unwanted movement.
gdscript
Good: Has deadzone
var stick = PSG1Input.get_left_stick(0.2)
Bad: No deadzone, stick drift causes issues
var stick = PSG1Input.get_left_stick(0.0) Check for just_pressed on actions: Use is_action_just_pressed() for single actions like jumping or shooting. Use is_action_pressed() for continuous actions like running.
gdscript
Good: Jump once per press
if PSG1Input.is_action_just_pressed("psg1_south"): jump()
Bad: Jumps every frame while held
if PSG1Input.is_action_pressed("psg1_south"): jump() Normalize diagonal movement: When using sticks for movement, diagonal input can be faster than cardinal directions. The stick values are already normalized, but if you're combining multiple inputs, normalize the final vector.
gdscript var movement = PSG1Input.get_left_stick() if movement.length() > 1.0: movement = movement.normalized() velocity = movement * speed Test with actual hardware: The PSG1 controller behaves differently than keyboard input. Always test your game with the real hardware.
Troubleshooting No input detected:
Make sure PSG1Input is set as an AutoLoad singleton Call PSG1Input.debug_print_state() to see what the library detects Check that your controller is connected and recognized by your device Wrong button mappings:
The library uses standard Android keycodes If buttons seem swapped, check the button constant definitions at the top of the script Stick drift:
Increase the deadzone value: PSG1Input.get_left_stick(0.3) Clean your controller's analog sticks Multiple controllers not working:
Use PSG1Input.set_device(1) to switch to the second controller Call PSG1Input.refresh_actions() after changing devices Technical Details Coordinate System: Y-axis is inverted to match Unity's behavior. Pushing the stick up returns negative Y values.
Button Indices: The library maps Android keycodes to Godot's JOY_BUTTON constants automatically.
Axis Mapping: Android axis indices are converted to Godot's JOY_AXIS constants.
Auto-Registration: Actions are registered to InputMap on first use. No manual setup required.
License This library is provided as-is for use with PSG1 hardware. Modify and distribute freely.
Play Solana Gen 1 Input key mapping
Read docs:
https://github.com/mira4sol/psg1_input_binding
Reviews
Quick Information
Play Solana Gen 1 Input key mappingRead docs:https://github.com/mira4sol/psg1_input_binding