Implement gamepad input
This commit is contained in:
+112
-32
@@ -1,48 +1,128 @@
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use winit::event::{ElementState, KeyEvent};
|
||||
|
||||
use crate::{
|
||||
emulator::{SimId, VBKey},
|
||||
input::InputMapper,
|
||||
use gilrs::{ev::Code, Event as GamepadEvent, EventType, GamepadId};
|
||||
use winit::{
|
||||
event::{ElementState, KeyEvent},
|
||||
keyboard::PhysicalKey,
|
||||
};
|
||||
|
||||
pub struct ControllerState {
|
||||
input_mapper: Arc<RwLock<InputMapper>>,
|
||||
pressed: Vec<VBKey>,
|
||||
use crate::{
|
||||
emulator::{EmulatorClient, EmulatorCommand, SimId, VBKey},
|
||||
input::{InputMapping, MappingProvider},
|
||||
};
|
||||
|
||||
pub struct Controller {
|
||||
pub sim_id: SimId,
|
||||
state: VBKey,
|
||||
mapping: Arc<RwLock<InputMapping>>,
|
||||
}
|
||||
|
||||
impl ControllerState {
|
||||
pub fn new(input_mapper: Arc<RwLock<InputMapper>>) -> Self {
|
||||
impl Controller {
|
||||
pub fn new(sim_id: SimId, mappings: &MappingProvider) -> Self {
|
||||
Self {
|
||||
input_mapper,
|
||||
pressed: vec![VBKey::SGN; 2],
|
||||
sim_id,
|
||||
state: VBKey::SGN,
|
||||
mapping: mappings.for_sim(sim_id).clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key_event(&mut self, event: &KeyEvent) -> Option<(SimId, VBKey)> {
|
||||
let (sim_id, input) = self.key_event_to_input(event)?;
|
||||
let pressed = &mut self.pressed[sim_id.to_index()];
|
||||
pub fn key_event(&mut self, event: &KeyEvent) -> Option<VBKey> {
|
||||
let keys = self.map_keys(&event.physical_key)?;
|
||||
match event.state {
|
||||
ElementState::Pressed => {
|
||||
if pressed.contains(input) {
|
||||
return None;
|
||||
}
|
||||
pressed.insert(input);
|
||||
Some((sim_id, *pressed))
|
||||
}
|
||||
ElementState::Released => {
|
||||
if !pressed.contains(input) {
|
||||
return None;
|
||||
}
|
||||
pressed.remove(input);
|
||||
Some((sim_id, *pressed))
|
||||
}
|
||||
ElementState::Pressed => self.update_state(keys, VBKey::empty()),
|
||||
ElementState::Released => self.update_state(VBKey::empty(), keys),
|
||||
}
|
||||
}
|
||||
|
||||
fn key_event_to_input(&self, event: &KeyEvent) -> Option<(SimId, VBKey)> {
|
||||
let mapper = self.input_mapper.read().unwrap();
|
||||
mapper.key_event(event)
|
||||
pub fn gamepad_event(&mut self, event: &GamepadEvent) -> Option<VBKey> {
|
||||
let (pressed, released) = match event.event {
|
||||
EventType::ButtonPressed(_, code) => {
|
||||
let mappings = self.map_button(&event.id, &code)?;
|
||||
(mappings, VBKey::empty())
|
||||
}
|
||||
EventType::ButtonReleased(_, code) => {
|
||||
let mappings = self.map_button(&event.id, &code)?;
|
||||
(VBKey::empty(), mappings)
|
||||
}
|
||||
EventType::AxisChanged(_, value, code) => {
|
||||
let (neg, pos) = self.map_axis(&event.id, &code)?;
|
||||
let mut pressed = VBKey::empty();
|
||||
let mut released = VBKey::empty();
|
||||
if value < -0.75 {
|
||||
pressed = pressed.union(neg);
|
||||
}
|
||||
if value > 0.75 {
|
||||
pressed = pressed.union(pos);
|
||||
}
|
||||
if value > -0.65 {
|
||||
released = released.union(neg);
|
||||
}
|
||||
if value < 0.65 {
|
||||
released = released.union(pos);
|
||||
}
|
||||
(pressed, released)
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
self.update_state(pressed, released)
|
||||
}
|
||||
|
||||
fn update_state(&mut self, pressed: VBKey, released: VBKey) -> Option<VBKey> {
|
||||
let old_state = self.state;
|
||||
self.state = self.state.union(pressed).difference(released);
|
||||
if self.state != old_state {
|
||||
Some(self.state)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn map_keys(&self, key: &PhysicalKey) -> Option<VBKey> {
|
||||
self.mapping.read().unwrap().map_keyboard(key)
|
||||
}
|
||||
|
||||
fn map_button(&self, id: &GamepadId, code: &Code) -> Option<VBKey> {
|
||||
self.mapping.read().unwrap().map_button(id, code)
|
||||
}
|
||||
|
||||
fn map_axis(&self, id: &GamepadId, code: &Code) -> Option<(VBKey, VBKey)> {
|
||||
self.mapping.read().unwrap().map_axis(id, code)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ControllerManager {
|
||||
client: EmulatorClient,
|
||||
controllers: [Controller; 2],
|
||||
}
|
||||
|
||||
impl ControllerManager {
|
||||
pub fn new(client: EmulatorClient, mappings: &MappingProvider) -> Self {
|
||||
Self {
|
||||
client,
|
||||
controllers: [
|
||||
Controller::new(SimId::Player1, mappings),
|
||||
Controller::new(SimId::Player2, mappings),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_key_event(&mut self, event: &KeyEvent) {
|
||||
for controller in &mut self.controllers {
|
||||
if let Some(pressed) = controller.key_event(event) {
|
||||
self.client
|
||||
.send_command(EmulatorCommand::SetKeys(controller.sim_id, pressed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_gamepad_event(&mut self, event: &GamepadEvent) {
|
||||
for controller in &mut self.controllers {
|
||||
if let Some(pressed) = controller.gamepad_event(event) {
|
||||
self.client
|
||||
.send_command(EmulatorCommand::SetKeys(controller.sim_id, pressed));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user