use sdl2; use sdl2::EventPump; use sdl2::EventSubsystem; use sdl2::GameControllerSubsystem; use sdl2::JoystickSubsystem; use sdl2::Sdl; use sdl2::controller::Axis; use sdl2::controller::Button; use sdl2::event::{Event as SdlEvent, EventType as SdlEventType, WindowEvent}; use sdl2::keyboard::Keycode; use sdl2::mouse::{MouseButton as SdlMouseButton, MouseUtil, MouseWheelDirection}; use ui::prelude::*; use std::collections::HashMap; use crate::Result; use super::controller::{Controller, ControllerDeadzones}; use super::joystick::Joystick; fn convert_button(button: Button) -> ControllerButton { match button { Button::A => ControllerButton::A, Button::B => ControllerButton::B, Button::Y => ControllerButton::Y, Button::X => ControllerButton::X, Button::Start => ControllerButton::Start, Button::Back => ControllerButton::Select, Button::RightShoulder => ControllerButton::RightButton, Button::LeftShoulder => ControllerButton::LeftButton, Button::DPadUp => ControllerButton::DPadUp, Button::DPadDown => ControllerButton::DPadDown, Button::DPadRight => ControllerButton::DPadRight, Button::DPadLeft => ControllerButton::DPadLeft, Button::Guide => ControllerButton::Guide, Button::LeftStick => ControllerButton::LeftStick, Button::RightStick => ControllerButton::RightStick, Button::Misc1 => ControllerButton::Misc, Button::Paddle1 => ControllerButton::Paddle1, Button::Paddle2 => ControllerButton::Paddle2, Button::Paddle3 => ControllerButton::Paddle3, Button::Paddle4 => ControllerButton::Paddle4, Button::Touchpad => ControllerButton::Touchpad, } } #[derive(Debug)] pub enum Event<'a> { // mouse events MouseMotion(u32, u32), MouseButtonDown(MouseButton), MouseButtonUp(MouseButton), MouseWheel(i32, i32, MouseWheelDirection), // keyboard events KeyDown(Keycode), KeyUp(Keycode), TextInput(String), // controller events ControllerAxis(&'a Controller), ControllerButtonDown(&'a Controller, ControllerButton), ControllerButtonUp(&'a Controller, ControllerButton), ControllerAdded(&'a Controller), ControllerRemoved(&'a Controller), // joystick events JoystickAxis(&'a Joystick), JoystickButtonDown(&'a Joystick), JoystickButtonUp(&'a Joystick), JoystickAdded(&'a Joystick), JoystickRemoved(&'a Joystick), // drag'n'drop FileDrop(String), } pub struct EventSystem { event_pump: EventPump, mouse: MouseUtil, controller_subsystem: GameControllerSubsystem, joystick_subsystem: JoystickSubsystem, event_subsystem: EventSubsystem, controller_deadzones: ControllerDeadzones, connected_controllers: HashMap, connected_joysticks: HashMap, } impl EventSystem { pub fn new(sdl2_context: &Sdl) -> Result { let mut event_system = EventSystem { event_pump: sdl2_context .event_pump() .map_err(|s| anyhow::Error::msg(s))?, mouse: sdl2_context.mouse(), controller_subsystem: sdl2_context .game_controller() .map_err(|s| anyhow::Error::msg(s))?, joystick_subsystem: sdl2_context.joystick().map_err(|s| anyhow::Error::msg(s))?, event_subsystem: sdl2_context.event().map_err(|s| anyhow::Error::msg(s))?, controller_deadzones: ControllerDeadzones::default(), connected_controllers: HashMap::new(), connected_joysticks: HashMap::new(), }; event_system.disable_mouse(); event_system.disable_keyboard(); event_system.disable_controller(); Ok(event_system) } pub fn enable_mouse(&mut self) { self.event_pump.enable_event(SdlEventType::MouseMotion); self.event_pump.enable_event(SdlEventType::MouseButtonDown); self.event_pump.enable_event(SdlEventType::MouseButtonUp); self.mouse.show_cursor(true); } pub fn disable_mouse(&mut self) { self.event_pump.disable_event(SdlEventType::MouseMotion); self.event_pump.disable_event(SdlEventType::MouseButtonDown); self.event_pump.disable_event(SdlEventType::MouseButtonUp); self.mouse.show_cursor(false); } pub fn enable_keyboard(&mut self) { self.event_pump.enable_event(SdlEventType::KeyUp); self.event_pump.enable_event(SdlEventType::KeyDown); } pub fn disable_keyboard(&mut self) { self.event_pump.disable_event(SdlEventType::KeyUp); self.event_pump.disable_event(SdlEventType::KeyDown); } pub fn enable_controller(&mut self) { self.event_pump .enable_event(SdlEventType::ControllerAxisMotion); self.event_pump .enable_event(SdlEventType::ControllerButtonDown); self.event_pump .enable_event(SdlEventType::ControllerButtonUp); } pub fn disable_controller(&mut self) { self.event_pump .disable_event(SdlEventType::ControllerAxisMotion); self.event_pump .disable_event(SdlEventType::ControllerButtonDown); self.event_pump .disable_event(SdlEventType::ControllerButtonUp); } pub fn set_controller_axis_enable_deadzone(&mut self, deadzone: f32) { self.controller_deadzones.axis_enable_deadzone = deadzone; } pub fn set_controller_axis_disable_deadzone(&mut self, deadzone: f32) { self.controller_deadzones.axis_disable_deadzone = deadzone; } pub fn set_controller_trigger_enable_deadzone(&mut self, deadzone: f32) { self.controller_deadzones.trigger_enable_deadzone = deadzone; } pub fn set_controller_trigger_disable_deadzone(&mut self, deadzone: f32) { self.controller_deadzones.trigger_disable_deadzone = deadzone; } pub fn quit(&self) -> Result<()> { Ok(self .event_subsystem .push_event(SdlEvent::Quit { timestamp: 0 }) .map_err(|s| anyhow::Error::msg(s))?) } pub fn poll_events(&mut self, mut event_callback: F, mut resize: R) -> Result where F: FnMut(Event<'_>) -> Result<()>, R: FnMut(u32, u32) -> Result<()>, { for event in self.event_pump.poll_iter() { match event { SdlEvent::Window { win_event, .. } => match win_event { WindowEvent::Resized(w, h) | WindowEvent::SizeChanged(w, h) => { resize(w as u32, h as u32)?; } _ => (), }, SdlEvent::Quit { .. } => return Ok(false), // ----------------- Mouse Events --------------------- SdlEvent::MouseMotion { x, y, .. } => { event_callback(Event::MouseMotion(x as u32, y as u32))?; } SdlEvent::MouseButtonDown { mouse_btn, .. } => { let mouse_button = match mouse_btn { SdlMouseButton::Left => MouseButton::Left, SdlMouseButton::Right => MouseButton::Right, SdlMouseButton::Middle => MouseButton::Middle, SdlMouseButton::X1 => MouseButton::Forward, SdlMouseButton::X2 => MouseButton::Backward, SdlMouseButton::Unknown => continue, }; event_callback(Event::MouseButtonDown(mouse_button))?; } SdlEvent::MouseButtonUp { mouse_btn, .. } => { let mouse_button = match mouse_btn { SdlMouseButton::Left => MouseButton::Left, SdlMouseButton::Right => MouseButton::Right, SdlMouseButton::Middle => MouseButton::Middle, SdlMouseButton::X1 => MouseButton::Forward, SdlMouseButton::X2 => MouseButton::Backward, SdlMouseButton::Unknown => continue, }; event_callback(Event::MouseButtonUp(mouse_button))?; } SdlEvent::MouseWheel { x, y, direction, .. } => { event_callback(Event::MouseWheel(x, y, direction))?; } // ------------------- Key Events --------------------- SdlEvent::KeyDown { keycode, repeat, .. } => { if repeat { continue; } if let Some(keycode) = keycode { event_callback(Event::KeyDown(keycode))?; } } SdlEvent::KeyUp { keycode, repeat, .. } => { if repeat { continue; } if let Some(keycode) = keycode { event_callback(Event::KeyUp(keycode))?; } } SdlEvent::TextInput { text, .. } => { event_callback(Event::TextInput(text))?; } // --------------- Controller Events ------------------- SdlEvent::ControllerDeviceAdded { which, .. } => { if cfg!(debug_assertions) { println!("New Device: {}", which); } if let Ok(controller) = Controller::new( &self.controller_subsystem, which as u32, self.controller_deadzones.clone(), ) { if cfg!(debug_assertions) { println!( "Controller added: {}({})", controller.name(), controller.id() ); } event_callback(Event::ControllerAdded(&controller))?; self.connected_controllers .insert(controller.id(), controller); } } SdlEvent::ControllerDeviceRemoved { which, .. } => { if let Some(controller) = self.connected_controllers.remove(&which) { if cfg!(debug_assertions) { println!( "Controller removed: {}({})", controller.name(), controller.id() ); } event_callback(Event::ControllerRemoved(&controller))?; } } SdlEvent::ControllerButtonDown { button, which, .. } => { event_callback(Event::ControllerButtonDown( self.connected_controllers.get(&which).unwrap(), convert_button(button), ))?; } SdlEvent::ControllerButtonUp { button, which, .. } => { event_callback(Event::ControllerButtonUp( self.connected_controllers.get(&which).unwrap(), convert_button(button), ))?; } SdlEvent::ControllerAxisMotion { axis, value, which, .. } => { let controller = self.connected_controllers.get_mut(&which).unwrap(); let normalized = value as f32 * 0.000_030_518; match axis { Axis::LeftX => { controller.set_left_x(normalized); } Axis::RightX => { controller.set_right_x(normalized); } Axis::LeftY => { controller.set_left_y(-normalized); } Axis::RightY => { controller.set_right_y(normalized); } Axis::TriggerLeft => { controller.set_left_trigger(normalized); } Axis::TriggerRight => { controller.set_right_trigger(normalized); } } event_callback(Event::ControllerAxis(&*controller))?; } SdlEvent::JoyDeviceAdded { which, .. } => { let joystick = Joystick::new(&self.joystick_subsystem, which)?; event_callback(Event::JoystickAdded(&joystick))?; self.connected_joysticks.insert(joystick.id(), joystick); } SdlEvent::DropFile { filename, .. } => { event_callback(Event::FileDrop(filename))?; } _ => (), } } Ok(true) } pub fn controllers(&self) -> impl Iterator { self.connected_controllers.values() } } unsafe impl Send for EventSystem {} unsafe impl Sync for EventSystem {}