Implement gamepad input

This commit is contained in:
2024-11-18 22:49:56 -05:00
parent c84531e70e
commit f60b10ce1d
6 changed files with 435 additions and 140 deletions
+41 -19
View File
@@ -1,10 +1,7 @@
use std::{
collections::HashMap,
fmt::Debug,
sync::{Arc, RwLock},
};
use std::{collections::HashMap, fmt::Debug, thread};
use game::GameWindow;
use gilrs::{EventType, Gilrs};
use input::InputWindow;
use winit::{
application::ApplicationHandler,
@@ -14,9 +11,9 @@ use winit::{
};
use crate::{
controller::ControllerState,
emulator::{EmulatorClient, EmulatorCommand, SimId},
input::InputMapper,
controller::ControllerManager,
emulator::{EmulatorClient, SimId},
input::MappingProvider,
};
mod common;
@@ -26,21 +23,26 @@ mod input;
pub struct App {
windows: HashMap<WindowId, Box<dyn AppWindow>>,
client: EmulatorClient,
input_mapper: Arc<RwLock<InputMapper>>,
controller: ControllerState,
mappings: MappingProvider,
controllers: ControllerManager,
proxy: EventLoopProxy<UserEvent>,
player_2_window: Option<WindowId>,
}
impl App {
pub fn new(client: EmulatorClient, proxy: EventLoopProxy<UserEvent>) -> Self {
let input_mapper = Arc::new(RwLock::new(InputMapper::new()));
let controller = ControllerState::new(input_mapper.clone());
let mappings = MappingProvider::new();
let controllers = ControllerManager::new(client.clone(), &mappings);
{
let mappings = mappings.clone();
let proxy = proxy.clone();
thread::spawn(|| process_gamepad_input(mappings, proxy));
}
Self {
windows: HashMap::new(),
client,
input_mapper,
controller,
mappings,
controllers,
proxy,
player_2_window: None,
}
@@ -65,10 +67,7 @@ impl ApplicationHandler<UserEvent> for App {
event: WindowEvent,
) {
if let WindowEvent::KeyboardInput { event, .. } = &event {
if let Some((sim_id, pressed)) = self.controller.key_event(event) {
self.client
.send_command(EmulatorCommand::SetKeys(sim_id, pressed));
}
self.controllers.handle_key_event(event);
}
let Some(window) = self.windows.get_mut(&window_id) else {
return;
@@ -80,7 +79,7 @@ impl ApplicationHandler<UserEvent> for App {
match event {
UserEvent::OpenInputWindow => {
let window =
InputWindow::new(event_loop, self.input_mapper.clone(), self.proxy.clone());
InputWindow::new(event_loop, self.mappings.clone(), self.proxy.clone());
self.windows.insert(window.id(), Box::new(window));
}
UserEvent::OpenPlayer2Window => {
@@ -102,6 +101,9 @@ impl ApplicationHandler<UserEvent> for App {
}
self.windows.remove(&window_id);
}
UserEvent::GamepadEvent(event) => {
self.controllers.handle_gamepad_event(&event);
}
}
}
@@ -139,4 +141,24 @@ pub enum UserEvent {
OpenInputWindow,
OpenPlayer2Window,
Close(WindowId),
GamepadEvent(gilrs::Event),
}
fn process_gamepad_input(mappings: MappingProvider, proxy: EventLoopProxy<UserEvent>) {
let Ok(mut gilrs) = Gilrs::new() else {
eprintln!("could not connect gamepad listener");
return;
};
while let Some(event) = gilrs.next_event_blocking(None) {
if event.event == EventType::Connected {
let Some(gamepad) = gilrs.connected_gamepad(event.id) else {
continue;
};
mappings.map_gamepad(SimId::Player1, &gamepad);
}
if proxy.send_event(UserEvent::GamepadEvent(event)).is_err() {
// main thread has closed! we done
return;
}
}
}