Compare commits

..

No commits in common. "6e3625420319e7f7641a7c3b0639d1258225761b" and "bb43c9aad8f297e61537884e61bd58029138134c" have entirely different histories.

4 changed files with 45 additions and 135 deletions

@ -1 +1 @@
Subproject commit 31b740325288d9a92debc024a26bf1d689b3ac58 Subproject commit 29ade46a0a58e885a9a913f738cdb30d54e0a9c5

View File

@ -1,7 +1,4 @@
use std::{ use std::sync::{Arc, RwLock};
collections::HashMap,
sync::{Arc, RwLock},
};
use gilrs::{Event as GamepadEvent, EventType, GamepadId, ev::Code}; use gilrs::{Event as GamepadEvent, EventType, GamepadId, ev::Code};
use winit::{ use winit::{
@ -11,13 +8,12 @@ use winit::{
use crate::{ use crate::{
emulator::{EmulatorClient, EmulatorCommand, SimId, VBKey}, emulator::{EmulatorClient, EmulatorCommand, SimId, VBKey},
input::{AxisMapping, InputMapping, MappingProvider}, input::{InputMapping, MappingProvider},
}; };
pub struct Controller { pub struct Controller {
pub sim_id: SimId, pub sim_id: SimId,
state: VBKey, state: VBKey,
axis_values: HashMap<(GamepadId, Code), f32>,
mapping: Arc<RwLock<InputMapping>>, mapping: Arc<RwLock<InputMapping>>,
} }
@ -26,7 +22,6 @@ impl Controller {
Self { Self {
sim_id, sim_id,
state: VBKey::SGN, state: VBKey::SGN,
axis_values: HashMap::new(),
mapping: mappings.for_sim(sim_id).clone(), mapping: mappings.for_sim(sim_id).clone(),
} }
} }
@ -50,18 +45,22 @@ impl Controller {
(VBKey::empty(), mappings) (VBKey::empty(), mappings)
} }
EventType::AxisChanged(_, value, code) => { EventType::AxisChanged(_, value, code) => {
let mapping = self.map_axis(&event.id, &code)?; let (neg, pos) = self.map_axis(&event.id, &code)?;
self.axis_values.insert((event.id, code), value); let mut pressed = VBKey::empty();
let mut released = VBKey::empty();
let pair_value = mapping if value < -0.75 {
.pair pressed = pressed.union(neg);
.and_then(|p| self.axis_values.get(&(event.id, p))) }
.copied() if value > 0.75 {
.unwrap_or_default(); pressed = pressed.union(pos);
let neg = mapping.neg; }
let pos = mapping.pos; if value > -0.65 {
released = released.union(neg);
axis_presses(value, pair_value, neg, pos) }
if value < 0.65 {
released = released.union(pos);
}
(pressed, released)
} }
_ => { _ => {
return None; return None;
@ -88,7 +87,7 @@ impl Controller {
self.mapping.read().unwrap().map_button(id, code) self.mapping.read().unwrap().map_button(id, code)
} }
fn map_axis(&self, id: &GamepadId, code: &Code) -> Option<AxisMapping> { fn map_axis(&self, id: &GamepadId, code: &Code) -> Option<(VBKey, VBKey)> {
self.mapping.read().unwrap().map_axis(id, code) self.mapping.read().unwrap().map_axis(id, code)
} }
} }
@ -127,81 +126,3 @@ impl ControllerManager {
} }
} }
} }
fn axis_presses(value: f32, pair_value: f32, neg: VBKey, pos: VBKey) -> (VBKey, VBKey) {
use std::f32::consts::FRAC_PI_3;
let mut pressed = VBKey::empty();
let mut released = VBKey::empty();
let magnitude = value.hypot(pair_value);
let abs_angle = pair_value.atan2(value);
if magnitude < 0.65 {
released = released.union(neg).union(pos);
} else if abs_angle <= FRAC_PI_3 {
// stick tilted towards positive
released = released.union(neg);
if magnitude >= 0.75 {
pressed = pressed.union(pos);
}
} else if abs_angle >= 2.0 * FRAC_PI_3 {
// stick tilted towards negative
released = released.union(pos);
if magnitude >= 0.75 {
pressed = pressed.union(neg);
}
} else {
released = released.union(neg).union(pos);
}
(pressed, released)
}
#[cfg(test)]
mod tests {
use super::{VBKey, axis_presses};
const NEG: VBKey = VBKey::LL;
const POS: VBKey = VBKey::LR;
const NONE: VBKey = VBKey::empty();
const BOTH: VBKey = NEG.union(POS);
#[test]
fn detects_no_input() {
let (pressed, released) = axis_presses(0.0, 0.0, NEG, POS);
assert_eq!(pressed, NONE);
assert_eq!(released, BOTH);
}
#[test]
fn detects_pos_input() {
let (pressed, released) = axis_presses(1.0, 0.0, NEG, POS);
assert_eq!(pressed, POS);
assert_eq!(released, NEG);
}
#[test]
fn detects_neg_input() {
let (pressed, released) = axis_presses(-1.0, 0.0, NEG, POS);
assert_eq!(pressed, NEG);
assert_eq!(released, POS);
}
#[test]
fn respects_dead_zone() {
let (pressed, released) = axis_presses(0.70, 0.0, NEG, POS);
assert_eq!(pressed, NONE);
assert_eq!(released, NEG);
}
#[test]
fn handles_diagonals_ok() {
let (pressed, released) = axis_presses(0.6, 0.6, NEG, POS);
assert_eq!(pressed, POS);
assert_eq!(released, NEG);
}
}

View File

@ -52,28 +52,12 @@ pub trait Mappings {
fn use_default_mappings(&mut self); fn use_default_mappings(&mut self);
} }
#[derive(Clone, Copy, Serialize, Deserialize)]
pub struct AxisMapping {
pub neg: VBKey,
pub pos: VBKey,
pub pair: Option<Code>,
}
impl Default for AxisMapping {
fn default() -> Self {
Self {
neg: VBKey::empty(),
pos: VBKey::empty(),
pair: None,
}
}
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct GamepadMapping { pub struct GamepadMapping {
buttons: HashMap<Code, VBKey>, buttons: HashMap<Code, VBKey>,
axes: HashMap<Code, AxisMapping>, axes: HashMap<Code, (VBKey, VBKey)>,
default_buttons: HashMap<Code, VBKey>, default_buttons: HashMap<Code, VBKey>,
default_axes: HashMap<Code, AxisMapping>, default_axes: HashMap<Code, (VBKey, VBKey)>,
} }
impl GamepadMapping { impl GamepadMapping {
@ -94,8 +78,7 @@ impl GamepadMapping {
let mut default_axes = HashMap::new(); let mut default_axes = HashMap::new();
let mut default_axis = |axis: Axis, neg: VBKey, pos: VBKey| { let mut default_axis = |axis: Axis, neg: VBKey, pos: VBKey| {
if let Some(code) = gamepad.axis_code(axis) { if let Some(code) = gamepad.axis_code(axis) {
let pair = axis.second_axis().and_then(|a| gamepad.axis_code(a)); default_axes.insert(code, (neg, pos));
default_axes.insert(code, AxisMapping { neg, pos, pair });
} }
}; };
default_axis(Axis::LeftStickX, VBKey::LL, VBKey::LR); default_axis(Axis::LeftStickX, VBKey::LL, VBKey::LR);
@ -119,13 +102,19 @@ impl GamepadMapping {
} }
pub fn add_axis_neg_mapping(&mut self, key: VBKey, code: Code) { pub fn add_axis_neg_mapping(&mut self, key: VBKey, code: Code) {
let entry = self.axes.entry(code).or_default(); let entry = self
entry.neg = entry.neg.union(key); .axes
.entry(code)
.or_insert((VBKey::empty(), VBKey::empty()));
entry.0 = entry.0.union(key);
} }
pub fn add_axis_pos_mapping(&mut self, key: VBKey, code: Code) { pub fn add_axis_pos_mapping(&mut self, key: VBKey, code: Code) {
let entry = self.axes.entry(code).or_default(); let entry = self
entry.pos = entry.pos.union(key); .axes
.entry(code)
.or_insert((VBKey::empty(), VBKey::empty()));
entry.1 = entry.1.union(key);
} }
fn save_mappings(&self) -> PersistedGamepadMapping { fn save_mappings(&self) -> PersistedGamepadMapping {
@ -156,11 +145,11 @@ impl GamepadMapping {
impl Mappings for GamepadMapping { impl Mappings for GamepadMapping {
fn mapping_names(&self) -> HashMap<VBKey, Vec<String>> { fn mapping_names(&self) -> HashMap<VBKey, Vec<String>> {
let mut results: HashMap<VBKey, Vec<String>> = HashMap::new(); let mut results: HashMap<VBKey, Vec<String>> = HashMap::new();
for (axis, mapping) in &self.axes { for (axis, (left_keys, right_keys)) in &self.axes {
for key in mapping.neg.iter() { for key in left_keys.iter() {
results.entry(key).or_default().push(format!("-{axis}")); results.entry(key).or_default().push(format!("-{axis}"));
} }
for key in mapping.pos.iter() { for key in right_keys.iter() {
results.entry(key).or_default().push(format!("+{axis}")); results.entry(key).or_default().push(format!("+{axis}"));
} }
} }
@ -173,10 +162,10 @@ impl Mappings for GamepadMapping {
} }
fn clear_mappings(&mut self, key: VBKey) { fn clear_mappings(&mut self, key: VBKey) {
self.axes.retain(|_, mapping| { self.axes.retain(|_, (left, right)| {
mapping.neg = mapping.neg.difference(key); *left = left.difference(key);
mapping.pos = mapping.pos.difference(key); *right = right.difference(key);
!(mapping.neg.is_empty() && mapping.pos.is_empty()) !(left.is_empty() && right.is_empty())
}); });
self.buttons.retain(|_, keys| { self.buttons.retain(|_, keys| {
*keys = keys.difference(key); *keys = keys.difference(key);
@ -211,7 +200,7 @@ impl InputMapping {
mappings.buttons.get(code).copied() mappings.buttons.get(code).copied()
} }
pub fn map_axis(&self, id: &GamepadId, code: &Code) -> Option<AxisMapping> { pub fn map_axis(&self, id: &GamepadId, code: &Code) -> Option<(VBKey, VBKey)> {
let mappings = self.gamepads.get(id)?.read().unwrap(); let mappings = self.gamepads.get(id)?.read().unwrap();
mappings.axes.get(code).copied() mappings.axes.get(code).copied()
} }
@ -470,9 +459,9 @@ struct PersistedKeyboardMapping {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct PersistedGamepadMapping { struct PersistedGamepadMapping {
buttons: Vec<(Code, VBKey)>, buttons: Vec<(Code, VBKey)>,
axes: Vec<(Code, AxisMapping)>, axes: Vec<(Code, (VBKey, VBKey))>,
default_buttons: Vec<(Code, VBKey)>, default_buttons: Vec<(Code, VBKey)>,
default_axes: Vec<(Code, AxisMapping)>, default_axes: Vec<(Code, (VBKey, VBKey))>,
} }
#[derive(Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]

View File

@ -1081,8 +1081,8 @@ impl<'a> SourceCoordCalculator<'a> {
(sx, sy) (sx, sy)
} }
SourceParam::Affine(affine) => { SourceParam::Affine(affine) => {
let sx = affine_coord(affine.src_x, x, affine.dx, -(affine.src_parallax.min(0))); let sx = affine_coord(affine.src_x, x, affine.dx, affine.src_parallax.min(0));
let sy = affine_coord(affine.src_y, x, affine.dy, -(affine.src_parallax.min(0))); let sy = affine_coord(affine.src_y, x, affine.dy, affine.src_parallax.min(0));
(sx, sy) (sx, sy)
} }
} }