Compare commits

..

No commits in common. "0c35a1e234133c55ac7f8d2f13414d7ad459322d" and "24474fabd0672139a561e06724ed14703e07283d" have entirely different histories.

4 changed files with 56 additions and 245 deletions

View File

@ -8,7 +8,7 @@ use egui::{
use gilrs::{EventType, Gilrs}; use gilrs::{EventType, Gilrs};
use winit::{ use winit::{
application::ApplicationHandler, application::ApplicationHandler,
event::WindowEvent, event::{KeyEvent, WindowEvent},
event_loop::{ActiveEventLoop, EventLoopProxy}, event_loop::{ActiveEventLoop, EventLoopProxy},
window::Window, window::Window,
}; };
@ -83,7 +83,7 @@ impl ApplicationHandler<UserEvent> for Application {
match &event { match &event {
WindowEvent::KeyboardInput { event, .. } => { WindowEvent::KeyboardInput { event, .. } => {
self.controllers.handle_key_event(event); self.controllers.handle_key_event(event);
viewport.app.handle_key_event(event); viewport.handle_key_event(event);
} }
WindowEvent::Focused(new_focused) => { WindowEvent::Focused(new_focused) => {
self.focused = new_focused.then_some(viewport_id); self.focused = new_focused.then_some(viewport_id);
@ -143,17 +143,7 @@ impl ApplicationHandler<UserEvent> for Application {
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) { fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) {
match event { match event {
UserEvent::GamepadEvent(event) => { UserEvent::GamepadEvent(event) => self.controllers.handle_gamepad_event(&event),
self.controllers.handle_gamepad_event(&event);
let Some(viewport) = self
.focused
.as_ref()
.and_then(|id| self.viewports.get_mut(id))
else {
return;
};
viewport.app.handle_gamepad_event(&event);
}
UserEvent::OpenInput => { UserEvent::OpenInput => {
let input = InputWindow::new(self.mappings.clone()); let input = InputWindow::new(self.mappings.clone());
self.open(event_loop, Box::new(input)); self.open(event_loop, Box::new(input));
@ -258,6 +248,10 @@ impl Viewport {
} }
} }
pub fn handle_key_event(&mut self, event: &KeyEvent) {
self.app.handle_key_event(event);
}
fn redraw(&mut self, event_loop: &ActiveEventLoop) -> Option<Action> { fn redraw(&mut self, event_loop: &ActiveEventLoop) -> Option<Action> {
let mut input = self.state.take_egui_input(&self.window); let mut input = self.state.take_egui_input(&self.window);
input.viewports = std::iter::once((ViewportId::ROOT, self.info.clone())).collect(); input.viewports = std::iter::once((ViewportId::ROOT, self.info.clone())).collect();

View File

@ -19,26 +19,17 @@ pub struct GamepadInfo {
pub bound_to: Option<SimId>, pub bound_to: Option<SimId>,
} }
pub trait Mappings {
fn mapping_names(&self) -> HashMap<VBKey, Vec<String>>;
fn clear_mappings(&mut self, key: VBKey);
fn clear_all_mappings(&mut self);
fn use_default_mappings(&mut self);
}
pub struct GamepadMapping { pub struct GamepadMapping {
buttons: HashMap<Code, VBKey>, buttons: HashMap<Code, VBKey>,
axes: HashMap<Code, (VBKey, VBKey)>, axes: HashMap<Code, (VBKey, VBKey)>,
default_buttons: HashMap<Code, VBKey>,
default_axes: HashMap<Code, (VBKey, VBKey)>,
} }
impl GamepadMapping { impl GamepadMapping {
fn for_gamepad(gamepad: &Gamepad) -> Self { fn for_gamepad(gamepad: &Gamepad) -> Self {
let mut default_buttons = HashMap::new(); let mut buttons = HashMap::new();
let mut default_button = |btn: Button, key: VBKey| { let mut default_button = |btn: Button, key: VBKey| {
if let Some(code) = gamepad.button_code(btn) { if let Some(code) = gamepad.button_code(btn) {
default_buttons.insert(code, key); buttons.insert(code, key);
} }
}; };
default_button(Button::South, VBKey::A); default_button(Button::South, VBKey::A);
@ -48,10 +39,10 @@ impl GamepadMapping {
default_button(Button::Start, VBKey::STA); default_button(Button::Start, VBKey::STA);
default_button(Button::Select, VBKey::SEL); default_button(Button::Select, VBKey::SEL);
let mut default_axes = HashMap::new(); let mut 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) {
default_axes.insert(code, (neg, pos)); axes.insert(code, (neg, pos));
} }
}; };
default_axis(Axis::LeftStickX, VBKey::LL, VBKey::LR); default_axis(Axis::LeftStickX, VBKey::LL, VBKey::LR);
@ -61,75 +52,7 @@ impl GamepadMapping {
default_axis(Axis::DPadX, VBKey::LL, VBKey::LR); default_axis(Axis::DPadX, VBKey::LL, VBKey::LR);
default_axis(Axis::DPadY, VBKey::LD, VBKey::LU); default_axis(Axis::DPadY, VBKey::LD, VBKey::LU);
Self { Self { buttons, axes }
buttons: default_buttons.clone(),
axes: default_axes.clone(),
default_buttons,
default_axes,
}
}
pub fn add_button_mapping(&mut self, key: VBKey, code: Code) {
let entry = self.buttons.entry(code).or_insert(VBKey::empty());
*entry = entry.union(key);
}
pub fn add_axis_neg_mapping(&mut self, key: VBKey, code: Code) {
let entry = self
.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) {
let entry = self
.axes
.entry(code)
.or_insert((VBKey::empty(), VBKey::empty()));
entry.1 = entry.1.union(key);
}
}
impl Mappings for GamepadMapping {
fn mapping_names(&self) -> HashMap<VBKey, Vec<String>> {
let mut results: HashMap<VBKey, Vec<String>> = HashMap::new();
for (axis, (left_keys, right_keys)) in &self.axes {
for key in left_keys.iter() {
results.entry(key).or_default().push(format!("-{axis}"));
}
for key in right_keys.iter() {
results.entry(key).or_default().push(format!("+{axis}"));
}
}
for (button, keys) in &self.buttons {
for key in keys.iter() {
results.entry(key).or_default().push(format!("{button}"));
}
}
results
}
fn clear_mappings(&mut self, key: VBKey) {
self.axes.retain(|_, (left, right)| {
*left = left.difference(key);
*right = right.difference(key);
!(left.is_empty() && right.is_empty())
});
self.buttons.retain(|_, keys| {
*keys = keys.difference(key);
!keys.is_empty()
});
}
fn clear_all_mappings(&mut self) {
self.axes.clear();
self.buttons.clear();
}
fn use_default_mappings(&mut self) {
self.axes = self.default_axes.clone();
self.buttons = self.default_buttons.clone();
} }
} }
@ -158,10 +81,15 @@ impl InputMapping {
let entry = self.keys.entry(keyboard_key).or_insert(VBKey::empty()); let entry = self.keys.entry(keyboard_key).or_insert(VBKey::empty());
*entry = entry.union(key); *entry = entry.union(key);
} }
}
impl Mappings for InputMapping { pub fn clear_keyboard_mappings(&mut self, key: VBKey) {
fn mapping_names(&self) -> HashMap<VBKey, Vec<String>> { self.keys.retain(|_, keys| {
*keys = keys.difference(key);
*keys != VBKey::empty()
});
}
pub fn keyboard_mapping_names(&self) -> HashMap<VBKey, String> {
let mut results: HashMap<VBKey, Vec<String>> = HashMap::new(); let mut results: HashMap<VBKey, Vec<String>> = HashMap::new();
for (keyboard_key, keys) in &self.keys { for (keyboard_key, keys) in &self.keys {
let name = match keyboard_key { let name = match keyboard_key {
@ -173,38 +101,12 @@ impl Mappings for InputMapping {
} }
} }
results results
} .into_iter()
.map(|(k, mut v)| {
fn clear_mappings(&mut self, key: VBKey) { v.sort();
self.keys.retain(|_, keys| { (k, v.join(", "))
*keys = keys.difference(key); })
!keys.is_empty() .collect()
});
}
fn clear_all_mappings(&mut self) {
self.keys.clear();
}
fn use_default_mappings(&mut self) {
self.keys.clear();
let mut default_key = |code, key| {
self.keys.insert(PhysicalKey::Code(code), key);
};
default_key(KeyCode::KeyA, VBKey::SEL);
default_key(KeyCode::KeyS, VBKey::STA);
default_key(KeyCode::KeyD, VBKey::B);
default_key(KeyCode::KeyF, VBKey::A);
default_key(KeyCode::KeyE, VBKey::LT);
default_key(KeyCode::KeyR, VBKey::RT);
default_key(KeyCode::KeyI, VBKey::RU);
default_key(KeyCode::KeyJ, VBKey::RL);
default_key(KeyCode::KeyK, VBKey::RD);
default_key(KeyCode::KeyL, VBKey::RR);
default_key(KeyCode::ArrowUp, VBKey::LU);
default_key(KeyCode::ArrowLeft, VBKey::LL);
default_key(KeyCode::ArrowDown, VBKey::LD);
default_key(KeyCode::ArrowRight, VBKey::LR);
} }
} }
@ -220,8 +122,24 @@ impl MappingProvider {
let mut mappings = HashMap::new(); let mut mappings = HashMap::new();
let mut p1_mappings = InputMapping::default(); let mut p1_mappings = InputMapping::default();
p1_mappings.use_default_mappings();
let p2_mappings = InputMapping::default(); let p2_mappings = InputMapping::default();
let mut default_key = |code, key| {
p1_mappings.add_keyboard_mapping(key, PhysicalKey::Code(code));
};
default_key(KeyCode::KeyA, VBKey::SEL);
default_key(KeyCode::KeyS, VBKey::STA);
default_key(KeyCode::KeyD, VBKey::B);
default_key(KeyCode::KeyF, VBKey::A);
default_key(KeyCode::KeyE, VBKey::LT);
default_key(KeyCode::KeyR, VBKey::RT);
default_key(KeyCode::KeyI, VBKey::RU);
default_key(KeyCode::KeyJ, VBKey::RL);
default_key(KeyCode::KeyK, VBKey::RD);
default_key(KeyCode::KeyL, VBKey::RR);
default_key(KeyCode::ArrowUp, VBKey::LU);
default_key(KeyCode::ArrowLeft, VBKey::LL);
default_key(KeyCode::ArrowDown, VBKey::LD);
default_key(KeyCode::ArrowRight, VBKey::LR);
mappings.insert(SimId::Player1, Arc::new(RwLock::new(p1_mappings))); mappings.insert(SimId::Player1, Arc::new(RwLock::new(p1_mappings)));
mappings.insert(SimId::Player2, Arc::new(RwLock::new(p2_mappings))); mappings.insert(SimId::Player2, Arc::new(RwLock::new(p2_mappings)));
@ -236,14 +154,6 @@ impl MappingProvider {
self.sim_mappings.get(&sim_id).unwrap() self.sim_mappings.get(&sim_id).unwrap()
} }
pub fn for_gamepad(&self, gamepad_id: GamepadId) -> Option<Arc<RwLock<GamepadMapping>>> {
let lock = self.gamepad_info.read().unwrap();
let device_id = lock.get(&gamepad_id)?.device_id;
drop(lock);
let lock = self.device_mappings.read().unwrap();
lock.get(&device_id).cloned()
}
pub fn handle_gamepad_connect(&self, gamepad: &Gamepad) { pub fn handle_gamepad_connect(&self, gamepad: &Gamepad) {
let device_id = DeviceId( let device_id = DeviceId(
gamepad.vendor_id().unwrap_or_default(), gamepad.vendor_id().unwrap_or_default(),

View File

@ -18,7 +18,4 @@ pub trait AppWindow {
fn handle_key_event(&mut self, event: &KeyEvent) { fn handle_key_event(&mut self, event: &KeyEvent) {
let _ = event; let _ = event;
} }
fn handle_gamepad_event(&mut self, event: &gilrs::Event) {
let _ = event;
}
} }

View File

@ -2,19 +2,17 @@ use egui::{
Button, CentralPanel, Context, Label, Layout, TopBottomPanel, Ui, ViewportBuilder, ViewportId, Button, CentralPanel, Context, Label, Layout, TopBottomPanel, Ui, ViewportBuilder, ViewportId,
}; };
use egui_extras::{Column, TableBuilder}; use egui_extras::{Column, TableBuilder};
use gilrs::{EventType, GamepadId};
use std::sync::RwLock;
use crate::{ use crate::{
emulator::{SimId, VBKey}, emulator::{SimId, VBKey},
input::{MappingProvider, Mappings}, input::MappingProvider,
}; };
use super::AppWindow; use super::AppWindow;
pub struct InputWindow { pub struct InputWindow {
mappings: MappingProvider, mappings: MappingProvider,
now_binding: Option<VBKey>, now_binding: Option<(SimId, VBKey)>,
active_tab: InputTab, active_tab: InputTab,
} }
@ -44,26 +42,11 @@ impl InputWindow {
} }
} }
fn show_bindings<T: Mappings>( fn show_key_bindings(&mut self, ui: &mut Ui, sim_id: SimId) {
&mut self, let mappings = self.mappings.for_sim(sim_id);
ui: &mut Ui, let binding_names = {
mappings: &RwLock<T>,
bind_message: &str,
) {
ui.horizontal(|ui| {
if ui.button("Use defaults").clicked() {
mappings.write().unwrap().use_default_mappings();
self.now_binding = None;
}
if ui.button("Clear all").clicked() {
mappings.write().unwrap().clear_all_mappings();
self.now_binding = None;
}
});
ui.separator();
let mut names = {
let mapping = mappings.read().unwrap(); let mapping = mappings.read().unwrap();
mapping.mapping_names() mapping.keyboard_mapping_names()
}; };
TableBuilder::new(ui) TableBuilder::new(ui)
.column(Column::remainder()) .column(Column::remainder())
@ -73,33 +56,29 @@ impl InputWindow {
for keys in KEY_NAMES.chunks_exact(2) { for keys in KEY_NAMES.chunks_exact(2) {
body.row(20.0, |mut row| { body.row(20.0, |mut row| {
for (key, name) in keys { for (key, name) in keys {
let binding = names.remove(key).map(|mut s| { let binding = binding_names.get(key).map(|s| s.as_str());
s.sort();
s.join(", ")
});
row.col(|ui| { row.col(|ui| {
let size = ui.available_size_before_wrap(); let size = ui.available_size_before_wrap();
let width = size.x; let width = size.x;
let height = size.y; let height = size.y;
ui.add_sized((width * 0.2, height), Label::new(*name)); ui.add_sized((width * 0.2, height), Label::new(*name));
let label_text = if self.now_binding == Some(*key) { let label_text = if self.now_binding == Some((sim_id, *key)) {
bind_message "Press any input"
} else { } else {
binding.as_deref().unwrap_or("") binding.unwrap_or("")
}; };
if ui if ui
.add_sized((width * 0.6, height), Button::new(label_text)) .add_sized((width * 0.6, height), Button::new(label_text))
.clicked() .clicked()
{ {
self.now_binding = Some(*key); self.now_binding = Some((sim_id, *key))
} }
if ui if ui
.add_sized(ui.available_size(), Button::new("Clear")) .add_sized(ui.available_size(), Button::new("Clear"))
.clicked() .clicked()
{ {
let mut mapping = mappings.write().unwrap(); let mut mapping = mappings.write().unwrap();
mapping.clear_mappings(*key); mapping.clear_keyboard_mappings(*key);
self.now_binding = None;
} }
}); });
} }
@ -108,11 +87,6 @@ impl InputWindow {
}); });
} }
fn show_key_bindings(&mut self, ui: &mut Ui, sim_id: SimId) {
let mappings = self.mappings.for_sim(sim_id).clone();
self.show_bindings(ui, &mappings, "Press any key");
}
fn show_gamepads(&mut self, ui: &mut Ui) { fn show_gamepads(&mut self, ui: &mut Ui) {
let mut gamepads = self.mappings.gamepad_info(); let mut gamepads = self.mappings.gamepad_info();
gamepads.sort_by_key(|g| usize::from(g.id)); gamepads.sort_by_key(|g| usize::from(g.id));
@ -140,21 +114,9 @@ impl InputWindow {
None => self.mappings.unassign_gamepad(gamepad.id), None => self.mappings.unassign_gamepad(gamepad.id),
} }
} }
ui.separator();
if ui.button("Rebind").clicked() {
self.active_tab = InputTab::RebindGamepad(gamepad.id);
}
}); });
} }
} }
fn show_gamepad_bindings(&mut self, ui: &mut Ui, gamepad_id: GamepadId) {
let Some(mappings) = self.mappings.for_gamepad(gamepad_id) else {
self.active_tab = InputTab::Gamepads;
return;
};
self.show_bindings(ui, &mappings, "Press any input");
}
} }
impl AppWindow for InputWindow { impl AppWindow for InputWindow {
@ -171,17 +133,9 @@ impl AppWindow for InputWindow {
fn show(&mut self, ctx: &Context) { fn show(&mut self, ctx: &Context) {
TopBottomPanel::top("options").show(ctx, |ui| { TopBottomPanel::top("options").show(ctx, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
let old_active_tab = self.active_tab;
ui.selectable_value(&mut self.active_tab, InputTab::Player1, "Player 1"); ui.selectable_value(&mut self.active_tab, InputTab::Player1, "Player 1");
ui.selectable_value(&mut self.active_tab, InputTab::Player2, "Player 2"); ui.selectable_value(&mut self.active_tab, InputTab::Player2, "Player 2");
ui.selectable_value(&mut self.active_tab, InputTab::Gamepads, "Gamepads"); ui.selectable_value(&mut self.active_tab, InputTab::Gamepads, "Gamepads");
if matches!(self.active_tab, InputTab::RebindGamepad(_)) {
let tab = self.active_tab;
ui.selectable_value(&mut self.active_tab, tab, "Rebind Gamepad");
}
if old_active_tab != self.active_tab {
self.now_binding = None;
}
}); });
}); });
CentralPanel::default().show(ctx, |ui| { CentralPanel::default().show(ctx, |ui| {
@ -189,7 +143,6 @@ impl AppWindow for InputWindow {
InputTab::Player1 => self.show_key_bindings(ui, SimId::Player1), InputTab::Player1 => self.show_key_bindings(ui, SimId::Player1),
InputTab::Player2 => self.show_key_bindings(ui, SimId::Player2), InputTab::Player2 => self.show_key_bindings(ui, SimId::Player2),
InputTab::Gamepads => self.show_gamepads(ui), InputTab::Gamepads => self.show_gamepads(ui),
InputTab::RebindGamepad(id) => self.show_gamepad_bindings(ui, id),
}; };
}); });
} }
@ -198,54 +151,12 @@ impl AppWindow for InputWindow {
if !event.state.is_pressed() { if !event.state.is_pressed() {
return; return;
} }
let sim_id = match self.active_tab { let Some((sim_id, vb)) = self.now_binding.take() else {
InputTab::Player1 => SimId::Player1,
InputTab::Player2 => SimId::Player2,
_ => {
return;
}
};
let Some(vb) = self.now_binding.take() else {
return; return;
}; };
let mut mappings = self.mappings.for_sim(sim_id).write().unwrap(); let mut mappings = self.mappings.for_sim(sim_id).write().unwrap();
mappings.add_keyboard_mapping(vb, event.physical_key); mappings.add_keyboard_mapping(vb, event.physical_key);
} }
fn handle_gamepad_event(&mut self, event: &gilrs::Event) {
let InputTab::RebindGamepad(gamepad_id) = self.active_tab else {
return;
};
if gamepad_id != event.id {
return;
}
let Some(mappings) = self.mappings.for_gamepad(gamepad_id) else {
return;
};
let Some(vb) = self.now_binding else {
return;
};
match event.event {
EventType::ButtonPressed(_, code) => {
let mut mapping = mappings.write().unwrap();
mapping.add_button_mapping(vb, code);
self.now_binding.take();
}
EventType::AxisChanged(_, value, code) => {
if value < -0.75 {
let mut mapping = mappings.write().unwrap();
mapping.add_axis_neg_mapping(vb, code);
self.now_binding.take();
}
if value > 0.75 {
let mut mapping = mappings.write().unwrap();
mapping.add_axis_pos_mapping(vb, code);
self.now_binding.take();
}
}
_ => {}
}
}
} }
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
@ -253,5 +164,4 @@ enum InputTab {
Player1, Player1,
Player2, Player2,
Gamepads, Gamepads,
RebindGamepad(GamepadId),
} }