use sdl2; use sdl2::EventPump; use sdl2::EventSubsystem; use sdl2::GameControllerSubsystem; use sdl2::Sdl; 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::sync::{Arc, RwLock}; use crate::Result; use super::controller::{Controller, ControllerDeadzones}; 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 { // mouse events MouseMotion(u32, u32), MouseButtonDown(MouseButton), MouseButtonUp(MouseButton), MouseWheel(i32, i32, MouseWheelDirection), // keyboard events KeyDown(Keycode), KeyUp(Keycode), TextInput(String), // controller events ControllerAxis(Arc>), ControllerButtonDown(ControllerButton), ControllerButtonUp(ControllerButton), ControllerAdded(Arc>), ControllerRemoved(Arc>), // drag'n'drop FileDrop(String), } pub struct EventSystem { event_pump: EventPump, mouse: MouseUtil, controller_subsystem: GameControllerSubsystem, event_subsystem: EventSubsystem, controller_deadzones: ControllerDeadzones, selected_controller: Option>>, connected_controllers: Vec>>, } 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))?, event_subsystem: sdl2_context.event().map_err(|s| anyhow::Error::msg(s))?, controller_deadzones: ControllerDeadzones::default(), selected_controller: None, connected_controllers: Vec::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, event_callback: F, mut resize: R) -> Result where F: Fn(Event) -> Result<()>, R: FnMut(u32, u32) -> Result<()>, { let mut controller_axis_changed = false; 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(), ) { let controller = { if cfg!(debug_assertions) { println!( "Controller added: {}({})", controller.name(), controller.id() ); } let arc_controller = Arc::new(RwLock::new(controller)); self.connected_controllers.push(arc_controller.clone()); if self.selected_controller.is_none() { if cfg!(debug_assertions) { let contr = arc_controller.read().unwrap(); println!( "New active controller: {}({})", contr.name(), contr.id() ); } self.selected_controller = Some(arc_controller.clone()); } arc_controller }; event_callback(Event::ControllerAdded(controller))?; } } SdlEvent::ControllerDeviceRemoved { which, .. } => { let removed_controller = { if self.selected_controller.is_some() { if cfg!(debug_assertions) { let contr = self.selected_controller.as_ref().unwrap().read().unwrap(); println!( "Remove active controller: {}({})", contr.name(), contr.id() ); } // unwrap is save since we just tested for `is_some()` if self .selected_controller .as_ref() .unwrap() .read() .unwrap() .id() == which { self.selected_controller = None; } } self.connected_controllers .iter() .position(|controller_cell| { let controller = controller_cell.read().unwrap(); controller.id() == which }) .map(|remove_index| { let removed_controller = self.connected_controllers.swap_remove(remove_index); if cfg!(debug_assertions) { let contr = removed_controller.read().unwrap(); println!( "Controller removed: {}({})", contr.name(), contr.id() ); } // if we removed the selected controller, take the controller at the first position if possible if self.selected_controller.is_none() && !self.connected_controllers.is_empty() { if cfg!(debug_assertions) { println!( "Set active controller: {}", self.connected_controllers[0].read().unwrap().name() ); } self.selected_controller = Some(self.connected_controllers[0].clone()); } removed_controller }) }; if let Some(removed_controller) = removed_controller { event_callback(Event::ControllerRemoved(removed_controller))?; } } // maybe make use of `which`, for support of multiple controllers SdlEvent::ControllerButtonDown { button, // which, .. } => { // // only call back if the selected controller pressed a button // match self.selected_controller.read().unwrap().as_ref() { // Some(selected_controller) => { // if selected_controller.read().unwrap().id() != which { // continue; // } // } // None => continue, // } event_callback(Event::ControllerButtonDown(convert_button(button)))?; } // maybe make use of `which`, for support of multiple controllers SdlEvent::ControllerButtonUp { button, // which, .. } => { // // only call back if the selected controller released a button // match self.selected_controller.read().unwrap().as_ref() { // Some(selected_controller) => { // if selected_controller.read().unwrap().id() != which { // continue; // } // } // None => continue, // } event_callback(Event::ControllerButtonUp(convert_button(button)))?; } SdlEvent::ControllerAxisMotion { axis, value, // which, .. } => { if let Some(controller) = self.selected_controller.as_mut() { let mut controller = controller.write().unwrap(); // // only update axis, when selected controller made the change // if controller.id() != which { // continue; // } // 1 / 32768 = 0,000030518 let normalized = value as f32 * 0.000_030_518; match axis { sdl2::controller::Axis::LeftX => { controller.set_left_x(normalized); } sdl2::controller::Axis::RightX => { controller.set_right_x(normalized); } sdl2::controller::Axis::LeftY => { controller.set_left_y(-normalized); } sdl2::controller::Axis::RightY => { controller.set_right_y(normalized); } sdl2::controller::Axis::TriggerLeft => { controller.set_left_trigger(normalized); } sdl2::controller::Axis::TriggerRight => { controller.set_right_trigger(normalized); } } controller_axis_changed = true; } } SdlEvent::DropFile { filename, .. } => { event_callback(Event::FileDrop(filename))?; } _ => (), } } if controller_axis_changed { if let Some(controller) = &self.selected_controller { let (left_trigger, right_trigger) = { let mut controller_lock = controller.write().unwrap(); ( controller_lock.left_trigger(), controller_lock.right_trigger(), ) }; if let Some(right_trigger) = right_trigger { if right_trigger { event_callback(Event::ControllerButtonDown( ControllerButton::RightTrigger, ))?; } else { event_callback(Event::ControllerButtonUp(ControllerButton::RightTrigger))?; } } if let Some(left_trigger) = left_trigger { if left_trigger { event_callback(Event::ControllerButtonDown(ControllerButton::LeftTrigger))?; } else { event_callback(Event::ControllerButtonUp(ControllerButton::LeftTrigger))?; } } event_callback(Event::ControllerAxis(controller.clone()))?; } } Ok(true) } pub fn controllers(&self) -> &[Arc>] { &self.connected_controllers } pub fn active_controller(&self) -> &Option>> { &self.selected_controller } pub fn set_active_controller(&mut self, controller: &Arc>) { if let Some(res) = self .connected_controllers .iter() .find(|c| Arc::ptr_eq(c, controller)) { self.selected_controller = Some(res.clone()); } } } unsafe impl Send for EventSystem {} unsafe impl Sync for EventSystem {}