sdl3/
event.rs

1/*!
2Event Handling
3 */
4
5use std::borrow::ToOwned;
6use std::collections::HashMap;
7use std::convert::TryFrom;
8use std::ffi::CStr;
9use std::iter::FromIterator;
10use std::marker::PhantomData;
11use std::mem;
12use std::mem::transmute;
13use std::ptr;
14use std::sync::Mutex;
15
16use crate::gamepad;
17use crate::gamepad::{Axis, Button};
18use crate::get_error;
19use crate::joystick;
20use crate::joystick::HatState;
21use crate::keyboard;
22use crate::keyboard::Keycode;
23use crate::keyboard::Mod;
24use crate::keyboard::Scancode;
25use crate::mouse;
26use crate::mouse::{MouseButton, MouseState, MouseWheelDirection};
27use crate::pen::PenAxis;
28use crate::sys;
29use crate::sys::events::SDL_EventFilter;
30use crate::video::{Display, Orientation};
31use crate::Error;
32use libc::c_int;
33use libc::c_void;
34use sys::events::{
35    SDL_DisplayEvent, SDL_EventType, SDL_GamepadAxisEvent, SDL_GamepadButtonEvent,
36    SDL_GamepadDeviceEvent, SDL_JoyAxisEvent, SDL_JoyButtonEvent, SDL_JoyDeviceEvent,
37    SDL_JoyHatEvent, SDL_KeyboardEvent, SDL_MouseButtonEvent, SDL_MouseMotionEvent,
38    SDL_MouseWheelEvent,
39};
40use sys::everything::SDL_DisplayOrientation;
41use sys::stdinc::Uint16;
42
43struct CustomEventTypeMaps {
44    sdl_id_to_type_id: HashMap<u32, ::std::any::TypeId>,
45    type_id_to_sdl_id: HashMap<::std::any::TypeId, u32>,
46}
47
48impl CustomEventTypeMaps {
49    fn new() -> Self {
50        CustomEventTypeMaps {
51            sdl_id_to_type_id: HashMap::new(),
52            type_id_to_sdl_id: HashMap::new(),
53        }
54    }
55}
56
57lazy_static! {
58    static ref CUSTOM_EVENT_TYPES: Mutex<CustomEventTypeMaps> =
59        Mutex::new(CustomEventTypeMaps::new());
60}
61
62impl crate::EventSubsystem {
63    /// Removes all events in the event queue that match the specified event type.
64    #[doc(alias = "SDL_FlushEvent")]
65    pub fn flush_event(&self, event_type: EventType) {
66        unsafe { sys::events::SDL_FlushEvent(event_type.into()) };
67    }
68
69    /// Removes all events in the event queue that match the specified type range.
70    #[doc(alias = "SDL_FlushEvents")]
71    pub fn flush_events(&self, min_type: u32, max_type: u32) {
72        unsafe { sys::events::SDL_FlushEvents(min_type, max_type) };
73    }
74
75    /// Reads the events at the front of the event queue, until the maximum amount
76    /// of events is read.
77    ///
78    /// The events will _not_ be removed from the queue.
79    ///
80    /// # Example
81    /// ```no_run
82    /// use sdl3::event::Event;
83    ///
84    /// let sdl_context = sdl3::init().unwrap();
85    /// let event_subsystem = sdl_context.event().unwrap();
86    ///
87    /// // Read up to 1024 events
88    /// let events: Vec<Event> = event_subsystem.peek_events(1024);
89    ///
90    /// // Print each one
91    /// for event in events {
92    ///     println!("{:?}", event);
93    /// }
94    /// ```
95    #[doc(alias = "SDL_PeepEvents")]
96    pub fn peek_events<B>(&self, max_amount: u32) -> B
97    where
98        B: FromIterator<Event>,
99    {
100        unsafe {
101            let mut events = Vec::with_capacity(max_amount as usize);
102
103            let result = {
104                let events_ptr = events.as_mut_ptr();
105
106                sys::events::SDL_PeepEvents(
107                    events_ptr,
108                    max_amount as c_int,
109                    sys::events::SDL_PEEKEVENT,
110                    sys::events::SDL_EVENT_FIRST.into(),
111                    sys::events::SDL_EVENT_LAST.into(),
112                )
113            };
114
115            if result < 0 {
116                // The only error possible is "Couldn't lock event queue"
117                panic!("{}", get_error());
118            } else {
119                events.set_len(result as usize);
120
121                events.into_iter().map(Event::from_ll).collect()
122            }
123        }
124    }
125
126    /// Pushes an event to the event queue.
127    pub fn push_event(&self, event: Event) -> Result<(), Error> {
128        self.event_sender().push_event(event)
129    }
130
131    /// Register a custom SDL event.
132    ///
133    /// When pushing a user event, you must make sure that the ``type_`` field is set to a
134    /// registered SDL event number.
135    ///
136    /// The ``code``, ``data1``,  and ``data2`` fields can be used to store user defined data.
137    ///
138    /// See the [SDL documentation](https://wiki.libsdl.org/SDL_UserEvent) for more information.
139    ///
140    /// # Example
141    /// ```
142    /// let sdl = sdl3::init().unwrap();
143    /// let ev = sdl.event().unwrap();
144    ///
145    /// let custom_event_type_id = unsafe { ev.register_event().unwrap() };
146    /// let event = sdl3::event::Event::User {
147    ///    timestamp: 0,
148    ///    window_id: 0,
149    ///    type_: custom_event_type_id,
150    ///    code: 456,
151    ///    data1: 0x1234 as *mut libc::c_void,
152    ///    data2: 0x5678 as *mut libc::c_void,
153    /// };
154    ///
155    /// ev.push_event(event);
156    ///
157    /// ```
158    #[inline(always)]
159    pub unsafe fn register_event(&self) -> Result<u32, Error> {
160        Ok(*self.register_events(1)?.first().unwrap())
161    }
162
163    /// Registers custom SDL events.
164    ///
165    /// Returns an error, if no more user events can be created.
166    pub unsafe fn register_events(&self, nr: u32) -> Result<Vec<u32>, Error> {
167        let result = sys::events::SDL_RegisterEvents(nr as ::libc::c_int);
168        const ERR_NR: u32 = u32::MAX - 1;
169
170        match result {
171            ERR_NR => Err(Error(
172                "No more user events can be created; SDL_EVENT_LAST reached".to_owned(),
173            )),
174            _ => {
175                let event_ids = (result..(result + nr)).collect();
176                Ok(event_ids)
177            }
178        }
179    }
180
181    /// Register a custom event
182    ///
183    /// It returns an error when the same type is registered twice.
184    ///
185    /// # Example
186    /// See [push_custom_event](#method.push_custom_event)
187    #[inline(always)]
188    pub fn register_custom_event<T: ::std::any::Any>(&self) -> Result<(), Error> {
189        use std::any::TypeId;
190        let event_id = *(unsafe { self.register_events(1) })?.first().unwrap();
191        let mut cet = CUSTOM_EVENT_TYPES.lock().unwrap();
192        let type_id = TypeId::of::<Box<T>>();
193
194        if cet.type_id_to_sdl_id.contains_key(&type_id) {
195            return Err(Error(
196                "The same event type can not be registered twice!".to_owned(),
197            ));
198        }
199
200        cet.sdl_id_to_type_id.insert(event_id, type_id);
201        cet.type_id_to_sdl_id.insert(type_id, event_id);
202
203        Ok(())
204    }
205
206    /// Push a custom event
207    ///
208    /// If the event type ``T`` was not registered using
209    /// [register_custom_event](#method.register_custom_event),
210    /// this method will panic.
211    ///
212    /// # Example: pushing and receiving a custom event
213    /// ```
214    /// struct SomeCustomEvent {
215    ///     a: i32
216    /// }
217    ///
218    /// let sdl = sdl3::init().unwrap();
219    /// let ev = sdl.event().unwrap();
220    /// let mut ep = sdl.event_pump().unwrap();
221    ///
222    /// ev.register_custom_event::<SomeCustomEvent>().unwrap();
223    ///
224    /// let event = SomeCustomEvent { a: 42 };
225    ///
226    /// ev.push_custom_event(event);
227    ///
228    /// let received = ep.poll_event().unwrap(); // or within a for event in ep.poll_iter()
229    /// if received.is_user_event() {
230    ///     let e2 = received.as_user_event_type::<SomeCustomEvent>().unwrap();
231    ///     assert_eq!(e2.a, 42);
232    /// }
233    /// ```
234    pub fn push_custom_event<T: ::std::any::Any>(&self, event: T) -> Result<(), Error> {
235        self.event_sender().push_custom_event(event)
236    }
237
238    /// Create an event sender that can be sent to other threads.
239    ///
240    /// An `EventSender` will not keep the event subsystem alive. If the event subsystem is
241    /// shut down calls to `push_event` and `push_custom_event` will return errors.
242    pub fn event_sender(&self) -> EventSender {
243        EventSender { _priv: () }
244    }
245
246    /// Create an event watcher which is called every time an event is added to event queue.
247    ///
248    /// The watcher is disabled when the return value is dropped.
249    /// Just calling this function without binding to a variable immediately disables the watcher.
250    /// In order to make it persistent, you have to bind in a variable and keep it until it's no
251    /// longer needed.
252    ///
253    /// # Example: dump every event to stderr
254    /// ```
255    /// let sdl = sdl3::init().unwrap();
256    /// let ev = sdl.event().unwrap();
257    ///
258    /// // `let _ = ...` is insufficient, as it is dropped immediately.
259    /// let _event_watch = ev.add_event_watch(|event| {
260    ///     dbg!(event);
261    /// });
262    /// ```
263    pub fn add_event_watch<'a, CB: EventWatchCallback + 'a>(
264        &self,
265        callback: CB,
266    ) -> EventWatch<'a, CB> {
267        EventWatch::add(callback)
268    }
269}
270
271/// Types of events that can be delivered.
272#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
273#[repr(u32)]
274pub enum EventType {
275    First = sys::events::SDL_EVENT_FIRST.0,
276
277    Quit = sys::events::SDL_EVENT_QUIT.0,
278    AppTerminating = sys::events::SDL_EVENT_TERMINATING.0,
279    AppLowMemory = sys::events::SDL_EVENT_LOW_MEMORY.0,
280    AppWillEnterBackground = sys::events::SDL_EVENT_WILL_ENTER_BACKGROUND.0,
281    AppDidEnterBackground = sys::events::SDL_EVENT_DID_ENTER_BACKGROUND.0,
282    AppWillEnterForeground = sys::events::SDL_EVENT_WILL_ENTER_FOREGROUND.0,
283    AppDidEnterForeground = sys::events::SDL_EVENT_DID_ENTER_FOREGROUND.0,
284
285    DisplayAdded = sys::events::SDL_EVENT_DISPLAY_ADDED.0,
286    DisplayRemoved = sys::events::SDL_EVENT_DISPLAY_REMOVED.0,
287    DisplayOrientation = sys::events::SDL_EVENT_DISPLAY_ORIENTATION.0,
288    DisplayMoved = sys::events::SDL_EVENT_DISPLAY_MOVED.0,
289    DisplayDesktopModeChanged = sys::events::SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED.0,
290    DisplayCurrentModeChanged = sys::events::SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED.0,
291    DisplayContentScaleChanged = sys::events::SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED.0,
292
293    WindowShown = sys::events::SDL_EVENT_WINDOW_SHOWN.0,
294    WindowHidden = sys::events::SDL_EVENT_WINDOW_HIDDEN.0,
295    WindowExposed = sys::events::SDL_EVENT_WINDOW_EXPOSED.0,
296    WindowMoved = sys::events::SDL_EVENT_WINDOW_MOVED.0,
297    WindowResized = sys::events::SDL_EVENT_WINDOW_RESIZED.0,
298    WindowPixelSizeChanged = sys::events::SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED.0,
299    WindowMinimized = sys::events::SDL_EVENT_WINDOW_MINIMIZED.0,
300    WindowMaximized = sys::events::SDL_EVENT_WINDOW_MAXIMIZED.0,
301    WindowRestored = sys::events::SDL_EVENT_WINDOW_RESTORED.0,
302    WindowMouseEnter = sys::events::SDL_EVENT_WINDOW_MOUSE_ENTER.0,
303    WindowMouseLeave = sys::events::SDL_EVENT_WINDOW_MOUSE_LEAVE.0,
304    WindowFocusGained = sys::events::SDL_EVENT_WINDOW_FOCUS_GAINED.0,
305    WindowFocusLost = sys::events::SDL_EVENT_WINDOW_FOCUS_LOST.0,
306    WindowCloseRequested = sys::events::SDL_EVENT_WINDOW_CLOSE_REQUESTED.0,
307    WindowHitTest = sys::events::SDL_EVENT_WINDOW_HIT_TEST.0,
308    WindowICCProfileChanged = sys::events::SDL_EVENT_WINDOW_ICCPROF_CHANGED.0,
309    WindowDisplayChanged = sys::events::SDL_EVENT_WINDOW_DISPLAY_CHANGED.0,
310
311    // TODO: SysWM = sys::events::SDL_EVENT_SYSWM .0,
312    KeyDown = sys::events::SDL_EVENT_KEY_DOWN.0,
313    KeyUp = sys::events::SDL_EVENT_KEY_UP.0,
314    TextEditing = sys::events::SDL_EVENT_TEXT_EDITING.0,
315    TextInput = sys::events::SDL_EVENT_TEXT_INPUT.0,
316
317    MouseMotion = sys::events::SDL_EVENT_MOUSE_MOTION.0,
318    MouseButtonDown = sys::events::SDL_EVENT_MOUSE_BUTTON_DOWN.0,
319    MouseButtonUp = sys::events::SDL_EVENT_MOUSE_BUTTON_UP.0,
320    MouseWheel = sys::events::SDL_EVENT_MOUSE_WHEEL.0,
321
322    JoyAxisMotion = sys::events::SDL_EVENT_JOYSTICK_AXIS_MOTION.0,
323    JoyHatMotion = sys::events::SDL_EVENT_JOYSTICK_HAT_MOTION.0,
324    JoyButtonDown = sys::events::SDL_EVENT_JOYSTICK_BUTTON_DOWN.0,
325    JoyButtonUp = sys::events::SDL_EVENT_JOYSTICK_BUTTON_UP.0,
326    JoyDeviceAdded = sys::events::SDL_EVENT_JOYSTICK_ADDED.0,
327    JoyDeviceRemoved = sys::events::SDL_EVENT_JOYSTICK_REMOVED.0,
328
329    ControllerAxisMotion = sys::events::SDL_EVENT_GAMEPAD_AXIS_MOTION.0,
330    ControllerButtonDown = sys::events::SDL_EVENT_GAMEPAD_BUTTON_DOWN.0,
331    ControllerButtonUp = sys::events::SDL_EVENT_GAMEPAD_BUTTON_UP.0,
332    ControllerDeviceAdded = sys::events::SDL_EVENT_GAMEPAD_ADDED.0,
333    ControllerDeviceRemoved = sys::events::SDL_EVENT_GAMEPAD_REMOVED.0,
334    ControllerDeviceRemapped = sys::events::SDL_EVENT_GAMEPAD_REMAPPED.0,
335    ControllerTouchpadDown = sys::events::SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN.0,
336    ControllerTouchpadMotion = sys::events::SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION.0,
337    ControllerTouchpadUp = sys::events::SDL_EVENT_GAMEPAD_TOUCHPAD_UP.0,
338    #[cfg(feature = "hidapi")]
339    ControllerSensorUpdated = sys::events::SDL_EVENT_GAMEPAD_SENSOR_UPDATE.0,
340
341    FingerDown = sys::events::SDL_EVENT_FINGER_DOWN.0,
342    FingerUp = sys::events::SDL_EVENT_FINGER_UP.0,
343    FingerMotion = sys::events::SDL_EVENT_FINGER_MOTION.0,
344    // gestures have been removed from SD3: https://github.com/libsdl-org/SDL_gesture
345    ClipboardUpdate = sys::events::SDL_EVENT_CLIPBOARD_UPDATE.0,
346    DropFile = sys::events::SDL_EVENT_DROP_FILE.0,
347    DropText = sys::events::SDL_EVENT_DROP_TEXT.0,
348    DropBegin = sys::events::SDL_EVENT_DROP_BEGIN.0,
349    DropComplete = sys::events::SDL_EVENT_DROP_COMPLETE.0,
350
351    AudioDeviceAdded = sys::events::SDL_EVENT_AUDIO_DEVICE_ADDED.0,
352    AudioDeviceRemoved = sys::events::SDL_EVENT_AUDIO_DEVICE_REMOVED.0,
353
354    PenProximityIn = sys::events::SDL_EVENT_PEN_PROXIMITY_IN.0,
355    PenProximityOut = sys::events::SDL_EVENT_PEN_PROXIMITY_OUT.0,
356    PenDown = sys::events::SDL_EVENT_PEN_DOWN.0,
357    PenUp = sys::events::SDL_EVENT_PEN_UP.0,
358    PenButtonUp = sys::events::SDL_EVENT_PEN_BUTTON_UP.0,
359    PenButtonDown = sys::events::SDL_EVENT_PEN_BUTTON_DOWN.0,
360    PenMotion = sys::events::SDL_EVENT_PEN_MOTION.0,
361    PenAxis = sys::events::SDL_EVENT_PEN_AXIS.0,
362
363    RenderTargetsReset = sys::events::SDL_EVENT_RENDER_TARGETS_RESET.0,
364    RenderDeviceReset = sys::events::SDL_EVENT_RENDER_DEVICE_RESET.0,
365
366    User = sys::events::SDL_EVENT_USER.0,
367    Last = sys::events::SDL_EVENT_LAST.0,
368}
369
370impl From<EventType> for u32 {
371    fn from(t: EventType) -> u32 {
372        t as u32
373    }
374}
375impl From<EventType> for SDL_EventType {
376    fn from(t: EventType) -> SDL_EventType {
377        SDL_EventType(t as u32)
378    }
379}
380
381impl TryFrom<u32> for EventType {
382    type Error = ();
383
384    fn try_from(n: u32) -> Result<Self, Self::Error> {
385        use self::EventType::*;
386        use crate::sys::events::*;
387
388        Ok(match SDL_EventType(n) {
389            SDL_EVENT_FIRST => First,
390
391            SDL_EVENT_QUIT => Quit,
392            SDL_EVENT_TERMINATING => AppTerminating,
393            SDL_EVENT_LOW_MEMORY => AppLowMemory,
394            SDL_EVENT_WILL_ENTER_BACKGROUND => AppWillEnterBackground,
395            SDL_EVENT_DID_ENTER_BACKGROUND => AppDidEnterBackground,
396            SDL_EVENT_WILL_ENTER_FOREGROUND => AppWillEnterForeground,
397            SDL_EVENT_DID_ENTER_FOREGROUND => AppDidEnterForeground,
398
399            SDL_EVENT_DISPLAY_ADDED => DisplayAdded,
400            SDL_EVENT_DISPLAY_REMOVED => DisplayRemoved,
401            SDL_EVENT_DISPLAY_ORIENTATION => DisplayOrientation,
402            SDL_EVENT_DISPLAY_MOVED => DisplayMoved,
403            SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED => DisplayDesktopModeChanged,
404            SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED => DisplayCurrentModeChanged,
405            SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED => DisplayContentScaleChanged,
406
407            SDL_EVENT_WINDOW_SHOWN => WindowShown,
408            SDL_EVENT_WINDOW_HIDDEN => WindowHidden,
409            SDL_EVENT_WINDOW_EXPOSED => WindowExposed,
410            SDL_EVENT_WINDOW_MOVED => WindowMoved,
411            SDL_EVENT_WINDOW_RESIZED => WindowResized,
412            SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED => WindowPixelSizeChanged,
413            SDL_EVENT_WINDOW_MINIMIZED => WindowMinimized,
414            SDL_EVENT_WINDOW_MAXIMIZED => WindowMaximized,
415            SDL_EVENT_WINDOW_RESTORED => WindowRestored,
416            SDL_EVENT_WINDOW_MOUSE_ENTER => WindowMouseEnter,
417            SDL_EVENT_WINDOW_MOUSE_LEAVE => WindowMouseLeave,
418            SDL_EVENT_WINDOW_FOCUS_GAINED => WindowFocusGained,
419            SDL_EVENT_WINDOW_FOCUS_LOST => WindowFocusLost,
420            SDL_EVENT_WINDOW_CLOSE_REQUESTED => WindowCloseRequested,
421
422            SDL_EVENT_KEY_DOWN => KeyDown,
423            SDL_EVENT_KEY_UP => KeyUp,
424            SDL_EVENT_TEXT_EDITING => TextEditing,
425            SDL_EVENT_TEXT_INPUT => TextInput,
426
427            SDL_EVENT_MOUSE_MOTION => MouseMotion,
428            SDL_EVENT_MOUSE_BUTTON_DOWN => MouseButtonDown,
429            SDL_EVENT_MOUSE_BUTTON_UP => MouseButtonUp,
430            SDL_EVENT_MOUSE_WHEEL => MouseWheel,
431
432            SDL_EVENT_JOYSTICK_AXIS_MOTION => JoyAxisMotion,
433            SDL_EVENT_JOYSTICK_HAT_MOTION => JoyHatMotion,
434            SDL_EVENT_JOYSTICK_BUTTON_DOWN => JoyButtonDown,
435            SDL_EVENT_JOYSTICK_BUTTON_UP => JoyButtonUp,
436            SDL_EVENT_JOYSTICK_ADDED => JoyDeviceAdded,
437            SDL_EVENT_JOYSTICK_REMOVED => JoyDeviceRemoved,
438
439            SDL_EVENT_GAMEPAD_AXIS_MOTION => ControllerAxisMotion,
440            SDL_EVENT_GAMEPAD_BUTTON_DOWN => ControllerButtonDown,
441            SDL_EVENT_GAMEPAD_BUTTON_UP => ControllerButtonUp,
442            SDL_EVENT_GAMEPAD_ADDED => ControllerDeviceAdded,
443            SDL_EVENT_GAMEPAD_REMOVED => ControllerDeviceRemoved,
444            SDL_EVENT_GAMEPAD_REMAPPED => ControllerDeviceRemapped,
445            SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN => ControllerTouchpadDown,
446            SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION => ControllerTouchpadMotion,
447            SDL_EVENT_GAMEPAD_TOUCHPAD_UP => ControllerTouchpadUp,
448            #[cfg(feature = "hidapi")]
449            SDL_EVENT_GAMEPAD_SENSOR_UPDATE => ControllerSensorUpdated,
450
451            SDL_EVENT_FINGER_DOWN => FingerDown,
452            SDL_EVENT_FINGER_UP => FingerUp,
453            SDL_EVENT_FINGER_MOTION => FingerMotion,
454
455            SDL_EVENT_CLIPBOARD_UPDATE => ClipboardUpdate,
456            SDL_EVENT_DROP_FILE => DropFile,
457            SDL_EVENT_DROP_TEXT => DropText,
458            SDL_EVENT_DROP_BEGIN => DropBegin,
459            SDL_EVENT_DROP_COMPLETE => DropComplete,
460
461            SDL_EVENT_AUDIO_DEVICE_ADDED => AudioDeviceAdded,
462            SDL_EVENT_AUDIO_DEVICE_REMOVED => AudioDeviceRemoved,
463
464            SDL_EVENT_PEN_PROXIMITY_IN => PenProximityIn,
465            SDL_EVENT_PEN_PROXIMITY_OUT => PenProximityOut,
466            SDL_EVENT_PEN_DOWN => PenDown,
467            SDL_EVENT_PEN_UP => PenUp,
468            SDL_EVENT_PEN_BUTTON_UP => PenButtonUp,
469            SDL_EVENT_PEN_BUTTON_DOWN => PenButtonDown,
470            SDL_EVENT_PEN_MOTION => PenMotion,
471            SDL_EVENT_PEN_AXIS => PenAxis,
472
473            SDL_EVENT_RENDER_TARGETS_RESET => RenderTargetsReset,
474            SDL_EVENT_RENDER_DEVICE_RESET => RenderDeviceReset,
475
476            SDL_EVENT_USER => User,
477            SDL_EVENT_LAST => Last,
478
479            _ => return Err(()),
480        })
481    }
482}
483
484#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
485/// An enum of display events.
486pub enum DisplayEvent {
487    None,
488    Orientation(Orientation),
489    Added,
490    Removed,
491    Moved,
492    DesktopModeChanged,
493    CurrentModeChanged,
494    ContentScaleChanged,
495}
496
497impl DisplayEvent {
498    #[allow(clippy::match_same_arms)]
499    fn from_ll(id: u32, data1: i32) -> DisplayEvent {
500        match unsafe { transmute(id) } {
501            sys::events::SDL_EVENT_DISPLAY_ORIENTATION => {
502                let orientation = if data1 > SDL_DisplayOrientation::PORTRAIT_FLIPPED.0 {
503                    Orientation::Unknown
504                } else {
505                    let sdl_orientation = SDL_DisplayOrientation(data1);
506                    Orientation::from_ll(sdl_orientation)
507                };
508                DisplayEvent::Orientation(orientation)
509            }
510            sys::events::SDL_EVENT_DISPLAY_ADDED => DisplayEvent::Added,
511            sys::events::SDL_EVENT_DISPLAY_REMOVED => DisplayEvent::Removed,
512            sys::events::SDL_EVENT_DISPLAY_MOVED => DisplayEvent::Moved,
513            sys::events::SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED => DisplayEvent::DesktopModeChanged,
514            sys::events::SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED => DisplayEvent::CurrentModeChanged,
515            sys::events::SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED => {
516                DisplayEvent::ContentScaleChanged
517            }
518            _ => DisplayEvent::None,
519        }
520    }
521
522    fn to_ll(self) -> (u32, i32) {
523        match self {
524            DisplayEvent::Orientation(orientation) => (
525                sys::events::SDL_EVENT_DISPLAY_ORIENTATION.into(),
526                orientation.to_ll().into(),
527            ),
528            DisplayEvent::Added => (sys::events::SDL_EVENT_DISPLAY_ADDED.into(), 0),
529            DisplayEvent::Removed => (sys::events::SDL_EVENT_DISPLAY_REMOVED.into(), 0),
530            DisplayEvent::None => panic!("DisplayEvent::None cannot be converted"),
531            DisplayEvent::Moved => (sys::events::SDL_EVENT_DISPLAY_MOVED.into(), 0),
532            DisplayEvent::DesktopModeChanged => (
533                sys::events::SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED.into(),
534                0,
535            ),
536            DisplayEvent::CurrentModeChanged => (
537                sys::events::SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED.into(),
538                0,
539            ),
540            DisplayEvent::ContentScaleChanged => (
541                sys::events::SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED.into(),
542                0,
543            ),
544        }
545    }
546
547    pub fn is_same_kind_as(&self, other: &DisplayEvent) -> bool {
548        matches!(
549            (self, other),
550            (Self::None, Self::None)
551                | (Self::Orientation(_), Self::Orientation(_))
552                | (Self::Added, Self::Added)
553                | (Self::Removed, Self::Removed)
554        )
555    }
556}
557
558#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
559/// An enum of window events.
560pub enum WindowEvent {
561    None,
562    Shown,
563    Hidden,
564    Exposed,
565    Moved(i32, i32),
566    Resized(i32, i32),
567    PixelSizeChanged(i32, i32),
568    Minimized,
569    Maximized,
570    Restored,
571    MouseEnter,
572    MouseLeave,
573    FocusGained,
574    FocusLost,
575    CloseRequested,
576    HitTest(i32, i32),
577    ICCProfChanged,
578    DisplayChanged(i32),
579}
580
581impl WindowEvent {
582    #[allow(clippy::match_same_arms)]
583    fn from_ll(id: u32, data1: i32, data2: i32) -> WindowEvent {
584        match EventType::try_from(id) {
585            Ok(ev) => match ev {
586                EventType::WindowShown => WindowEvent::Shown,
587                EventType::WindowHidden => WindowEvent::Hidden,
588                EventType::WindowExposed => WindowEvent::Exposed,
589                EventType::WindowMoved => WindowEvent::Moved(data1, data2),
590                EventType::WindowResized => WindowEvent::Resized(data1, data2),
591                EventType::WindowPixelSizeChanged => WindowEvent::PixelSizeChanged(data1, data2),
592                EventType::WindowMinimized => WindowEvent::Minimized,
593                EventType::WindowMaximized => WindowEvent::Maximized,
594                EventType::WindowRestored => WindowEvent::Restored,
595                EventType::WindowMouseEnter => WindowEvent::MouseEnter,
596                EventType::WindowMouseLeave => WindowEvent::MouseLeave,
597                EventType::WindowFocusGained => WindowEvent::FocusGained,
598                EventType::WindowFocusLost => WindowEvent::FocusLost,
599                EventType::WindowCloseRequested => WindowEvent::CloseRequested,
600                EventType::WindowHitTest => WindowEvent::HitTest(data1, data2),
601                EventType::WindowICCProfileChanged => WindowEvent::ICCProfChanged,
602                EventType::WindowDisplayChanged => WindowEvent::DisplayChanged(data1),
603                _ => WindowEvent::None,
604            },
605            Err(_) => WindowEvent::None,
606        }
607    }
608
609    fn to_ll(self) -> (EventType, i32, i32) {
610        match self {
611            WindowEvent::None => panic!("Cannot convert WindowEvent::None"),
612            WindowEvent::Shown => (EventType::WindowShown, 0, 0),
613            WindowEvent::Hidden => (EventType::WindowHidden, 0, 0),
614            WindowEvent::Exposed => (EventType::WindowExposed, 0, 0),
615            WindowEvent::Moved(d1, d2) => (EventType::WindowMoved, d1, d2),
616            WindowEvent::Resized(d1, d2) => (EventType::WindowResized, d1, d2),
617            WindowEvent::PixelSizeChanged(d1, d2) => (EventType::WindowPixelSizeChanged, d1, d2),
618            WindowEvent::Minimized => (EventType::WindowMinimized, 0, 0),
619            WindowEvent::Maximized => (EventType::WindowMaximized, 0, 0),
620            WindowEvent::Restored => (EventType::WindowRestored, 0, 0),
621            WindowEvent::MouseEnter => (EventType::WindowMouseEnter, 0, 0),
622            WindowEvent::MouseLeave => (EventType::WindowMouseLeave, 0, 0),
623            WindowEvent::FocusGained => (EventType::WindowFocusGained, 0, 0),
624            WindowEvent::FocusLost => (EventType::WindowFocusLost, 0, 0),
625            WindowEvent::CloseRequested => (EventType::WindowCloseRequested, 0, 0),
626            WindowEvent::HitTest(d1, d2) => (EventType::WindowHitTest, d1, d2),
627            WindowEvent::ICCProfChanged => (EventType::WindowICCProfileChanged, 0, 0),
628            WindowEvent::DisplayChanged(d1) => (EventType::WindowDisplayChanged, d1, 0),
629        }
630    }
631
632    pub fn is_same_kind_as(&self, other: &WindowEvent) -> bool {
633        matches!(
634            (self, other),
635            (Self::None, Self::None)
636                | (Self::Shown, Self::Shown)
637                | (Self::Hidden, Self::Hidden)
638                | (Self::Exposed, Self::Exposed)
639                | (Self::Moved(_, _), Self::Moved(_, _))
640                | (Self::Resized(_, _), Self::Resized(_, _))
641                | (Self::PixelSizeChanged(_, _), Self::PixelSizeChanged(_, _))
642                | (Self::Minimized, Self::Minimized)
643                | (Self::Maximized, Self::Maximized)
644                | (Self::Restored, Self::Restored)
645                | (Self::MouseEnter, Self::MouseEnter)
646                | (Self::MouseLeave, Self::MouseLeave)
647                | (Self::FocusGained, Self::FocusGained)
648                | (Self::FocusLost, Self::FocusLost)
649                | (Self::CloseRequested, Self::CloseRequested)
650                | (Self::HitTest(_, _), Self::HitTest(_, _))
651                | (Self::ICCProfChanged, Self::ICCProfChanged)
652                | (Self::DisplayChanged(_), Self::DisplayChanged(_))
653        )
654    }
655}
656
657#[derive(Clone, PartialEq, Debug)]
658/// Different event types.
659pub enum Event {
660    Quit {
661        timestamp: u64,
662    },
663    AppTerminating {
664        timestamp: u64,
665    },
666    AppLowMemory {
667        timestamp: u64,
668    },
669    AppWillEnterBackground {
670        timestamp: u64,
671    },
672    AppDidEnterBackground {
673        timestamp: u64,
674    },
675    AppWillEnterForeground {
676        timestamp: u64,
677    },
678    AppDidEnterForeground {
679        timestamp: u64,
680    },
681
682    Window {
683        timestamp: u64,
684        window_id: u32,
685        win_event: WindowEvent,
686    },
687
688    // TODO: SysWMEvent
689    KeyDown {
690        timestamp: u64,
691        window_id: u32,
692        keycode: Option<Keycode>,
693        scancode: Option<Scancode>,
694        keymod: Mod,
695        repeat: bool,
696        which: u32,
697        raw: Uint16,
698    },
699    KeyUp {
700        timestamp: u64,
701        window_id: u32,
702        keycode: Option<Keycode>,
703        scancode: Option<Scancode>,
704        keymod: Mod,
705        repeat: bool,
706        which: u32,
707        raw: Uint16,
708    },
709
710    TextEditing {
711        timestamp: u64,
712        window_id: u32,
713        text: String,
714        start: i32,
715        length: i32,
716    },
717
718    TextInput {
719        timestamp: u64,
720        window_id: u32,
721        text: String,
722    },
723
724    MouseMotion {
725        timestamp: u64,
726        window_id: u32,
727        which: u32,
728        mousestate: MouseState,
729        x: f32,
730        y: f32,
731        xrel: f32,
732        yrel: f32,
733    },
734
735    MouseButtonDown {
736        timestamp: u64,
737        window_id: u32,
738        which: u32,
739        mouse_btn: MouseButton,
740        clicks: u8,
741        x: f32,
742        y: f32,
743    },
744    MouseButtonUp {
745        timestamp: u64,
746        window_id: u32,
747        which: u32,
748        mouse_btn: MouseButton,
749        clicks: u8,
750        x: f32,
751        y: f32,
752    },
753
754    MouseWheel {
755        timestamp: u64,
756        window_id: u32,
757        which: u32,
758        x: f32,
759        y: f32,
760        direction: MouseWheelDirection,
761        mouse_x: f32,
762        mouse_y: f32,
763    },
764
765    JoyAxisMotion {
766        timestamp: u64,
767        /// The joystick's `id`
768        which: u32,
769        axis_idx: u8,
770        value: i16,
771    },
772
773    JoyHatMotion {
774        timestamp: u64,
775        /// The joystick's `id`
776        which: u32,
777        hat_idx: u8,
778        state: HatState,
779    },
780
781    JoyButtonDown {
782        timestamp: u64,
783        /// The joystick's `id`
784        which: u32,
785        button_idx: u8,
786    },
787    JoyButtonUp {
788        timestamp: u64,
789        /// The joystick's `id`
790        which: u32,
791        button_idx: u8,
792    },
793
794    JoyDeviceAdded {
795        timestamp: u64,
796        /// The newly added joystick's `joystick_index`
797        which: u32,
798    },
799    JoyDeviceRemoved {
800        timestamp: u64,
801        /// The joystick's `id`
802        which: u32,
803    },
804
805    ControllerAxisMotion {
806        timestamp: u64,
807        /// The controller's joystick `id`
808        which: u32,
809        axis: Axis,
810        value: i16,
811    },
812
813    ControllerButtonDown {
814        timestamp: u64,
815        /// The controller's joystick `id`
816        which: u32,
817        button: Button,
818    },
819    ControllerButtonUp {
820        timestamp: u64,
821        /// The controller's joystick `id`
822        which: u32,
823        button: Button,
824    },
825
826    ControllerDeviceAdded {
827        timestamp: u64,
828        /// The newly added controller's `joystick_index`
829        which: u32,
830    },
831    ControllerDeviceRemoved {
832        timestamp: u64,
833        /// The controller's joystick `id`
834        which: u32,
835    },
836    ControllerDeviceRemapped {
837        timestamp: u64,
838        /// The controller's joystick `id`
839        which: u32,
840    },
841
842    ControllerTouchpadDown {
843        timestamp: u64,
844        /// The joystick instance id
845        which: u32,
846        /// The index of the touchpad
847        touchpad: i32,
848        /// The index of the finger on the touchpad
849        finger: i32,
850        /// Normalized in the range 0...1 with 0 being on the left
851        x: f32,
852        /// Normalized in the range 0...1 with 0 being at the top
853        y: f32,
854        /// Normalized in the range 0...1
855        pressure: f32,
856    },
857    ControllerTouchpadMotion {
858        timestamp: u64,
859        /// The joystick instance id
860        which: u32,
861        /// The index of the touchpad
862        touchpad: i32,
863        /// The index of the finger on the touchpad
864        finger: i32,
865        /// Normalized in the range 0...1 with 0 being on the left
866        x: f32,
867        /// Normalized in the range 0...1 with 0 being at the top
868        y: f32,
869        /// Normalized in the range 0...1
870        pressure: f32,
871    },
872    ControllerTouchpadUp {
873        timestamp: u64,
874        /// The joystick instance id
875        which: u32,
876        /// The index of the touchpad
877        touchpad: i32,
878        /// The index of the finger on the touchpad
879        finger: i32,
880        /// Normalized in the range 0...1 with 0 being on the left
881        x: f32,
882        /// Normalized in the range 0...1 with 0 being at the top
883        y: f32,
884        /// Normalized in the range 0...1
885        pressure: f32,
886    },
887
888    /// Triggered when the gyroscope or accelerometer is updated
889    #[cfg(feature = "hidapi")]
890    ControllerSensorUpdated {
891        timestamp: u64,
892        which: u32,
893        sensor: crate::sensor::SensorType,
894        /// Data from the sensor.
895        ///
896        /// See the `sensor` module for more information.
897        data: [f32; 3],
898    },
899
900    FingerDown {
901        timestamp: u64,
902        touch_id: u64,
903        finger_id: u64,
904        x: f32,
905        y: f32,
906        dx: f32,
907        dy: f32,
908        pressure: f32,
909    },
910    FingerUp {
911        timestamp: u64,
912        touch_id: u64,
913        finger_id: u64,
914        x: f32,
915        y: f32,
916        dx: f32,
917        dy: f32,
918        pressure: f32,
919    },
920    FingerMotion {
921        timestamp: u64,
922        touch_id: u64,
923        finger_id: u64,
924        x: f32,
925        y: f32,
926        dx: f32,
927        dy: f32,
928        pressure: f32,
929    },
930
931    DollarRecord {
932        timestamp: u64,
933        touch_id: i64,
934        gesture_id: i64,
935        num_fingers: u32,
936        error: f32,
937        x: f32,
938        y: f32,
939    },
940
941    MultiGesture {
942        timestamp: u64,
943        touch_id: i64,
944        d_theta: f32,
945        d_dist: f32,
946        x: f32,
947        y: f32,
948        num_fingers: u16,
949    },
950
951    ClipboardUpdate {
952        timestamp: u64,
953    },
954
955    DropFile {
956        timestamp: u64,
957        window_id: u32,
958        filename: String,
959    },
960    DropText {
961        timestamp: u64,
962        window_id: u32,
963        filename: String,
964    },
965    DropBegin {
966        timestamp: u64,
967        window_id: u32,
968    },
969    DropComplete {
970        timestamp: u64,
971        window_id: u32,
972    },
973
974    AudioDeviceAdded {
975        timestamp: u64,
976        which: u32,
977        iscapture: bool,
978    },
979    AudioDeviceRemoved {
980        timestamp: u64,
981        which: u32,
982        iscapture: bool,
983    },
984
985    PenProximityIn {
986        timestamp: u64,
987        which: u32,
988        window: u32,
989    },
990    PenProximityOut {
991        timestamp: u64,
992        which: u32,
993        window: u32,
994    },
995    PenDown {
996        timestamp: u64,
997        which: u32,
998        window: u32,
999        x: f32,
1000        y: f32,
1001        eraser: bool,
1002    },
1003    PenUp {
1004        timestamp: u64,
1005        which: u32,
1006        window: u32,
1007        x: f32,
1008        y: f32,
1009        eraser: bool,
1010    },
1011    PenMotion {
1012        timestamp: u64,
1013        which: u32,
1014        window: u32,
1015        x: f32,
1016        y: f32,
1017    },
1018    PenButtonUp {
1019        timestamp: u64,
1020        which: u32,
1021        window: u32,
1022        x: f32,
1023        y: f32,
1024        button: u8,
1025    },
1026    PenButtonDown {
1027        timestamp: u64,
1028        which: u32,
1029        window: u32,
1030        x: f32,
1031        y: f32,
1032        button: u8,
1033    },
1034    PenAxis {
1035        timestamp: u64,
1036        which: u32,
1037        window: u32,
1038        x: f32,
1039        y: f32,
1040        axis: PenAxis,
1041        value: f32,
1042    },
1043
1044    RenderTargetsReset {
1045        timestamp: u64,
1046    },
1047    RenderDeviceReset {
1048        timestamp: u64,
1049    },
1050
1051    User {
1052        timestamp: u64,
1053        window_id: u32,
1054        type_: u32,
1055        code: i32,
1056        data1: *mut c_void,
1057        data2: *mut c_void,
1058    },
1059
1060    Unknown {
1061        timestamp: u64,
1062        type_: u32,
1063    },
1064
1065    Display {
1066        timestamp: u64,
1067        display: Display,
1068        display_event: DisplayEvent,
1069    },
1070}
1071
1072/// This does not auto-derive because `User`'s `data` fields can be used to
1073/// store pointers to types that are `!Send`. Dereferencing these as pointers
1074/// requires using `unsafe` and ensuring your own safety guarantees.
1075unsafe impl Send for Event {}
1076
1077/// This does not auto-derive because `User`'s `data` fields can be used to
1078/// store pointers to types that are `!Sync`. Dereferencing these as pointers
1079/// requires using `unsafe` and ensuring your own safety guarantees.
1080unsafe impl Sync for Event {}
1081
1082// TODO: Remove this when from_utf8 is updated in Rust
1083// This would honestly be nice if it took &self instead of self,
1084// but Event::User's raw pointers kind of removes that possibility.
1085impl Event {
1086    fn to_ll(&self) -> Option<sys::events::SDL_Event> {
1087        let mut ret = mem::MaybeUninit::uninit();
1088        match *self {
1089            Event::User {
1090                window_id,
1091                type_,
1092                code,
1093                data1,
1094                data2,
1095                timestamp,
1096            } => {
1097                let event = sys::events::SDL_UserEvent {
1098                    r#type: type_,
1099                    timestamp,
1100                    windowID: window_id,
1101                    code,
1102                    data1,
1103                    data2,
1104                    reserved: 0,
1105                };
1106                unsafe {
1107                    ptr::copy(
1108                        &event,
1109                        ret.as_mut_ptr() as *mut sys::events::SDL_UserEvent,
1110                        1,
1111                    );
1112                    Some(ret.assume_init())
1113                }
1114            }
1115
1116            Event::Quit { timestamp } => {
1117                let event = sys::events::SDL_QuitEvent {
1118                    r#type: sys::events::SDL_EVENT_QUIT,
1119                    timestamp,
1120                    reserved: 0,
1121                };
1122                unsafe {
1123                    ptr::copy(
1124                        &event,
1125                        ret.as_mut_ptr() as *mut sys::events::SDL_QuitEvent,
1126                        1,
1127                    );
1128                    Some(ret.assume_init())
1129                }
1130            }
1131
1132            Event::Window {
1133                timestamp,
1134                window_id,
1135                win_event,
1136            } => {
1137                let (win_event_id, data1, data2) = win_event.to_ll();
1138                let event = sys::events::SDL_WindowEvent {
1139                    r#type: win_event_id.into(),
1140                    timestamp,
1141                    windowID: window_id,
1142                    data1,
1143                    data2,
1144                    reserved: 0,
1145                };
1146                unsafe {
1147                    ptr::copy(
1148                        &event,
1149                        ret.as_mut_ptr() as *mut sys::events::SDL_WindowEvent,
1150                        1,
1151                    );
1152                    Some(ret.assume_init())
1153                }
1154            }
1155
1156            Event::KeyDown {
1157                timestamp,
1158                window_id,
1159                keycode,
1160                scancode,
1161                keymod,
1162                repeat,
1163                which,
1164                raw,
1165            } => {
1166                let event = SDL_KeyboardEvent {
1167                    r#type: sys::events::SDL_EVENT_KEY_DOWN,
1168                    timestamp,
1169                    windowID: window_id,
1170                    repeat,
1171                    reserved: 0,
1172                    scancode: scancode?.into(),
1173                    which,
1174                    down: true,
1175                    key: keycode?.into(),
1176                    r#mod: keymod.bits(),
1177                    raw,
1178                };
1179                unsafe {
1180                    ptr::copy(
1181                        &event,
1182                        ret.as_mut_ptr() as *mut sys::events::SDL_KeyboardEvent,
1183                        1,
1184                    );
1185                    Some(ret.assume_init())
1186                }
1187            }
1188            Event::KeyUp {
1189                timestamp,
1190                window_id,
1191                keycode,
1192                scancode,
1193                keymod,
1194                repeat,
1195                which,
1196                raw,
1197            } => {
1198                let event = SDL_KeyboardEvent {
1199                    r#type: sys::events::SDL_EVENT_KEY_UP,
1200                    timestamp,
1201                    windowID: window_id,
1202                    repeat,
1203                    reserved: 0,
1204                    scancode: scancode?.into(),
1205                    which,
1206                    down: false,
1207                    key: keycode?.into(),
1208                    r#mod: keymod.bits(),
1209                    raw,
1210                };
1211                unsafe {
1212                    ptr::copy(
1213                        &event,
1214                        ret.as_mut_ptr() as *mut sys::events::SDL_KeyboardEvent,
1215                        1,
1216                    );
1217                    Some(ret.assume_init())
1218                }
1219            }
1220            Event::MouseMotion {
1221                timestamp,
1222                window_id,
1223                which,
1224                mousestate,
1225                x,
1226                y,
1227                xrel,
1228                yrel,
1229            } => {
1230                let state = mousestate.to_sdl_state();
1231                let event = SDL_MouseMotionEvent {
1232                    r#type: sys::events::SDL_EVENT_MOUSE_MOTION,
1233                    timestamp,
1234                    windowID: window_id,
1235                    which,
1236                    state,
1237                    x,
1238                    y,
1239                    xrel,
1240                    yrel,
1241                    reserved: 0,
1242                };
1243                unsafe {
1244                    ptr::copy(
1245                        &event,
1246                        ret.as_mut_ptr() as *mut sys::events::SDL_MouseMotionEvent,
1247                        1,
1248                    );
1249                    Some(ret.assume_init())
1250                }
1251            }
1252            Event::MouseButtonDown {
1253                timestamp,
1254                window_id,
1255                which,
1256                mouse_btn,
1257                clicks,
1258                x,
1259                y,
1260            } => {
1261                let event = SDL_MouseButtonEvent {
1262                    r#type: sys::events::SDL_EVENT_MOUSE_BUTTON_DOWN,
1263                    timestamp,
1264                    windowID: window_id,
1265                    which,
1266                    button: mouse_btn as u8,
1267                    down: true,
1268                    clicks,
1269                    x,
1270                    y,
1271                    padding: 0,
1272                    reserved: 0,
1273                };
1274                unsafe {
1275                    ptr::copy(
1276                        &event,
1277                        ret.as_mut_ptr() as *mut sys::events::SDL_MouseButtonEvent,
1278                        1,
1279                    );
1280                    Some(ret.assume_init())
1281                }
1282            }
1283            Event::MouseButtonUp {
1284                timestamp,
1285                window_id,
1286                which,
1287                mouse_btn,
1288                clicks,
1289                x,
1290                y,
1291            } => {
1292                let event = sys::events::SDL_MouseButtonEvent {
1293                    r#type: sys::events::SDL_EVENT_MOUSE_BUTTON_UP,
1294                    timestamp,
1295                    windowID: window_id,
1296                    which,
1297                    button: mouse_btn as u8,
1298                    clicks,
1299                    padding: 0,
1300                    x,
1301                    y,
1302                    down: false,
1303                    reserved: 0,
1304                };
1305                unsafe {
1306                    ptr::copy(
1307                        &event,
1308                        ret.as_mut_ptr() as *mut sys::events::SDL_MouseButtonEvent,
1309                        1,
1310                    );
1311                    Some(ret.assume_init())
1312                }
1313            }
1314
1315            Event::MouseWheel {
1316                timestamp,
1317                window_id,
1318                which,
1319                x,
1320                y,
1321                direction,
1322                mouse_x,
1323                mouse_y,
1324            } => {
1325                let event = SDL_MouseWheelEvent {
1326                    r#type: sys::events::SDL_EVENT_MOUSE_WHEEL,
1327                    timestamp,
1328                    windowID: window_id,
1329                    which,
1330                    x,
1331                    y,
1332                    direction: direction.into(),
1333                    mouse_x,
1334                    mouse_y,
1335                    integer_x: 0,
1336                    integer_y: 0,
1337                    reserved: 0,
1338                };
1339                unsafe {
1340                    ptr::copy(
1341                        &event,
1342                        ret.as_mut_ptr() as *mut sys::events::SDL_MouseWheelEvent,
1343                        1,
1344                    );
1345                    Some(ret.assume_init())
1346                }
1347            }
1348            Event::JoyAxisMotion {
1349                timestamp,
1350                which,
1351                axis_idx,
1352                value,
1353            } => {
1354                let event = SDL_JoyAxisEvent {
1355                    r#type: sys::events::SDL_EVENT_JOYSTICK_AXIS_MOTION,
1356                    timestamp,
1357                    which,
1358                    axis: axis_idx,
1359                    value,
1360                    padding1: 0,
1361                    padding2: 0,
1362                    padding3: 0,
1363                    padding4: 0,
1364                    reserved: 0,
1365                };
1366                unsafe {
1367                    ptr::copy(
1368                        &event,
1369                        ret.as_mut_ptr() as *mut sys::events::SDL_JoyAxisEvent,
1370                        1,
1371                    );
1372                    Some(ret.assume_init())
1373                }
1374            }
1375            Event::JoyHatMotion {
1376                timestamp,
1377                which,
1378                hat_idx,
1379                state,
1380            } => {
1381                let hatvalue = state.to_raw();
1382                let event = SDL_JoyHatEvent {
1383                    r#type: sys::events::SDL_EVENT_JOYSTICK_HAT_MOTION,
1384                    timestamp,
1385                    which,
1386                    hat: hat_idx,
1387                    value: hatvalue,
1388                    padding1: 0,
1389                    padding2: 0,
1390                    reserved: 0,
1391                };
1392                unsafe {
1393                    ptr::copy(
1394                        &event,
1395                        ret.as_mut_ptr() as *mut sys::events::SDL_JoyHatEvent,
1396                        1,
1397                    );
1398                    Some(ret.assume_init())
1399                }
1400            }
1401            Event::JoyButtonDown {
1402                timestamp,
1403                which,
1404                button_idx,
1405            } => {
1406                let event = SDL_JoyButtonEvent {
1407                    r#type: sys::events::SDL_EVENT_JOYSTICK_BUTTON_DOWN,
1408                    timestamp,
1409                    which,
1410                    button: button_idx,
1411                    down: true,
1412                    padding1: 0,
1413                    padding2: 0,
1414                    reserved: 0,
1415                };
1416                unsafe {
1417                    ptr::copy(
1418                        &event,
1419                        ret.as_mut_ptr() as *mut sys::events::SDL_JoyButtonEvent,
1420                        1,
1421                    );
1422                    Some(ret.assume_init())
1423                }
1424            }
1425
1426            Event::JoyButtonUp {
1427                timestamp,
1428                which,
1429                button_idx,
1430            } => {
1431                let event = SDL_JoyButtonEvent {
1432                    r#type: sys::events::SDL_EVENT_JOYSTICK_BUTTON_UP,
1433                    timestamp,
1434                    which,
1435                    button: button_idx,
1436                    down: false,
1437                    padding1: 0,
1438                    padding2: 0,
1439                    reserved: 0,
1440                };
1441                unsafe {
1442                    ptr::copy(
1443                        &event,
1444                        ret.as_mut_ptr() as *mut sys::events::SDL_JoyButtonEvent,
1445                        1,
1446                    );
1447                    Some(ret.assume_init())
1448                }
1449            }
1450
1451            Event::JoyDeviceAdded { timestamp, which } => {
1452                let event = SDL_JoyDeviceEvent {
1453                    r#type: sys::events::SDL_EVENT_JOYSTICK_ADDED,
1454                    timestamp,
1455                    which,
1456                    reserved: 0,
1457                };
1458                unsafe {
1459                    ptr::copy(
1460                        &event,
1461                        ret.as_mut_ptr() as *mut sys::events::SDL_JoyDeviceEvent,
1462                        1,
1463                    );
1464                    Some(ret.assume_init())
1465                }
1466            }
1467
1468            Event::JoyDeviceRemoved { timestamp, which } => {
1469                let event = SDL_JoyDeviceEvent {
1470                    r#type: sys::events::SDL_EVENT_JOYSTICK_REMOVED,
1471                    timestamp,
1472                    which,
1473                    reserved: 0,
1474                };
1475                unsafe {
1476                    ptr::copy(
1477                        &event,
1478                        ret.as_mut_ptr() as *mut sys::events::SDL_JoyDeviceEvent,
1479                        1,
1480                    );
1481                    Some(ret.assume_init())
1482                }
1483            }
1484            Event::ControllerAxisMotion {
1485                timestamp,
1486                which,
1487                axis,
1488                value,
1489            } => {
1490                let event = SDL_GamepadAxisEvent {
1491                    r#type: sys::events::SDL_EVENT_GAMEPAD_AXIS_MOTION,
1492                    timestamp,
1493                    which,
1494                    axis: axis.into(),
1495                    value,
1496                    padding1: 0,
1497                    padding2: 0,
1498                    padding3: 0,
1499                    padding4: 0,
1500                    reserved: 0,
1501                };
1502                unsafe {
1503                    ptr::copy(
1504                        &event,
1505                        ret.as_mut_ptr() as *mut sys::events::SDL_GamepadAxisEvent,
1506                        1,
1507                    );
1508                    Some(ret.assume_init())
1509                }
1510            }
1511            Event::ControllerButtonDown {
1512                timestamp,
1513                which,
1514                button,
1515            } => {
1516                let event = SDL_GamepadButtonEvent {
1517                    r#type: sys::events::SDL_EVENT_GAMEPAD_BUTTON_DOWN,
1518                    timestamp,
1519                    which,
1520                    // This conversion turns an i32 into a u8; signed-to-unsigned conversions
1521                    // are a bit of a code smell, but that appears to be how SDL defines it.
1522                    button: button.into(),
1523                    down: true,
1524                    padding1: 0,
1525                    padding2: 0,
1526                    reserved: 0,
1527                };
1528                unsafe {
1529                    ptr::copy(
1530                        &event,
1531                        ret.as_mut_ptr() as *mut sys::events::SDL_GamepadButtonEvent,
1532                        1,
1533                    );
1534                    Some(ret.assume_init())
1535                }
1536            }
1537
1538            Event::ControllerButtonUp {
1539                timestamp,
1540                which,
1541                button,
1542            } => {
1543                let event = SDL_GamepadButtonEvent {
1544                    r#type: sys::events::SDL_EVENT_GAMEPAD_BUTTON_UP,
1545                    reserved: 0,
1546                    timestamp,
1547                    which,
1548                    button: button.into(),
1549                    down: false,
1550                    padding1: 0,
1551                    padding2: 0,
1552                };
1553                unsafe {
1554                    ptr::copy(
1555                        &event,
1556                        ret.as_mut_ptr() as *mut sys::events::SDL_GamepadButtonEvent,
1557                        1,
1558                    );
1559                    Some(ret.assume_init())
1560                }
1561            }
1562
1563            Event::ControllerDeviceAdded { timestamp, which } => {
1564                let event = SDL_GamepadDeviceEvent {
1565                    r#type: sys::events::SDL_EVENT_GAMEPAD_ADDED,
1566                    timestamp,
1567                    which,
1568                    reserved: 0,
1569                };
1570                unsafe {
1571                    ptr::copy(
1572                        &event,
1573                        ret.as_mut_ptr() as *mut sys::events::SDL_GamepadDeviceEvent,
1574                        1,
1575                    );
1576                    Some(ret.assume_init())
1577                }
1578            }
1579
1580            Event::ControllerDeviceRemoved { timestamp, which } => {
1581                let event = SDL_GamepadDeviceEvent {
1582                    r#type: sys::events::SDL_EVENT_GAMEPAD_REMOVED,
1583                    timestamp,
1584                    which,
1585                    reserved: 0,
1586                };
1587                unsafe {
1588                    ptr::copy(
1589                        &event,
1590                        ret.as_mut_ptr() as *mut sys::events::SDL_GamepadDeviceEvent,
1591                        1,
1592                    );
1593                    Some(ret.assume_init())
1594                }
1595            }
1596
1597            Event::ControllerDeviceRemapped { timestamp, which } => {
1598                let event = SDL_GamepadDeviceEvent {
1599                    r#type: sys::events::SDL_EVENT_GAMEPAD_REMAPPED,
1600                    timestamp,
1601                    which,
1602                    reserved: 0,
1603                };
1604                unsafe {
1605                    ptr::copy(
1606                        &event,
1607                        ret.as_mut_ptr() as *mut sys::events::SDL_GamepadDeviceEvent,
1608                        1,
1609                    );
1610                    Some(ret.assume_init())
1611                }
1612            }
1613
1614            Event::Display {
1615                timestamp,
1616                display,
1617                display_event,
1618            } => {
1619                let display_event = display_event.to_ll();
1620                let event = SDL_DisplayEvent {
1621                    r#type: SDL_EventType(display_event.0),
1622                    displayID: display.id,
1623                    data1: display_event.1,
1624                    data2: 0,
1625                    timestamp,
1626                    reserved: 0,
1627                };
1628                unsafe {
1629                    ptr::copy(
1630                        &event,
1631                        ret.as_mut_ptr() as *mut sys::events::SDL_DisplayEvent,
1632                        1,
1633                    );
1634                    Some(ret.assume_init())
1635                }
1636            }
1637
1638            Event::FingerDown { .. }
1639            | Event::FingerUp { .. }
1640            | Event::FingerMotion { .. }
1641            | Event::DollarRecord { .. }
1642            | Event::MultiGesture { .. }
1643            | Event::ClipboardUpdate { .. }
1644            | Event::DropFile { .. }
1645            | Event::TextEditing { .. }
1646            | Event::TextInput { .. }
1647            | Event::Unknown { .. }
1648            | _ => {
1649                // don't know how to convert!
1650                None
1651            }
1652        }
1653    }
1654
1655    pub fn from_ll(raw: sys::events::SDL_Event) -> Event {
1656        let raw_type = unsafe { raw.r#type };
1657
1658        // if event type has not been defined, treat it as a UserEvent
1659        let event_type: EventType = EventType::try_from(raw_type).unwrap_or(EventType::User);
1660        unsafe {
1661            match event_type {
1662                EventType::WindowShown
1663                | EventType::WindowHidden
1664                | EventType::WindowExposed
1665                | EventType::WindowMoved
1666                | EventType::WindowResized
1667                | EventType::WindowPixelSizeChanged
1668                | EventType::WindowMinimized
1669                | EventType::WindowMaximized
1670                | EventType::WindowRestored
1671                | EventType::WindowMouseEnter
1672                | EventType::WindowMouseLeave
1673                | EventType::WindowFocusGained
1674                | EventType::WindowFocusLost
1675                | EventType::WindowCloseRequested
1676                | EventType::WindowHitTest
1677                | EventType::WindowICCProfileChanged
1678                | EventType::WindowDisplayChanged => {
1679                    let event = raw.window;
1680                    Event::Window {
1681                        timestamp: event.timestamp,
1682                        window_id: event.windowID,
1683                        win_event: WindowEvent::from_ll(
1684                            event.r#type.into(),
1685                            event.data1,
1686                            event.data2,
1687                        ),
1688                    }
1689                }
1690
1691                EventType::Quit => {
1692                    let event = raw.quit;
1693                    Event::Quit {
1694                        timestamp: event.timestamp,
1695                    }
1696                }
1697                EventType::AppTerminating => {
1698                    let event = raw.common;
1699                    Event::AppTerminating {
1700                        timestamp: event.timestamp,
1701                    }
1702                }
1703                EventType::AppLowMemory => {
1704                    let event = raw.common;
1705                    Event::AppLowMemory {
1706                        timestamp: event.timestamp,
1707                    }
1708                }
1709                EventType::AppWillEnterBackground => {
1710                    let event = raw.common;
1711                    Event::AppWillEnterBackground {
1712                        timestamp: event.timestamp,
1713                    }
1714                }
1715                EventType::AppDidEnterBackground => {
1716                    let event = raw.common;
1717                    Event::AppDidEnterBackground {
1718                        timestamp: event.timestamp,
1719                    }
1720                }
1721                EventType::AppWillEnterForeground => {
1722                    let event = raw.common;
1723                    Event::AppWillEnterForeground {
1724                        timestamp: event.timestamp,
1725                    }
1726                }
1727                EventType::AppDidEnterForeground => {
1728                    let event = raw.common;
1729                    Event::AppDidEnterForeground {
1730                        timestamp: event.timestamp,
1731                    }
1732                }
1733
1734                EventType::DisplayOrientation
1735                | EventType::DisplayAdded
1736                | EventType::DisplayRemoved
1737                | EventType::DisplayMoved
1738                | EventType::DisplayDesktopModeChanged
1739                | EventType::DisplayCurrentModeChanged
1740                | EventType::DisplayContentScaleChanged => {
1741                    let event = raw.display;
1742
1743                    Event::Display {
1744                        timestamp: event.timestamp,
1745                        display: Display::from_ll(event.displayID),
1746                        display_event: DisplayEvent::from_ll(event.r#type.into(), event.data1),
1747                    }
1748                }
1749
1750                // TODO: SysWMEventType
1751                EventType::KeyDown => {
1752                    let event = raw.key;
1753
1754                    Event::KeyDown {
1755                        timestamp: event.timestamp,
1756                        window_id: event.windowID,
1757                        keycode: Keycode::from_i32(event.key as i32),
1758                        scancode: Scancode::from_i32(event.scancode.into()),
1759                        keymod: keyboard::Mod::from_bits_truncate(event.r#mod),
1760                        repeat: event.repeat,
1761                        which: event.which,
1762                        raw: event.raw,
1763                    }
1764                }
1765                EventType::KeyUp => {
1766                    let event = raw.key;
1767
1768                    Event::KeyUp {
1769                        timestamp: event.timestamp,
1770                        window_id: event.windowID,
1771                        keycode: Keycode::from_i32(event.key as i32),
1772                        scancode: Scancode::from_i32(event.scancode.into()),
1773                        keymod: keyboard::Mod::from_bits_truncate(event.r#mod),
1774                        repeat: event.repeat,
1775                        which: event.which,
1776                        raw: event.raw,
1777                    }
1778                }
1779                EventType::TextEditing => {
1780                    let event = raw.edit;
1781
1782                    // event.text is a *const c_char (pointer to a C string)
1783                    let c_str: &CStr = CStr::from_ptr(event.text);
1784
1785                    // Convert the CStr to a Rust &str
1786                    let text_str = c_str.to_str().expect("Invalid UTF-8 string");
1787                    let text = text_str.to_owned();
1788
1789                    Event::TextEditing {
1790                        timestamp: event.timestamp,
1791                        window_id: event.windowID,
1792                        text,
1793                        start: event.start,
1794                        length: event.length,
1795                    }
1796                }
1797                EventType::TextInput => {
1798                    let event = raw.text;
1799
1800                    // event.text is a *const c_char (pointer to a C string)
1801                    let c_str: &CStr = CStr::from_ptr(event.text);
1802
1803                    // Convert the CStr to a Rust &str
1804                    let text_str = c_str.to_str().expect("Invalid UTF-8 string");
1805                    let text = text_str.to_owned();
1806
1807                    Event::TextInput {
1808                        timestamp: event.timestamp,
1809                        window_id: event.windowID,
1810                        text,
1811                    }
1812                }
1813
1814                EventType::MouseMotion => {
1815                    let event = raw.motion;
1816
1817                    Event::MouseMotion {
1818                        timestamp: event.timestamp,
1819                        window_id: event.windowID,
1820                        which: event.which,
1821                        mousestate: mouse::MouseState::from_sdl_state(event.state),
1822                        x: event.x,
1823                        y: event.y,
1824                        xrel: event.xrel,
1825                        yrel: event.yrel,
1826                    }
1827                }
1828                EventType::MouseButtonDown => {
1829                    let event = raw.button;
1830
1831                    Event::MouseButtonDown {
1832                        timestamp: event.timestamp,
1833                        window_id: event.windowID,
1834                        which: event.which,
1835                        mouse_btn: mouse::MouseButton::from_ll(event.button),
1836                        clicks: event.clicks,
1837                        x: event.x,
1838                        y: event.y,
1839                    }
1840                }
1841                EventType::MouseButtonUp => {
1842                    let event = raw.button;
1843
1844                    Event::MouseButtonUp {
1845                        timestamp: event.timestamp,
1846                        window_id: event.windowID,
1847                        which: event.which,
1848                        mouse_btn: mouse::MouseButton::from_ll(event.button),
1849                        clicks: event.clicks,
1850                        x: event.x,
1851                        y: event.y,
1852                    }
1853                }
1854                EventType::MouseWheel => {
1855                    let event = raw.wheel;
1856
1857                    Event::MouseWheel {
1858                        timestamp: event.timestamp,
1859                        window_id: event.windowID,
1860                        which: event.which,
1861                        x: event.x,
1862                        y: event.y,
1863                        direction: event.direction.into(),
1864                        mouse_x: event.mouse_x,
1865                        mouse_y: event.mouse_y,
1866                    }
1867                }
1868
1869                EventType::JoyAxisMotion => {
1870                    let event = raw.jaxis;
1871                    Event::JoyAxisMotion {
1872                        timestamp: event.timestamp,
1873                        which: event.which,
1874                        axis_idx: event.axis,
1875                        value: event.value,
1876                    }
1877                }
1878                EventType::JoyHatMotion => {
1879                    let event = raw.jhat;
1880                    Event::JoyHatMotion {
1881                        timestamp: event.timestamp,
1882                        which: event.which,
1883                        hat_idx: event.hat,
1884                        state: joystick::HatState::from_raw(event.value),
1885                    }
1886                }
1887                EventType::JoyButtonDown => {
1888                    let event = raw.jbutton;
1889                    Event::JoyButtonDown {
1890                        timestamp: event.timestamp,
1891                        which: event.which,
1892                        button_idx: event.button,
1893                    }
1894                }
1895                EventType::JoyButtonUp => {
1896                    let event = raw.jbutton;
1897                    Event::JoyButtonUp {
1898                        timestamp: event.timestamp,
1899                        which: event.which,
1900                        button_idx: event.button,
1901                    }
1902                }
1903                EventType::JoyDeviceAdded => {
1904                    let event = raw.jdevice;
1905                    Event::JoyDeviceAdded {
1906                        timestamp: event.timestamp,
1907                        which: event.which,
1908                    }
1909                }
1910                EventType::JoyDeviceRemoved => {
1911                    let event = raw.jdevice;
1912                    Event::JoyDeviceRemoved {
1913                        timestamp: event.timestamp,
1914                        which: event.which,
1915                    }
1916                }
1917
1918                EventType::ControllerAxisMotion => {
1919                    let event = raw.gaxis;
1920                    let axis = gamepad::Axis::from_ll(transmute(event.axis as i32)).unwrap();
1921
1922                    Event::ControllerAxisMotion {
1923                        timestamp: event.timestamp,
1924                        which: event.which,
1925                        axis,
1926                        value: event.value,
1927                    }
1928                }
1929                EventType::ControllerButtonDown => {
1930                    let event = raw.gbutton;
1931                    let button = gamepad::Button::from_ll(transmute(event.button as i32)).unwrap();
1932
1933                    Event::ControllerButtonDown {
1934                        timestamp: event.timestamp,
1935                        which: event.which,
1936                        button,
1937                    }
1938                }
1939                EventType::ControllerButtonUp => {
1940                    let event = raw.gbutton;
1941                    let button = gamepad::Button::from_ll(transmute(event.button as i32)).unwrap();
1942
1943                    Event::ControllerButtonUp {
1944                        timestamp: event.timestamp,
1945                        which: event.which,
1946                        button,
1947                    }
1948                }
1949                EventType::ControllerDeviceAdded => {
1950                    let event = raw.gdevice;
1951                    Event::ControllerDeviceAdded {
1952                        timestamp: event.timestamp,
1953                        which: event.which,
1954                    }
1955                }
1956                EventType::ControllerDeviceRemoved => {
1957                    let event = raw.gdevice;
1958                    Event::ControllerDeviceRemoved {
1959                        timestamp: event.timestamp,
1960                        which: event.which,
1961                    }
1962                }
1963                EventType::ControllerDeviceRemapped => {
1964                    let event = raw.gdevice;
1965                    Event::ControllerDeviceRemapped {
1966                        timestamp: event.timestamp,
1967                        which: event.which,
1968                    }
1969                }
1970                EventType::ControllerTouchpadDown => {
1971                    let event = raw.gtouchpad;
1972                    Event::ControllerTouchpadDown {
1973                        timestamp: event.timestamp,
1974                        which: event.which,
1975                        touchpad: event.touchpad,
1976                        finger: event.finger,
1977                        x: event.x,
1978                        y: event.y,
1979                        pressure: event.pressure,
1980                    }
1981                }
1982                EventType::ControllerTouchpadMotion => {
1983                    let event = raw.gtouchpad;
1984                    Event::ControllerTouchpadMotion {
1985                        timestamp: event.timestamp,
1986                        which: event.which,
1987                        touchpad: event.touchpad,
1988                        finger: event.finger,
1989                        x: event.x,
1990                        y: event.y,
1991                        pressure: event.pressure,
1992                    }
1993                }
1994                EventType::ControllerTouchpadUp => {
1995                    let event = raw.gtouchpad;
1996                    Event::ControllerTouchpadUp {
1997                        timestamp: event.timestamp,
1998                        which: event.which,
1999                        touchpad: event.touchpad,
2000                        finger: event.finger,
2001                        x: event.x,
2002                        y: event.y,
2003                        pressure: event.pressure,
2004                    }
2005                }
2006                #[cfg(feature = "hidapi")]
2007                EventType::ControllerSensorUpdated => {
2008                    let event = raw.gsensor;
2009                    Event::ControllerSensorUpdated {
2010                        timestamp: event.timestamp,
2011                        which: event.which,
2012                        sensor: crate::sensor::SensorType::from_ll(event.sensor),
2013                        data: event.data,
2014                    }
2015                }
2016
2017                EventType::FingerDown => {
2018                    let event = raw.tfinger;
2019                    Event::FingerDown {
2020                        timestamp: event.timestamp,
2021                        touch_id: event.touchID,
2022                        finger_id: event.fingerID,
2023                        x: event.x,
2024                        y: event.y,
2025                        dx: event.dx,
2026                        dy: event.dy,
2027                        pressure: event.pressure,
2028                    }
2029                }
2030                EventType::FingerUp => {
2031                    let event = raw.tfinger;
2032                    Event::FingerUp {
2033                        timestamp: event.timestamp,
2034                        touch_id: event.touchID,
2035                        finger_id: event.fingerID,
2036                        x: event.x,
2037                        y: event.y,
2038                        dx: event.dx,
2039                        dy: event.dy,
2040                        pressure: event.pressure,
2041                    }
2042                }
2043                EventType::FingerMotion => {
2044                    let event = raw.tfinger;
2045                    Event::FingerMotion {
2046                        timestamp: event.timestamp,
2047                        touch_id: event.touchID,
2048                        finger_id: event.fingerID,
2049                        x: event.x,
2050                        y: event.y,
2051                        dx: event.dx,
2052                        dy: event.dy,
2053                        pressure: event.pressure,
2054                    }
2055                }
2056
2057                EventType::ClipboardUpdate => {
2058                    let event = raw.common;
2059                    Event::ClipboardUpdate {
2060                        timestamp: event.timestamp,
2061                    }
2062                }
2063                EventType::DropFile => {
2064                    let event = raw.drop;
2065
2066                    let buf = CStr::from_ptr(event.data as *const _).to_bytes();
2067                    let text = String::from_utf8_lossy(buf).to_string();
2068
2069                    Event::DropFile {
2070                        timestamp: event.timestamp,
2071                        window_id: event.windowID,
2072                        filename: text,
2073                    }
2074                }
2075                EventType::DropText => {
2076                    let event = raw.drop;
2077
2078                    let buf = CStr::from_ptr(event.data as *const _).to_bytes();
2079                    let text = String::from_utf8_lossy(buf).to_string();
2080
2081                    Event::DropText {
2082                        timestamp: event.timestamp,
2083                        window_id: event.windowID,
2084                        filename: text,
2085                    }
2086                }
2087                EventType::DropBegin => {
2088                    let event = raw.drop;
2089
2090                    Event::DropBegin {
2091                        timestamp: event.timestamp,
2092                        window_id: event.windowID,
2093                    }
2094                }
2095                EventType::DropComplete => {
2096                    let event = raw.drop;
2097
2098                    Event::DropComplete {
2099                        timestamp: event.timestamp,
2100                        window_id: event.windowID,
2101                    }
2102                }
2103                EventType::AudioDeviceAdded => {
2104                    let event = raw.adevice;
2105                    Event::AudioDeviceAdded {
2106                        timestamp: event.timestamp,
2107                        which: event.which,
2108                        // false if an audio output device, true if an audio capture device
2109                        iscapture: event.recording,
2110                    }
2111                }
2112                EventType::AudioDeviceRemoved => {
2113                    let event = raw.adevice;
2114                    Event::AudioDeviceRemoved {
2115                        timestamp: event.timestamp,
2116                        which: event.which,
2117                        // false if an audio output device, true if an audio capture device
2118                        iscapture: event.recording,
2119                    }
2120                }
2121
2122                EventType::PenProximityIn => {
2123                    let event = raw.pproximity;
2124                    Event::PenProximityIn {
2125                        timestamp: event.timestamp,
2126                        which: event.which,
2127                        window: event.windowID,
2128                    }
2129                }
2130                EventType::PenProximityOut => {
2131                    let event = raw.pproximity;
2132                    Event::PenProximityOut {
2133                        timestamp: event.timestamp,
2134                        which: event.which,
2135                        window: event.windowID,
2136                    }
2137                }
2138                EventType::PenDown => {
2139                    let event = raw.ptouch;
2140                    Event::PenDown {
2141                        timestamp: event.timestamp,
2142                        which: event.which,
2143                        window: event.windowID,
2144                        x: event.x,
2145                        y: event.y,
2146                        eraser: event.eraser,
2147                    }
2148                }
2149                EventType::PenUp => {
2150                    let event = raw.ptouch;
2151                    Event::PenUp {
2152                        timestamp: event.timestamp,
2153                        which: event.which,
2154                        window: event.windowID,
2155                        x: event.x,
2156                        y: event.y,
2157                        eraser: event.eraser,
2158                    }
2159                }
2160                EventType::PenMotion => {
2161                    let event = raw.pmotion;
2162                    Event::PenMotion {
2163                        timestamp: event.timestamp,
2164                        which: event.which,
2165                        window: event.windowID,
2166                        x: event.x,
2167                        y: event.y,
2168                    }
2169                }
2170
2171                EventType::PenButtonUp => {
2172                    let event = raw.pbutton;
2173                    Event::PenButtonUp {
2174                        timestamp: event.timestamp,
2175                        which: event.which,
2176                        window: event.windowID,
2177                        x: event.x,
2178                        y: event.y,
2179                        button: event.button,
2180                    }
2181                }
2182                EventType::PenButtonDown => {
2183                    let event = raw.pbutton;
2184                    Event::PenButtonDown {
2185                        timestamp: event.timestamp,
2186                        which: event.which,
2187                        window: event.windowID,
2188                        x: event.x,
2189                        y: event.y,
2190                        button: event.button,
2191                    }
2192                }
2193                EventType::PenAxis => {
2194                    let event = raw.paxis;
2195                    Event::PenAxis {
2196                        timestamp: event.timestamp,
2197                        which: event.which,
2198                        window: event.windowID,
2199                        x: event.x,
2200                        y: event.y,
2201                        axis: PenAxis::from_ll(event.axis),
2202                        value: event.value,
2203                    }
2204                }
2205
2206                EventType::RenderTargetsReset => Event::RenderTargetsReset {
2207                    timestamp: raw.common.timestamp,
2208                },
2209                EventType::RenderDeviceReset => Event::RenderDeviceReset {
2210                    timestamp: raw.common.timestamp,
2211                },
2212
2213                EventType::First => panic!("Unused event, EventType::First, was encountered"),
2214                EventType::Last => panic!("Unusable event, EventType::Last, was encountered"),
2215
2216                // If we have no other match and the event type is >= 32768
2217                // this is a user event
2218                EventType::User => {
2219                    if raw_type < 32_768 {
2220                        // The type is unknown to us.
2221                        // It's a newer sdl3 type.
2222                        let event = raw.common;
2223
2224                        Event::Unknown {
2225                            timestamp: event.timestamp,
2226                            type_: event.r#type,
2227                        }
2228                    } else {
2229                        let event = raw.user;
2230
2231                        Event::User {
2232                            timestamp: event.timestamp,
2233                            window_id: event.windowID,
2234                            type_: raw_type,
2235                            code: event.code,
2236                            data1: event.data1,
2237                            data2: event.data2,
2238                        }
2239                    }
2240                }
2241            }
2242        } // close unsafe & match
2243    }
2244
2245    pub fn is_user_event(&self) -> bool {
2246        matches!(*self, Event::User { .. })
2247    }
2248
2249    pub fn as_user_event_type<T: ::std::any::Any>(&self) -> Option<T> {
2250        use std::any::TypeId;
2251        let type_id = TypeId::of::<Box<T>>();
2252
2253        let (event_id, event_box_ptr) = match *self {
2254            Event::User { type_, data1, .. } => (type_, data1),
2255            _ => return None,
2256        };
2257
2258        let cet = CUSTOM_EVENT_TYPES.lock().unwrap();
2259
2260        let event_type_id = match cet.sdl_id_to_type_id.get(&event_id) {
2261            Some(id) => id,
2262            None => {
2263                panic!("internal error; could not find typeid")
2264            }
2265        };
2266
2267        if &type_id != event_type_id {
2268            return None;
2269        }
2270
2271        let event_box: Box<T> = unsafe { Box::from_raw(event_box_ptr as *mut T) };
2272
2273        Some(*event_box)
2274    }
2275
2276    /// Returns `true` if they are the same "kind" of events.
2277    ///
2278    /// # Example:
2279    ///
2280    /// ```
2281    /// use sdl3::event::Event;
2282    ///
2283    /// let ev1 = Event::JoyButtonDown {
2284    ///     timestamp: 0,
2285    ///     which: 0,
2286    ///     button_idx: 0,
2287    /// };
2288    /// let ev2 = Event::JoyButtonDown {
2289    ///     timestamp: 1,
2290    ///     which: 1,
2291    ///     button_idx: 1,
2292    /// };
2293    ///
2294    /// assert!(ev1 != ev2); // The events aren't equal (they contain different values).
2295    /// assert!(ev1.is_same_kind_as(&ev2)); // But they are of the same kind!
2296    /// ```
2297    pub fn is_same_kind_as(&self, other: &Event) -> bool {
2298        match (self, other) {
2299            (Self::Quit { .. }, Self::Quit { .. })
2300            | (Self::AppTerminating { .. }, Self::AppTerminating { .. })
2301            | (Self::AppLowMemory { .. }, Self::AppLowMemory { .. })
2302            | (Self::AppWillEnterBackground { .. }, Self::AppWillEnterBackground { .. })
2303            | (Self::AppDidEnterBackground { .. }, Self::AppDidEnterBackground { .. })
2304            | (Self::AppWillEnterForeground { .. }, Self::AppWillEnterForeground { .. })
2305            | (Self::AppDidEnterForeground { .. }, Self::AppDidEnterForeground { .. })
2306            | (Self::Display { .. }, Self::Display { .. })
2307            | (Self::Window { .. }, Self::Window { .. })
2308            | (Self::KeyDown { .. }, Self::KeyDown { .. })
2309            | (Self::KeyUp { .. }, Self::KeyUp { .. })
2310            | (Self::TextEditing { .. }, Self::TextEditing { .. })
2311            | (Self::TextInput { .. }, Self::TextInput { .. })
2312            | (Self::MouseMotion { .. }, Self::MouseMotion { .. })
2313            | (Self::MouseButtonDown { .. }, Self::MouseButtonDown { .. })
2314            | (Self::MouseButtonUp { .. }, Self::MouseButtonUp { .. })
2315            | (Self::MouseWheel { .. }, Self::MouseWheel { .. })
2316            | (Self::JoyAxisMotion { .. }, Self::JoyAxisMotion { .. })
2317            | (Self::JoyHatMotion { .. }, Self::JoyHatMotion { .. })
2318            | (Self::JoyButtonDown { .. }, Self::JoyButtonDown { .. })
2319            | (Self::JoyButtonUp { .. }, Self::JoyButtonUp { .. })
2320            | (Self::JoyDeviceAdded { .. }, Self::JoyDeviceAdded { .. })
2321            | (Self::JoyDeviceRemoved { .. }, Self::JoyDeviceRemoved { .. })
2322            | (Self::ControllerAxisMotion { .. }, Self::ControllerAxisMotion { .. })
2323            | (Self::ControllerButtonDown { .. }, Self::ControllerButtonDown { .. })
2324            | (Self::ControllerButtonUp { .. }, Self::ControllerButtonUp { .. })
2325            | (Self::ControllerDeviceAdded { .. }, Self::ControllerDeviceAdded { .. })
2326            | (Self::ControllerDeviceRemoved { .. }, Self::ControllerDeviceRemoved { .. })
2327            | (Self::ControllerDeviceRemapped { .. }, Self::ControllerDeviceRemapped { .. })
2328            | (Self::FingerDown { .. }, Self::FingerDown { .. })
2329            | (Self::FingerUp { .. }, Self::FingerUp { .. })
2330            | (Self::FingerMotion { .. }, Self::FingerMotion { .. })
2331            | (Self::DollarRecord { .. }, Self::DollarRecord { .. })
2332            | (Self::MultiGesture { .. }, Self::MultiGesture { .. })
2333            | (Self::ClipboardUpdate { .. }, Self::ClipboardUpdate { .. })
2334            | (Self::DropFile { .. }, Self::DropFile { .. })
2335            | (Self::DropText { .. }, Self::DropText { .. })
2336            | (Self::DropBegin { .. }, Self::DropBegin { .. })
2337            | (Self::DropComplete { .. }, Self::DropComplete { .. })
2338            | (Self::AudioDeviceAdded { .. }, Self::AudioDeviceAdded { .. })
2339            | (Self::AudioDeviceRemoved { .. }, Self::AudioDeviceRemoved { .. })
2340            | (Self::RenderTargetsReset { .. }, Self::RenderTargetsReset { .. })
2341            | (Self::RenderDeviceReset { .. }, Self::RenderDeviceReset { .. })
2342            | (Self::User { .. }, Self::User { .. })
2343            | (Self::Unknown { .. }, Self::Unknown { .. }) => true,
2344            #[cfg(feature = "hidapi")]
2345            (Self::ControllerSensorUpdated { .. }, Self::ControllerSensorUpdated { .. }) => true,
2346            _ => false,
2347        }
2348    }
2349
2350    /// Returns the `timestamp` field of the event.
2351    ///
2352    /// # Example
2353    ///
2354    /// ```
2355    /// use sdl3::event::Event;
2356    ///
2357    /// let ev = Event::JoyButtonDown {
2358    ///     timestamp: 12,
2359    ///     which: 0,
2360    ///     button_idx: 0,
2361    /// };
2362    /// assert!(ev.get_timestamp() == 12);
2363    /// ```
2364    pub fn get_timestamp(&self) -> u64 {
2365        *match self {
2366            Self::Quit { timestamp, .. } => timestamp,
2367            Self::Window { timestamp, .. } => timestamp,
2368            Self::AppTerminating { timestamp, .. } => timestamp,
2369            Self::AppLowMemory { timestamp, .. } => timestamp,
2370            Self::AppWillEnterBackground { timestamp, .. } => timestamp,
2371            Self::AppDidEnterBackground { timestamp, .. } => timestamp,
2372            Self::AppWillEnterForeground { timestamp, .. } => timestamp,
2373            Self::AppDidEnterForeground { timestamp, .. } => timestamp,
2374            Self::Display { timestamp, .. } => timestamp,
2375            Self::KeyDown { timestamp, .. } => timestamp,
2376            Self::KeyUp { timestamp, .. } => timestamp,
2377            Self::TextEditing { timestamp, .. } => timestamp,
2378            Self::TextInput { timestamp, .. } => timestamp,
2379            Self::MouseMotion { timestamp, .. } => timestamp,
2380            Self::MouseButtonDown { timestamp, .. } => timestamp,
2381            Self::MouseButtonUp { timestamp, .. } => timestamp,
2382            Self::MouseWheel { timestamp, .. } => timestamp,
2383            Self::JoyAxisMotion { timestamp, .. } => timestamp,
2384            Self::JoyHatMotion { timestamp, .. } => timestamp,
2385            Self::JoyButtonDown { timestamp, .. } => timestamp,
2386            Self::JoyButtonUp { timestamp, .. } => timestamp,
2387            Self::JoyDeviceAdded { timestamp, .. } => timestamp,
2388            Self::JoyDeviceRemoved { timestamp, .. } => timestamp,
2389            Self::ControllerAxisMotion { timestamp, .. } => timestamp,
2390            Self::ControllerButtonDown { timestamp, .. } => timestamp,
2391            Self::ControllerButtonUp { timestamp, .. } => timestamp,
2392            Self::ControllerDeviceAdded { timestamp, .. } => timestamp,
2393            Self::ControllerDeviceRemoved { timestamp, .. } => timestamp,
2394            Self::ControllerDeviceRemapped { timestamp, .. } => timestamp,
2395            Self::ControllerTouchpadDown { timestamp, .. } => timestamp,
2396            Self::ControllerTouchpadMotion { timestamp, .. } => timestamp,
2397            Self::ControllerTouchpadUp { timestamp, .. } => timestamp,
2398            #[cfg(feature = "hidapi")]
2399            Self::ControllerSensorUpdated { timestamp, .. } => timestamp,
2400            Self::FingerDown { timestamp, .. } => timestamp,
2401            Self::FingerUp { timestamp, .. } => timestamp,
2402            Self::FingerMotion { timestamp, .. } => timestamp,
2403            Self::DollarRecord { timestamp, .. } => timestamp,
2404            Self::MultiGesture { timestamp, .. } => timestamp,
2405            Self::ClipboardUpdate { timestamp, .. } => timestamp,
2406            Self::DropFile { timestamp, .. } => timestamp,
2407            Self::DropText { timestamp, .. } => timestamp,
2408            Self::DropBegin { timestamp, .. } => timestamp,
2409            Self::DropComplete { timestamp, .. } => timestamp,
2410            Self::AudioDeviceAdded { timestamp, .. } => timestamp,
2411            Self::AudioDeviceRemoved { timestamp, .. } => timestamp,
2412            Self::PenProximityIn { timestamp, .. } => timestamp,
2413            Self::PenProximityOut { timestamp, .. } => timestamp,
2414            Self::PenDown { timestamp, .. } => timestamp,
2415            Self::PenUp { timestamp, .. } => timestamp,
2416            Self::PenMotion { timestamp, .. } => timestamp,
2417            Self::PenButtonUp { timestamp, .. } => timestamp,
2418            Self::PenButtonDown { timestamp, .. } => timestamp,
2419            Self::PenAxis { timestamp, .. } => timestamp,
2420            Self::RenderTargetsReset { timestamp, .. } => timestamp,
2421            Self::RenderDeviceReset { timestamp, .. } => timestamp,
2422            Self::User { timestamp, .. } => timestamp,
2423            Self::Unknown { timestamp, .. } => timestamp,
2424        }
2425    }
2426
2427    /// Returns the `window_id` field of the event if it's present (not all events have it!).
2428    ///
2429    /// # Example
2430    ///
2431    /// ```
2432    /// use sdl3::event::Event;
2433    ///
2434    /// let ev = Event::JoyButtonDown {
2435    ///     timestamp: 0,
2436    ///     which: 0,
2437    ///     button_idx: 0,
2438    /// };
2439    /// assert!(ev.get_window_id() == None);
2440    ///
2441    /// let another_ev = Event::DropBegin {
2442    ///     timestamp: 0,
2443    ///     window_id: 3,
2444    /// };
2445    /// assert!(another_ev.get_window_id() == Some(3));
2446    /// ```
2447    pub fn get_window_id(&self) -> Option<u32> {
2448        match self {
2449            Self::Window { window_id, .. } => Some(*window_id),
2450            Self::KeyDown { window_id, .. } => Some(*window_id),
2451            Self::KeyUp { window_id, .. } => Some(*window_id),
2452            Self::TextEditing { window_id, .. } => Some(*window_id),
2453            Self::TextInput { window_id, .. } => Some(*window_id),
2454            Self::MouseMotion { window_id, .. } => Some(*window_id),
2455            Self::MouseButtonDown { window_id, .. } => Some(*window_id),
2456            Self::MouseButtonUp { window_id, .. } => Some(*window_id),
2457            Self::MouseWheel { window_id, .. } => Some(*window_id),
2458            Self::DropFile { window_id, .. } => Some(*window_id),
2459            Self::DropText { window_id, .. } => Some(*window_id),
2460            Self::DropBegin { window_id, .. } => Some(*window_id),
2461            Self::DropComplete { window_id, .. } => Some(*window_id),
2462            Self::User { window_id, .. } => Some(*window_id),
2463            _ => None,
2464        }
2465    }
2466
2467    /// Returns `true` if this is a window event.
2468    ///
2469    /// # Example
2470    ///
2471    /// ```
2472    /// use sdl3::event::Event;
2473    ///
2474    /// let ev = Event::Quit {
2475    ///     timestamp: 0,
2476    /// };
2477    /// assert!(ev.is_window());
2478    ///
2479    /// let ev = Event::AppLowMemory {
2480    ///     timestamp: 0,
2481    /// };
2482    /// assert!(ev.is_window());
2483    ///
2484    /// let another_ev = Event::TextInput {
2485    ///     timestamp: 0,
2486    ///     window_id: 0,
2487    ///     text: String::new(),
2488    /// };
2489    /// assert!(another_ev.is_window() == false); // Not a window event!
2490    /// ```
2491    pub fn is_window(&self) -> bool {
2492        matches!(
2493            self,
2494            Self::Quit { .. }
2495                | Self::AppTerminating { .. }
2496                | Self::AppLowMemory { .. }
2497                | Self::AppWillEnterBackground { .. }
2498                | Self::AppDidEnterBackground { .. }
2499                | Self::AppWillEnterForeground { .. }
2500                | Self::AppDidEnterForeground { .. }
2501                | Self::Window { .. }
2502        )
2503    }
2504
2505    /// Returns `true` if this is a keyboard event.
2506    ///
2507    /// # Example
2508    ///
2509    /// ```
2510    /// use sdl3::event::Event;
2511    /// use sdl3::keyboard::Mod;
2512    ///
2513    /// let ev = Event::KeyDown {
2514    ///     timestamp: 0,
2515    ///     window_id: 0,
2516    ///     keycode: None,
2517    ///     scancode: None,
2518    ///     keymod: Mod::empty(),
2519    ///     repeat: false,
2520    ///     which: 0,
2521    ///     raw: 0,
2522    /// };
2523    /// assert!(ev.is_keyboard());
2524    ///
2525    /// let another_ev = Event::Quit {
2526    ///     timestamp: 0,
2527    /// };
2528    /// assert!(another_ev.is_keyboard() == false); // Not a keyboard event!
2529    /// ```
2530    pub fn is_keyboard(&self) -> bool {
2531        matches!(self, Self::KeyDown { .. } | Self::KeyUp { .. })
2532    }
2533
2534    /// Returns `true` if this is a text event.
2535    ///
2536    /// # Example
2537    ///
2538    /// ```
2539    /// use sdl3::event::Event;
2540    ///
2541    /// let ev = Event::TextInput {
2542    ///     timestamp: 0,
2543    ///     window_id: 0,
2544    ///     text: String::new(),
2545    /// };
2546    /// assert!(ev.is_text());
2547    ///
2548    /// let another_ev = Event::Quit {
2549    ///     timestamp: 0,
2550    /// };
2551    /// assert!(another_ev.is_text() == false); // Not a text event!
2552    /// ```
2553    pub fn is_text(&self) -> bool {
2554        matches!(self, Self::TextEditing { .. } | Self::TextInput { .. })
2555    }
2556
2557    /// Returns `true` if this is a mouse event.
2558    ///
2559    /// # Example
2560    ///
2561    /// ```
2562    /// use sdl3::event::Event;
2563    /// use sdl3::mouse::MouseWheelDirection;
2564    ///
2565    /// let ev = Event::MouseWheel {
2566    ///     timestamp: 0,
2567    ///     window_id: 0,
2568    ///     which: 0,
2569    ///     mouse_x: 0.0,
2570    ///     mouse_y: 0.0,
2571    ///     x: 0.0,
2572    ///     y: 0.0,
2573    ///     direction: MouseWheelDirection::Normal,
2574    /// };
2575    /// assert!(ev.is_mouse());
2576    ///
2577    /// let another_ev = Event::Quit {
2578    ///     timestamp: 0,
2579    /// };
2580    /// assert!(another_ev.is_mouse() == false); // Not a mouse event!
2581    /// ```
2582    pub fn is_mouse(&self) -> bool {
2583        matches!(
2584            self,
2585            Self::MouseMotion { .. }
2586                | Self::MouseButtonDown { .. }
2587                | Self::MouseButtonUp { .. }
2588                | Self::MouseWheel { .. }
2589        )
2590    }
2591
2592    /// Returns `true` if this is a controller event.
2593    ///
2594    /// # Example
2595    ///
2596    /// ```
2597    /// use sdl3::event::Event;
2598    ///
2599    /// let ev = Event::ControllerDeviceAdded {
2600    ///     timestamp: 0,
2601    ///     which: 0,
2602    /// };
2603    /// assert!(ev.is_controller());
2604    ///
2605    /// let another_ev = Event::Quit {
2606    ///     timestamp: 0,
2607    /// };
2608    /// assert!(another_ev.is_controller() == false); // Not a controller event!
2609    /// ```
2610    pub fn is_controller(&self) -> bool {
2611        matches!(
2612            self,
2613            Self::ControllerAxisMotion { .. }
2614                | Self::ControllerButtonDown { .. }
2615                | Self::ControllerButtonUp { .. }
2616                | Self::ControllerDeviceAdded { .. }
2617                | Self::ControllerDeviceRemoved { .. }
2618                | Self::ControllerDeviceRemapped { .. }
2619        )
2620    }
2621
2622    /// Returns `true` if this is a joy event.
2623    ///
2624    /// # Example
2625    ///
2626    /// ```
2627    /// use sdl3::event::Event;
2628    ///
2629    /// let ev = Event::JoyButtonUp {
2630    ///     timestamp: 0,
2631    ///     which: 0,
2632    ///     button_idx: 0,
2633    /// };
2634    /// assert!(ev.is_joy());
2635    ///
2636    /// let another_ev = Event::Quit {
2637    ///     timestamp: 0,
2638    /// };
2639    /// assert!(another_ev.is_joy() == false); // Not a joy event!
2640    /// ```
2641    pub fn is_joy(&self) -> bool {
2642        matches!(
2643            self,
2644            Self::JoyAxisMotion { .. }
2645                | Self::JoyHatMotion { .. }
2646                | Self::JoyButtonDown { .. }
2647                | Self::JoyButtonUp { .. }
2648                | Self::JoyDeviceAdded { .. }
2649                | Self::JoyDeviceRemoved { .. }
2650        )
2651    }
2652
2653    /// Returns `true` if this is a finger event.
2654    ///
2655    /// # Example
2656    ///
2657    /// ```
2658    /// use sdl3::event::Event;
2659    ///
2660    /// let ev = Event::FingerMotion {
2661    ///     timestamp: 0,
2662    ///     touch_id: 0,
2663    ///     finger_id: 0,
2664    ///     x: 0.,
2665    ///     y: 0.,
2666    ///     dx: 0.,
2667    ///     dy: 0.,
2668    ///     pressure: 0.,
2669    /// };
2670    /// assert!(ev.is_finger());
2671    ///
2672    /// let another_ev = Event::Quit {
2673    ///     timestamp: 0,
2674    /// };
2675    /// assert!(another_ev.is_finger() == false); // Not a finger event!
2676    /// ```
2677    pub fn is_finger(&self) -> bool {
2678        matches!(
2679            self,
2680            Self::FingerDown { .. } | Self::FingerUp { .. } | Self::FingerMotion { .. }
2681        )
2682    }
2683
2684    /// Returns `true` if this is a pen event.
2685    ///
2686    /// # Example
2687    ///
2688    /// ```
2689    /// use sdl3::event::Event;
2690    ///
2691    /// let ev = Event::PenDown {
2692    ///     timestamp: 0,
2693    ///     which: 0,
2694    ///     window: 0,
2695    ///     x: 0.,
2696    ///     y: 0.,
2697    ///     eraser: false,
2698    /// };
2699    /// assert!(ev.is_pen());
2700    ///
2701    /// let another_ev = Event::Quit {
2702    ///     timestamp: 0,
2703    /// };
2704    /// assert!(another_ev.is_pen() == false); // Not a pen event!
2705    /// ```
2706    pub fn is_pen(&self) -> bool {
2707        matches!(
2708            self,
2709            Self::PenProximityIn { .. }
2710                | Self::PenProximityOut { .. }
2711                | Self::PenDown { .. }
2712                | Self::PenUp { .. }
2713                | Self::PenMotion { .. }
2714                | Self::PenButtonUp { .. }
2715                | Self::PenButtonDown { .. }
2716                | Self::PenAxis { .. }
2717        )
2718    }
2719
2720    /// Returns `true` if this is a drop event.
2721    ///
2722    /// # Example
2723    ///
2724    /// ```
2725    /// use sdl3::event::Event;
2726    ///
2727    /// let ev = Event::DropBegin {
2728    ///     timestamp: 0,
2729    ///     window_id: 3,
2730    /// };
2731    /// assert!(ev.is_drop());
2732    ///
2733    /// let another_ev = Event::Quit {
2734    ///     timestamp: 0,
2735    /// };
2736    /// assert!(another_ev.is_drop() == false); // Not a drop event!
2737    /// ```
2738    pub fn is_drop(&self) -> bool {
2739        matches!(
2740            self,
2741            Self::DropFile { .. }
2742                | Self::DropText { .. }
2743                | Self::DropBegin { .. }
2744                | Self::DropComplete { .. }
2745        )
2746    }
2747
2748    /// Returns `true` if this is an audio event.
2749    ///
2750    /// # Example
2751    ///
2752    /// ```
2753    /// use sdl3::event::Event;
2754    ///
2755    /// let ev = Event::AudioDeviceAdded {
2756    ///     timestamp: 0,
2757    ///     which: 3,
2758    ///     iscapture: false,
2759    /// };
2760    /// assert!(ev.is_audio());
2761    ///
2762    /// let another_ev = Event::Quit {
2763    ///     timestamp: 0,
2764    /// };
2765    /// assert!(another_ev.is_audio() == false); // Not an audio event!
2766    /// ```
2767    pub fn is_audio(&self) -> bool {
2768        matches!(
2769            self,
2770            Self::AudioDeviceAdded { .. } | Self::AudioDeviceRemoved { .. }
2771        )
2772    }
2773
2774    /// Returns `true` if this is a render event.
2775    ///
2776    /// # Example
2777    ///
2778    /// ```
2779    /// use sdl3::event::Event;
2780    ///
2781    /// let ev = Event::RenderTargetsReset {
2782    ///     timestamp: 0,
2783    /// };
2784    /// assert!(ev.is_render());
2785    ///
2786    /// let another_ev = Event::Quit {
2787    ///     timestamp: 0,
2788    /// };
2789    /// assert!(another_ev.is_render() == false); // Not a render event!
2790    /// ```
2791    pub fn is_render(&self) -> bool {
2792        matches!(
2793            self,
2794            Self::RenderTargetsReset { .. } | Self::RenderDeviceReset { .. }
2795        )
2796    }
2797
2798    /// Returns `true` if this is a user event.
2799    ///
2800    /// # Example
2801    ///
2802    /// ```
2803    /// use sdl3::event::Event;
2804    ///
2805    /// let ev = Event::User {
2806    ///     timestamp: 0,
2807    ///     window_id: 0,
2808    ///     type_: 0,
2809    ///     code: 0,
2810    ///     data1: ::std::ptr::null_mut(),
2811    ///     data2: ::std::ptr::null_mut(),
2812    /// };
2813    /// assert!(ev.is_user());
2814    ///
2815    /// let another_ev = Event::Quit {
2816    ///     timestamp: 0,
2817    /// };
2818    /// assert!(another_ev.is_user() == false); // Not a user event!
2819    /// ```
2820    pub fn is_user(&self) -> bool {
2821        matches!(self, Self::User { .. })
2822    }
2823
2824    /// Returns `true` if this is an unknown event.
2825    ///
2826    /// # Example
2827    ///
2828    /// ```
2829    /// use sdl3::event::Event;
2830    ///
2831    /// let ev = Event::Unknown {
2832    ///     timestamp: 0,
2833    ///     type_: 0,
2834    /// };
2835    /// assert!(ev.is_unknown());
2836    ///
2837    /// let another_ev = Event::Quit {
2838    ///     timestamp: 0,
2839    /// };
2840    /// assert!(another_ev.is_unknown() == false); // Not an unknown event!
2841    /// ```
2842    pub fn is_unknown(&self) -> bool {
2843        matches!(self, Self::Unknown { .. })
2844    }
2845
2846    // Returns `None` if the event cannot be converted to its raw form (should not happen).
2847    pub fn get_converted_coords<T: crate::render::RenderTarget>(
2848        &self,
2849        canvas: &crate::render::Canvas<T>,
2850    ) -> Option<Event> {
2851        let mut raw = self.to_ll()?;
2852        unsafe {
2853            sys::render::SDL_ConvertEventToRenderCoordinates(canvas.raw(), &mut raw);
2854        }
2855        Some(Self::from_ll(raw))
2856    }
2857
2858    // Returns `true` on success and false if the event cannot be converted to its raw form (should not happen)
2859    pub fn convert_coords<T: crate::render::RenderTarget>(
2860        &mut self,
2861        canvas: &crate::render::Canvas<T>,
2862    ) -> bool {
2863        if let Some(mut raw) = self.to_ll() {
2864            unsafe {
2865                sys::render::SDL_ConvertEventToRenderCoordinates(canvas.raw(), &mut raw);
2866            }
2867            *self = Self::from_ll(raw);
2868            true
2869        } else {
2870            false
2871        }
2872    }
2873}
2874
2875unsafe fn poll_event() -> Option<Event> {
2876    let mut raw = mem::MaybeUninit::uninit();
2877    let has_pending = sys::events::SDL_PollEvent(raw.as_mut_ptr());
2878
2879    if has_pending {
2880        Some(Event::from_ll(raw.assume_init()))
2881    } else {
2882        None
2883    }
2884}
2885
2886unsafe fn wait_event() -> Event {
2887    let mut raw = mem::MaybeUninit::uninit();
2888    let success = sys::events::SDL_WaitEvent(raw.as_mut_ptr());
2889
2890    if success {
2891        Event::from_ll(raw.assume_init())
2892    } else {
2893        panic!("{}", get_error())
2894    }
2895}
2896
2897unsafe fn wait_event_timeout(timeout: u32) -> Option<Event> {
2898    let mut raw = mem::MaybeUninit::uninit();
2899    let success = sys::events::SDL_WaitEventTimeout(raw.as_mut_ptr(), timeout as c_int);
2900
2901    if success {
2902        Some(Event::from_ll(raw.assume_init()))
2903    } else {
2904        None
2905    }
2906}
2907
2908impl crate::EventPump {
2909    /// Polls for currently pending events.
2910    ///
2911    /// If no events are pending, `None` is returned.
2912    pub fn poll_event(&mut self) -> Option<Event> {
2913        unsafe { poll_event() }
2914    }
2915
2916    /// Returns a polling iterator that calls `poll_event()`.
2917    /// The iterator will terminate once there are no more pending events.
2918    ///
2919    /// # Example
2920    /// ```no_run
2921    /// let sdl_context = sdl3::init().unwrap();
2922    /// let mut event_pump = sdl_context.event_pump().unwrap();
2923    ///
2924    /// for event in event_pump.poll_iter() {
2925    ///     use sdl3::event::Event;
2926    ///     match event {
2927    ///         Event::KeyDown {..} => { /*...*/ }
2928    ///         _ => ()
2929    ///     }
2930    /// }
2931    /// ```
2932    pub fn poll_iter(&mut self) -> EventPollIterator {
2933        EventPollIterator {
2934            _marker: PhantomData,
2935        }
2936    }
2937
2938    /// Pumps the event loop, gathering events from the input devices.
2939    #[doc(alias = "SDL_PumpEvents")]
2940    pub fn pump_events(&mut self) {
2941        unsafe {
2942            sys::events::SDL_PumpEvents();
2943        };
2944    }
2945
2946    /// Waits indefinitely for the next available event.
2947    pub fn wait_event(&mut self) -> Event {
2948        unsafe { wait_event() }
2949    }
2950
2951    /// Waits until the specified timeout (in milliseconds) for the next available event.
2952    pub fn wait_event_timeout(&mut self, timeout: u32) -> Option<Event> {
2953        unsafe { wait_event_timeout(timeout) }
2954    }
2955
2956    /// Returns a waiting iterator that calls `wait_event()`.
2957    ///
2958    /// Note: The iterator will never terminate.
2959    pub fn wait_iter(&mut self) -> EventWaitIterator {
2960        EventWaitIterator {
2961            _marker: PhantomData,
2962        }
2963    }
2964
2965    /// Returns a waiting iterator that calls `wait_event_timeout()`.
2966    ///
2967    /// Note: The iterator will never terminate, unless waiting for an event
2968    /// exceeds the specified timeout.
2969    pub fn wait_timeout_iter(&mut self, timeout: u32) -> EventWaitTimeoutIterator {
2970        EventWaitTimeoutIterator {
2971            _marker: PhantomData,
2972            timeout,
2973        }
2974    }
2975
2976    #[inline]
2977    pub fn keyboard_state(&self) -> crate::keyboard::KeyboardState {
2978        crate::keyboard::KeyboardState::new(self)
2979    }
2980
2981    #[inline]
2982    pub fn mouse_state(&self) -> crate::mouse::MouseState {
2983        crate::mouse::MouseState::new(self)
2984    }
2985
2986    #[inline]
2987    pub fn relative_mouse_state(&self) -> crate::mouse::RelativeMouseState {
2988        crate::mouse::RelativeMouseState::new(self)
2989    }
2990}
2991
2992/// An iterator that calls `EventPump::poll_event()`.
2993#[must_use = "iterators are lazy and do nothing unless consumed"]
2994pub struct EventPollIterator<'a> {
2995    _marker: PhantomData<&'a ()>,
2996}
2997
2998impl Iterator for EventPollIterator<'_> {
2999    type Item = Event;
3000
3001    fn next(&mut self) -> Option<Event> {
3002        unsafe { poll_event() }
3003    }
3004}
3005
3006/// An iterator that calls `EventPump::wait_event()`.
3007#[must_use = "iterators are lazy and do nothing unless consumed"]
3008pub struct EventWaitIterator<'a> {
3009    _marker: PhantomData<&'a ()>,
3010}
3011
3012impl Iterator for EventWaitIterator<'_> {
3013    type Item = Event;
3014    fn next(&mut self) -> Option<Event> {
3015        unsafe { Some(wait_event()) }
3016    }
3017}
3018
3019/// An iterator that calls `EventPump::wait_event_timeout()`.
3020#[must_use = "iterators are lazy and do nothing unless consumed"]
3021pub struct EventWaitTimeoutIterator<'a> {
3022    _marker: PhantomData<&'a ()>,
3023    timeout: u32,
3024}
3025
3026impl Iterator for EventWaitTimeoutIterator<'_> {
3027    type Item = Event;
3028    fn next(&mut self) -> Option<Event> {
3029        unsafe { wait_event_timeout(self.timeout) }
3030    }
3031}
3032
3033/// A sendible type that can push events to the event queue.
3034pub struct EventSender {
3035    _priv: (),
3036}
3037
3038impl EventSender {
3039    /// Pushes an event to the event queue.
3040    #[doc(alias = "SDL_PushEvent")]
3041    pub fn push_event(&self, event: Event) -> Result<(), Error> {
3042        match event.to_ll() {
3043            Some(mut raw_event) => {
3044                let ok = unsafe { sys::events::SDL_PushEvent(&mut raw_event) };
3045                if ok {
3046                    Ok(())
3047                } else {
3048                    Err(get_error())
3049                }
3050            }
3051            None => Err(Error(
3052                "Cannot push unsupported event type to the queue".to_owned(),
3053            )),
3054        }
3055    }
3056
3057    /// Push a custom event
3058    ///
3059    /// If the event type ``T`` was not registered using
3060    /// [EventSubsystem::register_custom_event]
3061    /// (../struct.EventSubsystem.html#method.register_custom_event),
3062    /// this method will panic.
3063    ///
3064    /// # Example: pushing and receiving a custom event
3065    /// ```
3066    /// struct SomeCustomEvent {
3067    ///     a: i32
3068    /// }
3069    ///
3070    /// let sdl = sdl3::init().unwrap();
3071    /// let ev = sdl.event().unwrap();
3072    /// let mut ep = sdl.event_pump().unwrap();
3073    ///
3074    /// ev.register_custom_event::<SomeCustomEvent>().unwrap();
3075    ///
3076    /// let event = SomeCustomEvent { a: 42 };
3077    ///
3078    /// ev.push_custom_event(event);
3079    ///
3080    /// let received = ep.poll_event().unwrap(); // or within a for event in ep.poll_iter()
3081    /// if received.is_user_event() {
3082    ///     let e2 = received.as_user_event_type::<SomeCustomEvent>().unwrap();
3083    ///     assert_eq!(e2.a, 42);
3084    /// }
3085    /// ```
3086    pub fn push_custom_event<T: ::std::any::Any>(&self, event: T) -> Result<(), Error> {
3087        use std::any::TypeId;
3088        let cet = CUSTOM_EVENT_TYPES.lock().unwrap();
3089        let type_id = TypeId::of::<Box<T>>();
3090
3091        let user_event_id = *match cet.type_id_to_sdl_id.get(&type_id) {
3092            Some(id) => id,
3093            None => {
3094                return Err(Error(
3095                    "Type is not registered as a custom event type!".to_owned(),
3096                ));
3097            }
3098        };
3099
3100        let event_box = Box::new(event);
3101        let event = Event::User {
3102            timestamp: 0,
3103            window_id: 0,
3104            type_: user_event_id,
3105            code: 0,
3106            data1: Box::into_raw(event_box) as *mut c_void,
3107            data2: ::std::ptr::null_mut(),
3108        };
3109        drop(cet);
3110
3111        self.push_event(event)?;
3112
3113        Ok(())
3114    }
3115}
3116
3117/// A callback trait for [`EventSubsystem::add_event_watch`].
3118pub trait EventWatchCallback {
3119    fn callback(&mut self, event: Event);
3120}
3121
3122/// An handler for the event watch callback.
3123/// One must bind this struct in a variable as long as you want to keep the callback active.
3124/// For further information, see [`EventSubsystem::add_event_watch`].
3125pub struct EventWatch<'a, CB: EventWatchCallback + 'a> {
3126    activated: bool,
3127    callback: Box<CB>,
3128    _phantom: PhantomData<&'a CB>,
3129}
3130
3131impl<'a, CB: EventWatchCallback + 'a> EventWatch<'a, CB> {
3132    fn add(callback: CB) -> EventWatch<'a, CB> {
3133        let f = Box::new(callback);
3134        let mut watch = EventWatch {
3135            activated: false,
3136            callback: f,
3137            _phantom: PhantomData,
3138        };
3139        watch.activate();
3140        watch
3141    }
3142
3143    /// Activates the event watch.
3144    /// Does nothing if it is already activated.
3145    pub fn activate(&mut self) {
3146        if !self.activated {
3147            self.activated = true;
3148            unsafe { sys::events::SDL_AddEventWatch(self.filter(), self.callback()) };
3149        }
3150    }
3151
3152    /// Deactivates the event watch.
3153    /// Does nothing if it is already activated.
3154    pub fn deactivate(&mut self) {
3155        if self.activated {
3156            self.activated = false;
3157            unsafe { sys::events::SDL_RemoveEventWatch(self.filter(), self.callback()) };
3158        }
3159    }
3160
3161    /// Returns if the event watch is activated.
3162    pub fn activated(&self) -> bool {
3163        self.activated
3164    }
3165
3166    /// Set the activation state of the event watch.
3167    pub fn set_activated(&mut self, activate: bool) {
3168        if activate {
3169            self.activate();
3170        } else {
3171            self.deactivate();
3172        }
3173    }
3174
3175    fn filter(&self) -> SDL_EventFilter {
3176        Some(event_callback_marshall::<CB>)
3177    }
3178
3179    fn callback(&mut self) -> *mut c_void {
3180        &mut *self.callback as *mut _ as *mut c_void
3181    }
3182}
3183
3184impl<'a, CB: EventWatchCallback + 'a> Drop for EventWatch<'a, CB> {
3185    fn drop(&mut self) {
3186        self.deactivate();
3187    }
3188}
3189
3190extern "C" fn event_callback_marshall<CB: EventWatchCallback>(
3191    user_data: *mut c_void,
3192    event: *mut sdl3_sys::events::SDL_Event,
3193) -> bool {
3194    let f: &mut CB = unsafe { &mut *(user_data as *mut _) };
3195    let event = Event::from_ll(unsafe { *event });
3196    f.callback(event);
3197    false
3198}
3199
3200impl<F: FnMut(Event)> EventWatchCallback for F {
3201    fn callback(&mut self, event: Event) {
3202        self(event)
3203    }
3204}
3205
3206#[cfg(test)]
3207mod test {
3208    use crate::video::Display;
3209
3210    use super::super::gamepad::{Axis, Button};
3211    use super::super::joystick::HatState;
3212    use super::super::keyboard::{Keycode, Mod, Scancode};
3213    use super::super::mouse::{MouseButton, MouseState, MouseWheelDirection};
3214    use super::super::video::Orientation;
3215    use super::DisplayEvent;
3216    use super::Event;
3217    use super::WindowEvent;
3218
3219    // Tests a round-trip conversion from an Event type to
3220    // the SDL event type and back, to make sure it's sane.
3221    #[test]
3222    fn test_to_from_ll() {
3223        {
3224            let e = Event::Quit { timestamp: 0 };
3225            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3226            assert_eq!(e, e2);
3227        }
3228        {
3229            let e = Event::Display {
3230                timestamp: 0,
3231                display: Display::from_ll(1),
3232                display_event: DisplayEvent::Orientation(Orientation::LandscapeFlipped),
3233            };
3234            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3235            assert_eq!(e, e2);
3236        }
3237        {
3238            let e = Event::Window {
3239                timestamp: 0,
3240                window_id: 0,
3241                win_event: WindowEvent::Resized(1, 2),
3242            };
3243            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3244            assert_eq!(e, e2);
3245        }
3246        {
3247            let e = Event::KeyDown {
3248                timestamp: 0,
3249                window_id: 1,
3250                keycode: Some(Keycode::Q),
3251                scancode: Some(Scancode::Q),
3252                keymod: Mod::all(),
3253                repeat: false,
3254                which: 0,
3255                raw: 0,
3256            };
3257            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3258            assert_eq!(e, e2);
3259        }
3260        {
3261            let e = Event::KeyUp {
3262                timestamp: 123,
3263                window_id: 0,
3264                keycode: Some(Keycode::R),
3265                scancode: Some(Scancode::R),
3266                keymod: Mod::empty(),
3267                repeat: true,
3268                which: 0,
3269                raw: 0,
3270            };
3271            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3272            assert_eq!(e, e2);
3273        }
3274        {
3275            let e = Event::MouseMotion {
3276                timestamp: 0,
3277                window_id: 0,
3278                which: 1,
3279                mousestate: MouseState::from_sdl_state(1),
3280                x: 3.,
3281                y: 91.,
3282                xrel: -1.,
3283                yrel: 43.,
3284            };
3285            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3286            assert_eq!(e, e2);
3287        }
3288        {
3289            let e = Event::MouseButtonDown {
3290                timestamp: 5634,
3291                window_id: 2,
3292                which: 0,
3293                mouse_btn: MouseButton::Left,
3294                clicks: 1,
3295                x: 543.,
3296                y: 345.,
3297            };
3298            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3299            assert_eq!(e, e2);
3300        }
3301        {
3302            let e = Event::MouseButtonUp {
3303                timestamp: 0,
3304                window_id: 2,
3305                which: 0,
3306                mouse_btn: MouseButton::Left,
3307                clicks: 1,
3308                x: 543.,
3309                y: 345.,
3310            };
3311            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3312            assert_eq!(e, e2);
3313        }
3314        {
3315            let e = Event::MouseWheel {
3316                timestamp: 1,
3317                window_id: 0,
3318                which: 32,
3319                x: 23.,
3320                y: 91.,
3321                direction: MouseWheelDirection::Flipped,
3322                mouse_x: 2.,
3323                mouse_y: 3.,
3324            };
3325            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3326            assert_eq!(e, e2);
3327        }
3328        {
3329            let e = Event::JoyAxisMotion {
3330                timestamp: 0,
3331                which: 1,
3332                axis_idx: 1,
3333                value: 12,
3334            };
3335            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3336            assert_eq!(e, e2);
3337        }
3338        {
3339            let e = Event::JoyHatMotion {
3340                timestamp: 0,
3341                which: 3,
3342                hat_idx: 1,
3343                state: HatState::Left,
3344            };
3345            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3346            assert_eq!(e, e2);
3347        }
3348        {
3349            let e = Event::JoyButtonDown {
3350                timestamp: 0,
3351                which: 0,
3352                button_idx: 3,
3353            };
3354            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3355            assert_eq!(e, e2);
3356        }
3357        {
3358            let e = Event::JoyButtonUp {
3359                timestamp: 9876,
3360                which: 1,
3361                button_idx: 2,
3362            };
3363            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3364            assert_eq!(e, e2);
3365        }
3366        {
3367            let e = Event::JoyDeviceAdded {
3368                timestamp: 0,
3369                which: 1,
3370            };
3371            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3372            assert_eq!(e, e2);
3373        }
3374        {
3375            let e = Event::JoyDeviceRemoved {
3376                timestamp: 0,
3377                which: 2,
3378            };
3379            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3380            assert_eq!(e, e2);
3381        }
3382        {
3383            let e = Event::ControllerAxisMotion {
3384                timestamp: 53,
3385                which: 0,
3386                axis: Axis::LeftX,
3387                value: 3,
3388            };
3389            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3390            assert_eq!(e, e2);
3391        }
3392        {
3393            let e = Event::ControllerButtonDown {
3394                timestamp: 0,
3395                which: 1,
3396                button: Button::Guide,
3397            };
3398            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3399            assert_eq!(e, e2);
3400        }
3401        {
3402            let e = Event::ControllerButtonUp {
3403                timestamp: 654214,
3404                which: 0,
3405                button: Button::DPadRight,
3406            };
3407            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3408            assert_eq!(e, e2);
3409        }
3410        {
3411            let e = Event::ControllerDeviceAdded {
3412                timestamp: 543,
3413                which: 3,
3414            };
3415            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3416            assert_eq!(e, e2);
3417        }
3418        {
3419            let e = Event::ControllerDeviceRemoved {
3420                timestamp: 555,
3421                which: 3,
3422            };
3423            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3424            assert_eq!(e, e2);
3425        }
3426        {
3427            let e = Event::ControllerDeviceRemapped {
3428                timestamp: 654,
3429                which: 0,
3430            };
3431            let e2 = Event::from_ll(e.clone().to_ll().unwrap());
3432            assert_eq!(e, e2);
3433        }
3434    }
3435
3436    #[test]
3437    fn test_from_ll_keymod_keydown_unknown_bits() {
3438        let mut raw_event = Event::KeyDown {
3439            timestamp: 0,
3440            window_id: 1,
3441            keycode: Some(Keycode::Q),
3442            scancode: Some(Scancode::Q),
3443            keymod: Mod::empty(),
3444            repeat: false,
3445            which: 0,
3446            raw: 0,
3447        }
3448        .to_ll()
3449        .unwrap();
3450
3451        // Simulate SDL setting bits unknown to us, see PR #780
3452        unsafe {
3453            raw_event.key.r#mod = 0xffff;
3454        }
3455
3456        if let Event::KeyDown { keymod, .. } = Event::from_ll(raw_event) {
3457            assert_eq!(keymod, Mod::all());
3458        } else {
3459            panic!()
3460        }
3461    }
3462
3463    #[test]
3464    fn test_from_ll_keymod_keyup_unknown_bits() {
3465        let mut raw_event = Event::KeyUp {
3466            timestamp: 0,
3467            window_id: 1,
3468            keycode: Some(Keycode::Q),
3469            scancode: Some(Scancode::Q),
3470            keymod: Mod::empty(),
3471            repeat: false,
3472            which: 0,
3473            raw: 0,
3474        }
3475        .to_ll()
3476        .unwrap();
3477
3478        // Simulate SDL setting bits unknown to us, see PR #780
3479        unsafe {
3480            raw_event.key.r#mod = 0xffff;
3481        }
3482
3483        if let Event::KeyUp { keymod, .. } = Event::from_ll(raw_event) {
3484            assert_eq!(keymod, Mod::all());
3485        } else {
3486            panic!()
3487        }
3488    }
3489}