use std::collections::HashMap; use crate::base::ControlFlow; use crate::prelude::*; use sdl2::Sdl; use sdl2::event::Event; use sdl2::keyboard::Keycode; // FIXME: make it not hard require EventPump ownership, or allow user-provided function? /// Maps the first "RetroPad" layout to the keyboard. /// /// NOTE: This component is intended for exceedingly simple use-cases, and *must own* the /// [sdl2::EventPump]. pub struct SimpleSdl2KeyboardComponent { button_map: HashMap, button_state: HashMap, event_pump: sdl2::EventPump, } impl RetroCallbacks for SimpleSdl2KeyboardComponent { fn input_state(&mut self, port: u32, device: InputDeviceId, _index: InputIndex) -> i16 { if port != 0 { return 0; } self.button_state.get(&device).cloned().unwrap_or_default() } fn get_input_device_capabilities(&mut self) -> Option { let bits = 1 << (DeviceType::Joypad as u32); Some(bits as u64) } } impl RetroComponent for SimpleSdl2KeyboardComponent { fn pre_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow { for event in self.event_pump.poll_iter() { match event { Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return ControlFlow::Break, Event::KeyDown { keycode: Some(k), .. } => { if let Some(button) = self.button_map.get(&k) { self.button_state.insert(button.to_owned(), 1); } } Event::KeyUp { keycode: Some(k), .. } => { if let Some(button) = self.button_map.get(&k) { self.button_state.remove(button); } } _ => {} } } ControlFlow::Continue } } impl SimpleSdl2KeyboardComponent { pub fn new(sdl_context: &mut Sdl) -> crate::base::Result { let event_pump = sdl_context.event_pump()?; Ok(SimpleSdl2KeyboardComponent { button_map: [ (Keycode::W, InputDeviceId::Joypad(JoypadButton::Up)), (Keycode::S, InputDeviceId::Joypad(JoypadButton::Down)), (Keycode::A, InputDeviceId::Joypad(JoypadButton::Left)), (Keycode::D, InputDeviceId::Joypad(JoypadButton::Right)), (Keycode::L, InputDeviceId::Joypad(JoypadButton::A)), (Keycode::K, InputDeviceId::Joypad(JoypadButton::B)), (Keycode::I, InputDeviceId::Joypad(JoypadButton::X)), (Keycode::J, InputDeviceId::Joypad(JoypadButton::Y)), (Keycode::LShift, InputDeviceId::Joypad(JoypadButton::L)), (Keycode::RShift, InputDeviceId::Joypad(JoypadButton::R)), (Keycode::LCtrl, InputDeviceId::Joypad(JoypadButton::L2)), (Keycode::RCtrl, InputDeviceId::Joypad(JoypadButton::R2)), (Keycode::LAlt, InputDeviceId::Joypad(JoypadButton::L3)), (Keycode::RAlt, InputDeviceId::Joypad(JoypadButton::R3)), (Keycode::Return, InputDeviceId::Joypad(JoypadButton::Start)), (Keycode::Backspace, InputDeviceId::Joypad(JoypadButton::Select)), (Keycode::Tab, InputDeviceId::Joypad(JoypadButton::Select)), ].into_iter().collect(), button_state: Default::default(), event_pump, }) } }