511 lines
19 KiB
Rust
511 lines
19 KiB
Rust
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<RwLock<Controller>>),
|
|
ControllerButtonDown(ControllerButton),
|
|
ControllerButtonUp(ControllerButton),
|
|
ControllerAdded(Arc<RwLock<Controller>>),
|
|
ControllerRemoved(Arc<RwLock<Controller>>),
|
|
|
|
// 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<Arc<RwLock<Controller>>>,
|
|
connected_controllers: Vec<Arc<RwLock<Controller>>>,
|
|
}
|
|
|
|
impl EventSystem {
|
|
pub fn new(sdl2_context: &Sdl) -> Result<EventSystem> {
|
|
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<F, R>(&mut self, event_callback: F, mut resize: R) -> Result<bool>
|
|
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<RwLock<Controller>>] {
|
|
&self.connected_controllers
|
|
}
|
|
|
|
pub fn active_controller(&self) -> &Option<Arc<RwLock<Controller>>> {
|
|
&self.selected_controller
|
|
}
|
|
|
|
pub fn set_active_controller(&mut self, controller: &Arc<RwLock<Controller>>) {
|
|
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 {}
|