Implement gamepad input
This commit is contained in:
+41
-19
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user