handle controller reconnection (#815)

This commit is contained in:
Logan McNaughton
2026-04-27 08:38:20 -06:00
committed by GitHub
parent ca00ee1a42
commit b2ef544513
6 changed files with 106 additions and 9 deletions
+1
View File
@@ -211,6 +211,7 @@ fn main() {
.allowlist_function("rdp_save_state")
.allowlist_function("rdp_load_state")
.allowlist_function("rdp_set_fps")
.allowlist_function("get_joystick_event")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate()
.expect("Unable to generate bindings");
+28 -2
View File
@@ -98,8 +98,8 @@ static GFX_INFO gfx_info;
static const uint32_t *fragment_spirv;
static size_t fragment_size;
std::vector<bool> rdram_dirty;
uint64_t sync_signal;
static std::vector<bool> rdram_dirty;
static uint64_t sync_signal;
static TTF_Font *message_font;
static std::queue<Message> messages;
@@ -114,6 +114,8 @@ static bool display_challenge_indicator;
static bool display_fps;
static Vulkan::ImageHandle fps_image;
static std::queue<JoystickEvent> joystick_events;
typedef struct {
float SourceSize[4];
float OutputSize[4];
@@ -125,6 +127,12 @@ static const unsigned cmd_len_lut[64] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
static void add_joystick_event(void *userdata) {
JoystickEvent *joystick_event = (JoystickEvent *)userdata;
joystick_events.push(*joystick_event);
delete joystick_event;
}
bool sdl_event_filter(void *userdata, SDL_Event *event) {
if (event->type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) {
callback.paused = false;
@@ -209,11 +217,29 @@ bool sdl_event_filter(void *userdata, SDL_Event *event) {
default:
break;
}
} else if (event->type == SDL_EVENT_JOYSTICK_ADDED) {
JoystickEvent *joystick_event = new JoystickEvent;
joystick_event->joystick_id = event->jdevice.which;
joystick_event->connected = true;
SDL_RunOnMainThread(add_joystick_event, joystick_event, false);
} else if (event->type == SDL_EVENT_JOYSTICK_REMOVED) {
JoystickEvent *joystick_event = new JoystickEvent;
joystick_event->joystick_id = event->jdevice.which;
joystick_event->connected = false;
SDL_RunOnMainThread(add_joystick_event, joystick_event, false);
}
return 0;
}
JoystickEvent get_joystick_event() {
if (joystick_events.empty())
return JoystickEvent{0, false};
JoystickEvent joystick_event = joystick_events.front();
joystick_events.pop();
return joystick_event;
}
void rdp_new_processor(GFX_INFO _gfx_info) {
gfx_info = _gfx_info;
+7
View File
@@ -37,6 +37,11 @@ typedef struct {
uint32_t save_state_slot;
} CALL_BACK;
typedef struct {
uint32_t joystick_id;
bool connected;
} JoystickEvent;
typedef enum {
MESSAGE_VERY_SHORT = 500,
MESSAGE_SHORT = 3000,
@@ -59,6 +64,8 @@ void rdp_save_state(uint8_t *state);
void rdp_load_state(const uint8_t *state);
void rdp_set_fps(uint32_t fps, uint32_t vis);
JoystickEvent get_joystick_event();
void achievement_challenge_indicator_add(const char *achievement_title);
void achievement_challenge_indicator_remove(const char *achievement_title);
void achievement_progress_add(const char *achievement_title,
+2 -2
View File
@@ -58,12 +58,12 @@ pub fn process(device: &mut device::Device, channel: usize) {
let offset = device.pif.channels[channel].rx_buf.unwrap();
let input = if let Some(netplay) = &mut device.netplay {
if netplay.player_number as usize == channel {
let local_input = ui::input::get(&device.ui, 0);
let local_input = ui::input::get(&mut device.ui, 0);
netplay::send_input(netplay, local_input);
}
netplay::get_input(device, channel)
} else {
ui::input::get(&device.ui, channel)
ui::input::get(&mut device.ui, channel)
};
device.pif.ram[offset..offset + 4].copy_from_slice(&input.data.to_ne_bytes());
+4
View File
@@ -151,21 +151,25 @@ impl Ui {
game_controller: std::ptr::null_mut(),
joystick: std::ptr::null_mut(),
rumble: false,
guid: sdl3_sys::guid::SDL_GUID::default(),
},
input::Controllers {
game_controller: std::ptr::null_mut(),
joystick: std::ptr::null_mut(),
rumble: false,
guid: sdl3_sys::guid::SDL_GUID::default(),
},
input::Controllers {
game_controller: std::ptr::null_mut(),
joystick: std::ptr::null_mut(),
rumble: false,
guid: sdl3_sys::guid::SDL_GUID::default(),
},
input::Controllers {
game_controller: std::ptr::null_mut(),
joystick: std::ptr::null_mut(),
rumble: false,
guid: sdl3_sys::guid::SDL_GUID::default(),
},
],
keyboard_state: std::ptr::null_mut(),
+64 -5
View File
@@ -34,6 +34,7 @@ pub struct Controllers {
pub rumble: bool,
pub game_controller: *mut sdl3_sys::gamepad::SDL_Gamepad,
pub joystick: *mut sdl3_sys::joystick::SDL_Joystick,
pub guid: sdl3_sys::guid::SDL_GUID,
}
pub struct InputData {
@@ -400,9 +401,59 @@ pub fn get_controller_paths(game_ui: &ui::Ui) -> Vec<Option<String>> {
controller_paths
}
pub fn get(ui: &ui::Ui, channel: usize) -> InputData {
let profile_name = ui.config.input.input_profile_binding[channel].clone();
let profile = ui.config.input.input_profiles.get(&profile_name).unwrap();
fn handle_joystick_events(ui: &mut ui::Ui) {
let joystick_event = unsafe { ui::video::get_joystick_event() };
if joystick_event.joystick_id != 0 {
let joystick_id = sdl3_sys::joystick::SDL_JoystickID(joystick_event.joystick_id);
for (i, controller) in ui.input.controllers.iter_mut().enumerate() {
if joystick_event.connected {
let profile = ui
.config
.input
.input_profiles
.get(&ui.config.input.input_profile_binding[i])
.unwrap();
if profile.dinput {
if controller.joystick.is_null()
&& controller.guid
== unsafe { sdl3_sys::joystick::SDL_GetJoystickGUIDForID(joystick_id) }
{
controller.joystick =
unsafe { sdl3_sys::joystick::SDL_OpenJoystick(joystick_id) };
}
} else {
if controller.game_controller.is_null()
&& controller.guid
== unsafe { sdl3_sys::gamepad::SDL_GetGamepadGUIDForID(joystick_id) }
{
controller.game_controller =
unsafe { sdl3_sys::gamepad::SDL_OpenGamepad(joystick_id) };
}
}
} else {
if !controller.joystick.is_null()
&& controller.joystick
== unsafe { sdl3_sys::joystick::SDL_GetJoystickFromID(joystick_id) }
{
unsafe { sdl3_sys::joystick::SDL_CloseJoystick(controller.joystick) };
controller.joystick = std::ptr::null_mut();
} else if !controller.game_controller.is_null()
&& controller.game_controller
== unsafe { sdl3_sys::gamepad::SDL_GetGamepadFromID(joystick_id) }
{
unsafe { sdl3_sys::gamepad::SDL_CloseGamepad(controller.game_controller) };
controller.game_controller = std::ptr::null_mut();
}
}
}
}
}
pub fn get(ui: &mut ui::Ui, channel: usize) -> InputData {
handle_joystick_events(ui);
let profile_name = &ui.config.input.input_profile_binding[channel];
let profile = ui.config.input.input_profiles.get(profile_name).unwrap();
let mut keys = 0;
let controller = ui.input.controllers[channel].game_controller;
let joystick = ui.input.controllers[channel].joystick;
@@ -990,8 +1041,12 @@ pub fn init(ui: &mut ui::Ui) {
}
if joystick_id != 0 {
let profile_name = ui.config.input.input_profile_binding[i].clone();
let profile = ui.config.input.input_profiles.get(&profile_name).unwrap();
let profile = ui
.config
.input
.input_profiles
.get(&ui.config.input.input_profile_binding[i])
.unwrap();
if !profile.dinput {
let gamepad = unsafe { sdl3_sys::gamepad::SDL_OpenGamepad(joystick_id) };
@@ -999,6 +1054,8 @@ pub fn init(ui: &mut ui::Ui) {
println!("could not connect gamepad: {}", u32::from(joystick_id))
} else {
ui.input.controllers[i].game_controller = gamepad;
ui.input.controllers[i].guid =
unsafe { sdl3_sys::gamepad::SDL_GetGamepadGUIDForID(joystick_id) };
let properties =
unsafe { sdl3_sys::gamepad::SDL_GetGamepadProperties(gamepad) };
if properties == 0 {
@@ -1018,6 +1075,8 @@ pub fn init(ui: &mut ui::Ui) {
println!("could not connect joystick: {}", u32::from(joystick_id))
} else {
ui.input.controllers[i].joystick = joystick;
ui.input.controllers[i].guid =
unsafe { sdl3_sys::joystick::SDL_GetJoystickGUIDForID(joystick_id) };
let properties =
unsafe { sdl3_sys::joystick::SDL_GetJoystickProperties(joystick) };
if properties == 0 {