Support rebinding gamepad inputs
This commit is contained in:
		
							parent
							
								
									24474fabd0
								
							
						
					
					
						commit
						ce7ba71ea0
					
				
							
								
								
									
										20
									
								
								src/app.rs
								
								
								
								
							
							
						
						
									
										20
									
								
								src/app.rs
								
								
								
								
							| 
						 | 
					@ -8,7 +8,7 @@ use egui::{
 | 
				
			||||||
use gilrs::{EventType, Gilrs};
 | 
					use gilrs::{EventType, Gilrs};
 | 
				
			||||||
use winit::{
 | 
					use winit::{
 | 
				
			||||||
    application::ApplicationHandler,
 | 
					    application::ApplicationHandler,
 | 
				
			||||||
    event::{KeyEvent, WindowEvent},
 | 
					    event::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.handle_key_event(event);
 | 
					                viewport.app.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,7 +143,17 @@ 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) => self.controllers.handle_gamepad_event(&event),
 | 
					            UserEvent::GamepadEvent(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));
 | 
				
			||||||
| 
						 | 
					@ -248,10 +258,6 @@ 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();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										90
									
								
								src/input.rs
								
								
								
								
							
							
						
						
									
										90
									
								
								src/input.rs
								
								
								
								
							| 
						 | 
					@ -19,6 +19,11 @@ 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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct GamepadMapping {
 | 
					pub struct GamepadMapping {
 | 
				
			||||||
    buttons: HashMap<Code, VBKey>,
 | 
					    buttons: HashMap<Code, VBKey>,
 | 
				
			||||||
    axes: HashMap<Code, (VBKey, VBKey)>,
 | 
					    axes: HashMap<Code, (VBKey, VBKey)>,
 | 
				
			||||||
| 
						 | 
					@ -54,6 +59,59 @@ impl GamepadMapping {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Self { buttons, axes }
 | 
					        Self { buttons, 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()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Default)]
 | 
					#[derive(Default)]
 | 
				
			||||||
| 
						 | 
					@ -81,15 +139,10 @@ 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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn clear_keyboard_mappings(&mut self, key: VBKey) {
 | 
					impl Mappings for InputMapping {
 | 
				
			||||||
        self.keys.retain(|_, keys| {
 | 
					    fn mapping_names(&self) -> HashMap<VBKey, Vec<String>> {
 | 
				
			||||||
            *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 {
 | 
				
			||||||
| 
						 | 
					@ -101,12 +154,13 @@ impl InputMapping {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        results
 | 
					        results
 | 
				
			||||||
            .into_iter()
 | 
					    }
 | 
				
			||||||
            .map(|(k, mut v)| {
 | 
					
 | 
				
			||||||
                v.sort();
 | 
					    fn clear_mappings(&mut self, key: VBKey) {
 | 
				
			||||||
                (k, v.join(", "))
 | 
					        self.keys.retain(|_, keys| {
 | 
				
			||||||
            })
 | 
					            *keys = keys.difference(key);
 | 
				
			||||||
            .collect()
 | 
					            !keys.is_empty()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -154,6 +208,14 @@ 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(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,4 +18,7 @@ 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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,17 +2,19 @@ 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,
 | 
					    input::{MappingProvider, Mappings},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::AppWindow;
 | 
					use super::AppWindow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct InputWindow {
 | 
					pub struct InputWindow {
 | 
				
			||||||
    mappings: MappingProvider,
 | 
					    mappings: MappingProvider,
 | 
				
			||||||
    now_binding: Option<(SimId, VBKey)>,
 | 
					    now_binding: Option<VBKey>,
 | 
				
			||||||
    active_tab: InputTab,
 | 
					    active_tab: InputTab,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,11 +44,15 @@ impl InputWindow {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn show_key_bindings(&mut self, ui: &mut Ui, sim_id: SimId) {
 | 
					    fn show_bindings<T: Mappings>(
 | 
				
			||||||
        let mappings = self.mappings.for_sim(sim_id);
 | 
					        &mut self,
 | 
				
			||||||
        let binding_names = {
 | 
					        ui: &mut Ui,
 | 
				
			||||||
 | 
					        mappings: &RwLock<T>,
 | 
				
			||||||
 | 
					        bind_message: &str,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        let mut names = {
 | 
				
			||||||
            let mapping = mappings.read().unwrap();
 | 
					            let mapping = mappings.read().unwrap();
 | 
				
			||||||
            mapping.keyboard_mapping_names()
 | 
					            mapping.mapping_names()
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        TableBuilder::new(ui)
 | 
					        TableBuilder::new(ui)
 | 
				
			||||||
            .column(Column::remainder())
 | 
					            .column(Column::remainder())
 | 
				
			||||||
| 
						 | 
					@ -56,29 +62,33 @@ 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 = binding_names.get(key).map(|s| s.as_str());
 | 
					                            let binding = names.remove(key).map(|mut s| {
 | 
				
			||||||
 | 
					                                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((sim_id, *key)) {
 | 
					                                let label_text = if self.now_binding == Some(*key) {
 | 
				
			||||||
                                    "Press any input"
 | 
					                                    bind_message
 | 
				
			||||||
                                } else {
 | 
					                                } else {
 | 
				
			||||||
                                    binding.unwrap_or("")
 | 
					                                    binding.as_deref().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((sim_id, *key))
 | 
					                                    self.now_binding = Some(*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_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) {
 | 
					    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));
 | 
				
			||||||
| 
						 | 
					@ -114,9 +129,21 @@ 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 {
 | 
				
			||||||
| 
						 | 
					@ -133,9 +160,17 @@ 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| {
 | 
				
			||||||
| 
						 | 
					@ -143,6 +178,7 @@ 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),
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -151,12 +187,54 @@ impl AppWindow for InputWindow {
 | 
				
			||||||
        if !event.state.is_pressed() {
 | 
					        if !event.state.is_pressed() {
 | 
				
			||||||
            return;
 | 
					            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;
 | 
					            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)]
 | 
				
			||||||
| 
						 | 
					@ -164,4 +242,5 @@ enum InputTab {
 | 
				
			||||||
    Player1,
 | 
					    Player1,
 | 
				
			||||||
    Player2,
 | 
					    Player2,
 | 
				
			||||||
    Gamepads,
 | 
					    Gamepads,
 | 
				
			||||||
 | 
					    RebindGamepad(GamepadId),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue