Support rebinding gamepad inputs

This commit is contained in:
2024-11-29 18:54:26 -05:00
parent 24474fabd0
commit ce7ba71ea0
4 changed files with 184 additions and 34 deletions
+92 -13
View File
@@ -2,17 +2,19 @@ use egui::{
Button, CentralPanel, Context, Label, Layout, TopBottomPanel, Ui, ViewportBuilder, ViewportId,
};
use egui_extras::{Column, TableBuilder};
use gilrs::{EventType, GamepadId};
use std::sync::RwLock;
use crate::{
emulator::{SimId, VBKey},
input::MappingProvider,
input::{MappingProvider, Mappings},
};
use super::AppWindow;
pub struct InputWindow {
mappings: MappingProvider,
now_binding: Option<(SimId, VBKey)>,
now_binding: Option<VBKey>,
active_tab: InputTab,
}
@@ -42,11 +44,15 @@ impl InputWindow {
}
}
fn show_key_bindings(&mut self, ui: &mut Ui, sim_id: SimId) {
let mappings = self.mappings.for_sim(sim_id);
let binding_names = {
fn show_bindings<T: Mappings>(
&mut self,
ui: &mut Ui,
mappings: &RwLock<T>,
bind_message: &str,
) {
let mut names = {
let mapping = mappings.read().unwrap();
mapping.keyboard_mapping_names()
mapping.mapping_names()
};
TableBuilder::new(ui)
.column(Column::remainder())
@@ -56,29 +62,33 @@ impl InputWindow {
for keys in KEY_NAMES.chunks_exact(2) {
body.row(20.0, |mut row| {
for (key, name) in keys {
let binding = binding_names.get(key).map(|s| s.as_str());
let binding = names.remove(key).map(|mut s| {
s.sort();
s.join(", ")
});
row.col(|ui| {
let size = ui.available_size_before_wrap();
let width = size.x;
let height = size.y;
ui.add_sized((width * 0.2, height), Label::new(*name));
let label_text = if self.now_binding == Some((sim_id, *key)) {
"Press any input"
let label_text = if self.now_binding == Some(*key) {
bind_message
} else {
binding.unwrap_or("")
binding.as_deref().unwrap_or("")
};
if ui
.add_sized((width * 0.6, height), Button::new(label_text))
.clicked()
{
self.now_binding = Some((sim_id, *key))
self.now_binding = Some(*key);
}
if ui
.add_sized(ui.available_size(), Button::new("Clear"))
.clicked()
{
let mut mapping = mappings.write().unwrap();
mapping.clear_keyboard_mappings(*key);
mapping.clear_mappings(*key);
self.now_binding = None;
}
});
}
@@ -87,6 +97,11 @@ 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) {
let mut gamepads = self.mappings.gamepad_info();
gamepads.sort_by_key(|g| usize::from(g.id));
@@ -114,9 +129,21 @@ impl InputWindow {
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 {
@@ -133,9 +160,17 @@ impl AppWindow for InputWindow {
fn show(&mut self, ctx: &Context) {
TopBottomPanel::top("options").show(ctx, |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::Player2, "Player 2");
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| {
@@ -143,6 +178,7 @@ impl AppWindow for InputWindow {
InputTab::Player1 => self.show_key_bindings(ui, SimId::Player1),
InputTab::Player2 => self.show_key_bindings(ui, SimId::Player2),
InputTab::Gamepads => self.show_gamepads(ui),
InputTab::RebindGamepad(id) => self.show_gamepad_bindings(ui, id),
};
});
}
@@ -151,12 +187,54 @@ impl AppWindow for InputWindow {
if !event.state.is_pressed() {
return;
}
let Some((sim_id, vb)) = self.now_binding.take() else {
let sim_id = match self.active_tab {
InputTab::Player1 => SimId::Player1,
InputTab::Player2 => SimId::Player2,
_ => {
return;
}
};
let Some(vb) = self.now_binding.take() else {
return;
};
let mut mappings = self.mappings.for_sim(sim_id).write().unwrap();
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)]
@@ -164,4 +242,5 @@ enum InputTab {
Player1,
Player2,
Gamepads,
RebindGamepad(GamepadId),
}