use libc::c_int;
use libc::c_void;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::ffi::CStr;
use std::iter::FromIterator;
use std::marker::PhantomData;
use std::mem;
use std::mem::transmute;
use std::ptr;
use std::sync::Mutex;
use crate::controller;
use crate::controller::{Axis, Button};
use crate::get_error;
use crate::joystick;
use crate::joystick::HatState;
use crate::keyboard;
use crate::keyboard::Keycode;
use crate::keyboard::Mod;
use crate::keyboard::Scancode;
use crate::mouse;
use crate::mouse::{MouseButton, MouseState, MouseWheelDirection};
use crate::sys;
use crate::sys::SDL_EventFilter;
use crate::sys::SDL_EventType;
struct CustomEventTypeMaps {
sdl_id_to_type_id: HashMap<u32, ::std::any::TypeId>,
type_id_to_sdl_id: HashMap<::std::any::TypeId, u32>,
}
impl CustomEventTypeMaps {
fn new() -> Self {
CustomEventTypeMaps {
sdl_id_to_type_id: HashMap::new(),
type_id_to_sdl_id: HashMap::new(),
}
}
}
lazy_static! {
static ref CUSTOM_EVENT_TYPES: Mutex<CustomEventTypeMaps> =
Mutex::new(CustomEventTypeMaps::new());
}
impl crate::EventSubsystem {
#[doc(alias = "SDL_FlushEvent")]
pub fn flush_event(&self, event_type: EventType) {
unsafe { sys::SDL_FlushEvent(event_type as u32) };
}
#[doc(alias = "SDL_FlushEvents")]
pub fn flush_events(&self, min_type: u32, max_type: u32) {
unsafe { sys::SDL_FlushEvents(min_type, max_type) };
}
#[doc(alias = "SDL_PeepEvents")]
pub fn peek_events<B>(&self, max_amount: u32) -> B
where
B: FromIterator<Event>,
{
unsafe {
let mut events = Vec::with_capacity(max_amount as usize);
let result = {
let events_ptr = events.as_mut_ptr();
sys::SDL_PeepEvents(
events_ptr,
max_amount as c_int,
sys::SDL_eventaction::SDL_PEEKEVENT,
SDL_EventType::SDL_FIRSTEVENT as u32,
SDL_EventType::SDL_LASTEVENT as u32,
)
};
if result < 0 {
panic!("{}", get_error());
} else {
events.set_len(result as usize);
events
.into_iter()
.map(|event_raw| Event::from_ll(event_raw))
.collect()
}
}
}
pub fn push_event(&self, event: Event) -> Result<(), String> {
self.event_sender().push_event(event)
}
#[inline(always)]
pub unsafe fn register_event(&self) -> Result<u32, String> {
Ok(*self.register_events(1)?.first().unwrap())
}
pub unsafe fn register_events(&self, nr: u32) -> Result<Vec<u32>, String> {
let result = sys::SDL_RegisterEvents(nr as ::libc::c_int);
const ERR_NR: u32 = ::std::u32::MAX - 1;
match result {
ERR_NR => Err("No more user events can be created; SDL_LASTEVENT reached".to_owned()),
_ => {
let event_ids = (result..(result + nr)).collect();
Ok(event_ids)
}
}
}
#[inline(always)]
pub fn register_custom_event<T: ::std::any::Any>(&self) -> Result<(), String> {
use std::any::TypeId;
let event_id = *(unsafe { self.register_events(1) })?.first().unwrap();
let mut cet = CUSTOM_EVENT_TYPES.lock().unwrap();
let type_id = TypeId::of::<Box<T>>();
if cet.type_id_to_sdl_id.contains_key(&type_id) {
return Err("The same event type can not be registered twice!".to_owned());
}
cet.sdl_id_to_type_id.insert(event_id, type_id);
cet.type_id_to_sdl_id.insert(type_id, event_id);
Ok(())
}
pub fn push_custom_event<T: ::std::any::Any>(&self, event: T) -> Result<(), String> {
self.event_sender().push_custom_event(event)
}
pub fn event_sender(&self) -> EventSender {
EventSender { _priv: () }
}
pub fn add_event_watch<'a, CB: EventWatchCallback + 'a>(
&self,
callback: CB,
) -> EventWatch<'a, CB> {
EventWatch::add(callback)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(u32)]
pub enum EventType {
First = SDL_EventType::SDL_FIRSTEVENT as u32,
Quit = SDL_EventType::SDL_QUIT as u32,
AppTerminating = SDL_EventType::SDL_APP_TERMINATING as u32,
AppLowMemory = SDL_EventType::SDL_APP_LOWMEMORY as u32,
AppWillEnterBackground = SDL_EventType::SDL_APP_WILLENTERBACKGROUND as u32,
AppDidEnterBackground = SDL_EventType::SDL_APP_DIDENTERBACKGROUND as u32,
AppWillEnterForeground = SDL_EventType::SDL_APP_WILLENTERFOREGROUND as u32,
AppDidEnterForeground = SDL_EventType::SDL_APP_DIDENTERFOREGROUND as u32,
Window = SDL_EventType::SDL_WINDOWEVENT as u32,
KeyDown = SDL_EventType::SDL_KEYDOWN as u32,
KeyUp = SDL_EventType::SDL_KEYUP as u32,
TextEditing = SDL_EventType::SDL_TEXTEDITING as u32,
TextInput = SDL_EventType::SDL_TEXTINPUT as u32,
MouseMotion = SDL_EventType::SDL_MOUSEMOTION as u32,
MouseButtonDown = SDL_EventType::SDL_MOUSEBUTTONDOWN as u32,
MouseButtonUp = SDL_EventType::SDL_MOUSEBUTTONUP as u32,
MouseWheel = SDL_EventType::SDL_MOUSEWHEEL as u32,
JoyAxisMotion = SDL_EventType::SDL_JOYAXISMOTION as u32,
JoyBallMotion = SDL_EventType::SDL_JOYBALLMOTION as u32,
JoyHatMotion = SDL_EventType::SDL_JOYHATMOTION as u32,
JoyButtonDown = SDL_EventType::SDL_JOYBUTTONDOWN as u32,
JoyButtonUp = SDL_EventType::SDL_JOYBUTTONUP as u32,
JoyDeviceAdded = SDL_EventType::SDL_JOYDEVICEADDED as u32,
JoyDeviceRemoved = SDL_EventType::SDL_JOYDEVICEREMOVED as u32,
ControllerAxisMotion = SDL_EventType::SDL_CONTROLLERAXISMOTION as u32,
ControllerButtonDown = SDL_EventType::SDL_CONTROLLERBUTTONDOWN as u32,
ControllerButtonUp = SDL_EventType::SDL_CONTROLLERBUTTONUP as u32,
ControllerDeviceAdded = SDL_EventType::SDL_CONTROLLERDEVICEADDED as u32,
ControllerDeviceRemoved = SDL_EventType::SDL_CONTROLLERDEVICEREMOVED as u32,
ControllerDeviceRemapped = SDL_EventType::SDL_CONTROLLERDEVICEREMAPPED as u32,
FingerDown = SDL_EventType::SDL_FINGERDOWN as u32,
FingerUp = SDL_EventType::SDL_FINGERUP as u32,
FingerMotion = SDL_EventType::SDL_FINGERMOTION as u32,
DollarGesture = SDL_EventType::SDL_DOLLARGESTURE as u32,
DollarRecord = SDL_EventType::SDL_DOLLARRECORD as u32,
MultiGesture = SDL_EventType::SDL_MULTIGESTURE as u32,
ClipboardUpdate = SDL_EventType::SDL_CLIPBOARDUPDATE as u32,
DropFile = SDL_EventType::SDL_DROPFILE as u32,
DropText = SDL_EventType::SDL_DROPTEXT as u32,
DropBegin = SDL_EventType::SDL_DROPBEGIN as u32,
DropComplete = SDL_EventType::SDL_DROPCOMPLETE as u32,
AudioDeviceAdded = SDL_EventType::SDL_AUDIODEVICEADDED as u32,
AudioDeviceRemoved = SDL_EventType::SDL_AUDIODEVICEREMOVED as u32,
RenderTargetsReset = SDL_EventType::SDL_RENDER_TARGETS_RESET as u32,
RenderDeviceReset = SDL_EventType::SDL_RENDER_DEVICE_RESET as u32,
User = SDL_EventType::SDL_USEREVENT as u32,
Last = SDL_EventType::SDL_LASTEVENT as u32,
}
impl TryFrom<u32> for EventType {
type Error = ();
fn try_from(n: u32) -> Result<Self, Self::Error> {
use self::EventType::*;
use crate::sys::SDL_EventType::*;
Ok(match unsafe { transmute(n) } {
SDL_FIRSTEVENT => First,
SDL_QUIT => Quit,
SDL_APP_TERMINATING => AppTerminating,
SDL_APP_LOWMEMORY => AppLowMemory,
SDL_APP_WILLENTERBACKGROUND => AppWillEnterBackground,
SDL_APP_DIDENTERBACKGROUND => AppDidEnterBackground,
SDL_APP_WILLENTERFOREGROUND => AppWillEnterForeground,
SDL_APP_DIDENTERFOREGROUND => AppDidEnterForeground,
SDL_WINDOWEVENT => Window,
SDL_KEYDOWN => KeyDown,
SDL_KEYUP => KeyUp,
SDL_TEXTEDITING => TextEditing,
SDL_TEXTINPUT => TextInput,
SDL_MOUSEMOTION => MouseMotion,
SDL_MOUSEBUTTONDOWN => MouseButtonDown,
SDL_MOUSEBUTTONUP => MouseButtonUp,
SDL_MOUSEWHEEL => MouseWheel,
SDL_JOYAXISMOTION => JoyAxisMotion,
SDL_JOYBALLMOTION => JoyBallMotion,
SDL_JOYHATMOTION => JoyHatMotion,
SDL_JOYBUTTONDOWN => JoyButtonDown,
SDL_JOYBUTTONUP => JoyButtonUp,
SDL_JOYDEVICEADDED => JoyDeviceAdded,
SDL_JOYDEVICEREMOVED => JoyDeviceRemoved,
SDL_CONTROLLERAXISMOTION => ControllerAxisMotion,
SDL_CONTROLLERBUTTONDOWN => ControllerButtonDown,
SDL_CONTROLLERBUTTONUP => ControllerButtonUp,
SDL_CONTROLLERDEVICEADDED => ControllerDeviceAdded,
SDL_CONTROLLERDEVICEREMOVED => ControllerDeviceRemoved,
SDL_CONTROLLERDEVICEREMAPPED => ControllerDeviceRemapped,
SDL_FINGERDOWN => FingerDown,
SDL_FINGERUP => FingerUp,
SDL_FINGERMOTION => FingerMotion,
SDL_DOLLARGESTURE => DollarGesture,
SDL_DOLLARRECORD => DollarRecord,
SDL_MULTIGESTURE => MultiGesture,
SDL_CLIPBOARDUPDATE => ClipboardUpdate,
SDL_DROPFILE => DropFile,
SDL_DROPTEXT => DropText,
SDL_DROPBEGIN => DropBegin,
SDL_DROPCOMPLETE => DropComplete,
SDL_AUDIODEVICEADDED => AudioDeviceAdded,
SDL_AUDIODEVICEREMOVED => AudioDeviceRemoved,
SDL_RENDER_TARGETS_RESET => RenderTargetsReset,
SDL_RENDER_DEVICE_RESET => RenderDeviceReset,
SDL_USEREVENT => User,
SDL_LASTEVENT => Last,
_ => return Err(()),
})
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum WindowEvent {
None,
Shown,
Hidden,
Exposed,
Moved(i32, i32),
Resized(i32, i32),
SizeChanged(i32, i32),
Minimized,
Maximized,
Restored,
Enter,
Leave,
FocusGained,
FocusLost,
Close,
TakeFocus,
HitTest,
}
impl WindowEvent {
#[allow(clippy::match_same_arms)]
fn from_ll(id: u8, data1: i32, data2: i32) -> WindowEvent {
match id {
0 => WindowEvent::None,
1 => WindowEvent::Shown,
2 => WindowEvent::Hidden,
3 => WindowEvent::Exposed,
4 => WindowEvent::Moved(data1, data2),
5 => WindowEvent::Resized(data1, data2),
6 => WindowEvent::SizeChanged(data1, data2),
7 => WindowEvent::Minimized,
8 => WindowEvent::Maximized,
9 => WindowEvent::Restored,
10 => WindowEvent::Enter,
11 => WindowEvent::Leave,
12 => WindowEvent::FocusGained,
13 => WindowEvent::FocusLost,
14 => WindowEvent::Close,
15 => WindowEvent::TakeFocus,
16 => WindowEvent::HitTest,
_ => WindowEvent::None,
}
}
fn to_ll(&self) -> (u8, i32, i32) {
match *self {
WindowEvent::None => (0, 0, 0),
WindowEvent::Shown => (1, 0, 0),
WindowEvent::Hidden => (2, 0, 0),
WindowEvent::Exposed => (3, 0, 0),
WindowEvent::Moved(d1, d2) => (4, d1, d2),
WindowEvent::Resized(d1, d2) => (5, d1, d2),
WindowEvent::SizeChanged(d1, d2) => (6, d1, d2),
WindowEvent::Minimized => (7, 0, 0),
WindowEvent::Maximized => (8, 0, 0),
WindowEvent::Restored => (9, 0, 0),
WindowEvent::Enter => (10, 0, 0),
WindowEvent::Leave => (11, 0, 0),
WindowEvent::FocusGained => (12, 0, 0),
WindowEvent::FocusLost => (13, 0, 0),
WindowEvent::Close => (14, 0, 0),
WindowEvent::TakeFocus => (15, 0, 0),
WindowEvent::HitTest => (16, 0, 0),
}
}
pub fn is_same_kind_as(&self, other: &WindowEvent) -> bool {
match (self, other) {
(Self::None, Self::None)
| (Self::Shown, Self::Shown)
| (Self::Hidden, Self::Hidden)
| (Self::Exposed, Self::Exposed)
| (Self::Moved(_, _), Self::Moved(_, _))
| (Self::Resized(_, _), Self::Resized(_, _))
| (Self::SizeChanged(_, _), Self::SizeChanged(_, _))
| (Self::Minimized, Self::Minimized)
| (Self::Maximized, Self::Maximized)
| (Self::Restored, Self::Restored)
| (Self::Enter, Self::Enter)
| (Self::Leave, Self::Leave)
| (Self::FocusGained, Self::FocusGained)
| (Self::FocusLost, Self::FocusLost)
| (Self::Close, Self::Close)
| (Self::TakeFocus, Self::TakeFocus)
| (Self::HitTest, Self::HitTest) => true,
_ => false,
}
}
}
#[derive(Clone, PartialEq, Debug)]
pub enum Event {
Quit {
timestamp: u32,
},
AppTerminating {
timestamp: u32,
},
AppLowMemory {
timestamp: u32,
},
AppWillEnterBackground {
timestamp: u32,
},
AppDidEnterBackground {
timestamp: u32,
},
AppWillEnterForeground {
timestamp: u32,
},
AppDidEnterForeground {
timestamp: u32,
},
Window {
timestamp: u32,
window_id: u32,
win_event: WindowEvent,
},
KeyDown {
timestamp: u32,
window_id: u32,
keycode: Option<Keycode>,
scancode: Option<Scancode>,
keymod: Mod,
repeat: bool,
},
KeyUp {
timestamp: u32,
window_id: u32,
keycode: Option<Keycode>,
scancode: Option<Scancode>,
keymod: Mod,
repeat: bool,
},
TextEditing {
timestamp: u32,
window_id: u32,
text: String,
start: i32,
length: i32,
},
TextInput {
timestamp: u32,
window_id: u32,
text: String,
},
MouseMotion {
timestamp: u32,
window_id: u32,
which: u32,
mousestate: MouseState,
x: i32,
y: i32,
xrel: i32,
yrel: i32,
},
MouseButtonDown {
timestamp: u32,
window_id: u32,
which: u32,
mouse_btn: MouseButton,
clicks: u8,
x: i32,
y: i32,
},
MouseButtonUp {
timestamp: u32,
window_id: u32,
which: u32,
mouse_btn: MouseButton,
clicks: u8,
x: i32,
y: i32,
},
MouseWheel {
timestamp: u32,
window_id: u32,
which: u32,
x: i32,
y: i32,
direction: MouseWheelDirection,
},
JoyAxisMotion {
timestamp: u32,
which: u32,
axis_idx: u8,
value: i16,
},
JoyBallMotion {
timestamp: u32,
which: u32,
ball_idx: u8,
xrel: i16,
yrel: i16,
},
JoyHatMotion {
timestamp: u32,
which: u32,
hat_idx: u8,
state: HatState,
},
JoyButtonDown {
timestamp: u32,
which: u32,
button_idx: u8,
},
JoyButtonUp {
timestamp: u32,
which: u32,
button_idx: u8,
},
JoyDeviceAdded {
timestamp: u32,
which: u32,
},
JoyDeviceRemoved {
timestamp: u32,
which: u32,
},
ControllerAxisMotion {
timestamp: u32,
which: u32,
axis: Axis,
value: i16,
},
ControllerButtonDown {
timestamp: u32,
which: u32,
button: Button,
},
ControllerButtonUp {
timestamp: u32,
which: u32,
button: Button,
},
ControllerDeviceAdded {
timestamp: u32,
which: u32,
},
ControllerDeviceRemoved {
timestamp: u32,
which: u32,
},
ControllerDeviceRemapped {
timestamp: u32,
which: u32,
},
FingerDown {
timestamp: u32,
touch_id: i64,
finger_id: i64,
x: f32,
y: f32,
dx: f32,
dy: f32,
pressure: f32,
},
FingerUp {
timestamp: u32,
touch_id: i64,
finger_id: i64,
x: f32,
y: f32,
dx: f32,
dy: f32,
pressure: f32,
},
FingerMotion {
timestamp: u32,
touch_id: i64,
finger_id: i64,
x: f32,
y: f32,
dx: f32,
dy: f32,
pressure: f32,
},
DollarGesture {
timestamp: u32,
touch_id: i64,
gesture_id: i64,
num_fingers: u32,
error: f32,
x: f32,
y: f32,
},
DollarRecord {
timestamp: u32,
touch_id: i64,
gesture_id: i64,
num_fingers: u32,
error: f32,
x: f32,
y: f32,
},
MultiGesture {
timestamp: u32,
touch_id: i64,
d_theta: f32,
d_dist: f32,
x: f32,
y: f32,
num_fingers: u16,
},
ClipboardUpdate {
timestamp: u32,
},
DropFile {
timestamp: u32,
window_id: u32,
filename: String,
},
DropText {
timestamp: u32,
window_id: u32,
filename: String,
},
DropBegin {
timestamp: u32,
window_id: u32,
},
DropComplete {
timestamp: u32,
window_id: u32,
},
AudioDeviceAdded {
timestamp: u32,
which: u32,
iscapture: bool,
},
AudioDeviceRemoved {
timestamp: u32,
which: u32,
iscapture: bool,
},
RenderTargetsReset {
timestamp: u32,
},
RenderDeviceReset {
timestamp: u32,
},
User {
timestamp: u32,
window_id: u32,
type_: u32,
code: i32,
data1: *mut c_void,
data2: *mut c_void,
},
Unknown {
timestamp: u32,
type_: u32,
},
}
unsafe impl Send for Event {}
unsafe impl Sync for Event {}
#[doc(alias = "SDL_Keysym")]
fn mk_keysym<S, K>(scancode: S, keycode: K, keymod: Mod) -> sys::SDL_Keysym
where
S: Into<Option<Scancode>>,
K: Into<Option<Keycode>>,
{
let scancode = scancode
.into()
.map(|sc| unsafe { transmute::<u32, sys::SDL_Scancode>(sc as u32) })
.unwrap_or(sys::SDL_Scancode::SDL_SCANCODE_UNKNOWN);
let keycode = keycode
.into()
.map(|kc| kc as sys::SDL_Keycode)
.unwrap_or(sys::SDLK_UNKNOWN as i32);
let keymod = keymod.bits() as u16;
sys::SDL_Keysym {
scancode,
sym: keycode,
mod_: keymod,
unused: 0,
}
}
impl Event {
fn to_ll(&self) -> Option<sys::SDL_Event> {
let mut ret = mem::MaybeUninit::uninit();
match *self {
Event::User {
window_id,
type_,
code,
data1,
data2,
timestamp,
} => {
let event = sys::SDL_UserEvent {
type_: type_ as u32,
timestamp,
windowID: window_id,
code: code as i32,
data1,
data2,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_UserEvent, 1);
Some(ret.assume_init())
}
}
Event::Quit { timestamp } => {
let event = sys::SDL_QuitEvent {
type_: SDL_EventType::SDL_QUIT as u32,
timestamp,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_QuitEvent, 1);
Some(ret.assume_init())
}
}
Event::Window {
timestamp,
window_id,
win_event,
} => {
let (win_event_id, data1, data2) = win_event.to_ll();
let event = sys::SDL_WindowEvent {
type_: SDL_EventType::SDL_WINDOWEVENT as u32,
timestamp,
windowID: window_id,
event: win_event_id,
padding1: 0,
padding2: 0,
padding3: 0,
data1,
data2,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_WindowEvent, 1);
Some(ret.assume_init())
}
}
Event::KeyDown {
timestamp,
window_id,
keycode,
scancode,
keymod,
repeat,
} => {
let keysym = mk_keysym(scancode, keycode, keymod);
let event = sys::SDL_KeyboardEvent {
type_: SDL_EventType::SDL_KEYDOWN as u32,
timestamp,
windowID: window_id,
state: sys::SDL_PRESSED as u8,
repeat: repeat as u8,
padding2: 0,
padding3: 0,
keysym,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_KeyboardEvent, 1);
Some(ret.assume_init())
}
}
Event::KeyUp {
timestamp,
window_id,
keycode,
scancode,
keymod,
repeat,
} => {
let keysym = mk_keysym(scancode, keycode, keymod);
let event = sys::SDL_KeyboardEvent {
type_: SDL_EventType::SDL_KEYUP as u32,
timestamp,
windowID: window_id,
state: sys::SDL_RELEASED as u8,
repeat: repeat as u8,
padding2: 0,
padding3: 0,
keysym,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_KeyboardEvent, 1);
Some(ret.assume_init())
}
}
Event::MouseMotion {
timestamp,
window_id,
which,
mousestate,
x,
y,
xrel,
yrel,
} => {
let state = mousestate.to_sdl_state();
let event = sys::SDL_MouseMotionEvent {
type_: SDL_EventType::SDL_MOUSEMOTION as u32,
timestamp,
windowID: window_id,
which,
state,
x,
y,
xrel,
yrel,
};
unsafe {
ptr::copy(
&event,
ret.as_mut_ptr() as *mut sys::SDL_MouseMotionEvent,
1,
);
Some(ret.assume_init())
}
}
Event::MouseButtonDown {
timestamp,
window_id,
which,
mouse_btn,
clicks,
x,
y,
} => {
let event = sys::SDL_MouseButtonEvent {
type_: SDL_EventType::SDL_MOUSEBUTTONDOWN as u32,
timestamp,
windowID: window_id,
which,
button: mouse_btn as u8,
state: sys::SDL_PRESSED as u8,
clicks,
padding1: 0,
x,
y,
};
unsafe {
ptr::copy(
&event,
ret.as_mut_ptr() as *mut sys::SDL_MouseButtonEvent,
1,
);
Some(ret.assume_init())
}
}
Event::MouseButtonUp {
timestamp,
window_id,
which,
mouse_btn,
clicks,
x,
y,
} => {
let event = sys::SDL_MouseButtonEvent {
type_: SDL_EventType::SDL_MOUSEBUTTONUP as u32,
timestamp,
windowID: window_id,
which,
button: mouse_btn as u8,
state: sys::SDL_RELEASED as u8,
clicks,
padding1: 0,
x,
y,
};
unsafe {
ptr::copy(
&event,
ret.as_mut_ptr() as *mut sys::SDL_MouseButtonEvent,
1,
);
Some(ret.assume_init())
}
}
Event::MouseWheel {
timestamp,
window_id,
which,
x,
y,
direction,
} => {
let event = sys::SDL_MouseWheelEvent {
type_: SDL_EventType::SDL_MOUSEWHEEL as u32,
timestamp,
windowID: window_id,
which,
x,
y,
direction: direction.to_ll(),
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_MouseWheelEvent, 1);
Some(ret.assume_init())
}
}
Event::JoyAxisMotion {
timestamp,
which,
axis_idx,
value,
} => {
let event = sys::SDL_JoyAxisEvent {
type_: SDL_EventType::SDL_JOYAXISMOTION as u32,
timestamp,
which: which as i32,
axis: axis_idx,
value,
padding1: 0,
padding2: 0,
padding3: 0,
padding4: 0,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_JoyAxisEvent, 1);
Some(ret.assume_init())
}
}
Event::JoyBallMotion {
timestamp,
which,
ball_idx,
xrel,
yrel,
} => {
let event = sys::SDL_JoyBallEvent {
type_: SDL_EventType::SDL_JOYBALLMOTION as u32,
timestamp,
which: which as i32,
ball: ball_idx,
xrel,
yrel,
padding1: 0,
padding2: 0,
padding3: 0,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_JoyBallEvent, 1);
Some(ret.assume_init())
}
}
Event::JoyHatMotion {
timestamp,
which,
hat_idx,
state,
} => {
let hatvalue = state.to_raw();
let event = sys::SDL_JoyHatEvent {
type_: SDL_EventType::SDL_JOYHATMOTION as u32,
timestamp,
which: which as i32,
hat: hat_idx,
value: hatvalue,
padding1: 0,
padding2: 0,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_JoyHatEvent, 1);
Some(ret.assume_init())
}
}
Event::JoyButtonDown {
timestamp,
which,
button_idx,
} => {
let event = sys::SDL_JoyButtonEvent {
type_: SDL_EventType::SDL_JOYBUTTONDOWN as u32,
timestamp,
which: which as i32,
button: button_idx,
state: sys::SDL_PRESSED as u8,
padding1: 0,
padding2: 0,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_JoyButtonEvent, 1);
Some(ret.assume_init())
}
}
Event::JoyButtonUp {
timestamp,
which,
button_idx,
} => {
let event = sys::SDL_JoyButtonEvent {
type_: SDL_EventType::SDL_JOYBUTTONUP as u32,
timestamp,
which: which as i32,
button: button_idx,
state: sys::SDL_RELEASED as u8,
padding1: 0,
padding2: 0,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_JoyButtonEvent, 1);
Some(ret.assume_init())
}
}
Event::JoyDeviceAdded { timestamp, which } => {
let event = sys::SDL_JoyDeviceEvent {
type_: SDL_EventType::SDL_JOYDEVICEADDED as u32,
timestamp,
which: which as i32,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_JoyDeviceEvent, 1);
Some(ret.assume_init())
}
}
Event::JoyDeviceRemoved { timestamp, which } => {
let event = sys::SDL_JoyDeviceEvent {
type_: SDL_EventType::SDL_JOYDEVICEREMOVED as u32,
timestamp,
which: which as i32,
};
unsafe {
ptr::copy(&event, ret.as_mut_ptr() as *mut sys::SDL_JoyDeviceEvent, 1);
Some(ret.assume_init())
}
}
Event::ControllerAxisMotion {
timestamp,
which,
axis,
value,
} => {
let axisval = axis.to_ll();
let event = sys::SDL_ControllerAxisEvent {
type_: SDL_EventType::SDL_CONTROLLERAXISMOTION as u32,
timestamp,
which: which as i32,
axis: axisval as u8,
value,
padding1: 0,
padding2: 0,
padding3: 0,
padding4: 0,
};
unsafe {
ptr::copy(
&event,
ret.as_mut_ptr() as *mut sys::SDL_ControllerAxisEvent,
1,
);
Some(ret.assume_init())
}
}
Event::ControllerButtonDown {
timestamp,
which,
button,
} => {
let buttonval = button.to_ll();
let event = sys::SDL_ControllerButtonEvent {
type_: SDL_EventType::SDL_CONTROLLERBUTTONDOWN as u32,
timestamp,
which: which as i32,
button: buttonval as u8,
state: sys::SDL_PRESSED as u8,
padding1: 0,
padding2: 0,
};
unsafe {
ptr::copy(
&event,
ret.as_mut_ptr() as *mut sys::SDL_ControllerButtonEvent,
1,
);
Some(ret.assume_init())
}
}
Event::ControllerButtonUp {
timestamp,
which,
button,
} => {
let buttonval = button.to_ll();
let event = sys::SDL_ControllerButtonEvent {
type_: SDL_EventType::SDL_CONTROLLERBUTTONUP as u32,
timestamp,
which: which as i32,
button: buttonval as u8,
state: sys::SDL_RELEASED as u8,
padding1: 0,
padding2: 0,
};
unsafe {
ptr::copy(
&event,
ret.as_mut_ptr() as *mut sys::SDL_ControllerButtonEvent,
1,
);
Some(ret.assume_init())
}
}
Event::ControllerDeviceAdded { timestamp, which } => {
let event = sys::SDL_ControllerDeviceEvent {
type_: SDL_EventType::SDL_CONTROLLERDEVICEADDED as u32,
timestamp,
which: which as i32,
};
unsafe {
ptr::copy(
&event,
ret.as_mut_ptr() as *mut sys::SDL_ControllerDeviceEvent,
1,
);
Some(ret.assume_init())
}
}
Event::ControllerDeviceRemoved { timestamp, which } => {
let event = sys::SDL_ControllerDeviceEvent {
type_: SDL_EventType::SDL_CONTROLLERDEVICEREMOVED as u32,
timestamp,
which: which as i32,
};
unsafe {
ptr::copy(
&event,
ret.as_mut_ptr() as *mut sys::SDL_ControllerDeviceEvent,
1,
);
Some(ret.assume_init())
}
}
Event::ControllerDeviceRemapped { timestamp, which } => {
let event = sys::SDL_ControllerDeviceEvent {
type_: SDL_EventType::SDL_CONTROLLERDEVICEREMAPPED as u32,
timestamp,
which: which as i32,
};
unsafe {
ptr::copy(
&event,
ret.as_mut_ptr() as *mut sys::SDL_ControllerDeviceEvent,
1,
);
Some(ret.assume_init())
}
}
Event::FingerDown { .. }
| Event::FingerUp { .. }
| Event::FingerMotion { .. }
| Event::DollarGesture { .. }
| Event::DollarRecord { .. }
| Event::MultiGesture { .. }
| Event::ClipboardUpdate { .. }
| Event::DropFile { .. }
| Event::TextEditing { .. }
| Event::TextInput { .. }
| Event::Unknown { .. }
| _ => {
None
}
}
}
fn from_ll(raw: sys::SDL_Event) -> Event {
let raw_type = unsafe { raw.type_ };
let event_type: EventType = EventType::try_from(raw_type as u32).unwrap_or(EventType::User);
unsafe {
match event_type {
EventType::Quit => {
let event = raw.quit;
Event::Quit {
timestamp: event.timestamp,
}
}
EventType::AppTerminating => {
let event = raw.common;
Event::AppTerminating {
timestamp: event.timestamp,
}
}
EventType::AppLowMemory => {
let event = raw.common;
Event::AppLowMemory {
timestamp: event.timestamp,
}
}
EventType::AppWillEnterBackground => {
let event = raw.common;
Event::AppWillEnterBackground {
timestamp: event.timestamp,
}
}
EventType::AppDidEnterBackground => {
let event = raw.common;
Event::AppDidEnterBackground {
timestamp: event.timestamp,
}
}
EventType::AppWillEnterForeground => {
let event = raw.common;
Event::AppWillEnterForeground {
timestamp: event.timestamp,
}
}
EventType::AppDidEnterForeground => {
let event = raw.common;
Event::AppDidEnterForeground {
timestamp: event.timestamp,
}
}
EventType::Window => {
let event = raw.window;
Event::Window {
timestamp: event.timestamp,
window_id: event.windowID,
win_event: WindowEvent::from_ll(event.event, event.data1, event.data2),
}
}
EventType::KeyDown => {
let event = raw.key;
Event::KeyDown {
timestamp: event.timestamp,
window_id: event.windowID,
keycode: Keycode::from_i32(event.keysym.sym as i32),
scancode: Scancode::from_i32(event.keysym.scancode as i32),
keymod: keyboard::Mod::from_bits_truncate(event.keysym.mod_),
repeat: event.repeat != 0,
}
}
EventType::KeyUp => {
let event = raw.key;
Event::KeyUp {
timestamp: event.timestamp,
window_id: event.windowID,
keycode: Keycode::from_i32(event.keysym.sym as i32),
scancode: Scancode::from_i32(event.keysym.scancode as i32),
keymod: keyboard::Mod::from_bits_truncate(event.keysym.mod_),
repeat: event.repeat != 0,
}
}
EventType::TextEditing => {
let event = raw.edit;
let text = String::from_utf8(
event
.text
.iter()
.take_while(|&b| (*b) != 0)
.map(|&b| b as u8)
.collect::<Vec<u8>>(),
)
.expect("Invalid TextEditing string");
Event::TextEditing {
timestamp: event.timestamp,
window_id: event.windowID,
text,
start: event.start,
length: event.length,
}
}
EventType::TextInput => {
let event = raw.text;
let text = String::from_utf8(
event
.text
.iter()
.take_while(|&b| (*b) != 0)
.map(|&b| b as u8)
.collect::<Vec<u8>>(),
)
.expect("Invalid TextInput string");
Event::TextInput {
timestamp: event.timestamp,
window_id: event.windowID,
text,
}
}
EventType::MouseMotion => {
let event = raw.motion;
Event::MouseMotion {
timestamp: event.timestamp,
window_id: event.windowID,
which: event.which as u32,
mousestate: mouse::MouseState::from_sdl_state(event.state),
x: event.x,
y: event.y,
xrel: event.xrel,
yrel: event.yrel,
}
}
EventType::MouseButtonDown => {
let event = raw.button;
Event::MouseButtonDown {
timestamp: event.timestamp,
window_id: event.windowID,
which: event.which as u32,
mouse_btn: mouse::MouseButton::from_ll(event.button),
clicks: event.clicks,
x: event.x,
y: event.y,
}
}
EventType::MouseButtonUp => {
let event = raw.button;
Event::MouseButtonUp {
timestamp: event.timestamp,
window_id: event.windowID,
which: event.which as u32,
mouse_btn: mouse::MouseButton::from_ll(event.button),
clicks: event.clicks,
x: event.x,
y: event.y,
}
}
EventType::MouseWheel => {
let event = raw.wheel;
Event::MouseWheel {
timestamp: event.timestamp,
window_id: event.windowID,
which: event.which as u32,
x: event.x,
y: event.y,
direction: mouse::MouseWheelDirection::from_ll(event.direction),
}
}
EventType::JoyAxisMotion => {
let event = raw.jaxis;
Event::JoyAxisMotion {
timestamp: event.timestamp,
which: event.which as u32,
axis_idx: event.axis,
value: event.value,
}
}
EventType::JoyBallMotion => {
let event = raw.jball;
Event::JoyBallMotion {
timestamp: event.timestamp,
which: event.which as u32,
ball_idx: event.ball,
xrel: event.xrel,
yrel: event.yrel,
}
}
EventType::JoyHatMotion => {
let event = raw.jhat;
Event::JoyHatMotion {
timestamp: event.timestamp,
which: event.which as u32,
hat_idx: event.hat,
state: joystick::HatState::from_raw(event.value),
}
}
EventType::JoyButtonDown => {
let event = raw.jbutton;
Event::JoyButtonDown {
timestamp: event.timestamp,
which: event.which as u32,
button_idx: event.button,
}
}
EventType::JoyButtonUp => {
let event = raw.jbutton;
Event::JoyButtonUp {
timestamp: event.timestamp,
which: event.which as u32,
button_idx: event.button,
}
}
EventType::JoyDeviceAdded => {
let event = raw.jdevice;
Event::JoyDeviceAdded {
timestamp: event.timestamp,
which: event.which as u32,
}
}
EventType::JoyDeviceRemoved => {
let event = raw.jdevice;
Event::JoyDeviceRemoved {
timestamp: event.timestamp,
which: event.which as u32,
}
}
EventType::ControllerAxisMotion => {
let event = raw.caxis;
let axis = controller::Axis::from_ll(transmute(event.axis as i32)).unwrap();
Event::ControllerAxisMotion {
timestamp: event.timestamp,
which: event.which as u32,
axis,
value: event.value,
}
}
EventType::ControllerButtonDown => {
let event = raw.cbutton;
let button =
controller::Button::from_ll(transmute(event.button as i32)).unwrap();
Event::ControllerButtonDown {
timestamp: event.timestamp,
which: event.which as u32,
button,
}
}
EventType::ControllerButtonUp => {
let event = raw.cbutton;
let button =
controller::Button::from_ll(transmute(event.button as i32)).unwrap();
Event::ControllerButtonUp {
timestamp: event.timestamp,
which: event.which as u32,
button,
}
}
EventType::ControllerDeviceAdded => {
let event = raw.cdevice;
Event::ControllerDeviceAdded {
timestamp: event.timestamp,
which: event.which as u32,
}
}
EventType::ControllerDeviceRemoved => {
let event = raw.cdevice;
Event::ControllerDeviceRemoved {
timestamp: event.timestamp,
which: event.which as u32,
}
}
EventType::ControllerDeviceRemapped => {
let event = raw.cdevice;
Event::ControllerDeviceRemapped {
timestamp: event.timestamp,
which: event.which as u32,
}
}
EventType::FingerDown => {
let event = raw.tfinger;
Event::FingerDown {
timestamp: event.timestamp,
touch_id: event.touchId,
finger_id: event.fingerId,
x: event.x,
y: event.y,
dx: event.dx,
dy: event.dy,
pressure: event.pressure,
}
}
EventType::FingerUp => {
let event = raw.tfinger;
Event::FingerUp {
timestamp: event.timestamp,
touch_id: event.touchId,
finger_id: event.fingerId,
x: event.x,
y: event.y,
dx: event.dx,
dy: event.dy,
pressure: event.pressure,
}
}
EventType::FingerMotion => {
let event = raw.tfinger;
Event::FingerMotion {
timestamp: event.timestamp,
touch_id: event.touchId,
finger_id: event.fingerId,
x: event.x,
y: event.y,
dx: event.dx,
dy: event.dy,
pressure: event.pressure,
}
}
EventType::DollarGesture => {
let event = raw.dgesture;
Event::DollarGesture {
timestamp: event.timestamp,
touch_id: event.touchId,
gesture_id: event.gestureId,
num_fingers: event.numFingers,
error: event.error,
x: event.x,
y: event.y,
}
}
EventType::DollarRecord => {
let event = raw.dgesture;
Event::DollarRecord {
timestamp: event.timestamp,
touch_id: event.touchId,
gesture_id: event.gestureId,
num_fingers: event.numFingers,
error: event.error,
x: event.x,
y: event.y,
}
}
EventType::MultiGesture => {
let event = raw.mgesture;
Event::MultiGesture {
timestamp: event.timestamp,
touch_id: event.touchId,
d_theta: event.dTheta,
d_dist: event.dDist,
x: event.x,
y: event.y,
num_fingers: event.numFingers,
}
}
EventType::ClipboardUpdate => {
let event = raw.common;
Event::ClipboardUpdate {
timestamp: event.timestamp,
}
}
EventType::DropFile => {
let event = raw.drop;
let buf = CStr::from_ptr(event.file as *const _).to_bytes();
let text = String::from_utf8_lossy(buf).to_string();
sys::SDL_free(event.file as *mut c_void);
Event::DropFile {
timestamp: event.timestamp,
window_id: event.windowID,
filename: text,
}
}
EventType::DropText => {
let event = raw.drop;
let buf = CStr::from_ptr(event.file as *const _).to_bytes();
let text = String::from_utf8_lossy(buf).to_string();
sys::SDL_free(event.file as *mut c_void);
Event::DropText {
timestamp: event.timestamp,
window_id: event.windowID,
filename: text,
}
}
EventType::DropBegin => {
let event = raw.drop;
Event::DropBegin {
timestamp: event.timestamp,
window_id: event.windowID,
}
}
EventType::DropComplete => {
let event = raw.drop;
Event::DropComplete {
timestamp: event.timestamp,
window_id: event.windowID,
}
}
EventType::AudioDeviceAdded => {
let event = raw.adevice;
Event::AudioDeviceAdded {
timestamp: event.timestamp,
which: event.which,
iscapture: event.iscapture != 0,
}
}
EventType::AudioDeviceRemoved => {
let event = raw.adevice;
Event::AudioDeviceRemoved {
timestamp: event.timestamp,
which: event.which,
iscapture: event.iscapture != 0,
}
}
EventType::RenderTargetsReset => Event::RenderTargetsReset {
timestamp: raw.common.timestamp,
},
EventType::RenderDeviceReset => Event::RenderDeviceReset {
timestamp: raw.common.timestamp,
},
EventType::First => panic!("Unused event, EventType::First, was encountered"),
EventType::Last => panic!("Unusable event, EventType::Last, was encountered"),
EventType::User => {
if raw_type < 32_768 {
let event = raw.common;
Event::Unknown {
timestamp: event.timestamp,
type_: event.type_,
}
} else {
let event = raw.user;
Event::User {
timestamp: event.timestamp,
window_id: event.windowID,
type_: raw_type,
code: event.code,
data1: event.data1,
data2: event.data2,
}
}
}
}
}
}
pub fn is_user_event(&self) -> bool {
match *self {
Event::User { .. } => true,
_ => false,
}
}
pub fn as_user_event_type<T: ::std::any::Any>(&self) -> Option<T> {
use std::any::TypeId;
let type_id = TypeId::of::<Box<T>>();
let (event_id, event_box_ptr) = match *self {
Event::User { type_, data1, .. } => (type_, data1),
_ => return None,
};
let cet = CUSTOM_EVENT_TYPES.lock().unwrap();
let event_type_id = match cet.sdl_id_to_type_id.get(&event_id) {
Some(id) => id,
None => {
panic!("internal error; could not find typeid")
}
};
if &type_id != event_type_id {
return None;
}
let event_box: Box<T> = unsafe { Box::from_raw(event_box_ptr as *mut T) };
Some(*event_box)
}
pub fn is_same_kind_as(&self, other: &Event) -> bool {
match (self, other) {
(Self::Quit { .. }, Self::Quit { .. })
| (Self::AppTerminating { .. }, Self::AppTerminating { .. })
| (Self::AppLowMemory { .. }, Self::AppLowMemory { .. })
| (Self::AppWillEnterBackground { .. }, Self::AppWillEnterBackground { .. })
| (Self::AppDidEnterBackground { .. }, Self::AppDidEnterBackground { .. })
| (Self::AppWillEnterForeground { .. }, Self::AppWillEnterForeground { .. })
| (Self::AppDidEnterForeground { .. }, Self::AppDidEnterForeground { .. })
| (Self::Window { .. }, Self::Window { .. })
| (Self::KeyDown { .. }, Self::KeyDown { .. })
| (Self::KeyUp { .. }, Self::KeyUp { .. })
| (Self::TextEditing { .. }, Self::TextEditing { .. })
| (Self::TextInput { .. }, Self::TextInput { .. })
| (Self::MouseMotion { .. }, Self::MouseMotion { .. })
| (Self::MouseButtonDown { .. }, Self::MouseButtonDown { .. })
| (Self::MouseButtonUp { .. }, Self::MouseButtonUp { .. })
| (Self::MouseWheel { .. }, Self::MouseWheel { .. })
| (Self::JoyAxisMotion { .. }, Self::JoyAxisMotion { .. })
| (Self::JoyBallMotion { .. }, Self::JoyBallMotion { .. })
| (Self::JoyHatMotion { .. }, Self::JoyHatMotion { .. })
| (Self::JoyButtonDown { .. }, Self::JoyButtonDown { .. })
| (Self::JoyButtonUp { .. }, Self::JoyButtonUp { .. })
| (Self::JoyDeviceAdded { .. }, Self::JoyDeviceAdded { .. })
| (Self::JoyDeviceRemoved { .. }, Self::JoyDeviceRemoved { .. })
| (Self::ControllerAxisMotion { .. }, Self::ControllerAxisMotion { .. })
| (Self::ControllerButtonDown { .. }, Self::ControllerButtonDown { .. })
| (Self::ControllerButtonUp { .. }, Self::ControllerButtonUp { .. })
| (Self::ControllerDeviceAdded { .. }, Self::ControllerDeviceAdded { .. })
| (Self::ControllerDeviceRemoved { .. }, Self::ControllerDeviceRemoved { .. })
| (Self::ControllerDeviceRemapped { .. }, Self::ControllerDeviceRemapped { .. })
| (Self::FingerDown { .. }, Self::FingerDown { .. })
| (Self::FingerUp { .. }, Self::FingerUp { .. })
| (Self::FingerMotion { .. }, Self::FingerMotion { .. })
| (Self::DollarGesture { .. }, Self::DollarGesture { .. })
| (Self::DollarRecord { .. }, Self::DollarRecord { .. })
| (Self::MultiGesture { .. }, Self::MultiGesture { .. })
| (Self::ClipboardUpdate { .. }, Self::ClipboardUpdate { .. })
| (Self::DropFile { .. }, Self::DropFile { .. })
| (Self::DropText { .. }, Self::DropText { .. })
| (Self::DropBegin { .. }, Self::DropBegin { .. })
| (Self::DropComplete { .. }, Self::DropComplete { .. })
| (Self::AudioDeviceAdded { .. }, Self::AudioDeviceAdded { .. })
| (Self::AudioDeviceRemoved { .. }, Self::AudioDeviceRemoved { .. })
| (Self::RenderTargetsReset { .. }, Self::RenderTargetsReset { .. })
| (Self::RenderDeviceReset { .. }, Self::RenderDeviceReset { .. })
| (Self::User { .. }, Self::User { .. })
| (Self::Unknown { .. }, Self::Unknown { .. }) => true,
_ => false,
}
}
pub fn get_timestamp(&self) -> u32 {
*match self {
Self::Quit { timestamp, .. } => timestamp,
Self::AppTerminating { timestamp, .. } => timestamp,
Self::AppLowMemory { timestamp, .. } => timestamp,
Self::AppWillEnterBackground { timestamp, .. } => timestamp,
Self::AppDidEnterBackground { timestamp, .. } => timestamp,
Self::AppWillEnterForeground { timestamp, .. } => timestamp,
Self::AppDidEnterForeground { timestamp, .. } => timestamp,
Self::Window { timestamp, .. } => timestamp,
Self::KeyDown { timestamp, .. } => timestamp,
Self::KeyUp { timestamp, .. } => timestamp,
Self::TextEditing { timestamp, .. } => timestamp,
Self::TextInput { timestamp, .. } => timestamp,
Self::MouseMotion { timestamp, .. } => timestamp,
Self::MouseButtonDown { timestamp, .. } => timestamp,
Self::MouseButtonUp { timestamp, .. } => timestamp,
Self::MouseWheel { timestamp, .. } => timestamp,
Self::JoyAxisMotion { timestamp, .. } => timestamp,
Self::JoyBallMotion { timestamp, .. } => timestamp,
Self::JoyHatMotion { timestamp, .. } => timestamp,
Self::JoyButtonDown { timestamp, .. } => timestamp,
Self::JoyButtonUp { timestamp, .. } => timestamp,
Self::JoyDeviceAdded { timestamp, .. } => timestamp,
Self::JoyDeviceRemoved { timestamp, .. } => timestamp,
Self::ControllerAxisMotion { timestamp, .. } => timestamp,
Self::ControllerButtonDown { timestamp, .. } => timestamp,
Self::ControllerButtonUp { timestamp, .. } => timestamp,
Self::ControllerDeviceAdded { timestamp, .. } => timestamp,
Self::ControllerDeviceRemoved { timestamp, .. } => timestamp,
Self::ControllerDeviceRemapped { timestamp, .. } => timestamp,
Self::FingerDown { timestamp, .. } => timestamp,
Self::FingerUp { timestamp, .. } => timestamp,
Self::FingerMotion { timestamp, .. } => timestamp,
Self::DollarGesture { timestamp, .. } => timestamp,
Self::DollarRecord { timestamp, .. } => timestamp,
Self::MultiGesture { timestamp, .. } => timestamp,
Self::ClipboardUpdate { timestamp, .. } => timestamp,
Self::DropFile { timestamp, .. } => timestamp,
Self::DropText { timestamp, .. } => timestamp,
Self::DropBegin { timestamp, .. } => timestamp,
Self::DropComplete { timestamp, .. } => timestamp,
Self::AudioDeviceAdded { timestamp, .. } => timestamp,
Self::AudioDeviceRemoved { timestamp, .. } => timestamp,
Self::RenderTargetsReset { timestamp, .. } => timestamp,
Self::RenderDeviceReset { timestamp, .. } => timestamp,
Self::User { timestamp, .. } => timestamp,
Self::Unknown { timestamp, .. } => timestamp,
}
}
pub fn get_window_id(&self) -> Option<u32> {
match self {
Self::Window { window_id, .. } => Some(*window_id),
Self::KeyDown { window_id, .. } => Some(*window_id),
Self::KeyUp { window_id, .. } => Some(*window_id),
Self::TextEditing { window_id, .. } => Some(*window_id),
Self::TextInput { window_id, .. } => Some(*window_id),
Self::MouseMotion { window_id, .. } => Some(*window_id),
Self::MouseButtonDown { window_id, .. } => Some(*window_id),
Self::MouseButtonUp { window_id, .. } => Some(*window_id),
Self::MouseWheel { window_id, .. } => Some(*window_id),
Self::DropFile { window_id, .. } => Some(*window_id),
Self::DropText { window_id, .. } => Some(*window_id),
Self::DropBegin { window_id, .. } => Some(*window_id),
Self::DropComplete { window_id, .. } => Some(*window_id),
Self::User { window_id, .. } => Some(*window_id),
_ => None,
}
}
pub fn is_window(&self) -> bool {
match self {
Self::Quit { .. }
| Self::AppTerminating { .. }
| Self::AppLowMemory { .. }
| Self::AppWillEnterBackground { .. }
| Self::AppDidEnterBackground { .. }
| Self::AppWillEnterForeground { .. }
| Self::AppDidEnterForeground { .. }
| Self::Window { .. } => true,
_ => false,
}
}
pub fn is_keyboard(&self) -> bool {
match self {
Self::KeyDown { .. } | Self::KeyUp { .. } => true,
_ => false,
}
}
pub fn is_text(&self) -> bool {
match self {
Self::TextEditing { .. } | Self::TextInput { .. } => true,
_ => false,
}
}
pub fn is_mouse(&self) -> bool {
match self {
Self::MouseMotion { .. }
| Self::MouseButtonDown { .. }
| Self::MouseButtonUp { .. }
| Self::MouseWheel { .. } => true,
_ => false,
}
}
pub fn is_controller(&self) -> bool {
match self {
Self::ControllerAxisMotion { .. }
| Self::ControllerButtonDown { .. }
| Self::ControllerButtonUp { .. }
| Self::ControllerDeviceAdded { .. }
| Self::ControllerDeviceRemoved { .. }
| Self::ControllerDeviceRemapped { .. } => true,
_ => false,
}
}
pub fn is_joy(&self) -> bool {
match self {
Self::JoyAxisMotion { .. }
| Self::JoyBallMotion { .. }
| Self::JoyHatMotion { .. }
| Self::JoyButtonDown { .. }
| Self::JoyButtonUp { .. }
| Self::JoyDeviceAdded { .. }
| Self::JoyDeviceRemoved { .. } => true,
_ => false,
}
}
pub fn is_finger(&self) -> bool {
match self {
Self::FingerDown { .. } | Self::FingerUp { .. } | Self::FingerMotion { .. } => true,
_ => false,
}
}
pub fn is_dollar(&self) -> bool {
match self {
Self::DollarGesture { .. } | Self::DollarRecord { .. } => true,
_ => false,
}
}
pub fn is_drop(&self) -> bool {
match self {
Self::DropFile { .. }
| Self::DropText { .. }
| Self::DropBegin { .. }
| Self::DropComplete { .. } => true,
_ => false,
}
}
pub fn is_audio(&self) -> bool {
match self {
Self::AudioDeviceAdded { .. } | Self::AudioDeviceRemoved { .. } => true,
_ => false,
}
}
pub fn is_render(&self) -> bool {
match self {
Self::RenderTargetsReset { .. } | Self::RenderDeviceReset { .. } => true,
_ => false,
}
}
pub fn is_user(&self) -> bool {
match self {
Self::User { .. } => true,
_ => false,
}
}
pub fn is_unknown(&self) -> bool {
match self {
Self::Unknown { .. } => true,
_ => false,
}
}
}
unsafe fn poll_event() -> Option<Event> {
let mut raw = mem::MaybeUninit::uninit();
let has_pending = sys::SDL_PollEvent(raw.as_mut_ptr()) == 1;
if has_pending {
Some(Event::from_ll(raw.assume_init()))
} else {
None
}
}
unsafe fn wait_event() -> Event {
let mut raw = mem::MaybeUninit::uninit();
let success = sys::SDL_WaitEvent(raw.as_mut_ptr()) == 1;
if success {
Event::from_ll(raw.assume_init())
} else {
panic!("{}", get_error())
}
}
unsafe fn wait_event_timeout(timeout: u32) -> Option<Event> {
let mut raw = mem::MaybeUninit::uninit();
let success = sys::SDL_WaitEventTimeout(raw.as_mut_ptr(), timeout as c_int) == 1;
if success {
Some(Event::from_ll(raw.assume_init()))
} else {
None
}
}
impl crate::EventPump {
#[doc(alias = "SDL_EventState")]
pub fn is_event_enabled(&self, event_type: EventType) -> bool {
let result = unsafe { sys::SDL_EventState(event_type as u32, sys::SDL_QUERY) };
result != sys::SDL_DISABLE as u8
}
#[doc(alias = "SDL_EventState")]
pub fn enable_event(&mut self, event_type: EventType) -> bool {
let result = unsafe { sys::SDL_EventState(event_type as u32, sys::SDL_ENABLE as c_int) };
result != sys::SDL_DISABLE as u8
}
#[doc(alias = "SDL_EventState")]
pub fn disable_event(&mut self, event_type: EventType) -> bool {
let result = unsafe { sys::SDL_EventState(event_type as u32, sys::SDL_DISABLE as c_int) };
result != sys::SDL_DISABLE as u8
}
pub fn poll_event(&mut self) -> Option<Event> {
unsafe { poll_event() }
}
pub fn poll_iter(&mut self) -> EventPollIterator {
EventPollIterator {
_marker: PhantomData,
}
}
#[doc(alias = "SDL_PumpEvents")]
pub fn pump_events(&mut self) {
unsafe {
sys::SDL_PumpEvents();
};
}
pub fn wait_event(&mut self) -> Event {
unsafe { wait_event() }
}
pub fn wait_event_timeout(&mut self, timeout: u32) -> Option<Event> {
unsafe { wait_event_timeout(timeout) }
}
pub fn wait_iter(&mut self) -> EventWaitIterator {
EventWaitIterator {
_marker: PhantomData,
}
}
pub fn wait_timeout_iter(&mut self, timeout: u32) -> EventWaitTimeoutIterator {
EventWaitTimeoutIterator {
_marker: PhantomData,
timeout,
}
}
#[inline]
pub fn keyboard_state(&self) -> crate::keyboard::KeyboardState {
crate::keyboard::KeyboardState::new(self)
}
#[inline]
pub fn mouse_state(&self) -> crate::mouse::MouseState {
crate::mouse::MouseState::new(self)
}
#[inline]
pub fn relative_mouse_state(&self) -> crate::mouse::RelativeMouseState {
crate::mouse::RelativeMouseState::new(self)
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct EventPollIterator<'a> {
_marker: PhantomData<&'a ()>,
}
impl<'a> Iterator for EventPollIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Event> {
unsafe { poll_event() }
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct EventWaitIterator<'a> {
_marker: PhantomData<&'a ()>,
}
impl<'a> Iterator for EventWaitIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Event> {
unsafe { Some(wait_event()) }
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct EventWaitTimeoutIterator<'a> {
_marker: PhantomData<&'a ()>,
timeout: u32,
}
impl<'a> Iterator for EventWaitTimeoutIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Event> {
unsafe { wait_event_timeout(self.timeout) }
}
}
#[cfg(test)]
mod test {
use super::super::controller::{Axis, Button};
use super::super::joystick::HatState;
use super::super::keyboard::{Keycode, Mod, Scancode};
use super::super::mouse::{MouseButton, MouseState, MouseWheelDirection};
use super::Event;
use super::WindowEvent;
#[test]
fn test_to_from_ll() {
{
let e = Event::Quit { timestamp: 0 };
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::Window {
timestamp: 0,
window_id: 0,
win_event: WindowEvent::Resized(1, 2),
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::KeyDown {
timestamp: 0,
window_id: 1,
keycode: None,
scancode: Some(Scancode::Q),
keymod: Mod::all(),
repeat: false,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::KeyUp {
timestamp: 123,
window_id: 0,
keycode: Some(Keycode::R),
scancode: Some(Scancode::R),
keymod: Mod::empty(),
repeat: true,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::MouseMotion {
timestamp: 0,
window_id: 0,
which: 1,
mousestate: MouseState::from_sdl_state(1),
x: 3,
y: 91,
xrel: -1,
yrel: 43,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::MouseButtonDown {
timestamp: 5634,
window_id: 2,
which: 0,
mouse_btn: MouseButton::Left,
clicks: 1,
x: 543,
y: 345,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::MouseButtonUp {
timestamp: 0,
window_id: 2,
which: 0,
mouse_btn: MouseButton::Left,
clicks: 1,
x: 543,
y: 345,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::MouseWheel {
timestamp: 1,
window_id: 0,
which: 32,
x: 23,
y: 91,
direction: MouseWheelDirection::Flipped,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::JoyAxisMotion {
timestamp: 0,
which: 1,
axis_idx: 1,
value: 12,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::JoyBallMotion {
timestamp: 0,
which: 0,
ball_idx: 1,
xrel: 123,
yrel: 321,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::JoyHatMotion {
timestamp: 0,
which: 3,
hat_idx: 1,
state: HatState::Left,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::JoyButtonDown {
timestamp: 0,
which: 0,
button_idx: 3,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::JoyButtonUp {
timestamp: 9876,
which: 1,
button_idx: 2,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::JoyDeviceAdded {
timestamp: 0,
which: 1,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::JoyDeviceRemoved {
timestamp: 0,
which: 2,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::ControllerAxisMotion {
timestamp: 53,
which: 0,
axis: Axis::LeftX,
value: 3,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::ControllerButtonDown {
timestamp: 0,
which: 1,
button: Button::Guide,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::ControllerButtonUp {
timestamp: 654214,
which: 0,
button: Button::DPadRight,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::ControllerDeviceAdded {
timestamp: 543,
which: 3,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::ControllerDeviceRemoved {
timestamp: 555,
which: 3,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
{
let e = Event::ControllerDeviceRemapped {
timestamp: 654,
which: 0,
};
let e2 = Event::from_ll(e.clone().to_ll().unwrap());
assert_eq!(e, e2);
}
}
#[test]
fn test_from_ll_keymod_keydown_unknown_bits() {
let mut raw_event = Event::KeyDown {
timestamp: 0,
window_id: 1,
keycode: None,
scancode: Some(Scancode::Q),
keymod: Mod::empty(),
repeat: false,
}
.to_ll()
.unwrap();
raw_event.key.keysym.mod_ = 0xffff;
if let Event::KeyDown { keymod, .. } = Event::from_ll(raw_event) {
assert_eq!(keymod, Mod::all());
} else {
panic!()
}
}
#[test]
fn test_from_ll_keymod_keyup_unknown_bits() {
let mut raw_event = Event::KeyUp {
timestamp: 0,
window_id: 1,
keycode: None,
scancode: Some(Scancode::Q),
keymod: Mod::empty(),
repeat: false,
}
.to_ll()
.unwrap();
raw_event.key.keysym.mod_ = 0xffff;
if let Event::KeyUp { keymod, .. } = Event::from_ll(raw_event) {
assert_eq!(keymod, Mod::all());
} else {
panic!()
}
}
}
pub struct EventSender {
_priv: (),
}
impl EventSender {
#[doc(alias = "SDL_PushEvent")]
pub fn push_event(&self, event: Event) -> Result<(), String> {
match event.to_ll() {
Some(mut raw_event) => {
let ok = unsafe { sys::SDL_PushEvent(&mut raw_event) == 1 };
if ok {
Ok(())
} else {
Err(get_error())
}
}
None => Err("Cannot push unsupported event type to the queue".to_owned()),
}
}
pub fn push_custom_event<T: ::std::any::Any>(&self, event: T) -> Result<(), String> {
use std::any::TypeId;
let cet = CUSTOM_EVENT_TYPES.lock().unwrap();
let type_id = TypeId::of::<Box<T>>();
let user_event_id = *match cet.type_id_to_sdl_id.get(&type_id) {
Some(id) => id,
None => {
return Err("Type is not registered as a custom event type!".to_owned());
}
};
let event_box = Box::new(event);
let event = Event::User {
timestamp: 0,
window_id: 0,
type_: user_event_id,
code: 0,
data1: Box::into_raw(event_box) as *mut c_void,
data2: ::std::ptr::null_mut(),
};
self.push_event(event)?;
Ok(())
}
}
pub trait EventWatchCallback {
fn callback(&mut self, event: Event) -> ();
}
pub struct EventWatch<'a, CB: EventWatchCallback + 'a> {
activated: bool,
callback: Box<CB>,
_phantom: PhantomData<&'a CB>,
}
impl<'a, CB: EventWatchCallback + 'a> EventWatch<'a, CB> {
fn add(callback: CB) -> EventWatch<'a, CB> {
let f = Box::new(callback);
let mut watch = EventWatch {
activated: false,
callback: f,
_phantom: PhantomData,
};
watch.activate();
watch
}
pub fn activate(&mut self) {
if !self.activated {
self.activated = true;
unsafe { sys::SDL_AddEventWatch(self.filter(), self.callback()) };
}
}
pub fn deactivate(&mut self) {
if self.activated {
self.activated = false;
unsafe { sys::SDL_DelEventWatch(self.filter(), self.callback()) };
}
}
pub fn activated(&self) -> bool {
self.activated
}
pub fn set_activated(&mut self, activate: bool) {
if activate {
self.activate();
} else {
self.deactivate();
}
}
fn filter(&self) -> SDL_EventFilter {
Some(event_callback_marshall::<CB> as _)
}
fn callback(&mut self) -> *mut c_void {
&mut *self.callback as *mut _ as *mut c_void
}
}
impl<'a, CB: EventWatchCallback + 'a> Drop for EventWatch<'a, CB> {
fn drop(&mut self) {
self.deactivate();
}
}
extern "C" fn event_callback_marshall<CB: EventWatchCallback>(
user_data: *mut c_void,
event: *mut sdl2_sys::SDL_Event,
) -> i32 {
let f: &mut CB = unsafe { &mut *(user_data as *mut _) };
let event = Event::from_ll(unsafe { *event });
f.callback(event);
0
}
impl<F: FnMut(Event) -> ()> EventWatchCallback for F {
fn callback(&mut self, event: Event) -> () {
self(event)
}
}