diff --git a/examples/animation.rs b/examples/animation.rs index 23961794..81f2a3ae 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -1,7 +1,7 @@ extern crate sdl3; use std::path::Path; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::render::FRect; use std::time::Duration; @@ -55,11 +55,12 @@ fn main() -> Result<(), Box> { while running { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => { + }) => { running = false; } _ => {} diff --git a/examples/cursor.rs b/examples/cursor.rs index 378e48a2..1cc41747 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent, MouseButtonState, MouseEvent}; use sdl3::image::{InitFlag, LoadSurface}; use sdl3::keyboard::Keycode; use sdl3::mouse::Cursor; @@ -38,12 +38,18 @@ pub fn run(png: &Path) -> Result<(), Box> { 'mainloop: loop { for event in events.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { - keycode: Option::Some(Keycode::Escape), + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { + keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'mainloop, - Event::MouseButtonDown { x, y, .. } => { + }) => break 'mainloop, + Event::Mouse(MouseEvent::Button { + x, + y, + state: MouseButtonState::Down, + .. + }) => { canvas.fill_rect(Rect::new(x as i32, y as i32, 1, 1))?; canvas.present(); } diff --git a/examples/demo.rs b/examples/demo.rs index 7db38c3d..2ca4adef 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::Color; use std::time::Duration; @@ -26,11 +26,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, _ => {} } } diff --git a/examples/demo_games/a02_woodeneye_008.rs b/examples/demo_games/a02_woodeneye_008.rs index 786f4ba2..3a361584 100644 --- a/examples/demo_games/a02_woodeneye_008.rs +++ b/examples/demo_games/a02_woodeneye_008.rs @@ -1,6 +1,6 @@ // original code : https://github.com/libsdl-org/SDL/tree/main/examples/demo/02-woodeneye-008 -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent, MouseButtonState, MouseEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::Color; use sdl3::rect::Rect; @@ -598,10 +598,10 @@ fn main() -> Result<(), Box> { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } => break 'running, - Event::MouseMotion { + Event::Quit(_) => break 'running, + Event::Mouse(MouseEvent::Motion { which, xrel, yrel, .. - } => { + }) => { if let Some(index) = whose_mouse(which, &app_state.players, app_state.player_count) { @@ -626,18 +626,23 @@ fn main() -> Result<(), Box> { } } - Event::MouseButtonDown { which, .. } => { + Event::Mouse(MouseEvent::Button { + which, + state: MouseButtonState::Down, + .. + }) => { if let Some(index) = whose_mouse(which, &app_state.players, app_state.player_count) { shoot(index, &mut app_state.players, app_state.player_count); } } - Event::KeyDown { + Event::Keyboard(KeyboardEvent { keycode: Some(keycode), which, + state: KeyState::Down, .. - } => { + }) => { if let Some(index) = whose_keyboard(which, &app_state.players, app_state.player_count) { @@ -659,11 +664,12 @@ fn main() -> Result<(), Box> { } } } - Event::KeyUp { + Event::Keyboard(KeyboardEvent { keycode: Some(keycode), which, + state: KeyState::Up, .. - } => { + }) => { if keycode == Keycode::Escape { break 'running; } diff --git a/examples/dialog.rs b/examples/dialog.rs index 8139f731..ff7a1dd7 100644 --- a/examples/dialog.rs +++ b/examples/dialog.rs @@ -3,7 +3,7 @@ extern crate sdl3; use sdl3::dialog::{ show_open_file_dialog, show_open_folder_dialog, show_save_file_dialog, DialogFileFilter, }; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::Color; use std::path::PathBuf; @@ -47,17 +47,19 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => { + }) => { break 'running; } - Event::KeyDown { + Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::O), + state: KeyState::Down, .. - } => { + }) => { show_open_file_dialog( &filters, None::, @@ -76,10 +78,11 @@ pub fn main() -> Result<(), Box> { ) .unwrap_or_else(|e| panic!("Failed to show open file dialog: {e}")); } - Event::KeyDown { + Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::D), + state: KeyState::Down, .. - } => { + }) => { show_open_folder_dialog( Some(&default_path_path), false, @@ -96,10 +99,11 @@ pub fn main() -> Result<(), Box> { }), ); } - Event::KeyDown { + Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::S), + state: KeyState::Down, .. - } => { + }) => { show_save_file_dialog( &filters, Some("/home"), diff --git a/examples/draw_triangle.rs b/examples/draw_triangle.rs index c088c9ae..cef77f47 100644 --- a/examples/draw_triangle.rs +++ b/examples/draw_triangle.rs @@ -3,7 +3,12 @@ extern crate sdl3; use sdl3::{ - event::Event, keyboard::Keycode, pixels::Color, rect::Point, render::Canvas, video::Window, + event::{Event, KeyState, KeyboardEvent}, + keyboard::Keycode, + pixels::Color, + rect::Point, + render::Canvas, + video::Window, }; use std::time::Duration; @@ -94,11 +99,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, _ => {} } } diff --git a/examples/events.rs b/examples/events.rs index 1ed22353..23def21d 100644 --- a/examples/events.rs +++ b/examples/events.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent, MouseEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::Color; use std::time::Duration; @@ -28,13 +28,14 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, // skip mouse motion intentionally because of the verbose it might cause. - Event::MouseMotion { .. } => {} + Event::Mouse(MouseEvent::Motion { .. }) => {} e => { println!("{e:?}"); } diff --git a/examples/game-of-life-unsafe-textures.rs b/examples/game-of-life-unsafe-textures.rs index 51703394..4fe01812 100644 --- a/examples/game-of-life-unsafe-textures.rs +++ b/examples/game-of-life-unsafe-textures.rs @@ -3,7 +3,8 @@ extern crate sdl3; #[cfg(feature = "unsafe_textures")] use game_of_life::{PLAYGROUND_HEIGHT, PLAYGROUND_WIDTH, SQUARE_SIZE}; #[cfg(feature = "unsafe_textures")] -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent, MouseButtonState, MouseEvent}; + #[cfg(feature = "unsafe_textures")] use sdl3::keyboard::Keycode; #[cfg(feature = "unsafe_textures")] @@ -254,24 +255,27 @@ pub fn main() -> Result<(), Box> { // get the inputs here for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, - Event::KeyDown { + }) => break 'running, + Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Space), + state: KeyState::Down, repeat: false, .. - } => { + }) => { game.toggle_state(); } - Event::MouseButtonDown { + Event::Mouse(MouseEvent::Button { x, y, - mouse_btn: MouseButton::Left, + button: MouseButton::Left, + state: MouseButtonState::Down, .. - } => { + }) => { let x = (x as u32) / SQUARE_SIZE; let y = (y as u32) / SQUARE_SIZE; match game.get_mut(x as i32, y as i32) { diff --git a/examples/game-of-life.rs b/examples/game-of-life.rs index 7ccc8001..45b6164c 100644 --- a/examples/game-of-life.rs +++ b/examples/game-of-life.rs @@ -2,7 +2,7 @@ extern crate sdl3; #[cfg(not(feature = "unsafe_textures"))] use crate::game_of_life::{PLAYGROUND_HEIGHT, PLAYGROUND_WIDTH, SQUARE_SIZE}; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent, MouseButtonState, MouseEvent}; use sdl3::keyboard::Keycode; use sdl3::mouse::MouseButton; use sdl3::pixels::Color; @@ -258,24 +258,27 @@ pub fn main() -> Result<(), Box> { // get the inputs here for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, - Event::KeyDown { + }) => break 'running, + Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Space), + state: KeyState::Down, repeat: false, .. - } => { + }) => { game.toggle_state(); } - Event::MouseButtonDown { + Event::Mouse(MouseEvent::Button { x, y, - mouse_btn: MouseButton::Left, + button: MouseButton::Left, + state: MouseButtonState::Down, .. - } => { + }) => { let x = (x as u32) / SQUARE_SIZE; let y = (y as u32) / SQUARE_SIZE; match game.get_mut(x as i32, y as i32) { diff --git a/examples/gamepad.rs b/examples/gamepad.rs index df7856c2..5db22eb7 100644 --- a/examples/gamepad.rs +++ b/examples/gamepad.rs @@ -1,5 +1,10 @@ extern crate sdl3; +use sdl3::event::{ + ControllerButtonState, ControllerEvent, ControllerTouchpadKind, Event, KeyState, KeyboardEvent, +}; +use sdl3::gamepad::Axis; + fn main() -> Result<(), Box> { // This is required for certain controllers to work on Windows without the // video subsystem enabled: @@ -22,8 +27,6 @@ fn main() -> Result<(), Box> { match gamepad_subsystem.open(id) { Ok(c) => { - // We managed to find and open a game controller, - // exit the loop println!( "Success: opened \"{}\"", c.name().unwrap_or_else(|| "(unnamed)".to_owned()) @@ -40,76 +43,85 @@ fn main() -> Result<(), Box> { println!( "Controller mapping: {}", - controller.mapping().unwrap_or("".to_owned()) + controller.mapping().unwrap_or_default() ); - let (mut lo_freq, mut hi_freq) = (0, 0); + let (mut lo_freq, mut hi_freq) = (0u16, 0u16); for event in sdl_context.event_pump()?.wait_iter() { - use sdl3::event::Event; - use sdl3::gamepad::Axis; - match event { - Event::ControllerAxisMotion { + Event::Controller(ControllerEvent::Axis { axis: Axis::TriggerLeft, value: val, .. - } => { - // Trigger axes go from 0 to 32767, so this should be okay + }) => { lo_freq = (val as u16) * 2; - match controller.set_rumble(lo_freq, hi_freq, 15000) { - Ok(()) => println!("Set rumble to ({lo_freq}, {hi_freq})"), - Err(e) => println!("Error setting rumble to ({lo_freq}, {hi_freq}): {e:?}"), + if let Err(e) = controller.set_rumble(lo_freq, hi_freq, 15_000) { + println!("Error setting rumble to ({lo_freq}, {hi_freq}): {e:?}"); + } else { + println!("Set rumble to ({lo_freq}, {hi_freq})"); } } - Event::ControllerAxisMotion { + Event::Controller(ControllerEvent::Axis { axis: Axis::TriggerRight, value: val, .. - } => { - // Trigger axes go from 0 to 32767, so this should be okay + }) => { hi_freq = (val as u16) * 2; - match controller.set_rumble(lo_freq, hi_freq, 15000) { - Ok(()) => println!("Set rumble to ({lo_freq}, {hi_freq})"), - Err(e) => println!("Error setting rumble to ({lo_freq}, {hi_freq}): {e:?}"), + if let Err(e) = controller.set_rumble(lo_freq, hi_freq, 15_000) { + println!("Error setting rumble to ({lo_freq}, {hi_freq}): {e:?}"); + } else { + println!("Set rumble to ({lo_freq}, {hi_freq})"); } } - Event::ControllerAxisMotion { - axis, value: val, .. - } => { - // Axis motion is an absolute value in the range - // [-32768, 32767]. Let's simulate a very rough dead - // zone to ignore spurious events. + Event::Controller(ControllerEvent::Axis { axis, value, .. }) => { let dead_zone = 10_000; - if val > dead_zone || val < -dead_zone { - println!("Axis {axis:?} moved to {val}"); + if value > dead_zone || value < -dead_zone { + println!("Axis {axis:?} moved to {value}"); } } - Event::ControllerButtonDown { button, .. } => println!("Button {button:?} down"), - Event::ControllerButtonUp { button, .. } => println!("Button {button:?} up"), - Event::ControllerTouchpadDown { + Event::Controller(ControllerEvent::Button { + button, + state: ControllerButtonState::Down, + .. + }) => println!("Button {button:?} down"), + Event::Controller(ControllerEvent::Button { + button, + state: ControllerButtonState::Up, + .. + }) => println!("Button {button:?} up"), + Event::Controller(ControllerEvent::Touchpad { touchpad, finger, + kind: ControllerTouchpadKind::Down, x, y, .. - } => println!("Touchpad {touchpad} down finger:{finger} x:{x} y:{y}"), - Event::ControllerTouchpadMotion { + }) => println!("Touchpad {touchpad} down finger:{finger} x:{x} y:{y}"), + Event::Controller(ControllerEvent::Touchpad { touchpad, finger, + kind: ControllerTouchpadKind::Motion, x, y, .. - } => println!("Touchpad {touchpad} move finger:{finger} x:{x} y:{y}"), - Event::ControllerTouchpadUp { + }) => println!("Touchpad {touchpad} move finger:{finger} x:{x} y:{y}"), + Event::Controller(ControllerEvent::Touchpad { touchpad, finger, + kind: ControllerTouchpadKind::Up, x, y, .. - } => println!("Touchpad {touchpad} up finger:{finger} x:{x} y:{y}"), - Event::Quit { .. } => break, - _ => (), + }) => println!("Touchpad {touchpad} up finger:{finger} x:{x} y:{y}"), + Event::Quit(_) => break, + // Allow escape key to quit even if no controller events occur + Event::Keyboard(KeyboardEvent { + keycode: Some(sdl3::keyboard::Keycode::Escape), + state: KeyState::Down, + .. + }) => break, + _ => {} } } diff --git a/examples/gfx-demo.rs b/examples/gfx-demo.rs index ffe98739..27f2752a 100644 --- a/examples/gfx-demo.rs +++ b/examples/gfx-demo.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent, MouseButtonState, MouseEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels; @@ -37,12 +37,13 @@ fn main() -> Result<(), Box> { 'main: loop { for event in events.poll_iter() { match event { - Event::Quit { .. } => break 'main, + Event::Quit(_) => break 'main, - Event::KeyDown { + Event::Keyboard(KeyboardEvent { keycode: Some(keycode), + state: KeyState::Down, .. - } => { + }) => { if keycode == Keycode::Escape { break 'main; } else if keycode == Keycode::Space { @@ -54,7 +55,12 @@ fn main() -> Result<(), Box> { } } - Event::MouseButtonDown { x, y, .. } => { + Event::Mouse(MouseEvent::Button { + x, + y, + state: MouseButtonState::Down, + .. + }) => { let color = pixels::Color::RGB(x as u8, y as u8, 255); let _ = canvas.line(lastx, lasty, x as i16, y as i16, color); lastx = x as i16; diff --git a/examples/gpu-clear.rs b/examples/gpu-clear.rs index 3d86126d..042efaac 100644 --- a/examples/gpu-clear.rs +++ b/examples/gpu-clear.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; pub fn main() -> Result<(), Box> { @@ -26,11 +26,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, _ => {} } } diff --git a/examples/gpu-cube.rs b/examples/gpu-cube.rs index df638069..31f4533a 100644 --- a/examples/gpu-cube.rs +++ b/examples/gpu-cube.rs @@ -1,5 +1,5 @@ use sdl3::{ - event::Event, + event::{Event, KeyState, KeyboardEvent}, gpu::{ Buffer, BufferBinding, BufferRegion, BufferUsageFlags, ColorTargetDescription, ColorTargetInfo, CompareOp, CopyPass, CullMode, DepthStencilState, DepthStencilTargetInfo, @@ -219,11 +219,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, _ => {} } } diff --git a/examples/gpu-particles.rs b/examples/gpu-particles.rs index dfdaf7b7..63dbd2da 100644 --- a/examples/gpu-particles.rs +++ b/examples/gpu-particles.rs @@ -1,7 +1,10 @@ use rand::Rng; use sdl3::gpu::*; use sdl3::pixels::Color; -use sdl3::{event::Event, keyboard::Keycode}; +use sdl3::{ + event::{Event, KeyState, KeyboardEvent}, + keyboard::Keycode, +}; use std::mem::size_of; #[repr(C)] @@ -119,11 +122,12 @@ fn main() -> Result<(), Box> { 'running: loop { for e in events.poll_iter() { match e { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, _ => {} } } diff --git a/examples/gpu-texture.rs b/examples/gpu-texture.rs index 78f6414a..43e86fde 100644 --- a/examples/gpu-texture.rs +++ b/examples/gpu-texture.rs @@ -1,5 +1,5 @@ use sdl3::{ - event::Event, + event::{Event, KeyState, KeyboardEvent}, gpu::{ Buffer, BufferBinding, BufferRegion, BufferUsageFlags, ColorTargetDescription, ColorTargetInfo, CompareOp, CopyPass, CullMode, DepthStencilState, DepthStencilTargetInfo, @@ -346,11 +346,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, _ => {} } } diff --git a/examples/gpu-triangle.rs b/examples/gpu-triangle.rs index 2011f5c5..c6fda70d 100644 --- a/examples/gpu-triangle.rs +++ b/examples/gpu-triangle.rs @@ -1,7 +1,7 @@ extern crate sdl3; use sdl3::{ - event::Event, + event::{Event, KeyState, KeyboardEvent}, gpu::{ ColorTargetDescription, ColorTargetInfo, Device, FillMode, GraphicsPipelineTargetInfo, LoadOp, PrimitiveType, ShaderFormat, ShaderStage, StoreOp, @@ -75,11 +75,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, _ => {} } } diff --git a/examples/haptic.rs b/examples/haptic.rs index e24597ac..b8e0242b 100644 --- a/examples/haptic.rs +++ b/examples/haptic.rs @@ -1,5 +1,7 @@ extern crate sdl3; +use sdl3::event::{Event, JoyButtonState, JoystickEvent, KeyState, KeyboardEvent}; + fn main() -> Result<(), Box> { let sdl_context = sdl3::init()?; let joystick_subsystem = sdl_context.joystick()?; @@ -31,32 +33,42 @@ fn main() -> Result<(), Box> { .map_err(|e| e.to_string())?; for event in sdl_context.event_pump()?.wait_iter() { - use sdl3::event::Event; - match event { - Event::JoyAxisMotion { - axis_idx, - value: val, - .. - } => { - // Axis motion is an absolute value in the range - // [-32768, 32767]. Let's simulate a very rough dead - // zone to ignore spurious events. + Event::Joystick(JoystickEvent::Axis { + axis_index, value, .. + }) => { + // Axis motion is an absolute value in the range [-32768, 32767]. let dead_zone = 10_000; - if val > dead_zone || val < -dead_zone { - println!("Axis {axis_idx} moved to {val}"); + if value > dead_zone || value < -dead_zone { + println!("Axis {axis_index} moved to {value}"); } } - Event::JoyButtonDown { button_idx, .. } => { - println!("Button {button_idx} down"); + Event::Joystick(JoystickEvent::Button { + button_index, + state: JoyButtonState::Down, + .. + }) => { + println!("Button {button_index} down"); + // Play a short rumble haptic.rumble_play(0.5, 500); } - Event::JoyButtonUp { button_idx, .. } => println!("Button {button_idx} up"), - Event::JoyHatMotion { hat_idx, state, .. } => { - println!("Hat {hat_idx} moved to {state:?}") + Event::Joystick(JoystickEvent::Button { + button_index, + state: JoyButtonState::Up, + .. + }) => println!("Button {button_index} up"), + Event::Joystick(JoystickEvent::Hat { + hat_index, state, .. + }) => { + println!("Hat {hat_index} moved to {state:?}"); } - Event::Quit { .. } => break, - _ => (), + Event::Keyboard(KeyboardEvent { + keycode: Some(sdl3::keyboard::Keycode::Escape), + state: KeyState::Down, + .. + }) => break, + Event::Quit(_) => break, + _ => {} } } diff --git a/examples/image-demo.rs b/examples/image-demo.rs index 75f5e397..4cddfeb0 100644 --- a/examples/image-demo.rs +++ b/examples/image-demo.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent, MouseButtonState, MouseEvent}; use sdl3::image::LoadTexture; use sdl3::keyboard::Keycode; use std::env; @@ -25,11 +25,12 @@ pub fn run(png: &Path) -> Result<(), Box> { 'mainloop: loop { for event in sdl_context.event_pump()?.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { - keycode: Option::Some(Keycode::Escape), + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { + keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'mainloop, + }) => break 'mainloop, _ => {} } } diff --git a/examples/joystick.rs b/examples/joystick.rs index 1ef1e21d..978d8d6e 100644 --- a/examples/joystick.rs +++ b/examples/joystick.rs @@ -1,7 +1,9 @@ -use sdl3::get_error; - extern crate sdl3; +use sdl3::event::{Event, JoyButtonState, JoystickEvent, KeyState, KeyboardEvent}; +use sdl3::get_error; +use sdl3::keyboard::Keycode; + fn main() -> Result<(), Box> { let sdl_context = sdl3::init()?; let joystick_subsystem = sdl_context.joystick()?; @@ -15,7 +17,7 @@ fn main() -> Result<(), Box> { // Iterate over all available joysticks and stop once we manage to open one. let mut joystick = joysticks .into_iter() - .find_map(|joystick| match joystick_subsystem.open(joystick) { + .find_map(|joystick_id| match joystick_subsystem.open(joystick_id) { Ok(c) => { println!("Success: opened \"{}\"", c.name()); Some(c) @@ -34,34 +36,32 @@ fn main() -> Result<(), Box> { joystick.power_info().map_err(|e| e.to_string())? ); - let (mut lo_freq, mut hi_freq) = (0, 0); + let (mut lo_freq, mut hi_freq) = (0u16, 0u16); for event in sdl_context.event_pump()?.wait_iter() { - use sdl3::event::Event; - match event { - Event::JoyAxisMotion { - axis_idx, - value: val, - .. - } => { - // Axis motion is an absolute value in the range - // [-32768, 32767]. Let's simulate a very rough dead - // zone to ignore spurious events. + Event::Joystick(JoystickEvent::Axis { + axis_index, value, .. + }) => { + // Axis motion is an absolute value in the range [-32768, 32767]. let dead_zone = 10_000; - if val > dead_zone || val < -dead_zone { - println!("Axis {axis_idx} moved to {val}"); + if value > dead_zone || value < -dead_zone { + println!("Axis {axis_index} moved to {value}"); } } - Event::JoyButtonDown { button_idx, .. } => { - println!("Button {button_idx} down"); - if button_idx == 0 { + Event::Joystick(JoystickEvent::Button { + button_index, + state: JoyButtonState::Down, + .. + }) => { + println!("Button {button_index} down"); + if button_index == 0 { lo_freq = 65535; - } else if button_idx == 1 { + } else if button_index == 1 { hi_freq = 65535; } - if button_idx < 2 { - if joystick.set_rumble(lo_freq, hi_freq, 15000) { + if button_index < 2 { + if joystick.set_rumble(lo_freq, hi_freq, 15_000) { println!("Set rumble to ({lo_freq}, {hi_freq})"); } else { println!( @@ -73,15 +73,19 @@ fn main() -> Result<(), Box> { } } } - Event::JoyButtonUp { button_idx, .. } => { - println!("Button {button_idx} up"); - if button_idx == 0 { + Event::Joystick(JoystickEvent::Button { + button_index, + state: JoyButtonState::Up, + .. + }) => { + println!("Button {button_index} up"); + if button_index == 0 { lo_freq = 0; - } else if button_idx == 1 { + } else if button_index == 1 { hi_freq = 0; } - if button_idx < 2 { - if joystick.set_rumble(lo_freq, hi_freq, 15000) { + if button_index < 2 { + if joystick.set_rumble(lo_freq, hi_freq, 15_000) { println!("Set rumble to ({lo_freq}, {hi_freq})"); } else { println!( @@ -93,11 +97,18 @@ fn main() -> Result<(), Box> { } } } - Event::JoyHatMotion { hat_idx, state, .. } => { - println!("Hat {hat_idx} moved to {state:?}") + Event::Joystick(JoystickEvent::Hat { + hat_index, state, .. + }) => { + println!("Hat {hat_index} moved to {state:?}"); } - Event::Quit { .. } => break, - _ => (), + Event::Keyboard(KeyboardEvent { + keycode: Some(Keycode::Escape), + state: KeyState::Down, + .. + }) => break, + Event::Quit(_) => break, + _ => {} } } diff --git a/examples/keyboard-state.rs b/examples/keyboard-state.rs index 436ac9d6..bb27a884 100644 --- a/examples/keyboard-state.rs +++ b/examples/keyboard-state.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3_sys::keycode::SDL_KMOD_NONE; use std::collections::HashSet; @@ -22,9 +22,15 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in events.poll_iter() { - if let Event::Quit { .. } = event { - break 'running; - }; + match event { + Event::Quit(_) => break 'running, + Event::Keyboard(KeyboardEvent { + state: KeyState::Down, + keycode: Some(Keycode::Escape), + .. + }) => break 'running, + _ => {} + } } // Create a set of pressed Keys. diff --git a/examples/message-box.rs b/examples/message-box.rs index 3b3de0fb..572915c6 100644 --- a/examples/message-box.rs +++ b/examples/message-box.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::messagebox::*; use sdl3::pixels::Color; @@ -26,11 +26,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => { + }) => { show_simple_message_box( MessageBoxFlag::ERROR, "Some title", diff --git a/examples/mouse-state.rs b/examples/mouse-state.rs index 32c47a1e..f46a940a 100644 --- a/examples/mouse-state.rs +++ b/examples/mouse-state.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use std::collections::HashSet; use std::time::Duration; @@ -22,11 +22,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in events.poll_iter() { match event { - Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } - | Event::Quit { .. } => break 'running, + }) => break 'running, _ => {} } } diff --git a/examples/no-renderer.rs b/examples/no-renderer.rs index 185908e5..8c2e91f3 100644 --- a/examples/no-renderer.rs +++ b/examples/no-renderer.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::Color; use sdl3::rect::Rect; @@ -68,12 +68,17 @@ pub fn main() -> Result<(), Box> { let mut keypress: bool = false; for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, - Event::KeyDown { repeat: false, .. } => { + }) => break 'running, + Event::Keyboard(KeyboardEvent { + state: KeyState::Down, + repeat: false, + .. + }) => { keypress = true; } _ => {} diff --git a/examples/raw-window-handle-with-wgpu/main.rs b/examples/raw-window-handle-with-wgpu/main.rs index 52f7f9c0..1b78f22d 100644 --- a/examples/raw-window-handle-with-wgpu/main.rs +++ b/examples/raw-window-handle-with-wgpu/main.rs @@ -7,7 +7,7 @@ extern crate wgpu; use std::borrow::Cow; use wgpu::{InstanceDescriptor, SurfaceError}; -use sdl3::event::{Event, WindowEvent}; +use sdl3::event::{Event, KeyState, KeyboardEvent, WindowEvent, WindowEventKind}; use sdl3::keyboard::Keycode; fn main() -> Result<(), Box> { @@ -127,24 +127,23 @@ fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Window { + Event::Window(WindowEvent { window_id, - win_event: - WindowEvent::PixelSizeChanged(width, height) - | WindowEvent::Resized(width, height), + kind: + WindowEventKind::PixelSizeChanged { w, h } | WindowEventKind::Resized { w, h }, .. - } if window_id == window.id() => { - config.width = width as u32; - config.height = height as u32; + }) if window_id == window.id() => { + config.width = w as u32; + config.height = h as u32; surface.configure(&device, &config); } - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, + repeat: false, .. - } => { - break 'running; - } + }) => break 'running, e => { dbg!(e); } diff --git a/examples/relative-mouse-state.rs b/examples/relative-mouse-state.rs index 965dd72a..6dc3d61e 100644 --- a/examples/relative-mouse-state.rs +++ b/examples/relative-mouse-state.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::mouse::MouseButton; use std::time::Duration; @@ -21,11 +21,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in events.poll_iter() { match event { - Event::KeyDown { + Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } - | Event::Quit { .. } => break 'running, + }) + | Event::Quit(_) => break 'running, _ => {} } } diff --git a/examples/render-geometry.rs b/examples/render-geometry.rs index 810eaa70..de17300f 100644 --- a/examples/render-geometry.rs +++ b/examples/render-geometry.rs @@ -1,4 +1,4 @@ -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::{Color, FColor}; use sdl3::render::{FPoint, RenderGeometryTextureParams, Vertex, VertexIndices}; @@ -25,11 +25,12 @@ fn main() { while running { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => { + }) => { running = false; } _ => {} diff --git a/examples/renderer-target.rs b/examples/renderer-target.rs index 82f38828..f45d36d8 100644 --- a/examples/renderer-target.rs +++ b/examples/renderer-target.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::{Color, PixelFormat}; use sdl3::render::{FPoint, FRect}; @@ -29,11 +29,12 @@ fn main() -> Result<(), Box> { 'mainloop: loop { for event in sdl_context.event_pump()?.poll_iter() { match event { - Event::KeyDown { + Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } - | Event::Quit { .. } => break 'mainloop, + }) + | Event::Quit(_) => break 'mainloop, _ => {} } } diff --git a/examples/renderer-texture.rs b/examples/renderer-texture.rs index 54c483a1..e8681eb1 100644 --- a/examples/renderer-texture.rs +++ b/examples/renderer-texture.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::PixelFormat; use sdl3::render::FRect; @@ -57,11 +57,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, _ => {} } } diff --git a/examples/renderer-yuv.rs b/examples/renderer-yuv.rs index 18cd2e81..56831453 100644 --- a/examples/renderer-yuv.rs +++ b/examples/renderer-yuv.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::PixelFormat; use sdl3::render::FRect; @@ -65,11 +65,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, _ => {} } } diff --git a/examples/resource-manager.rs b/examples/resource-manager.rs index 25c87d52..faa90e9c 100644 --- a/examples/resource-manager.rs +++ b/examples/resource-manager.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::image::{InitFlag, LoadTexture}; use sdl3::keyboard::Keycode; use sdl3::pixels::Color; @@ -47,11 +47,12 @@ fn main() -> Result<(), Box> { 'mainloop: loop { for event in sdl_context.event_pump()?.poll_iter() { match event { - Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } - | Event::Quit { .. } => break 'mainloop, + }) => break 'mainloop, _ => {} } } diff --git a/examples/sensors.rs b/examples/sensors.rs index a939f28b..0b6047bd 100644 --- a/examples/sensors.rs +++ b/examples/sensors.rs @@ -1,7 +1,10 @@ extern crate sdl3; use std::time::{Duration, Instant}; -use sdl3::{event::Event, sensor::SensorType}; +use sdl3::{ + event::{ControllerEvent, Event}, + sensor::SensorType, +}; fn main() -> Result<(), String> { let sdl_context = sdl3::init().unwrap(); @@ -79,11 +82,11 @@ fn main() -> Result<(), String> { println!("gyro: {:?}, accel: {:?}", gyro_data, accel_data); } - if let Event::ControllerSensorUpdated { .. } = event { + if let Event::Controller(ControllerEvent::Sensor { .. }) = event { println!("{:?}", event); } - if let Event::Quit { .. } = event { + if let Event::Quit(_) = event { break; } } diff --git a/examples/spinning_cube.rs b/examples/spinning_cube.rs index 42ff79ed..cefaec56 100644 --- a/examples/spinning_cube.rs +++ b/examples/spinning_cube.rs @@ -6,7 +6,12 @@ extern crate sdl3; use sdl3::{ - event::Event, keyboard::Keycode, pixels::Color, rect::Point, render::Canvas, video::Window, + event::{Event, KeyState, KeyboardEvent}, + keyboard::Keycode, + pixels::Color, + rect::Point, + render::Canvas, + video::Window, }; use std::time::Duration; @@ -127,11 +132,12 @@ fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => { + }) => { break 'running; } _ => {} diff --git a/examples/ttf-demo.rs b/examples/ttf-demo.rs index c26d179b..118900f3 100644 --- a/examples/ttf-demo.rs +++ b/examples/ttf-demo.rs @@ -3,7 +3,7 @@ extern crate sdl3; use std::env; use std::path::Path; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::Color; use sdl3::rect::Rect; @@ -91,10 +91,11 @@ fn run(font_path: &Path) -> Result<(), Box> { 'mainloop: loop { for event in sdl_context.event_pump()?.poll_iter() { match event { - Event::KeyDown { + Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } + }) | Event::Quit { .. } => break 'mainloop, _ => {} } diff --git a/examples/window-properties.rs b/examples/window-properties.rs index 93d65f65..6a9d8506 100644 --- a/examples/window-properties.rs +++ b/examples/window-properties.rs @@ -1,6 +1,6 @@ extern crate sdl3; -use sdl3::event::Event; +use sdl3::event::{Event, KeyState, KeyboardEvent}; use sdl3::keyboard::Keycode; use sdl3::pixels::Color; @@ -28,11 +28,12 @@ pub fn main() -> Result<(), Box> { 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } - | Event::KeyDown { + Event::Quit(_) + | Event::Keyboard(KeyboardEvent { keycode: Some(Keycode::Escape), + state: KeyState::Down, .. - } => break 'running, + }) => break 'running, _ => {} } } diff --git a/src/sdl3/event.rs b/src/sdl3/event.rs index 53d4b066..f5b658b7 100644 --- a/src/sdl3/event.rs +++ b/src/sdl3/event.rs @@ -1,284 +1,61 @@ /*! -Event Handling + * Event Handling */ -use std::borrow::ToOwned; +use std::any::TypeId; use std::collections::HashMap; use std::convert::TryFrom; -use std::ffi::CStr; -use std::iter::FromIterator; +use std::ffi::{CStr, CString}; use std::marker::PhantomData; use std::mem; use std::mem::transmute; use std::ptr; use std::sync::Mutex; -use crate::gamepad; -use crate::gamepad::{Axis, Button}; +use libc::{c_int, c_void}; + use crate::get_error; -use crate::joystick; +use crate::Error; + +use crate::gamepad::{Axis as GamepadAxis, Button as GamepadButton}; use crate::joystick::HatState; -use crate::keyboard; -use crate::keyboard::Keycode; -use crate::keyboard::Mod; -use crate::keyboard::Scancode; -use crate::mouse; +use crate::keyboard::{Keycode, Mod, Scancode}; use crate::mouse::{MouseButton, MouseState, MouseWheelDirection}; use crate::pen::PenAxis; -use crate::sys; -use crate::sys::events::SDL_EventFilter; use crate::video::{Display, Orientation}; -use crate::Error; -use libc::c_int; -use libc::c_void; -use sys::events::{ - SDL_DisplayEvent, SDL_EventType, SDL_GamepadAxisEvent, SDL_GamepadButtonEvent, - SDL_GamepadDeviceEvent, SDL_JoyAxisEvent, SDL_JoyButtonEvent, SDL_JoyDeviceEvent, - SDL_JoyHatEvent, SDL_KeyboardEvent, SDL_MouseButtonEvent, SDL_MouseMotionEvent, - SDL_MouseWheelEvent, + +use crate::sys; +use crate::sys::events::{ + SDL_AudioDeviceEvent, SDL_CommonEvent, SDL_DisplayEvent, SDL_Event, SDL_EventType, + SDL_GamepadAxisEvent, SDL_GamepadButtonEvent, SDL_GamepadDeviceEvent, SDL_GamepadTouchpadEvent, + SDL_JoyAxisEvent, SDL_JoyButtonEvent, SDL_JoyDeviceEvent, SDL_JoyHatEvent, SDL_KeyboardEvent, + SDL_MouseButtonEvent, SDL_MouseMotionEvent, SDL_MouseWheelEvent, SDL_PenAxisEvent, + SDL_PenButtonEvent, SDL_PenMotionEvent, SDL_PenProximityEvent, SDL_PenTouchEvent, + SDL_QuitEvent, SDL_UserEvent, SDL_WindowEvent, }; -use sys::everything::SDL_DisplayOrientation; -use sys::stdinc::Uint16; +use crate::sys::everything::SDL_DisplayOrientation; +use crate::sys::stdinc::Uint16; -struct CustomEventTypeMaps { - sdl_id_to_type_id: HashMap, - type_id_to_sdl_id: HashMap<::std::any::TypeId, u32>, +lazy_static::lazy_static! { + static ref CUSTOM_EVENT_TYPES: Mutex = Mutex::new(CustomEventTypeMaps::new()); } +#[derive(Debug)] +struct CustomEventTypeMaps { + sdl_id_to_type_id: HashMap, + type_id_to_sdl_id: HashMap, +} impl CustomEventTypeMaps { fn new() -> Self { - CustomEventTypeMaps { + Self { sdl_id_to_type_id: HashMap::new(), type_id_to_sdl_id: HashMap::new(), } } } -lazy_static! { - static ref CUSTOM_EVENT_TYPES: Mutex = - Mutex::new(CustomEventTypeMaps::new()); -} - -impl crate::EventSubsystem { - /// Removes all events in the event queue that match the specified event type. - #[doc(alias = "SDL_FlushEvent")] - pub fn flush_event(&self, event_type: EventType) { - unsafe { sys::events::SDL_FlushEvent(event_type.into()) }; - } - - /// Removes all events in the event queue that match the specified type range. - #[doc(alias = "SDL_FlushEvents")] - pub fn flush_events(&self, min_type: u32, max_type: u32) { - unsafe { sys::events::SDL_FlushEvents(min_type, max_type) }; - } - - /// Reads the events at the front of the event queue, until the maximum amount - /// of events is read. - /// - /// The events will _not_ be removed from the queue. - /// - /// # Example - /// ```no_run - /// use sdl3::event::Event; - /// - /// let sdl_context = sdl3::init().unwrap(); - /// let event_subsystem = sdl_context.event().unwrap(); - /// - /// // Read up to 1024 events - /// let events: Vec = event_subsystem.peek_events(1024); - /// - /// // Print each one - /// for event in events { - /// println!("{:?}", event); - /// } - /// ``` - #[doc(alias = "SDL_PeepEvents")] - pub fn peek_events(&self, max_amount: u32) -> B - where - B: FromIterator, - { - unsafe { - let mut events = Vec::with_capacity(max_amount as usize); - - let result = { - let events_ptr = events.as_mut_ptr(); - - sys::events::SDL_PeepEvents( - events_ptr, - max_amount as c_int, - sys::events::SDL_PEEKEVENT, - sys::events::SDL_EVENT_FIRST.into(), - sys::events::SDL_EVENT_LAST.into(), - ) - }; - - if result < 0 { - // The only error possible is "Couldn't lock event queue" - panic!("{}", get_error()); - } else { - events.set_len(result as usize); - - events.into_iter().map(Event::from_ll).collect() - } - } - } - - /// Pushes an event to the event queue. - pub fn push_event(&self, event: Event) -> Result<(), Error> { - self.event_sender().push_event(event) - } - - /// Register a custom SDL event. - /// - /// When pushing a user event, you must make sure that the ``type_`` field is set to a - /// registered SDL event number. - /// - /// The ``code``, ``data1``, and ``data2`` fields can be used to store user defined data. - /// - /// See the [SDL documentation](https://wiki.libsdl.org/SDL_UserEvent) for more information. - /// - /// # Example - /// ``` - /// let sdl = sdl3::init().unwrap(); - /// let ev = sdl.event().unwrap(); - /// - /// let custom_event_type_id = unsafe { ev.register_event().unwrap() }; - /// let event = sdl3::event::Event::User { - /// timestamp: 0, - /// window_id: 0, - /// type_: custom_event_type_id, - /// code: 456, - /// data1: 0x1234 as *mut libc::c_void, - /// data2: 0x5678 as *mut libc::c_void, - /// }; - /// - /// ev.push_event(event); - /// - /// ``` - #[inline(always)] - pub unsafe fn register_event(&self) -> Result { - Ok(*self.register_events(1)?.first().unwrap()) - } - - /// Registers custom SDL events. - /// - /// Returns an error, if no more user events can be created. - pub unsafe fn register_events(&self, nr: u32) -> Result, Error> { - let result = sys::events::SDL_RegisterEvents(nr as ::libc::c_int); - const ERR_NR: u32 = u32::MAX - 1; - - match result { - ERR_NR => Err(Error( - "No more user events can be created; SDL_EVENT_LAST reached".to_owned(), - )), - _ => { - let event_ids = (result..(result + nr)).collect(); - Ok(event_ids) - } - } - } - - /// Register a custom event - /// - /// It returns an error when the same type is registered twice. - /// - /// # Example - /// See [push_custom_event](#method.push_custom_event) - #[inline(always)] - pub fn register_custom_event(&self) -> Result<(), Error> { - use std::any::TypeId; - let event_id = *(unsafe { self.register_events(1) })?.first().unwrap(); - let mut cet = CUSTOM_EVENT_TYPES.lock().unwrap(); - let type_id = TypeId::of::>(); - - if cet.type_id_to_sdl_id.contains_key(&type_id) { - return Err(Error( - "The same event type can not be registered twice!".to_owned(), - )); - } - - cet.sdl_id_to_type_id.insert(event_id, type_id); - cet.type_id_to_sdl_id.insert(type_id, event_id); - - Ok(()) - } - - /// Push a custom event - /// - /// If the event type ``T`` was not registered using - /// [register_custom_event](#method.register_custom_event), - /// this method will panic. - /// - /// # Example: pushing and receiving a custom event - /// ``` - /// struct SomeCustomEvent { - /// a: i32 - /// } - /// - /// let sdl = sdl3::init().unwrap(); - /// let ev = sdl.event().unwrap(); - /// let mut ep = sdl.event_pump().unwrap(); - /// - /// ev.register_custom_event::().unwrap(); - /// - /// let event = SomeCustomEvent { a: 42 }; - /// - /// ev.push_custom_event(event); - /// - /// let received = ep.poll_event().unwrap(); // or within a for event in ep.poll_iter() - /// if received.is_user_event() { - /// let e2 = received.as_user_event_type::().unwrap(); - /// assert_eq!(e2.a, 42); - /// } - /// ``` - pub fn push_custom_event(&self, event: T) -> Result<(), Error> { - self.event_sender().push_custom_event(event) - } - - /// Create an event sender that can be sent to other threads. - /// - /// An `EventSender` will not keep the event subsystem alive. If the event subsystem is - /// shut down calls to `push_event` and `push_custom_event` will return errors. - pub fn event_sender(&self) -> EventSender { - EventSender { _priv: () } - } - - /// Create an event watcher which is called every time an event is added to event queue. - /// - /// The watcher is disabled when the return value is dropped. - /// Just calling this function without binding to a variable immediately disables the watcher. - /// In order to make it persistent, you have to bind in a variable and keep it until it's no - /// longer needed. - /// - /// # Example: dump every event to stderr - /// ``` - /// let sdl = sdl3::init().unwrap(); - /// let ev = sdl.event().unwrap(); - /// - /// // `let _ = ...` is insufficient, as it is dropped immediately. - /// let _event_watch = ev.add_event_watch(|event| { - /// dbg!(event); - /// }); - /// ``` - pub fn add_event_watch<'a, CB: EventWatchCallback + 'a>( - &self, - callback: CB, - ) -> EventWatch<'a, CB> { - EventWatch::add(callback) - } - - #[doc(alias = "SDL_SetEventEnabled")] - pub fn set_event_enabled(event_type: EventType, enabled: bool) { - unsafe { sys::events::SDL_SetEventEnabled(event_type.into(), enabled) }; - } - - #[doc(alias = "SDL_EventEnabled")] - pub fn event_enabled(event_type: EventType) -> bool { - unsafe { sys::events::SDL_EventEnabled(event_type.into()) } - } -} +/* --------------------------- Raw Event Type Mapping --------------------------- */ -/// Types of events that can be delivered. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[repr(u32)] pub enum EventType { @@ -318,7 +95,6 @@ pub enum EventType { WindowICCProfileChanged = sys::events::SDL_EVENT_WINDOW_ICCPROF_CHANGED.0, WindowDisplayChanged = sys::events::SDL_EVENT_WINDOW_DISPLAY_CHANGED.0, - // TODO: SysWM = sys::events::SDL_EVENT_SYSWM .0, KeyDown = sys::events::SDL_EVENT_KEY_DOWN.0, KeyUp = sys::events::SDL_EVENT_KEY_UP.0, TextEditing = sys::events::SDL_EVENT_TEXT_EDITING.0, @@ -351,7 +127,7 @@ pub enum EventType { FingerDown = sys::events::SDL_EVENT_FINGER_DOWN.0, FingerUp = sys::events::SDL_EVENT_FINGER_UP.0, FingerMotion = sys::events::SDL_EVENT_FINGER_MOTION.0, - // gestures have been removed from SD3: https://github.com/libsdl-org/SDL_gesture + ClipboardUpdate = sys::events::SDL_EVENT_CLIPBOARD_UPDATE.0, DropFile = sys::events::SDL_EVENT_DROP_FILE.0, DropText = sys::events::SDL_EVENT_DROP_TEXT.0, @@ -376,7 +152,6 @@ pub enum EventType { User = sys::events::SDL_EVENT_USER.0, Last = sys::events::SDL_EVENT_LAST.0, } - impl From for u32 { fn from(t: EventType) -> u32 { t as u32 @@ -390,378 +165,247 @@ impl From for SDL_EventType { impl TryFrom for EventType { type Error = (); - fn try_from(n: u32) -> Result { - use self::EventType::*; use crate::sys::events::*; - Ok(match SDL_EventType(n) { - SDL_EVENT_FIRST => First, - - SDL_EVENT_QUIT => Quit, - SDL_EVENT_TERMINATING => AppTerminating, - SDL_EVENT_LOW_MEMORY => AppLowMemory, - SDL_EVENT_WILL_ENTER_BACKGROUND => AppWillEnterBackground, - SDL_EVENT_DID_ENTER_BACKGROUND => AppDidEnterBackground, - SDL_EVENT_WILL_ENTER_FOREGROUND => AppWillEnterForeground, - SDL_EVENT_DID_ENTER_FOREGROUND => AppDidEnterForeground, - - SDL_EVENT_DISPLAY_ADDED => DisplayAdded, - SDL_EVENT_DISPLAY_REMOVED => DisplayRemoved, - SDL_EVENT_DISPLAY_ORIENTATION => DisplayOrientation, - SDL_EVENT_DISPLAY_MOVED => DisplayMoved, - SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED => DisplayDesktopModeChanged, - SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED => DisplayCurrentModeChanged, - SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED => DisplayContentScaleChanged, - - SDL_EVENT_WINDOW_SHOWN => WindowShown, - SDL_EVENT_WINDOW_HIDDEN => WindowHidden, - SDL_EVENT_WINDOW_EXPOSED => WindowExposed, - SDL_EVENT_WINDOW_MOVED => WindowMoved, - SDL_EVENT_WINDOW_RESIZED => WindowResized, - SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED => WindowPixelSizeChanged, - SDL_EVENT_WINDOW_MINIMIZED => WindowMinimized, - SDL_EVENT_WINDOW_MAXIMIZED => WindowMaximized, - SDL_EVENT_WINDOW_RESTORED => WindowRestored, - SDL_EVENT_WINDOW_MOUSE_ENTER => WindowMouseEnter, - SDL_EVENT_WINDOW_MOUSE_LEAVE => WindowMouseLeave, - SDL_EVENT_WINDOW_FOCUS_GAINED => WindowFocusGained, - SDL_EVENT_WINDOW_FOCUS_LOST => WindowFocusLost, - SDL_EVENT_WINDOW_CLOSE_REQUESTED => WindowCloseRequested, - - SDL_EVENT_KEY_DOWN => KeyDown, - SDL_EVENT_KEY_UP => KeyUp, - SDL_EVENT_TEXT_EDITING => TextEditing, - SDL_EVENT_TEXT_INPUT => TextInput, - - SDL_EVENT_MOUSE_MOTION => MouseMotion, - SDL_EVENT_MOUSE_BUTTON_DOWN => MouseButtonDown, - SDL_EVENT_MOUSE_BUTTON_UP => MouseButtonUp, - SDL_EVENT_MOUSE_WHEEL => MouseWheel, - - SDL_EVENT_JOYSTICK_AXIS_MOTION => JoyAxisMotion, - SDL_EVENT_JOYSTICK_HAT_MOTION => JoyHatMotion, - SDL_EVENT_JOYSTICK_BUTTON_DOWN => JoyButtonDown, - SDL_EVENT_JOYSTICK_BUTTON_UP => JoyButtonUp, - SDL_EVENT_JOYSTICK_ADDED => JoyDeviceAdded, - SDL_EVENT_JOYSTICK_REMOVED => JoyDeviceRemoved, - - SDL_EVENT_GAMEPAD_AXIS_MOTION => ControllerAxisMotion, - SDL_EVENT_GAMEPAD_BUTTON_DOWN => ControllerButtonDown, - SDL_EVENT_GAMEPAD_BUTTON_UP => ControllerButtonUp, - SDL_EVENT_GAMEPAD_ADDED => ControllerDeviceAdded, - SDL_EVENT_GAMEPAD_REMOVED => ControllerDeviceRemoved, - SDL_EVENT_GAMEPAD_REMAPPED => ControllerDeviceRemapped, - SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN => ControllerTouchpadDown, - SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION => ControllerTouchpadMotion, - SDL_EVENT_GAMEPAD_TOUCHPAD_UP => ControllerTouchpadUp, + SDL_EVENT_FIRST => EventType::First, + + SDL_EVENT_QUIT => EventType::Quit, + SDL_EVENT_TERMINATING => EventType::AppTerminating, + SDL_EVENT_LOW_MEMORY => EventType::AppLowMemory, + SDL_EVENT_WILL_ENTER_BACKGROUND => EventType::AppWillEnterBackground, + SDL_EVENT_DID_ENTER_BACKGROUND => EventType::AppDidEnterBackground, + SDL_EVENT_WILL_ENTER_FOREGROUND => EventType::AppWillEnterForeground, + SDL_EVENT_DID_ENTER_FOREGROUND => EventType::AppDidEnterForeground, + + SDL_EVENT_DISPLAY_ADDED => EventType::DisplayAdded, + SDL_EVENT_DISPLAY_REMOVED => EventType::DisplayRemoved, + SDL_EVENT_DISPLAY_ORIENTATION => EventType::DisplayOrientation, + SDL_EVENT_DISPLAY_MOVED => EventType::DisplayMoved, + SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED => EventType::DisplayDesktopModeChanged, + SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED => EventType::DisplayCurrentModeChanged, + SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED => EventType::DisplayContentScaleChanged, + + SDL_EVENT_WINDOW_SHOWN => EventType::WindowShown, + SDL_EVENT_WINDOW_HIDDEN => EventType::WindowHidden, + SDL_EVENT_WINDOW_EXPOSED => EventType::WindowExposed, + SDL_EVENT_WINDOW_MOVED => EventType::WindowMoved, + SDL_EVENT_WINDOW_RESIZED => EventType::WindowResized, + SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED => EventType::WindowPixelSizeChanged, + SDL_EVENT_WINDOW_MINIMIZED => EventType::WindowMinimized, + SDL_EVENT_WINDOW_MAXIMIZED => EventType::WindowMaximized, + SDL_EVENT_WINDOW_RESTORED => EventType::WindowRestored, + SDL_EVENT_WINDOW_MOUSE_ENTER => EventType::WindowMouseEnter, + SDL_EVENT_WINDOW_MOUSE_LEAVE => EventType::WindowMouseLeave, + SDL_EVENT_WINDOW_FOCUS_GAINED => EventType::WindowFocusGained, + SDL_EVENT_WINDOW_FOCUS_LOST => EventType::WindowFocusLost, + SDL_EVENT_WINDOW_CLOSE_REQUESTED => EventType::WindowCloseRequested, + SDL_EVENT_WINDOW_HIT_TEST => EventType::WindowHitTest, + SDL_EVENT_WINDOW_ICCPROF_CHANGED => EventType::WindowICCProfileChanged, + SDL_EVENT_WINDOW_DISPLAY_CHANGED => EventType::WindowDisplayChanged, + + SDL_EVENT_KEY_DOWN => EventType::KeyDown, + SDL_EVENT_KEY_UP => EventType::KeyUp, + SDL_EVENT_TEXT_EDITING => EventType::TextEditing, + SDL_EVENT_TEXT_INPUT => EventType::TextInput, + + SDL_EVENT_MOUSE_MOTION => EventType::MouseMotion, + SDL_EVENT_MOUSE_BUTTON_DOWN => EventType::MouseButtonDown, + SDL_EVENT_MOUSE_BUTTON_UP => EventType::MouseButtonUp, + SDL_EVENT_MOUSE_WHEEL => EventType::MouseWheel, + + SDL_EVENT_JOYSTICK_AXIS_MOTION => EventType::JoyAxisMotion, + SDL_EVENT_JOYSTICK_HAT_MOTION => EventType::JoyHatMotion, + SDL_EVENT_JOYSTICK_BUTTON_DOWN => EventType::JoyButtonDown, + SDL_EVENT_JOYSTICK_BUTTON_UP => EventType::JoyButtonUp, + SDL_EVENT_JOYSTICK_ADDED => EventType::JoyDeviceAdded, + SDL_EVENT_JOYSTICK_REMOVED => EventType::JoyDeviceRemoved, + + SDL_EVENT_GAMEPAD_AXIS_MOTION => EventType::ControllerAxisMotion, + SDL_EVENT_GAMEPAD_BUTTON_DOWN => EventType::ControllerButtonDown, + SDL_EVENT_GAMEPAD_BUTTON_UP => EventType::ControllerButtonUp, + SDL_EVENT_GAMEPAD_ADDED => EventType::ControllerDeviceAdded, + SDL_EVENT_GAMEPAD_REMOVED => EventType::ControllerDeviceRemoved, + SDL_EVENT_GAMEPAD_REMAPPED => EventType::ControllerDeviceRemapped, + SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN => EventType::ControllerTouchpadDown, + SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION => EventType::ControllerTouchpadMotion, + SDL_EVENT_GAMEPAD_TOUCHPAD_UP => EventType::ControllerTouchpadUp, #[cfg(feature = "hidapi")] - SDL_EVENT_GAMEPAD_SENSOR_UPDATE => ControllerSensorUpdated, - - SDL_EVENT_FINGER_DOWN => FingerDown, - SDL_EVENT_FINGER_UP => FingerUp, - SDL_EVENT_FINGER_MOTION => FingerMotion, - - SDL_EVENT_CLIPBOARD_UPDATE => ClipboardUpdate, - SDL_EVENT_DROP_FILE => DropFile, - SDL_EVENT_DROP_TEXT => DropText, - SDL_EVENT_DROP_BEGIN => DropBegin, - SDL_EVENT_DROP_COMPLETE => DropComplete, - - SDL_EVENT_AUDIO_DEVICE_ADDED => AudioDeviceAdded, - SDL_EVENT_AUDIO_DEVICE_REMOVED => AudioDeviceRemoved, - - SDL_EVENT_PEN_PROXIMITY_IN => PenProximityIn, - SDL_EVENT_PEN_PROXIMITY_OUT => PenProximityOut, - SDL_EVENT_PEN_DOWN => PenDown, - SDL_EVENT_PEN_UP => PenUp, - SDL_EVENT_PEN_BUTTON_UP => PenButtonUp, - SDL_EVENT_PEN_BUTTON_DOWN => PenButtonDown, - SDL_EVENT_PEN_MOTION => PenMotion, - SDL_EVENT_PEN_AXIS => PenAxis, - - SDL_EVENT_RENDER_TARGETS_RESET => RenderTargetsReset, - SDL_EVENT_RENDER_DEVICE_RESET => RenderDeviceReset, - - SDL_EVENT_USER => User, - SDL_EVENT_LAST => Last, - + SDL_EVENT_GAMEPAD_SENSOR_UPDATE => EventType::ControllerSensorUpdated, + + SDL_EVENT_FINGER_DOWN => EventType::FingerDown, + SDL_EVENT_FINGER_UP => EventType::FingerUp, + SDL_EVENT_FINGER_MOTION => EventType::FingerMotion, + + SDL_EVENT_CLIPBOARD_UPDATE => EventType::ClipboardUpdate, + SDL_EVENT_DROP_FILE => EventType::DropFile, + SDL_EVENT_DROP_TEXT => EventType::DropText, + SDL_EVENT_DROP_BEGIN => EventType::DropBegin, + SDL_EVENT_DROP_COMPLETE => EventType::DropComplete, + + SDL_EVENT_AUDIO_DEVICE_ADDED => EventType::AudioDeviceAdded, + SDL_EVENT_AUDIO_DEVICE_REMOVED => EventType::AudioDeviceRemoved, + + SDL_EVENT_PEN_PROXIMITY_IN => EventType::PenProximityIn, + SDL_EVENT_PEN_PROXIMITY_OUT => EventType::PenProximityOut, + SDL_EVENT_PEN_DOWN => EventType::PenDown, + SDL_EVENT_PEN_UP => EventType::PenUp, + SDL_EVENT_PEN_BUTTON_UP => EventType::PenButtonUp, + SDL_EVENT_PEN_BUTTON_DOWN => EventType::PenButtonDown, + SDL_EVENT_PEN_MOTION => EventType::PenMotion, + SDL_EVENT_PEN_AXIS => EventType::PenAxis, + + SDL_EVENT_RENDER_TARGETS_RESET => EventType::RenderTargetsReset, + SDL_EVENT_RENDER_DEVICE_RESET => EventType::RenderDeviceReset, + + SDL_EVENT_USER => EventType::User, + SDL_EVENT_LAST => EventType::Last, _ => return Err(()), }) } } -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -/// An enum of display events. -pub enum DisplayEvent { - None, - Orientation(Orientation), - Added, - Removed, - Moved, - DesktopModeChanged, - CurrentModeChanged, - ContentScaleChanged, -} - -impl DisplayEvent { - #[allow(clippy::match_same_arms)] - fn from_ll(id: u32, data1: i32) -> DisplayEvent { - match unsafe { transmute(id) } { - sys::events::SDL_EVENT_DISPLAY_ORIENTATION => { - let orientation = if data1 > SDL_DisplayOrientation::PORTRAIT_FLIPPED.0 { - Orientation::Unknown - } else { - let sdl_orientation = SDL_DisplayOrientation(data1); - Orientation::from_ll(sdl_orientation) - }; - DisplayEvent::Orientation(orientation) - } - sys::events::SDL_EVENT_DISPLAY_ADDED => DisplayEvent::Added, - sys::events::SDL_EVENT_DISPLAY_REMOVED => DisplayEvent::Removed, - sys::events::SDL_EVENT_DISPLAY_MOVED => DisplayEvent::Moved, - sys::events::SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED => DisplayEvent::DesktopModeChanged, - sys::events::SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED => DisplayEvent::CurrentModeChanged, - sys::events::SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED => { - DisplayEvent::ContentScaleChanged - } - _ => DisplayEvent::None, - } - } - - fn to_ll(self) -> (u32, i32) { - match self { - DisplayEvent::Orientation(orientation) => ( - sys::events::SDL_EVENT_DISPLAY_ORIENTATION.into(), - orientation.to_ll().into(), - ), - DisplayEvent::Added => (sys::events::SDL_EVENT_DISPLAY_ADDED.into(), 0), - DisplayEvent::Removed => (sys::events::SDL_EVENT_DISPLAY_REMOVED.into(), 0), - DisplayEvent::None => panic!("DisplayEvent::None cannot be converted"), - DisplayEvent::Moved => (sys::events::SDL_EVENT_DISPLAY_MOVED.into(), 0), - DisplayEvent::DesktopModeChanged => ( - sys::events::SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED.into(), - 0, - ), - DisplayEvent::CurrentModeChanged => ( - sys::events::SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED.into(), - 0, - ), - DisplayEvent::ContentScaleChanged => ( - sys::events::SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED.into(), - 0, - ), - } - } - - pub fn is_same_kind_as(&self, other: &DisplayEvent) -> bool { - matches!( - (self, other), - (Self::None, Self::None) - | (Self::Orientation(_), Self::Orientation(_)) - | (Self::Added, Self::Added) - | (Self::Removed, Self::Removed) - ) - } -} +/* --------------------------- Hierarchical Kinds --------------------------- */ -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -/// An enum of window events. -pub enum WindowEvent { - None, - Shown, - Hidden, - Exposed, - Moved(i32, i32), - Resized(i32, i32), - PixelSizeChanged(i32, i32), - Minimized, - Maximized, - Restored, - MouseEnter, - MouseLeave, - FocusGained, - FocusLost, - CloseRequested, - HitTest(i32, i32), - ICCProfChanged, - DisplayChanged(i32), +#[derive(Clone, Debug, PartialEq)] +pub struct QuitEvent { + pub timestamp: u64, } -impl WindowEvent { - #[allow(clippy::match_same_arms)] - fn from_ll(id: u32, data1: i32, data2: i32) -> WindowEvent { - match EventType::try_from(id) { - Ok(ev) => match ev { - EventType::WindowShown => WindowEvent::Shown, - EventType::WindowHidden => WindowEvent::Hidden, - EventType::WindowExposed => WindowEvent::Exposed, - EventType::WindowMoved => WindowEvent::Moved(data1, data2), - EventType::WindowResized => WindowEvent::Resized(data1, data2), - EventType::WindowPixelSizeChanged => WindowEvent::PixelSizeChanged(data1, data2), - EventType::WindowMinimized => WindowEvent::Minimized, - EventType::WindowMaximized => WindowEvent::Maximized, - EventType::WindowRestored => WindowEvent::Restored, - EventType::WindowMouseEnter => WindowEvent::MouseEnter, - EventType::WindowMouseLeave => WindowEvent::MouseLeave, - EventType::WindowFocusGained => WindowEvent::FocusGained, - EventType::WindowFocusLost => WindowEvent::FocusLost, - EventType::WindowCloseRequested => WindowEvent::CloseRequested, - EventType::WindowHitTest => WindowEvent::HitTest(data1, data2), - EventType::WindowICCProfileChanged => WindowEvent::ICCProfChanged, - EventType::WindowDisplayChanged => WindowEvent::DisplayChanged(data1), - _ => WindowEvent::None, - }, - Err(_) => WindowEvent::None, - } - } - - fn to_ll(self) -> (EventType, i32, i32) { - match self { - WindowEvent::None => panic!("Cannot convert WindowEvent::None"), - WindowEvent::Shown => (EventType::WindowShown, 0, 0), - WindowEvent::Hidden => (EventType::WindowHidden, 0, 0), - WindowEvent::Exposed => (EventType::WindowExposed, 0, 0), - WindowEvent::Moved(d1, d2) => (EventType::WindowMoved, d1, d2), - WindowEvent::Resized(d1, d2) => (EventType::WindowResized, d1, d2), - WindowEvent::PixelSizeChanged(d1, d2) => (EventType::WindowPixelSizeChanged, d1, d2), - WindowEvent::Minimized => (EventType::WindowMinimized, 0, 0), - WindowEvent::Maximized => (EventType::WindowMaximized, 0, 0), - WindowEvent::Restored => (EventType::WindowRestored, 0, 0), - WindowEvent::MouseEnter => (EventType::WindowMouseEnter, 0, 0), - WindowEvent::MouseLeave => (EventType::WindowMouseLeave, 0, 0), - WindowEvent::FocusGained => (EventType::WindowFocusGained, 0, 0), - WindowEvent::FocusLost => (EventType::WindowFocusLost, 0, 0), - WindowEvent::CloseRequested => (EventType::WindowCloseRequested, 0, 0), - WindowEvent::HitTest(d1, d2) => (EventType::WindowHitTest, d1, d2), - WindowEvent::ICCProfChanged => (EventType::WindowICCProfileChanged, 0, 0), - WindowEvent::DisplayChanged(d1) => (EventType::WindowDisplayChanged, d1, 0), - } - } - - pub fn is_same_kind_as(&self, other: &WindowEvent) -> bool { - matches!( - (self, other), - (Self::None, Self::None) - | (Self::Shown, Self::Shown) - | (Self::Hidden, Self::Hidden) - | (Self::Exposed, Self::Exposed) - | (Self::Moved(_, _), Self::Moved(_, _)) - | (Self::Resized(_, _), Self::Resized(_, _)) - | (Self::PixelSizeChanged(_, _), Self::PixelSizeChanged(_, _)) - | (Self::Minimized, Self::Minimized) - | (Self::Maximized, Self::Maximized) - | (Self::Restored, Self::Restored) - | (Self::MouseEnter, Self::MouseEnter) - | (Self::MouseLeave, Self::MouseLeave) - | (Self::FocusGained, Self::FocusGained) - | (Self::FocusLost, Self::FocusLost) - | (Self::CloseRequested, Self::CloseRequested) - | (Self::HitTest(_, _), Self::HitTest(_, _)) - | (Self::ICCProfChanged, Self::ICCProfChanged) - | (Self::DisplayChanged(_), Self::DisplayChanged(_)) - ) - } +#[derive(Clone, Debug, PartialEq)] +pub enum AppEvent { + Terminating { timestamp: u64 }, + LowMemory { timestamp: u64 }, + WillEnterBackground { timestamp: u64 }, + DidEnterBackground { timestamp: u64 }, + WillEnterForeground { timestamp: u64 }, + DidEnterForeground { timestamp: u64 }, } -#[derive(Clone, PartialEq, Debug)] -/// Different event types. -pub enum Event { - Quit { +#[derive(Clone, Debug, PartialEq)] +pub enum DisplayEvent { + Orientation { timestamp: u64, + display: Display, + orientation: Orientation, }, - AppTerminating { + Added { timestamp: u64, + display: Display, }, - AppLowMemory { + Removed { timestamp: u64, + display: Display, }, - AppWillEnterBackground { + Moved { timestamp: u64, + display: Display, }, - AppDidEnterBackground { + DesktopModeChanged { timestamp: u64, + display: Display, }, - AppWillEnterForeground { + CurrentModeChanged { timestamp: u64, + display: Display, }, - AppDidEnterForeground { + ContentScaleChanged { timestamp: u64, + display: Display, }, +} - Window { - timestamp: u64, - window_id: u32, - win_event: WindowEvent, - }, +#[derive(Clone, Debug, PartialEq)] +pub struct WindowEvent { + pub timestamp: u64, + pub window_id: u32, + pub kind: WindowEventKind, +} +#[derive(Clone, Debug, PartialEq)] +pub enum WindowEventKind { + Shown, + Hidden, + Exposed, + Moved { x: i32, y: i32 }, + Resized { w: i32, h: i32 }, + PixelSizeChanged { w: i32, h: i32 }, + Minimized, + Maximized, + Restored, + MouseEnter, + MouseLeave, + FocusGained, + FocusLost, + CloseRequested, + HitTest { data1: i32, data2: i32 }, + ICCProfileChanged, + DisplayChanged { display_index: i32 }, +} - // TODO: SysWMEvent - KeyDown { - timestamp: u64, - window_id: u32, - keycode: Option, - scancode: Option, - keymod: Mod, - repeat: bool, - which: u32, - raw: Uint16, - }, - KeyUp { - timestamp: u64, - window_id: u32, - keycode: Option, - scancode: Option, - keymod: Mod, - repeat: bool, - which: u32, - raw: Uint16, - }, +#[derive(Clone, Debug, PartialEq)] +pub enum KeyState { + Down, + Up, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct KeyboardEvent { + pub timestamp: u64, + pub window_id: u32, + pub state: KeyState, + pub keycode: Option, + pub scancode: Option, + pub keymod: Mod, + pub repeat: bool, + pub which: u32, + pub raw: Uint16, +} - TextEditing { +#[derive(Clone, Debug, PartialEq)] +pub enum TextEvent { + Editing { timestamp: u64, window_id: u32, text: String, start: i32, length: i32, }, - - TextInput { + Input { timestamp: u64, window_id: u32, text: String, }, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum MouseButtonState { + Down, + Up, +} - MouseMotion { +#[derive(Clone, Debug, PartialEq)] +pub enum MouseEvent { + Motion { timestamp: u64, window_id: u32, which: u32, - mousestate: MouseState, + state: MouseState, x: f32, y: f32, xrel: f32, yrel: f32, }, - - MouseButtonDown { - timestamp: u64, - window_id: u32, - which: u32, - mouse_btn: MouseButton, - clicks: u8, - x: f32, - y: f32, - }, - MouseButtonUp { + Button { timestamp: u64, window_id: u32, which: u32, - mouse_btn: MouseButton, + button: MouseButton, clicks: u8, + state: MouseButtonState, x: f32, y: f32, }, - - MouseWheel { + Wheel { timestamp: u64, window_id: u32, which: u32, @@ -771,163 +415,115 @@ pub enum Event { mouse_x: f32, mouse_y: f32, }, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum JoyButtonState { + Down, + Up, +} - JoyAxisMotion { +#[derive(Clone, Debug, PartialEq)] +pub enum JoyDeviceChange { + Added, + Removed, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum JoystickEvent { + Axis { timestamp: u64, - /// The joystick's `id` which: u32, - axis_idx: u8, + axis_index: u8, value: i16, }, - - JoyHatMotion { + Hat { timestamp: u64, - /// The joystick's `id` which: u32, - hat_idx: u8, + hat_index: u8, state: HatState, }, - - JoyButtonDown { + Button { timestamp: u64, - /// The joystick's `id` which: u32, - button_idx: u8, + button_index: u8, + state: JoyButtonState, }, - JoyButtonUp { + Device { timestamp: u64, - /// The joystick's `id` which: u32, - button_idx: u8, + change: JoyDeviceChange, }, +} - JoyDeviceAdded { - timestamp: u64, - /// The newly added joystick's `joystick_index` - which: u32, - }, - JoyDeviceRemoved { - timestamp: u64, - /// The joystick's `id` - which: u32, - }, +#[derive(Clone, Debug, PartialEq)] +pub enum ControllerButtonState { + Down, + Up, +} - ControllerAxisMotion { - timestamp: u64, - /// The controller's joystick `id` - which: u32, - axis: Axis, - value: i16, - }, +#[derive(Clone, Debug, PartialEq)] +pub enum ControllerDeviceChange { + Added, + Removed, + Remapped, +} - ControllerButtonDown { - timestamp: u64, - /// The controller's joystick `id` - which: u32, - button: Button, - }, - ControllerButtonUp { - timestamp: u64, - /// The controller's joystick `id` - which: u32, - button: Button, - }, +#[derive(Clone, Debug, PartialEq)] +pub enum ControllerTouchpadKind { + Down, + Motion, + Up, +} - ControllerDeviceAdded { - timestamp: u64, - /// The newly added controller's `joystick_index` - which: u32, - }, - ControllerDeviceRemoved { - timestamp: u64, - /// The controller's joystick `id` - which: u32, - }, - ControllerDeviceRemapped { +#[derive(Clone, Debug, PartialEq)] +pub enum ControllerEvent { + Axis { timestamp: u64, - /// The controller's joystick `id` which: u32, + axis: GamepadAxis, + value: i16, }, - - ControllerTouchpadDown { + Button { timestamp: u64, - /// The joystick instance id which: u32, - /// The index of the touchpad - touchpad: i32, - /// The index of the finger on the touchpad - finger: i32, - /// Normalized in the range 0...1 with 0 being on the left - x: f32, - /// Normalized in the range 0...1 with 0 being at the top - y: f32, - /// Normalized in the range 0...1 - pressure: f32, + button: GamepadButton, + state: ControllerButtonState, }, - ControllerTouchpadMotion { + Device { timestamp: u64, - /// The joystick instance id which: u32, - /// The index of the touchpad - touchpad: i32, - /// The index of the finger on the touchpad - finger: i32, - /// Normalized in the range 0...1 with 0 being on the left - x: f32, - /// Normalized in the range 0...1 with 0 being at the top - y: f32, - /// Normalized in the range 0...1 - pressure: f32, + change: ControllerDeviceChange, }, - ControllerTouchpadUp { + Touchpad { timestamp: u64, - /// The joystick instance id which: u32, - /// The index of the touchpad touchpad: i32, - /// The index of the finger on the touchpad finger: i32, - /// Normalized in the range 0...1 with 0 being on the left + kind: ControllerTouchpadKind, x: f32, - /// Normalized in the range 0...1 with 0 being at the top y: f32, - /// Normalized in the range 0...1 pressure: f32, }, - - /// Triggered when the gyroscope or accelerometer is updated #[cfg(feature = "hidapi")] - ControllerSensorUpdated { + Sensor { timestamp: u64, which: u32, sensor: crate::sensor::SensorType, - /// Data from the sensor. - /// - /// See the `sensor` module for more information. data: [f32; 3], }, +} - FingerDown { - timestamp: u64, - touch_id: u64, - finger_id: u64, - x: f32, - y: f32, - dx: f32, - dy: f32, - pressure: f32, - }, - FingerUp { - timestamp: u64, - touch_id: u64, - finger_id: u64, - x: f32, - y: f32, - dx: f32, - dy: f32, - pressure: f32, - }, - FingerMotion { +#[derive(Clone, Debug, PartialEq)] +pub enum FingerState { + Down, + Up, + Motion, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum TouchEvent { + Finger { timestamp: u64, touch_id: u64, finger_id: u64, @@ -936,739 +532,1126 @@ pub enum Event { dx: f32, dy: f32, pressure: f32, + state: FingerState, }, +} - DollarRecord { - timestamp: u64, - touch_id: i64, - gesture_id: i64, - num_fingers: u32, - error: f32, - x: f32, - y: f32, - }, - - MultiGesture { - timestamp: u64, - touch_id: i64, - d_theta: f32, - d_dist: f32, - x: f32, - y: f32, - num_fingers: u16, - }, - - ClipboardUpdate { - timestamp: u64, - }, - - DropFile { +#[derive(Clone, Debug, PartialEq)] +pub enum DropEvent { + File { timestamp: u64, window_id: u32, filename: String, }, - DropText { + Text { timestamp: u64, window_id: u32, - filename: String, + text: String, }, - DropBegin { + Begin { timestamp: u64, window_id: u32, }, - DropComplete { + Complete { timestamp: u64, window_id: u32, }, +} - AudioDeviceAdded { +#[derive(Clone, Debug, PartialEq)] +pub enum AudioDeviceEvent { + Added { timestamp: u64, which: u32, iscapture: bool, }, - AudioDeviceRemoved { + Removed { timestamp: u64, which: u32, iscapture: bool, }, +} - PenProximityIn { - timestamp: u64, - which: u32, - window: u32, - }, - PenProximityOut { - timestamp: u64, - which: u32, - window: u32, - }, - PenDown { +#[derive(Clone, Debug, PartialEq)] +pub enum PenButtonState { + Down, + Up, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum PenProximityState { + In, + Out, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum PenEvent { + Proximity { timestamp: u64, which: u32, - window: u32, - x: f32, - y: f32, - eraser: bool, + window_id: u32, + state: PenProximityState, }, - PenUp { + Touch { timestamp: u64, which: u32, - window: u32, + window_id: u32, x: f32, y: f32, eraser: bool, + down: bool, }, - PenMotion { + Motion { timestamp: u64, which: u32, - window: u32, - x: f32, - y: f32, - }, - PenButtonUp { - timestamp: u64, - which: u32, - window: u32, + window_id: u32, x: f32, y: f32, - button: u8, }, - PenButtonDown { + Button { timestamp: u64, which: u32, - window: u32, + window_id: u32, x: f32, y: f32, button: u8, + state: PenButtonState, }, - PenAxis { + Axis { timestamp: u64, which: u32, - window: u32, + window_id: u32, x: f32, y: f32, axis: PenAxis, value: f32, }, +} - RenderTargetsReset { - timestamp: u64, - }, - RenderDeviceReset { - timestamp: u64, - }, +#[derive(Clone, Debug, PartialEq)] +pub enum RenderEvent { + TargetsReset { timestamp: u64 }, + DeviceReset { timestamp: u64 }, +} - User { - timestamp: u64, - window_id: u32, - type_: u32, - code: i32, - data1: *mut c_void, - data2: *mut c_void, - }, +#[derive(Clone, Debug, PartialEq)] +pub struct UserEvent { + pub timestamp: u64, + pub window_id: u32, + pub type_id: u32, + pub code: i32, + pub data1: *mut c_void, + pub data2: *mut c_void, +} - Unknown { - timestamp: u64, - type_: u32, - }, +#[derive(Clone, Debug, PartialEq)] +pub struct UnknownEvent { + pub timestamp: u64, + pub raw_type: u32, +} - Display { - timestamp: u64, - display: Display, - display_event: DisplayEvent, - }, +/* --------------------------- Top-Level Event --------------------------- */ + +#[derive(Clone, Debug, PartialEq)] +pub enum Event { + Quit(QuitEvent), + App(AppEvent), + Display(DisplayEvent), + Window(WindowEvent), + Keyboard(KeyboardEvent), + Text(TextEvent), + Mouse(MouseEvent), + Joystick(JoystickEvent), + Controller(ControllerEvent), + Touch(TouchEvent), + Drop(DropEvent), + Audio(AudioDeviceEvent), + Pen(PenEvent), + Render(RenderEvent), + User(UserEvent), + Unknown(UnknownEvent), } -/// This does not auto-derive because `User`'s `data` fields can be used to -/// store pointers to types that are `!Send`. Dereferencing these as pointers -/// requires using `unsafe` and ensuring your own safety guarantees. unsafe impl Send for Event {} - -/// This does not auto-derive because `User`'s `data` fields can be used to -/// store pointers to types that are `!Sync`. Dereferencing these as pointers -/// requires using `unsafe` and ensuring your own safety guarantees. unsafe impl Sync for Event {} -// TODO: Remove this when from_utf8 is updated in Rust -// This would honestly be nice if it took &self instead of self, -// but Event::User's raw pointers kind of removes that possibility. -impl Event { - fn to_ll(&self) -> Option { - let mut ret = mem::MaybeUninit::uninit(); - match *self { - Event::User { - window_id, - type_, - code, - data1, - data2, - timestamp, - } => { - let event = sys::events::SDL_UserEvent { - r#type: type_, - timestamp, - windowID: window_id, - code, - data1, - data2, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_UserEvent, - 1, - ); - Some(ret.assume_init()) - } - } +/* --------------------------- Conversion Helpers --------------------------- */ - Event::Quit { timestamp } => { - let event = sys::events::SDL_QuitEvent { - r#type: sys::events::SDL_EVENT_QUIT, - timestamp, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_QuitEvent, - 1, - ); - Some(ret.assume_init()) - } - } +pub struct OwnedRawEvent { + pub event: SDL_Event, + // Hold CStrings to keep their memory alive while SDL may read the pointers. + _buffers: Vec, +} - Event::Window { - timestamp, - window_id, - win_event, - } => { - let (win_event_id, data1, data2) = win_event.to_ll(); - let event = sys::events::SDL_WindowEvent { - r#type: win_event_id.into(), - timestamp, - windowID: window_id, - data1, - data2, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_WindowEvent, - 1, - ); - Some(ret.assume_init()) - } - } +impl Drop for OwnedRawEvent { + fn drop(&mut self) { + // Pointers become invalid automatically when CStrings drop. + } +} - Event::KeyDown { - timestamp, - window_id, - keycode, - scancode, - keymod, - repeat, - which, - raw, - } => { - let event = SDL_KeyboardEvent { - r#type: sys::events::SDL_EVENT_KEY_DOWN, - timestamp, - windowID: window_id, - repeat, - reserved: 0, - scancode: scancode?.into(), - which, - down: true, - key: keycode?.into(), - r#mod: keymod.bits(), - raw, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_KeyboardEvent, - 1, - ); - Some(ret.assume_init()) - } - } - Event::KeyUp { - timestamp, - window_id, - keycode, - scancode, - keymod, - repeat, - which, - raw, - } => { - let event = SDL_KeyboardEvent { - r#type: sys::events::SDL_EVENT_KEY_UP, - timestamp, - windowID: window_id, - repeat, - reserved: 0, - scancode: scancode?.into(), - which, - down: false, - key: keycode?.into(), - r#mod: keymod.bits(), - raw, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_KeyboardEvent, - 1, - ); - Some(ret.assume_init()) - } - } - Event::MouseMotion { - timestamp, - window_id, - which, - mousestate, - x, - y, - xrel, - yrel, - } => { - let state = mousestate.to_sdl_state(); - let event = SDL_MouseMotionEvent { - r#type: sys::events::SDL_EVENT_MOUSE_MOTION, - timestamp, - windowID: window_id, - which, - state, - x, - y, - xrel, - yrel, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_MouseMotionEvent, - 1, - ); - Some(ret.assume_init()) - } - } - Event::MouseButtonDown { - timestamp, - window_id, - which, - mouse_btn, - clicks, - x, - y, - } => { - let event = SDL_MouseButtonEvent { - r#type: sys::events::SDL_EVENT_MOUSE_BUTTON_DOWN, - timestamp, - windowID: window_id, - which, - button: mouse_btn as u8, - down: true, - clicks, - x, - y, - padding: 0, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_MouseButtonEvent, - 1, - ); - Some(ret.assume_init()) - } - } - Event::MouseButtonUp { - timestamp, - window_id, - which, - mouse_btn, - clicks, - x, - y, - } => { - let event = sys::events::SDL_MouseButtonEvent { - r#type: sys::events::SDL_EVENT_MOUSE_BUTTON_UP, - timestamp, - windowID: window_id, - which, - button: mouse_btn as u8, - clicks, - padding: 0, - x, - y, - down: false, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_MouseButtonEvent, - 1, - ); - Some(ret.assume_init()) +impl Event { + pub fn get_timestamp(&self) -> u64 { + match self { + Event::Quit(QuitEvent { timestamp }) => *timestamp, + Event::App(a) => match a { + AppEvent::Terminating { timestamp } + | AppEvent::LowMemory { timestamp } + | AppEvent::WillEnterBackground { timestamp } + | AppEvent::DidEnterBackground { timestamp } + | AppEvent::WillEnterForeground { timestamp } + | AppEvent::DidEnterForeground { timestamp } => *timestamp, + }, + Event::Display(d) => match d { + DisplayEvent::Orientation { timestamp, .. } + | DisplayEvent::Added { timestamp, .. } + | DisplayEvent::Removed { timestamp, .. } + | DisplayEvent::Moved { timestamp, .. } + | DisplayEvent::DesktopModeChanged { timestamp, .. } + | DisplayEvent::CurrentModeChanged { timestamp, .. } + | DisplayEvent::ContentScaleChanged { timestamp, .. } => *timestamp, + }, + Event::Window(w) => w.timestamp, + Event::Keyboard(k) => k.timestamp, + Event::Text(t) => match t { + TextEvent::Editing { timestamp, .. } | TextEvent::Input { timestamp, .. } => { + *timestamp } - } + }, + Event::Mouse(m) => match m { + MouseEvent::Motion { timestamp, .. } + | MouseEvent::Button { timestamp, .. } + | MouseEvent::Wheel { timestamp, .. } => *timestamp, + }, + Event::Joystick(j) => match j { + JoystickEvent::Axis { timestamp, .. } + | JoystickEvent::Hat { timestamp, .. } + | JoystickEvent::Button { timestamp, .. } + | JoystickEvent::Device { timestamp, .. } => *timestamp, + }, + Event::Controller(c) => match c { + ControllerEvent::Axis { timestamp, .. } => *timestamp, + ControllerEvent::Button { timestamp, .. } => *timestamp, + ControllerEvent::Device { timestamp, .. } => *timestamp, + ControllerEvent::Touchpad { timestamp, .. } => *timestamp, + #[cfg(feature = "hidapi")] + ControllerEvent::Sensor { timestamp, .. } => *timestamp, + }, + Event::Touch(tch) => match tch { + TouchEvent::Finger { timestamp, .. } => *timestamp, + }, + Event::Drop(d) => match d { + DropEvent::File { timestamp, .. } + | DropEvent::Text { timestamp, .. } + | DropEvent::Begin { timestamp, .. } + | DropEvent::Complete { timestamp, .. } => *timestamp, + }, + Event::Audio(a) => match a { + AudioDeviceEvent::Added { timestamp, .. } + | AudioDeviceEvent::Removed { timestamp, .. } => *timestamp, + }, + Event::Pen(p) => match p { + PenEvent::Proximity { timestamp, .. } + | PenEvent::Touch { timestamp, .. } + | PenEvent::Motion { timestamp, .. } + | PenEvent::Button { timestamp, .. } + | PenEvent::Axis { timestamp, .. } => *timestamp, + }, + Event::Render(r) => match r { + RenderEvent::TargetsReset { timestamp } + | RenderEvent::DeviceReset { timestamp } => *timestamp, + }, + Event::User(u) => u.timestamp, + Event::Unknown(u) => u.timestamp, + } + } - Event::MouseWheel { - timestamp, - window_id, - which, - x, - y, - direction, - mouse_x, - mouse_y, - } => { - let event = SDL_MouseWheelEvent { - r#type: sys::events::SDL_EVENT_MOUSE_WHEEL, - timestamp, - windowID: window_id, - which, - x, - y, - direction: direction.into(), - mouse_x, - mouse_y, - integer_x: 0, - integer_y: 0, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_MouseWheelEvent, - 1, - ); - Some(ret.assume_init()) - } - } - Event::JoyAxisMotion { - timestamp, - which, - axis_idx, - value, - } => { - let event = SDL_JoyAxisEvent { - r#type: sys::events::SDL_EVENT_JOYSTICK_AXIS_MOTION, - timestamp, - which, - axis: axis_idx, - value, - padding1: 0, - padding2: 0, - padding3: 0, - padding4: 0, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_JoyAxisEvent, - 1, - ); - Some(ret.assume_init()) - } - } - Event::JoyHatMotion { - timestamp, - which, - hat_idx, - state, - } => { - let hatvalue = state.to_raw(); - let event = SDL_JoyHatEvent { - r#type: sys::events::SDL_EVENT_JOYSTICK_HAT_MOTION, - timestamp, - which, - hat: hat_idx, - value: hatvalue, - padding1: 0, - padding2: 0, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_JoyHatEvent, - 1, - ); - Some(ret.assume_init()) - } - } - Event::JoyButtonDown { - timestamp, - which, - button_idx, - } => { - let event = SDL_JoyButtonEvent { - r#type: sys::events::SDL_EVENT_JOYSTICK_BUTTON_DOWN, - timestamp, - which, - button: button_idx, - down: true, - padding1: 0, - padding2: 0, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_JoyButtonEvent, - 1, - ); - Some(ret.assume_init()) + pub fn get_window_id(&self) -> Option { + match self { + Event::Window(w) => Some(w.window_id), + Event::Keyboard(k) => Some(k.window_id), + Event::Text(t) => match t { + TextEvent::Editing { window_id, .. } | TextEvent::Input { window_id, .. } => { + Some(*window_id) } - } + }, + Event::Mouse(m) => match m { + MouseEvent::Motion { window_id, .. } + | MouseEvent::Button { window_id, .. } + | MouseEvent::Wheel { window_id, .. } => Some(*window_id), + }, + Event::Drop(d) => match d { + DropEvent::File { window_id, .. } + | DropEvent::Text { window_id, .. } + | DropEvent::Begin { window_id, .. } + | DropEvent::Complete { window_id, .. } => Some(*window_id), + }, + Event::User(u) => Some(u.window_id), + Event::Pen(p) => match p { + PenEvent::Proximity { window_id, .. } + | PenEvent::Touch { window_id, .. } + | PenEvent::Motion { window_id, .. } + | PenEvent::Button { window_id, .. } + | PenEvent::Axis { window_id, .. } => Some(*window_id), + }, + _ => None, + } + } - Event::JoyButtonUp { - timestamp, - which, - button_idx, - } => { - let event = SDL_JoyButtonEvent { - r#type: sys::events::SDL_EVENT_JOYSTICK_BUTTON_UP, - timestamp, - which, - button: button_idx, - down: false, - padding1: 0, - padding2: 0, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_JoyButtonEvent, - 1, - ); - Some(ret.assume_init()) - } - } + pub fn is_keyboard(&self) -> bool { + matches!(self, Event::Keyboard(_)) + } + pub fn is_mouse(&self) -> bool { + matches!(self, Event::Mouse(_)) + } + pub fn is_window(&self) -> bool { + matches!(self, Event::Window(_)) + } + pub fn is_controller(&self) -> bool { + matches!(self, Event::Controller(_)) + } + pub fn is_joystick(&self) -> bool { + matches!(self, Event::Joystick(_)) + } + pub fn is_touch(&self) -> bool { + matches!(self, Event::Touch(_)) + } + pub fn is_pen(&self) -> bool { + matches!(self, Event::Pen(_)) + } + pub fn is_drop(&self) -> bool { + matches!(self, Event::Drop(_)) + } + pub fn is_audio(&self) -> bool { + matches!(self, Event::Audio(_)) + } + pub fn is_render(&self) -> bool { + matches!(self, Event::Render(_)) + } + pub fn is_user(&self) -> bool { + matches!(self, Event::User(_)) + } + pub fn is_unknown(&self) -> bool { + matches!(self, Event::Unknown(_)) + } - Event::JoyDeviceAdded { timestamp, which } => { - let event = SDL_JoyDeviceEvent { - r#type: sys::events::SDL_EVENT_JOYSTICK_ADDED, - timestamp, - which, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_JoyDeviceEvent, - 1, - ); - Some(ret.assume_init()) - } - } + /* ---------------- Category Accessors (as_*) ---------------- */ - Event::JoyDeviceRemoved { timestamp, which } => { - let event = SDL_JoyDeviceEvent { - r#type: sys::events::SDL_EVENT_JOYSTICK_REMOVED, - timestamp, - which, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_JoyDeviceEvent, - 1, - ); - Some(ret.assume_init()) - } - } - Event::ControllerAxisMotion { - timestamp, - which, - axis, - value, - } => { - let event = SDL_GamepadAxisEvent { - r#type: sys::events::SDL_EVENT_GAMEPAD_AXIS_MOTION, - timestamp, - which, - axis: axis.into(), - value, - padding1: 0, - padding2: 0, - padding3: 0, - padding4: 0, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_GamepadAxisEvent, - 1, - ); - Some(ret.assume_init()) - } - } - Event::ControllerButtonDown { - timestamp, - which, - button, - } => { - let event = SDL_GamepadButtonEvent { - r#type: sys::events::SDL_EVENT_GAMEPAD_BUTTON_DOWN, - timestamp, - which, - // This conversion turns an i32 into a u8; signed-to-unsigned conversions - // are a bit of a code smell, but that appears to be how SDL defines it. - button: button.into(), - down: true, - padding1: 0, - padding2: 0, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_GamepadButtonEvent, - 1, - ); - Some(ret.assume_init()) - } - } + pub fn as_quit(&self) -> Option<&QuitEvent> { + if let Event::Quit(e) = self { + Some(e) + } else { + None + } + } + pub fn as_app(&self) -> Option<&AppEvent> { + if let Event::App(e) = self { + Some(e) + } else { + None + } + } + pub fn as_display(&self) -> Option<&DisplayEvent> { + if let Event::Display(e) = self { + Some(e) + } else { + None + } + } + pub fn as_window(&self) -> Option<&WindowEvent> { + if let Event::Window(e) = self { + Some(e) + } else { + None + } + } + pub fn as_keyboard(&self) -> Option<&KeyboardEvent> { + if let Event::Keyboard(e) = self { + Some(e) + } else { + None + } + } + pub fn as_text(&self) -> Option<&TextEvent> { + if let Event::Text(e) = self { + Some(e) + } else { + None + } + } + pub fn as_mouse(&self) -> Option<&MouseEvent> { + if let Event::Mouse(e) = self { + Some(e) + } else { + None + } + } + pub fn as_joystick(&self) -> Option<&JoystickEvent> { + if let Event::Joystick(e) = self { + Some(e) + } else { + None + } + } + pub fn as_controller(&self) -> Option<&ControllerEvent> { + if let Event::Controller(e) = self { + Some(e) + } else { + None + } + } + pub fn as_touch(&self) -> Option<&TouchEvent> { + if let Event::Touch(e) = self { + Some(e) + } else { + None + } + } + pub fn as_drop(&self) -> Option<&DropEvent> { + if let Event::Drop(e) = self { + Some(e) + } else { + None + } + } + pub fn as_audio(&self) -> Option<&AudioDeviceEvent> { + if let Event::Audio(e) = self { + Some(e) + } else { + None + } + } + pub fn as_pen(&self) -> Option<&PenEvent> { + if let Event::Pen(e) = self { + Some(e) + } else { + None + } + } + pub fn as_render(&self) -> Option<&RenderEvent> { + if let Event::Render(e) = self { + Some(e) + } else { + None + } + } + pub fn as_user(&self) -> Option<&UserEvent> { + if let Event::User(e) = self { + Some(e) + } else { + None + } + } + pub fn as_unknown(&self) -> Option<&UnknownEvent> { + if let Event::Unknown(e) = self { + Some(e) + } else { + None + } + } - Event::ControllerButtonUp { - timestamp, - which, - button, - } => { - let event = SDL_GamepadButtonEvent { - r#type: sys::events::SDL_EVENT_GAMEPAD_BUTTON_UP, - reserved: 0, - timestamp, - which, - button: button.into(), - down: false, - padding1: 0, - padding2: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_GamepadButtonEvent, - 1, - ); - Some(ret.assume_init()) - } - } + pub fn is_same_kind_as(&self, other: &Event) -> bool { + use Event::*; + match (self, other) { + (Quit(_), Quit(_)) + | (App(_), App(_)) + | (Display(_), Display(_)) + | (Window(_), Window(_)) + | (Keyboard(_), Keyboard(_)) + | (Text(_), Text(_)) + | (Mouse(_), Mouse(_)) + | (Joystick(_), Joystick(_)) + | (Controller(_), Controller(_)) + | (Touch(_), Touch(_)) + | (Drop(_), Drop(_)) + | (Audio(_), Audio(_)) + | (Pen(_), Pen(_)) + | (Render(_), Render(_)) + | (User(_), User(_)) + | (Unknown(_), Unknown(_)) => true, + _ => false, + } + } - Event::ControllerDeviceAdded { timestamp, which } => { - let event = SDL_GamepadDeviceEvent { - r#type: sys::events::SDL_EVENT_GAMEPAD_ADDED, - timestamp, - which, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_GamepadDeviceEvent, - 1, - ); - Some(ret.assume_init()) - } + /* ---------------- Raw Conversion (to SDL) ---------------- */ + pub fn to_ll(&self) -> Option { + let mut raw = mem::MaybeUninit::::uninit(); + unsafe { + match self { + Event::Quit(q) => { + let mut e: SDL_QuitEvent = Default::default(); + e.r#type = SDL_EventType(EventType::Quit as u32); + e.timestamp = q.timestamp; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_QuitEvent, 1); + Some(raw.assume_init()) + } + Event::Window(w) => { + let (t, d1, d2) = window_kind_to_ll(&w.kind); + let mut e: SDL_WindowEvent = Default::default(); + e.r#type = SDL_EventType(t as u32); + e.timestamp = w.timestamp; + e.windowID = w.window_id; + e.data1 = d1; + e.data2 = d2; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_WindowEvent, 1); + Some(raw.assume_init()) + } + Event::Keyboard(k) => { + let down = matches!(k.state, KeyState::Down); + let sc = k.scancode?; + let kc = k.keycode?; + let mut e: SDL_KeyboardEvent = Default::default(); + e.r#type = SDL_EventType(match k.state { + KeyState::Down => EventType::KeyDown as u32, + KeyState::Up => EventType::KeyUp as u32, + }); + e.timestamp = k.timestamp; + e.windowID = k.window_id; + e.repeat = k.repeat; + e.scancode = sc.into(); + e.which = k.which; + e.down = down; + e.key = kc.into(); + e.r#mod = k.keymod.bits(); + e.raw = k.raw; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_KeyboardEvent, 1); + Some(raw.assume_init()) + } + Event::Mouse(m) => match m { + MouseEvent::Motion { + timestamp, + window_id, + which, + state, + x, + y, + xrel, + yrel, + } => { + let mut e: SDL_MouseMotionEvent = Default::default(); + e.r#type = SDL_EventType(EventType::MouseMotion as u32); + e.timestamp = *timestamp; + e.windowID = *window_id; + e.which = *which; + e.state = state.to_sdl_state(); + e.x = *x; + e.y = *y; + e.xrel = *xrel; + e.yrel = *yrel; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_MouseMotionEvent, 1); + Some(raw.assume_init()) + } + MouseEvent::Button { + timestamp, + window_id, + which, + button, + clicks, + state, + x, + y, + } => { + let mut e: SDL_MouseButtonEvent = Default::default(); + e.r#type = SDL_EventType(match state { + MouseButtonState::Down => EventType::MouseButtonDown as u32, + MouseButtonState::Up => EventType::MouseButtonUp as u32, + }); + e.timestamp = *timestamp; + e.windowID = *window_id; + e.which = *which; + e.button = *button as u8; + e.down = matches!(state, MouseButtonState::Down); + e.clicks = *clicks; + e.x = *x; + e.y = *y; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_MouseButtonEvent, 1); + Some(raw.assume_init()) + } + MouseEvent::Wheel { + timestamp, + window_id, + which, + x, + y, + direction, + mouse_x, + mouse_y, + } => { + let mut e: SDL_MouseWheelEvent = Default::default(); + e.r#type = SDL_EventType(EventType::MouseWheel as u32); + e.timestamp = *timestamp; + e.windowID = *window_id; + e.which = *which; + e.x = *x; + e.y = *y; + e.direction = (*direction).into(); + e.mouse_x = *mouse_x; + e.mouse_y = *mouse_y; + // integer_x / integer_y left at default (0) + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_MouseWheelEvent, 1); + Some(raw.assume_init()) + } + }, + Event::Joystick(j) => match j { + JoystickEvent::Axis { + timestamp, + which, + axis_index, + value, + } => { + let mut e: SDL_JoyAxisEvent = Default::default(); + e.r#type = SDL_EventType(EventType::JoyAxisMotion as u32); + e.timestamp = *timestamp; + e.which = *which; + e.axis = *axis_index; + e.value = *value; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_JoyAxisEvent, 1); + Some(raw.assume_init()) + } + JoystickEvent::Hat { + timestamp, + which, + hat_index, + state, + } => { + let mut e: SDL_JoyHatEvent = Default::default(); + e.r#type = SDL_EventType(EventType::JoyHatMotion as u32); + e.timestamp = *timestamp; + e.which = *which; + e.hat = *hat_index; + e.value = state.to_raw(); + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_JoyHatEvent, 1); + Some(raw.assume_init()) + } + JoystickEvent::Button { + timestamp, + which, + button_index, + state, + } => { + let mut e: SDL_JoyButtonEvent = Default::default(); + e.r#type = SDL_EventType(match state { + JoyButtonState::Down => EventType::JoyButtonDown as u32, + JoyButtonState::Up => EventType::JoyButtonUp as u32, + }); + e.timestamp = *timestamp; + e.which = *which; + e.button = *button_index; + e.down = matches!(state, JoyButtonState::Down); + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_JoyButtonEvent, 1); + Some(raw.assume_init()) + } + JoystickEvent::Device { + timestamp, + which, + change, + } => { + let et = match change { + JoyDeviceChange::Added => EventType::JoyDeviceAdded, + JoyDeviceChange::Removed => EventType::JoyDeviceRemoved, + }; + let e = SDL_JoyDeviceEvent { + r#type: SDL_EventType(et as u32), + timestamp: *timestamp, + which: *which, + reserved: 0, + }; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_JoyDeviceEvent, 1); + Some(raw.assume_init()) + } + }, + Event::Controller(c) => match c { + ControllerEvent::Axis { + timestamp, + which, + axis, + value, + } => { + let mut e: SDL_GamepadAxisEvent = Default::default(); + e.r#type = SDL_EventType(EventType::ControllerAxisMotion as u32); + e.timestamp = *timestamp; + e.which = *which; + e.axis = (*axis).into(); + e.value = *value; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_GamepadAxisEvent, 1); + Some(raw.assume_init()) + } + ControllerEvent::Button { + timestamp, + which, + button, + state, + } => { + let mut e: SDL_GamepadButtonEvent = Default::default(); + e.r#type = SDL_EventType(match state { + ControllerButtonState::Down => EventType::ControllerButtonDown as u32, + ControllerButtonState::Up => EventType::ControllerButtonUp as u32, + }); + e.timestamp = *timestamp; + e.which = *which; + e.button = (*button).into(); + e.down = matches!(state, ControllerButtonState::Down); + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_GamepadButtonEvent, 1); + Some(raw.assume_init()) + } + ControllerEvent::Device { + timestamp, + which, + change, + } => { + let et = match change { + ControllerDeviceChange::Added => EventType::ControllerDeviceAdded, + ControllerDeviceChange::Removed => EventType::ControllerDeviceRemoved, + ControllerDeviceChange::Remapped => EventType::ControllerDeviceRemapped, + }; + let mut e: SDL_GamepadDeviceEvent = Default::default(); + e.r#type = SDL_EventType(et as u32); + e.timestamp = *timestamp; + e.which = *which; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_GamepadDeviceEvent, 1); + Some(raw.assume_init()) + } + ControllerEvent::Touchpad { + timestamp, + which, + touchpad, + finger, + kind, + x, + y, + pressure, + } => { + let et = match kind { + ControllerTouchpadKind::Down => EventType::ControllerTouchpadDown, + ControllerTouchpadKind::Motion => EventType::ControllerTouchpadMotion, + ControllerTouchpadKind::Up => EventType::ControllerTouchpadUp, + }; + let mut e: SDL_GamepadTouchpadEvent = Default::default(); + e.r#type = SDL_EventType(et as u32); + e.timestamp = *timestamp; + e.which = *which; + e.touchpad = *touchpad; + e.finger = *finger; + e.x = *x; + e.y = *y; + e.pressure = *pressure; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_GamepadTouchpadEvent, 1); + Some(raw.assume_init()) + } + #[cfg(feature = "hidapi")] + ControllerEvent::Sensor { + timestamp, + which, + sensor, + data, + } => { + let mut e: sys::events::SDL_GamepadSensorEvent = Default::default(); + e.r#type = SDL_EventType(EventType::ControllerSensorUpdated as u32); + e.timestamp = *timestamp; + e.which = *which; + e.sensor = sensor.to_ll().0; + e.data = *data; + ptr::copy( + &e, + raw.as_mut_ptr() as *mut sys::events::SDL_GamepadSensorEvent, + 1, + ); + Some(raw.assume_init()) + } + }, + Event::Display(d) => { + let (et, display_id, data1) = match d { + DisplayEvent::Orientation { + timestamp: _, + display, + orientation, + } => ( + EventType::DisplayOrientation, + display.id, + orientation.to_ll().0 as i32, + ), + DisplayEvent::Added { display, .. } => { + (EventType::DisplayAdded, display.id, 0) + } + DisplayEvent::Removed { display, .. } => { + (EventType::DisplayRemoved, display.id, 0) + } + DisplayEvent::Moved { display, .. } => { + (EventType::DisplayMoved, display.id, 0) + } + DisplayEvent::DesktopModeChanged { display, .. } => { + (EventType::DisplayDesktopModeChanged, display.id, 0) + } + DisplayEvent::CurrentModeChanged { display, .. } => { + (EventType::DisplayCurrentModeChanged, display.id, 0) + } + DisplayEvent::ContentScaleChanged { display, .. } => { + (EventType::DisplayContentScaleChanged, display.id, 0) + } + }; + let ts = self.get_timestamp(); + let mut e: SDL_DisplayEvent = Default::default(); + e.r#type = SDL_EventType(et as u32); + e.displayID = display_id; + e.timestamp = ts; + e.data1 = data1; + // data2 left at default (0) + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_DisplayEvent, 1); + Some(raw.assume_init()) + } + Event::Text(_) => { + // Cannot safely reconstruct raw text pointer (SDL expects owned C buffer). + // For now we decline conversion. + None + } + Event::Touch(_) => { + // Touch events not convertible to raw form here. + None + } + Event::Drop(_) => { + // Similar to Text, cannot reconstruct original C string from owned Rust String. + None + } + Event::Audio(a) => match a { + AudioDeviceEvent::Added { + timestamp, + which, + iscapture, + } => { + let mut e: SDL_AudioDeviceEvent = Default::default(); + e.r#type = SDL_EventType(EventType::AudioDeviceAdded as u32); + e.timestamp = *timestamp; + e.which = *which; + e.recording = *iscapture; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_AudioDeviceEvent, 1); + Some(raw.assume_init()) + } + AudioDeviceEvent::Removed { + timestamp, + which, + iscapture, + } => { + let mut e: SDL_AudioDeviceEvent = Default::default(); + e.r#type = SDL_EventType(EventType::AudioDeviceRemoved as u32); + e.timestamp = *timestamp; + e.which = *which; + e.recording = *iscapture; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_AudioDeviceEvent, 1); + Some(raw.assume_init()) + } + }, + Event::Pen(p) => match p { + PenEvent::Proximity { + timestamp, + which, + window_id, + state, + } => { + let et = match state { + PenProximityState::In => EventType::PenProximityIn, + PenProximityState::Out => EventType::PenProximityOut, + }; + let mut e: SDL_PenProximityEvent = Default::default(); + e.r#type = SDL_EventType(et as u32); + e.timestamp = *timestamp; + e.which = *which; + e.windowID = *window_id; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_PenProximityEvent, 1); + Some(raw.assume_init()) + } + PenEvent::Touch { + timestamp, + which, + window_id, + x, + y, + eraser, + down, + } => { + let et = if *down { + EventType::PenDown + } else { + EventType::PenUp + }; + let mut e: SDL_PenTouchEvent = Default::default(); + e.r#type = SDL_EventType(et as u32); + e.timestamp = *timestamp; + e.which = *which; + e.windowID = *window_id; + e.x = *x; + e.y = *y; + e.eraser = *eraser; + e.down = *down; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_PenTouchEvent, 1); + Some(raw.assume_init()) + } + PenEvent::Motion { + timestamp, + which, + window_id, + x, + y, + } => { + let mut e: SDL_PenMotionEvent = Default::default(); + e.r#type = SDL_EventType(EventType::PenMotion as u32); + e.timestamp = *timestamp; + e.which = *which; + e.windowID = *window_id; + e.x = *x; + e.y = *y; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_PenMotionEvent, 1); + Some(raw.assume_init()) + } + PenEvent::Button { + timestamp, + which, + window_id, + x, + y, + button, + state, + } => { + let et = match state { + PenButtonState::Down => EventType::PenButtonDown, + PenButtonState::Up => EventType::PenButtonUp, + }; + let mut e: SDL_PenButtonEvent = Default::default(); + e.r#type = SDL_EventType(et as u32); + e.timestamp = *timestamp; + e.which = *which; + e.windowID = *window_id; + e.x = *x; + e.y = *y; + e.button = *button; + e.down = matches!(state, PenButtonState::Down); + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_PenButtonEvent, 1); + Some(raw.assume_init()) + } + PenEvent::Axis { + timestamp, + which, + window_id, + x, + y, + axis, + value, + } => { + let mut e: SDL_PenAxisEvent = Default::default(); + e.r#type = SDL_EventType(EventType::PenAxis as u32); + e.timestamp = *timestamp; + e.which = *which; + e.windowID = *window_id; + e.x = *x; + e.y = *y; + e.axis = axis.to_ll(); // PenAxis -> SDL_PenAxis + e.value = *value; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_PenAxisEvent, 1); + Some(raw.assume_init()) + } + }, + Event::Render(r) => { + let et = match r { + RenderEvent::TargetsReset { .. } => EventType::RenderTargetsReset, + RenderEvent::DeviceReset { .. } => EventType::RenderDeviceReset, + }; + let ts = self.get_timestamp(); + let mut e: SDL_CommonEvent = Default::default(); + e.r#type = et as u32; + e.timestamp = ts; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_CommonEvent, 1); + Some(raw.assume_init()) + } + Event::User(u) => { + let mut e: SDL_UserEvent = Default::default(); + e.r#type = u.type_id; + e.timestamp = u.timestamp; + e.windowID = u.window_id; + e.code = u.code; + e.data1 = u.data1; + e.data2 = u.data2; + ptr::copy(&e, raw.as_mut_ptr() as *mut SDL_UserEvent, 1); + Some(raw.assume_init()) + } + Event::App(_) | Event::Unknown(_) => None, } + } + } - Event::ControllerDeviceRemoved { timestamp, which } => { - let event = SDL_GamepadDeviceEvent { - r#type: sys::events::SDL_EVENT_GAMEPAD_REMOVED, - timestamp, - which, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_GamepadDeviceEvent, - 1, - ); - Some(ret.assume_init()) - } - } + /// Owned raw event conversion supporting Text and Drop events by retaining backing C strings. + /// For all other events it delegates to `to_ll`. + /// The returned SDL_Event is valid as long as the `OwnedRawEvent` is kept alive. + pub fn to_ll_owned(&self) -> Option { + use std::os::raw::c_char; - Event::ControllerDeviceRemapped { timestamp, which } => { - let event = SDL_GamepadDeviceEvent { - r#type: sys::events::SDL_EVENT_GAMEPAD_REMAPPED, - timestamp, - which, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_GamepadDeviceEvent, - 1, - ); - Some(ret.assume_init()) + // Fast path: for non-Text/Drop, reuse existing conversion. + match self { + Event::Text(t) => { + let mut buffers: Vec = Vec::new(); + match t { + TextEvent::Editing { + timestamp, + window_id, + text, + start, + length, + } => { + let c = CString::new(text.as_str()).ok()?; + let ptr = c.as_ptr(); + buffers.push(c); + let mut raw_event: SDL_Event = unsafe { std::mem::zeroed() }; + unsafe { + let e = &mut raw_event.edit; + e.r#type = SDL_EventType(EventType::TextEditing as u32); + e.timestamp = *timestamp; + e.windowID = *window_id; + // Copy text pointer + e.text = ptr as *mut c_char; + e.start = *start; + e.length = *length; + } + Some(OwnedRawEvent { + event: raw_event, + _buffers: buffers, + }) + } + TextEvent::Input { + timestamp, + window_id, + text, + } => { + let c = CString::new(text.as_str()).ok()?; + let ptr = c.as_ptr(); + buffers.push(c); + let mut raw_event: SDL_Event = unsafe { std::mem::zeroed() }; + unsafe { + let e = &mut raw_event.text; + e.r#type = SDL_EventType(EventType::TextInput as u32); + e.timestamp = *timestamp; + e.windowID = *window_id; + e.text = ptr as *mut c_char; + } + Some(OwnedRawEvent { + event: raw_event, + _buffers: buffers, + }) + } } } - - Event::Display { - timestamp, - display, - display_event, - } => { - let display_event = display_event.to_ll(); - let event = SDL_DisplayEvent { - r#type: SDL_EventType(display_event.0), - displayID: display.id, - data1: display_event.1, - data2: 0, - timestamp, - reserved: 0, - }; - unsafe { - ptr::copy( - &event, - ret.as_mut_ptr() as *mut sys::events::SDL_DisplayEvent, - 1, - ); - Some(ret.assume_init()) + Event::Drop(d) => { + let mut buffers: Vec = Vec::new(); + match d { + DropEvent::File { + timestamp, + window_id, + filename, + } => { + let c = CString::new(filename.as_str()).ok()?; + let ptr = c.as_ptr(); + buffers.push(c); + let mut raw_event: SDL_Event = unsafe { std::mem::zeroed() }; + unsafe { + let e = &mut raw_event.drop; + e.r#type = SDL_EventType(EventType::DropFile as u32); + e.timestamp = *timestamp; + e.windowID = *window_id; + e.data = ptr as *mut c_char; + } + Some(OwnedRawEvent { + event: raw_event, + _buffers: buffers, + }) + } + DropEvent::Text { + timestamp, + window_id, + text, + } => { + let c = CString::new(text.as_str()).ok()?; + let ptr = c.as_ptr(); + buffers.push(c); + let mut raw_event: SDL_Event = unsafe { std::mem::zeroed() }; + unsafe { + let e = &mut raw_event.drop; + e.r#type = SDL_EventType(EventType::DropText as u32); + e.timestamp = *timestamp; + e.windowID = *window_id; + e.data = ptr as *mut c_char; + } + Some(OwnedRawEvent { + event: raw_event, + _buffers: buffers, + }) + } + DropEvent::Begin { + timestamp, + window_id, + } => { + let mut raw_event: SDL_Event = unsafe { std::mem::zeroed() }; + unsafe { + let e = &mut raw_event.drop; + e.r#type = SDL_EventType(EventType::DropBegin as u32); + e.timestamp = *timestamp; + e.windowID = *window_id; + e.data = std::ptr::null_mut(); + } + Some(OwnedRawEvent { + event: raw_event, + _buffers: buffers, + }) + } + DropEvent::Complete { + timestamp, + window_id, + } => { + let mut raw_event: SDL_Event = unsafe { std::mem::zeroed() }; + unsafe { + let e = &mut raw_event.drop; + e.r#type = SDL_EventType(EventType::DropComplete as u32); + e.timestamp = *timestamp; + e.windowID = *window_id; + e.data = std::ptr::null_mut(); + } + Some(OwnedRawEvent { + event: raw_event, + _buffers: buffers, + }) + } } } - - Event::FingerDown { .. } - | Event::FingerUp { .. } - | Event::FingerMotion { .. } - | Event::DollarRecord { .. } - | Event::MultiGesture { .. } - | Event::ClipboardUpdate { .. } - | Event::DropFile { .. } - | Event::TextEditing { .. } - | Event::TextInput { .. } - | Event::Unknown { .. } - | _ => { - // don't know how to convert! - None - } + _ => self.to_ll().map(|ev| OwnedRawEvent { + event: ev, + _buffers: Vec::new(), + }), } } - pub fn from_ll(raw: sys::events::SDL_Event) -> Event { + /* ---------------- Raw Conversion (from SDL) ---------------- */ + pub fn from_ll(raw: SDL_Event) -> Event { let raw_type = unsafe { raw.r#type }; - - // if event type has not been defined, treat it as a UserEvent - let event_type: EventType = EventType::try_from(raw_type).unwrap_or(EventType::User); + let et = EventType::try_from(raw_type).unwrap_or(EventType::User); unsafe { - match event_type { + match et { + EventType::Quit => Event::Quit(QuitEvent { + timestamp: raw.quit.timestamp, + }), + EventType::AppTerminating => Event::App(AppEvent::Terminating { + timestamp: raw.common.timestamp, + }), + EventType::AppLowMemory => Event::App(AppEvent::LowMemory { + timestamp: raw.common.timestamp, + }), + EventType::AppWillEnterBackground => Event::App(AppEvent::WillEnterBackground { + timestamp: raw.common.timestamp, + }), + EventType::AppDidEnterBackground => Event::App(AppEvent::DidEnterBackground { + timestamp: raw.common.timestamp, + }), + EventType::AppWillEnterForeground => Event::App(AppEvent::WillEnterForeground { + timestamp: raw.common.timestamp, + }), + EventType::AppDidEnterForeground => Event::App(AppEvent::DidEnterForeground { + timestamp: raw.common.timestamp, + }), + EventType::WindowShown | EventType::WindowHidden | EventType::WindowExposed @@ -1686,59 +1669,46 @@ impl Event { | EventType::WindowHitTest | EventType::WindowICCProfileChanged | EventType::WindowDisplayChanged => { - let event = raw.window; - Event::Window { - timestamp: event.timestamp, - window_id: event.windowID, - win_event: WindowEvent::from_ll( - event.r#type.into(), - event.data1, - event.data2, - ), - } - } - - EventType::Quit => { - let event = raw.quit; - Event::Quit { - timestamp: event.timestamp, - } - } - EventType::AppTerminating => { - let event = raw.common; - Event::AppTerminating { - timestamp: event.timestamp, - } - } - EventType::AppLowMemory => { - let event = raw.common; - Event::AppLowMemory { - timestamp: event.timestamp, - } - } - EventType::AppWillEnterBackground => { - let event = raw.common; - Event::AppWillEnterBackground { - timestamp: event.timestamp, - } - } - EventType::AppDidEnterBackground => { - let event = raw.common; - Event::AppDidEnterBackground { - timestamp: event.timestamp, - } - } - EventType::AppWillEnterForeground => { - let event = raw.common; - Event::AppWillEnterForeground { - timestamp: event.timestamp, - } - } - EventType::AppDidEnterForeground => { - let event = raw.common; - Event::AppDidEnterForeground { - timestamp: event.timestamp, - } + let w = raw.window; + let kind = match et { + EventType::WindowShown => WindowEventKind::Shown, + EventType::WindowHidden => WindowEventKind::Hidden, + EventType::WindowExposed => WindowEventKind::Exposed, + EventType::WindowMoved => WindowEventKind::Moved { + x: w.data1, + y: w.data2, + }, + EventType::WindowResized => WindowEventKind::Resized { + w: w.data1, + h: w.data2, + }, + EventType::WindowPixelSizeChanged => WindowEventKind::PixelSizeChanged { + w: w.data1, + h: w.data2, + }, + EventType::WindowMinimized => WindowEventKind::Minimized, + EventType::WindowMaximized => WindowEventKind::Maximized, + EventType::WindowRestored => WindowEventKind::Restored, + EventType::WindowMouseEnter => WindowEventKind::MouseEnter, + EventType::WindowMouseLeave => WindowEventKind::MouseLeave, + EventType::WindowFocusGained => WindowEventKind::FocusGained, + EventType::WindowFocusLost => WindowEventKind::FocusLost, + EventType::WindowCloseRequested => WindowEventKind::CloseRequested, + EventType::WindowHitTest => WindowEventKind::HitTest { + data1: w.data1, + data2: w.data2, + }, + EventType::WindowICCProfileChanged => WindowEventKind::ICCProfileChanged, + EventType::WindowDisplayChanged => WindowEventKind::DisplayChanged { + display_index: w.data1, + }, + _ => WindowEventKind::Shown, + }; + Event::Window(WindowEvent { + timestamp: w.timestamp, + window_id: w.windowID, + kind, + }) } EventType::DisplayOrientation @@ -1748,1112 +1718,455 @@ impl Event { | EventType::DisplayDesktopModeChanged | EventType::DisplayCurrentModeChanged | EventType::DisplayContentScaleChanged => { - let event = raw.display; - - Event::Display { - timestamp: event.timestamp, - display: Display::from_ll(event.displayID), - display_event: DisplayEvent::from_ll(event.r#type.into(), event.data1), - } + let d = raw.display; + let display = Display::from_ll(d.displayID); + let timestamp = d.timestamp; + let ev = match et { + EventType::DisplayOrientation => { + let orientation = + if d.data1 > SDL_DisplayOrientation::PORTRAIT_FLIPPED.0 { + Orientation::Unknown + } else { + Orientation::from_ll(SDL_DisplayOrientation(d.data1)) + }; + DisplayEvent::Orientation { + timestamp, + display, + orientation, + } + } + EventType::DisplayAdded => DisplayEvent::Added { timestamp, display }, + EventType::DisplayRemoved => DisplayEvent::Removed { timestamp, display }, + EventType::DisplayMoved => DisplayEvent::Moved { timestamp, display }, + EventType::DisplayDesktopModeChanged => { + DisplayEvent::DesktopModeChanged { timestamp, display } + } + EventType::DisplayCurrentModeChanged => { + DisplayEvent::CurrentModeChanged { timestamp, display } + } + EventType::DisplayContentScaleChanged => { + DisplayEvent::ContentScaleChanged { timestamp, display } + } + _ => DisplayEvent::Added { timestamp, display }, + }; + Event::Display(ev) } - // TODO: SysWMEventType - EventType::KeyDown => { - let event = raw.key; - - Event::KeyDown { - timestamp: event.timestamp, - window_id: event.windowID, - keycode: Keycode::from_i32(event.key as i32), - scancode: Scancode::from_i32(event.scancode.into()), - keymod: keyboard::Mod::from_bits_truncate(event.r#mod), - repeat: event.repeat, - which: event.which, - raw: event.raw, - } - } - EventType::KeyUp => { - let event = raw.key; - - Event::KeyUp { - timestamp: event.timestamp, - window_id: event.windowID, - keycode: Keycode::from_i32(event.key as i32), - scancode: Scancode::from_i32(event.scancode.into()), - keymod: keyboard::Mod::from_bits_truncate(event.r#mod), - repeat: event.repeat, - which: event.which, - raw: event.raw, - } + EventType::KeyDown | EventType::KeyUp => { + let k = raw.key; + let state = if et == EventType::KeyDown { + KeyState::Down + } else { + KeyState::Up + }; + Event::Keyboard(KeyboardEvent { + timestamp: k.timestamp, + window_id: k.windowID, + state, + keycode: Keycode::from_i32(k.key as i32), + scancode: Scancode::from_i32(k.scancode.into()), + keymod: Mod::from_bits_truncate(k.r#mod), + repeat: k.repeat, + which: k.which, + raw: k.raw, + }) } - EventType::TextEditing => { - let event = raw.edit; - - // event.text is a *const c_char (pointer to a C string) - let c_str: &CStr = CStr::from_ptr(event.text); - // Convert the CStr to a Rust &str - let text_str = c_str.to_str().expect("Invalid UTF-8 string"); - let text = text_str.to_owned(); - - Event::TextEditing { - timestamp: event.timestamp, - window_id: event.windowID, + EventType::TextEditing => { + let e = raw.edit; + let text = CStr::from_ptr(e.text).to_string_lossy().into_owned(); + Event::Text(TextEvent::Editing { + timestamp: e.timestamp, + window_id: e.windowID, text, - start: event.start, - length: event.length, - } + start: e.start, + length: e.length, + }) } EventType::TextInput => { - let event = raw.text; - - // event.text is a *const c_char (pointer to a C string) - let c_str: &CStr = CStr::from_ptr(event.text); - - // Convert the CStr to a Rust &str - let text_str = c_str.to_str().expect("Invalid UTF-8 string"); - let text = text_str.to_owned(); - - Event::TextInput { - timestamp: event.timestamp, - window_id: event.windowID, + let e = raw.text; + let text = CStr::from_ptr(e.text).to_string_lossy().into_owned(); + Event::Text(TextEvent::Input { + timestamp: e.timestamp, + window_id: e.windowID, text, - } + }) } EventType::MouseMotion => { - let event = raw.motion; - - Event::MouseMotion { - timestamp: event.timestamp, - window_id: event.windowID, - which: event.which, - mousestate: mouse::MouseState::from_sdl_state(event.state), - x: event.x, - y: event.y, - xrel: event.xrel, - yrel: event.yrel, - } - } - EventType::MouseButtonDown => { - let event = raw.button; - - Event::MouseButtonDown { - timestamp: event.timestamp, - window_id: event.windowID, - which: event.which, - mouse_btn: mouse::MouseButton::from_ll(event.button), - clicks: event.clicks, - x: event.x, - y: event.y, - } - } - EventType::MouseButtonUp => { - let event = raw.button; - - Event::MouseButtonUp { - timestamp: event.timestamp, - window_id: event.windowID, - which: event.which, - mouse_btn: mouse::MouseButton::from_ll(event.button), - clicks: event.clicks, - x: event.x, - y: event.y, - } + let m = raw.motion; + Event::Mouse(MouseEvent::Motion { + timestamp: m.timestamp, + window_id: m.windowID, + which: m.which, + state: MouseState::from_sdl_state(m.state), + x: m.x, + y: m.y, + xrel: m.xrel, + yrel: m.yrel, + }) + } + EventType::MouseButtonDown | EventType::MouseButtonUp => { + let b = raw.button; + let state = if et == EventType::MouseButtonDown { + MouseButtonState::Down + } else { + MouseButtonState::Up + }; + Event::Mouse(MouseEvent::Button { + timestamp: b.timestamp, + window_id: b.windowID, + which: b.which, + button: crate::mouse::MouseButton::from_ll(b.button), + clicks: b.clicks, + state, + x: b.x, + y: b.y, + }) } EventType::MouseWheel => { - let event = raw.wheel; - - Event::MouseWheel { - timestamp: event.timestamp, - window_id: event.windowID, - which: event.which, - x: event.x, - y: event.y, - direction: event.direction.into(), - mouse_x: event.mouse_x, - mouse_y: event.mouse_y, - } + let w = raw.wheel; + Event::Mouse(MouseEvent::Wheel { + timestamp: w.timestamp, + window_id: w.windowID, + which: w.which, + x: w.x, + y: w.y, + direction: w.direction.into(), + mouse_x: w.mouse_x, + mouse_y: w.mouse_y, + }) } EventType::JoyAxisMotion => { - let event = raw.jaxis; - Event::JoyAxisMotion { - timestamp: event.timestamp, - which: event.which, - axis_idx: event.axis, - value: event.value, - } + let j = raw.jaxis; + Event::Joystick(JoystickEvent::Axis { + timestamp: j.timestamp, + which: j.which, + axis_index: j.axis, + value: j.value, + }) } EventType::JoyHatMotion => { - let event = raw.jhat; - Event::JoyHatMotion { - timestamp: event.timestamp, - which: event.which, - hat_idx: event.hat, - state: joystick::HatState::from_raw(event.value), - } - } - EventType::JoyButtonDown => { - let event = raw.jbutton; - Event::JoyButtonDown { - timestamp: event.timestamp, - which: event.which, - button_idx: event.button, - } - } - EventType::JoyButtonUp => { - let event = raw.jbutton; - Event::JoyButtonUp { - timestamp: event.timestamp, - which: event.which, - button_idx: event.button, - } + let j = raw.jhat; + Event::Joystick(JoystickEvent::Hat { + timestamp: j.timestamp, + which: j.which, + hat_index: j.hat, + state: HatState::from_raw(j.value), + }) + } + EventType::JoyButtonDown | EventType::JoyButtonUp => { + let jb = raw.jbutton; + let state = if et == EventType::JoyButtonDown { + JoyButtonState::Down + } else { + JoyButtonState::Up + }; + Event::Joystick(JoystickEvent::Button { + timestamp: jb.timestamp, + which: jb.which, + button_index: jb.button, + state, + }) } EventType::JoyDeviceAdded => { - let event = raw.jdevice; - Event::JoyDeviceAdded { - timestamp: event.timestamp, - which: event.which, - } + let jd = raw.jdevice; + Event::Joystick(JoystickEvent::Device { + timestamp: jd.timestamp, + which: jd.which, + change: JoyDeviceChange::Added, + }) } EventType::JoyDeviceRemoved => { - let event = raw.jdevice; - Event::JoyDeviceRemoved { - timestamp: event.timestamp, - which: event.which, - } + let jd = raw.jdevice; + Event::Joystick(JoystickEvent::Device { + timestamp: jd.timestamp, + which: jd.which, + change: JoyDeviceChange::Removed, + }) } EventType::ControllerAxisMotion => { - let event = raw.gaxis; - let axis = gamepad::Axis::from_ll(transmute(event.axis as i32)).unwrap(); - - Event::ControllerAxisMotion { - timestamp: event.timestamp, - which: event.which, + let g = raw.gaxis; + let axis = crate::gamepad::Axis::from_ll(transmute(g.axis as i32)).unwrap(); + Event::Controller(ControllerEvent::Axis { + timestamp: g.timestamp, + which: g.which, axis, - value: event.value, - } - } - EventType::ControllerButtonDown => { - let event = raw.gbutton; - let button = gamepad::Button::from_ll(transmute(event.button as i32)).unwrap(); - - Event::ControllerButtonDown { - timestamp: event.timestamp, - which: event.which, - button, - } - } - EventType::ControllerButtonUp => { - let event = raw.gbutton; - let button = gamepad::Button::from_ll(transmute(event.button as i32)).unwrap(); - - Event::ControllerButtonUp { - timestamp: event.timestamp, - which: event.which, + value: g.value, + }) + } + EventType::ControllerButtonDown | EventType::ControllerButtonUp => { + let b = raw.gbutton; + let button = + crate::gamepad::Button::from_ll(transmute(b.button as i32)).unwrap(); + let state = if et == EventType::ControllerButtonDown { + ControllerButtonState::Down + } else { + ControllerButtonState::Up + }; + Event::Controller(ControllerEvent::Button { + timestamp: b.timestamp, + which: b.which, button, - } + state, + }) } EventType::ControllerDeviceAdded => { - let event = raw.gdevice; - Event::ControllerDeviceAdded { - timestamp: event.timestamp, - which: event.which, - } + let d = raw.gdevice; + Event::Controller(ControllerEvent::Device { + timestamp: d.timestamp, + which: d.which, + change: ControllerDeviceChange::Added, + }) } EventType::ControllerDeviceRemoved => { - let event = raw.gdevice; - Event::ControllerDeviceRemoved { - timestamp: event.timestamp, - which: event.which, - } + let d = raw.gdevice; + Event::Controller(ControllerEvent::Device { + timestamp: d.timestamp, + which: d.which, + change: ControllerDeviceChange::Removed, + }) } EventType::ControllerDeviceRemapped => { - let event = raw.gdevice; - Event::ControllerDeviceRemapped { - timestamp: event.timestamp, - which: event.which, - } - } - EventType::ControllerTouchpadDown => { - let event = raw.gtouchpad; - Event::ControllerTouchpadDown { - timestamp: event.timestamp, - which: event.which, - touchpad: event.touchpad, - finger: event.finger, - x: event.x, - y: event.y, - pressure: event.pressure, - } - } - EventType::ControllerTouchpadMotion => { - let event = raw.gtouchpad; - Event::ControllerTouchpadMotion { - timestamp: event.timestamp, - which: event.which, - touchpad: event.touchpad, - finger: event.finger, - x: event.x, - y: event.y, - pressure: event.pressure, - } - } - EventType::ControllerTouchpadUp => { - let event = raw.gtouchpad; - Event::ControllerTouchpadUp { - timestamp: event.timestamp, - which: event.which, - touchpad: event.touchpad, - finger: event.finger, - x: event.x, - y: event.y, - pressure: event.pressure, - } + let d = raw.gdevice; + Event::Controller(ControllerEvent::Device { + timestamp: d.timestamp, + which: d.which, + change: ControllerDeviceChange::Remapped, + }) + } + EventType::ControllerTouchpadDown + | EventType::ControllerTouchpadMotion + | EventType::ControllerTouchpadUp => { + let t = raw.gtouchpad; + let kind = match et { + EventType::ControllerTouchpadDown => ControllerTouchpadKind::Down, + EventType::ControllerTouchpadMotion => ControllerTouchpadKind::Motion, + EventType::ControllerTouchpadUp => ControllerTouchpadKind::Up, + _ => ControllerTouchpadKind::Motion, + }; + Event::Controller(ControllerEvent::Touchpad { + timestamp: t.timestamp, + which: t.which, + touchpad: t.touchpad, + finger: t.finger, + kind, + x: t.x, + y: t.y, + pressure: t.pressure, + }) } #[cfg(feature = "hidapi")] EventType::ControllerSensorUpdated => { - let event = raw.gsensor; - Event::ControllerSensorUpdated { - timestamp: event.timestamp, - which: event.which, - sensor: crate::sensor::SensorType::from_ll(event.sensor), - data: event.data, - } - } - - EventType::FingerDown => { - let event = raw.tfinger; - Event::FingerDown { - timestamp: event.timestamp, - touch_id: event.touchID, - finger_id: event.fingerID, - x: event.x, - y: event.y, - dx: event.dx, - dy: event.dy, - pressure: event.pressure, - } - } - EventType::FingerUp => { - let event = raw.tfinger; - Event::FingerUp { - timestamp: event.timestamp, - touch_id: event.touchID, - finger_id: event.fingerID, - x: event.x, - y: event.y, - dx: event.dx, - dy: event.dy, - pressure: event.pressure, - } - } - EventType::FingerMotion => { - let event = raw.tfinger; - Event::FingerMotion { - timestamp: event.timestamp, - touch_id: event.touchID, - finger_id: event.fingerID, - x: event.x, - y: event.y, - dx: event.dx, - dy: event.dy, - pressure: event.pressure, - } - } + let s = raw.gsensor; + Event::Controller(ControllerEvent::Sensor { + timestamp: s.timestamp, + which: s.which, + sensor: crate::sensor::SensorType::from_ll(s.sensor), + data: s.data, + }) + } + + EventType::FingerDown | EventType::FingerUp | EventType::FingerMotion => { + let f = raw.tfinger; + let state = match et { + EventType::FingerDown => FingerState::Down, + EventType::FingerUp => FingerState::Up, + _ => FingerState::Motion, + }; + Event::Touch(TouchEvent::Finger { + timestamp: f.timestamp, + touch_id: f.touchID, + finger_id: f.fingerID, + x: f.x, + y: f.y, + dx: f.dx, + dy: f.dy, + pressure: f.pressure, + state, + }) + } + + EventType::ClipboardUpdate => Event::Unknown(UnknownEvent { + timestamp: raw.common.timestamp, + raw_type: et as u32, + }), - EventType::ClipboardUpdate => { - let event = raw.common; - Event::ClipboardUpdate { - timestamp: event.timestamp, - } - } EventType::DropFile => { - let event = raw.drop; - - let buf = CStr::from_ptr(event.data as *const _).to_bytes(); - let text = String::from_utf8_lossy(buf).to_string(); - - Event::DropFile { - timestamp: event.timestamp, - window_id: event.windowID, + let dr = raw.drop; + let text = CStr::from_ptr(dr.data as *const _) + .to_string_lossy() + .into_owned(); + Event::Drop(DropEvent::File { + timestamp: dr.timestamp, + window_id: dr.windowID, filename: text, - } + }) } EventType::DropText => { - let event = raw.drop; - - let buf = CStr::from_ptr(event.data as *const _).to_bytes(); - let text = String::from_utf8_lossy(buf).to_string(); - - Event::DropText { - timestamp: event.timestamp, - window_id: event.windowID, - filename: text, - } + let dr = raw.drop; + let text = CStr::from_ptr(dr.data as *const _) + .to_string_lossy() + .into_owned(); + Event::Drop(DropEvent::Text { + timestamp: dr.timestamp, + window_id: dr.windowID, + text, + }) } EventType::DropBegin => { - let event = raw.drop; - - Event::DropBegin { - timestamp: event.timestamp, - window_id: event.windowID, - } + let dr = raw.drop; + Event::Drop(DropEvent::Begin { + timestamp: dr.timestamp, + window_id: dr.windowID, + }) } EventType::DropComplete => { - let event = raw.drop; - - Event::DropComplete { - timestamp: event.timestamp, - window_id: event.windowID, - } + let dr = raw.drop; + Event::Drop(DropEvent::Complete { + timestamp: dr.timestamp, + window_id: dr.windowID, + }) } + EventType::AudioDeviceAdded => { - let event = raw.adevice; - Event::AudioDeviceAdded { - timestamp: event.timestamp, - which: event.which, - // false if an audio output device, true if an audio capture device - iscapture: event.recording, - } + let a = raw.adevice; + Event::Audio(AudioDeviceEvent::Added { + timestamp: a.timestamp, + which: a.which, + iscapture: a.recording, + }) } EventType::AudioDeviceRemoved => { - let event = raw.adevice; - Event::AudioDeviceRemoved { - timestamp: event.timestamp, - which: event.which, - // false if an audio output device, true if an audio capture device - iscapture: event.recording, - } - } - - EventType::PenProximityIn => { - let event = raw.pproximity; - Event::PenProximityIn { - timestamp: event.timestamp, - which: event.which, - window: event.windowID, - } - } - EventType::PenProximityOut => { - let event = raw.pproximity; - Event::PenProximityOut { - timestamp: event.timestamp, - which: event.which, - window: event.windowID, - } - } - EventType::PenDown => { - let event = raw.ptouch; - Event::PenDown { - timestamp: event.timestamp, - which: event.which, - window: event.windowID, - x: event.x, - y: event.y, - eraser: event.eraser, - } - } - EventType::PenUp => { - let event = raw.ptouch; - Event::PenUp { - timestamp: event.timestamp, - which: event.which, - window: event.windowID, - x: event.x, - y: event.y, - eraser: event.eraser, - } + let a = raw.adevice; + Event::Audio(AudioDeviceEvent::Removed { + timestamp: a.timestamp, + which: a.which, + iscapture: a.recording, + }) + } + + EventType::PenProximityIn | EventType::PenProximityOut => { + let p = raw.pproximity; + let state = if et == EventType::PenProximityIn { + PenProximityState::In + } else { + PenProximityState::Out + }; + Event::Pen(PenEvent::Proximity { + timestamp: p.timestamp, + which: p.which, + window_id: p.windowID, + state, + }) + } + EventType::PenDown | EventType::PenUp => { + let p = raw.ptouch; + let down = et == EventType::PenDown; + Event::Pen(PenEvent::Touch { + timestamp: p.timestamp, + which: p.which, + window_id: p.windowID, + x: p.x, + y: p.y, + eraser: p.eraser, + down, + }) } EventType::PenMotion => { - let event = raw.pmotion; - Event::PenMotion { - timestamp: event.timestamp, - which: event.which, - window: event.windowID, - x: event.x, - y: event.y, - } - } - - EventType::PenButtonUp => { - let event = raw.pbutton; - Event::PenButtonUp { - timestamp: event.timestamp, - which: event.which, - window: event.windowID, - x: event.x, - y: event.y, - button: event.button, - } - } - EventType::PenButtonDown => { - let event = raw.pbutton; - Event::PenButtonDown { - timestamp: event.timestamp, - which: event.which, - window: event.windowID, - x: event.x, - y: event.y, - button: event.button, - } + let p = raw.pmotion; + Event::Pen(PenEvent::Motion { + timestamp: p.timestamp, + which: p.which, + window_id: p.windowID, + x: p.x, + y: p.y, + }) + } + EventType::PenButtonDown | EventType::PenButtonUp => { + let p = raw.pbutton; + let state = if et == EventType::PenButtonDown { + PenButtonState::Down + } else { + PenButtonState::Up + }; + Event::Pen(PenEvent::Button { + timestamp: p.timestamp, + which: p.which, + window_id: p.windowID, + x: p.x, + y: p.y, + button: p.button, + state, + }) } EventType::PenAxis => { - let event = raw.paxis; - Event::PenAxis { - timestamp: event.timestamp, - which: event.which, - window: event.windowID, - x: event.x, - y: event.y, - axis: PenAxis::from_ll(event.axis), - value: event.value, - } - } - - EventType::RenderTargetsReset => Event::RenderTargetsReset { + let p = raw.paxis; + Event::Pen(PenEvent::Axis { + timestamp: p.timestamp, + which: p.which, + window_id: p.windowID, + x: p.x, + y: p.y, + axis: PenAxis::from_ll(p.axis), + value: p.value, + }) + } + + EventType::RenderTargetsReset => Event::Render(RenderEvent::TargetsReset { timestamp: raw.common.timestamp, - }, - EventType::RenderDeviceReset => Event::RenderDeviceReset { - timestamp: raw.common.timestamp, - }, - - EventType::First => panic!("Unused event, EventType::First, was encountered"), - EventType::Last => panic!("Unusable event, EventType::Last, was encountered"), - - // If we have no other match and the event type is >= 32768 - // this is a user event - EventType::User => { - if raw_type < 32_768 { - // The type is unknown to us. - // It's a newer sdl3 type. - let event = raw.common; - - Event::Unknown { - timestamp: event.timestamp, - type_: event.r#type, - } - } else { - let event = raw.user; - - Event::User { - timestamp: event.timestamp, - window_id: event.windowID, - type_: raw_type, - code: event.code, - data1: event.data1, - data2: event.data2, - } - } - } - } - } // close unsafe & match - } - - pub fn is_user_event(&self) -> bool { - matches!(*self, Event::User { .. }) - } - - pub fn as_user_event_type(&self) -> Option { - use std::any::TypeId; - let type_id = TypeId::of::>(); - - let (event_id, event_box_ptr) = match *self { - Event::User { type_, data1, .. } => (type_, data1), - _ => return None, - }; - - let cet = CUSTOM_EVENT_TYPES.lock().unwrap(); - - let event_type_id = match cet.sdl_id_to_type_id.get(&event_id) { - Some(id) => id, - None => { - panic!("internal error; could not find typeid") - } - }; - - if &type_id != event_type_id { - return None; - } - - let event_box: Box = unsafe { Box::from_raw(event_box_ptr as *mut T) }; - - Some(*event_box) - } - - /// Returns `true` if they are the same "kind" of events. - /// - /// # Example: - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev1 = Event::JoyButtonDown { - /// timestamp: 0, - /// which: 0, - /// button_idx: 0, - /// }; - /// let ev2 = Event::JoyButtonDown { - /// timestamp: 1, - /// which: 1, - /// button_idx: 1, - /// }; - /// - /// assert!(ev1 != ev2); // The events aren't equal (they contain different values). - /// assert!(ev1.is_same_kind_as(&ev2)); // But they are of the same kind! - /// ``` - pub fn is_same_kind_as(&self, other: &Event) -> bool { - match (self, other) { - (Self::Quit { .. }, Self::Quit { .. }) - | (Self::AppTerminating { .. }, Self::AppTerminating { .. }) - | (Self::AppLowMemory { .. }, Self::AppLowMemory { .. }) - | (Self::AppWillEnterBackground { .. }, Self::AppWillEnterBackground { .. }) - | (Self::AppDidEnterBackground { .. }, Self::AppDidEnterBackground { .. }) - | (Self::AppWillEnterForeground { .. }, Self::AppWillEnterForeground { .. }) - | (Self::AppDidEnterForeground { .. }, Self::AppDidEnterForeground { .. }) - | (Self::Display { .. }, Self::Display { .. }) - | (Self::Window { .. }, Self::Window { .. }) - | (Self::KeyDown { .. }, Self::KeyDown { .. }) - | (Self::KeyUp { .. }, Self::KeyUp { .. }) - | (Self::TextEditing { .. }, Self::TextEditing { .. }) - | (Self::TextInput { .. }, Self::TextInput { .. }) - | (Self::MouseMotion { .. }, Self::MouseMotion { .. }) - | (Self::MouseButtonDown { .. }, Self::MouseButtonDown { .. }) - | (Self::MouseButtonUp { .. }, Self::MouseButtonUp { .. }) - | (Self::MouseWheel { .. }, Self::MouseWheel { .. }) - | (Self::JoyAxisMotion { .. }, Self::JoyAxisMotion { .. }) - | (Self::JoyHatMotion { .. }, Self::JoyHatMotion { .. }) - | (Self::JoyButtonDown { .. }, Self::JoyButtonDown { .. }) - | (Self::JoyButtonUp { .. }, Self::JoyButtonUp { .. }) - | (Self::JoyDeviceAdded { .. }, Self::JoyDeviceAdded { .. }) - | (Self::JoyDeviceRemoved { .. }, Self::JoyDeviceRemoved { .. }) - | (Self::ControllerAxisMotion { .. }, Self::ControllerAxisMotion { .. }) - | (Self::ControllerButtonDown { .. }, Self::ControllerButtonDown { .. }) - | (Self::ControllerButtonUp { .. }, Self::ControllerButtonUp { .. }) - | (Self::ControllerDeviceAdded { .. }, Self::ControllerDeviceAdded { .. }) - | (Self::ControllerDeviceRemoved { .. }, Self::ControllerDeviceRemoved { .. }) - | (Self::ControllerDeviceRemapped { .. }, Self::ControllerDeviceRemapped { .. }) - | (Self::FingerDown { .. }, Self::FingerDown { .. }) - | (Self::FingerUp { .. }, Self::FingerUp { .. }) - | (Self::FingerMotion { .. }, Self::FingerMotion { .. }) - | (Self::DollarRecord { .. }, Self::DollarRecord { .. }) - | (Self::MultiGesture { .. }, Self::MultiGesture { .. }) - | (Self::ClipboardUpdate { .. }, Self::ClipboardUpdate { .. }) - | (Self::DropFile { .. }, Self::DropFile { .. }) - | (Self::DropText { .. }, Self::DropText { .. }) - | (Self::DropBegin { .. }, Self::DropBegin { .. }) - | (Self::DropComplete { .. }, Self::DropComplete { .. }) - | (Self::AudioDeviceAdded { .. }, Self::AudioDeviceAdded { .. }) - | (Self::AudioDeviceRemoved { .. }, Self::AudioDeviceRemoved { .. }) - | (Self::RenderTargetsReset { .. }, Self::RenderTargetsReset { .. }) - | (Self::RenderDeviceReset { .. }, Self::RenderDeviceReset { .. }) - | (Self::User { .. }, Self::User { .. }) - | (Self::Unknown { .. }, Self::Unknown { .. }) => true, - #[cfg(feature = "hidapi")] - (Self::ControllerSensorUpdated { .. }, Self::ControllerSensorUpdated { .. }) => true, - _ => false, - } - } + }), + EventType::RenderDeviceReset => Event::Render(RenderEvent::DeviceReset { + timestamp: raw.common.timestamp, + }), - /// Returns the `timestamp` field of the event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::JoyButtonDown { - /// timestamp: 12, - /// which: 0, - /// button_idx: 0, - /// }; - /// assert!(ev.get_timestamp() == 12); - /// ``` - pub fn get_timestamp(&self) -> u64 { - *match self { - Self::Quit { timestamp, .. } => timestamp, - Self::Window { timestamp, .. } => timestamp, - Self::AppTerminating { timestamp, .. } => timestamp, - Self::AppLowMemory { timestamp, .. } => timestamp, - Self::AppWillEnterBackground { timestamp, .. } => timestamp, - Self::AppDidEnterBackground { timestamp, .. } => timestamp, - Self::AppWillEnterForeground { timestamp, .. } => timestamp, - Self::AppDidEnterForeground { timestamp, .. } => timestamp, - Self::Display { timestamp, .. } => timestamp, - Self::KeyDown { timestamp, .. } => timestamp, - Self::KeyUp { timestamp, .. } => timestamp, - Self::TextEditing { timestamp, .. } => timestamp, - Self::TextInput { timestamp, .. } => timestamp, - Self::MouseMotion { timestamp, .. } => timestamp, - Self::MouseButtonDown { timestamp, .. } => timestamp, - Self::MouseButtonUp { timestamp, .. } => timestamp, - Self::MouseWheel { timestamp, .. } => timestamp, - Self::JoyAxisMotion { timestamp, .. } => timestamp, - Self::JoyHatMotion { timestamp, .. } => timestamp, - Self::JoyButtonDown { timestamp, .. } => timestamp, - Self::JoyButtonUp { timestamp, .. } => timestamp, - Self::JoyDeviceAdded { timestamp, .. } => timestamp, - Self::JoyDeviceRemoved { timestamp, .. } => timestamp, - Self::ControllerAxisMotion { timestamp, .. } => timestamp, - Self::ControllerButtonDown { timestamp, .. } => timestamp, - Self::ControllerButtonUp { timestamp, .. } => timestamp, - Self::ControllerDeviceAdded { timestamp, .. } => timestamp, - Self::ControllerDeviceRemoved { timestamp, .. } => timestamp, - Self::ControllerDeviceRemapped { timestamp, .. } => timestamp, - Self::ControllerTouchpadDown { timestamp, .. } => timestamp, - Self::ControllerTouchpadMotion { timestamp, .. } => timestamp, - Self::ControllerTouchpadUp { timestamp, .. } => timestamp, - #[cfg(feature = "hidapi")] - Self::ControllerSensorUpdated { timestamp, .. } => timestamp, - Self::FingerDown { timestamp, .. } => timestamp, - Self::FingerUp { timestamp, .. } => timestamp, - Self::FingerMotion { timestamp, .. } => timestamp, - Self::DollarRecord { timestamp, .. } => timestamp, - Self::MultiGesture { timestamp, .. } => timestamp, - Self::ClipboardUpdate { timestamp, .. } => timestamp, - Self::DropFile { timestamp, .. } => timestamp, - Self::DropText { timestamp, .. } => timestamp, - Self::DropBegin { timestamp, .. } => timestamp, - Self::DropComplete { timestamp, .. } => timestamp, - Self::AudioDeviceAdded { timestamp, .. } => timestamp, - Self::AudioDeviceRemoved { timestamp, .. } => timestamp, - Self::PenProximityIn { timestamp, .. } => timestamp, - Self::PenProximityOut { timestamp, .. } => timestamp, - Self::PenDown { timestamp, .. } => timestamp, - Self::PenUp { timestamp, .. } => timestamp, - Self::PenMotion { timestamp, .. } => timestamp, - Self::PenButtonUp { timestamp, .. } => timestamp, - Self::PenButtonDown { timestamp, .. } => timestamp, - Self::PenAxis { timestamp, .. } => timestamp, - Self::RenderTargetsReset { timestamp, .. } => timestamp, - Self::RenderDeviceReset { timestamp, .. } => timestamp, - Self::User { timestamp, .. } => timestamp, - Self::Unknown { timestamp, .. } => timestamp, + EventType::First => panic!("Encountered EventType::First sentinel"), + EventType::Last => panic!("Encountered EventType::Last sentinel"), + + EventType::User => { + // Distinguish unknown (built-in future) vs user. + if raw_type < 32_768 { + Event::Unknown(UnknownEvent { + timestamp: raw.common.timestamp, + raw_type, + }) + } else { + let u = raw.user; + Event::User(UserEvent { + timestamp: u.timestamp, + window_id: u.windowID, + type_id: raw_type, + code: u.code, + data1: u.data1, + data2: u.data2, + }) + } + } + } } } - /// Returns the `window_id` field of the event if it's present (not all events have it!). - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::JoyButtonDown { - /// timestamp: 0, - /// which: 0, - /// button_idx: 0, - /// }; - /// assert!(ev.get_window_id() == None); - /// - /// let another_ev = Event::DropBegin { - /// timestamp: 0, - /// window_id: 3, - /// }; - /// assert!(another_ev.get_window_id() == Some(3)); - /// ``` - pub fn get_window_id(&self) -> Option { - match self { - Self::Window { window_id, .. } => Some(*window_id), - Self::KeyDown { window_id, .. } => Some(*window_id), - Self::KeyUp { window_id, .. } => Some(*window_id), - Self::TextEditing { window_id, .. } => Some(*window_id), - Self::TextInput { window_id, .. } => Some(*window_id), - Self::MouseMotion { window_id, .. } => Some(*window_id), - Self::MouseButtonDown { window_id, .. } => Some(*window_id), - Self::MouseButtonUp { window_id, .. } => Some(*window_id), - Self::MouseWheel { window_id, .. } => Some(*window_id), - Self::DropFile { window_id, .. } => Some(*window_id), - Self::DropText { window_id, .. } => Some(*window_id), - Self::DropBegin { window_id, .. } => Some(*window_id), - Self::DropComplete { window_id, .. } => Some(*window_id), - Self::User { window_id, .. } => Some(*window_id), - _ => None, - } + pub fn is_user_event(&self) -> bool { + matches!(self, Event::User(_)) } - /// Returns `true` if this is a window event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(ev.is_window()); - /// - /// let ev = Event::AppLowMemory { - /// timestamp: 0, - /// }; - /// assert!(ev.is_window()); - /// - /// let another_ev = Event::TextInput { - /// timestamp: 0, - /// window_id: 0, - /// text: String::new(), - /// }; - /// assert!(another_ev.is_window() == false); // Not a window event! - /// ``` - pub fn is_window(&self) -> bool { - matches!( - self, - Self::Quit { .. } - | Self::AppTerminating { .. } - | Self::AppLowMemory { .. } - | Self::AppWillEnterBackground { .. } - | Self::AppDidEnterBackground { .. } - | Self::AppWillEnterForeground { .. } - | Self::AppDidEnterForeground { .. } - | Self::Window { .. } - ) - } - - /// Returns `true` if this is a keyboard event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// use sdl3::keyboard::Mod; - /// - /// let ev = Event::KeyDown { - /// timestamp: 0, - /// window_id: 0, - /// keycode: None, - /// scancode: None, - /// keymod: Mod::empty(), - /// repeat: false, - /// which: 0, - /// raw: 0, - /// }; - /// assert!(ev.is_keyboard()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_keyboard() == false); // Not a keyboard event! - /// ``` - pub fn is_keyboard(&self) -> bool { - matches!(self, Self::KeyDown { .. } | Self::KeyUp { .. }) - } - - /// Returns `true` if this is a text event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::TextInput { - /// timestamp: 0, - /// window_id: 0, - /// text: String::new(), - /// }; - /// assert!(ev.is_text()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_text() == false); // Not a text event! - /// ``` - pub fn is_text(&self) -> bool { - matches!(self, Self::TextEditing { .. } | Self::TextInput { .. }) - } - - /// Returns `true` if this is a mouse event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// use sdl3::mouse::MouseWheelDirection; - /// - /// let ev = Event::MouseWheel { - /// timestamp: 0, - /// window_id: 0, - /// which: 0, - /// mouse_x: 0.0, - /// mouse_y: 0.0, - /// x: 0.0, - /// y: 0.0, - /// direction: MouseWheelDirection::Normal, - /// }; - /// assert!(ev.is_mouse()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_mouse() == false); // Not a mouse event! - /// ``` - pub fn is_mouse(&self) -> bool { - matches!( - self, - Self::MouseMotion { .. } - | Self::MouseButtonDown { .. } - | Self::MouseButtonUp { .. } - | Self::MouseWheel { .. } - ) - } - - /// Returns `true` if this is a controller event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::ControllerDeviceAdded { - /// timestamp: 0, - /// which: 0, - /// }; - /// assert!(ev.is_controller()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_controller() == false); // Not a controller event! - /// ``` - pub fn is_controller(&self) -> bool { - matches!( - self, - Self::ControllerAxisMotion { .. } - | Self::ControllerButtonDown { .. } - | Self::ControllerButtonUp { .. } - | Self::ControllerDeviceAdded { .. } - | Self::ControllerDeviceRemoved { .. } - | Self::ControllerDeviceRemapped { .. } - ) - } - - /// Returns `true` if this is a joy event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::JoyButtonUp { - /// timestamp: 0, - /// which: 0, - /// button_idx: 0, - /// }; - /// assert!(ev.is_joy()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_joy() == false); // Not a joy event! - /// ``` - pub fn is_joy(&self) -> bool { - matches!( - self, - Self::JoyAxisMotion { .. } - | Self::JoyHatMotion { .. } - | Self::JoyButtonDown { .. } - | Self::JoyButtonUp { .. } - | Self::JoyDeviceAdded { .. } - | Self::JoyDeviceRemoved { .. } - ) - } - - /// Returns `true` if this is a finger event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::FingerMotion { - /// timestamp: 0, - /// touch_id: 0, - /// finger_id: 0, - /// x: 0., - /// y: 0., - /// dx: 0., - /// dy: 0., - /// pressure: 0., - /// }; - /// assert!(ev.is_finger()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_finger() == false); // Not a finger event! - /// ``` - pub fn is_finger(&self) -> bool { - matches!( - self, - Self::FingerDown { .. } | Self::FingerUp { .. } | Self::FingerMotion { .. } - ) - } - - /// Returns `true` if this is a pen event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::PenDown { - /// timestamp: 0, - /// which: 0, - /// window: 0, - /// x: 0., - /// y: 0., - /// eraser: false, - /// }; - /// assert!(ev.is_pen()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_pen() == false); // Not a pen event! - /// ``` - pub fn is_pen(&self) -> bool { - matches!( - self, - Self::PenProximityIn { .. } - | Self::PenProximityOut { .. } - | Self::PenDown { .. } - | Self::PenUp { .. } - | Self::PenMotion { .. } - | Self::PenButtonUp { .. } - | Self::PenButtonDown { .. } - | Self::PenAxis { .. } - ) - } - - /// Returns `true` if this is a drop event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::DropBegin { - /// timestamp: 0, - /// window_id: 3, - /// }; - /// assert!(ev.is_drop()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_drop() == false); // Not a drop event! - /// ``` - pub fn is_drop(&self) -> bool { - matches!( - self, - Self::DropFile { .. } - | Self::DropText { .. } - | Self::DropBegin { .. } - | Self::DropComplete { .. } - ) - } - - /// Returns `true` if this is an audio event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::AudioDeviceAdded { - /// timestamp: 0, - /// which: 3, - /// iscapture: false, - /// }; - /// assert!(ev.is_audio()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_audio() == false); // Not an audio event! - /// ``` - pub fn is_audio(&self) -> bool { - matches!( - self, - Self::AudioDeviceAdded { .. } | Self::AudioDeviceRemoved { .. } - ) - } - - /// Returns `true` if this is a render event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::RenderTargetsReset { - /// timestamp: 0, - /// }; - /// assert!(ev.is_render()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_render() == false); // Not a render event! - /// ``` - pub fn is_render(&self) -> bool { - matches!( - self, - Self::RenderTargetsReset { .. } | Self::RenderDeviceReset { .. } - ) - } - - /// Returns `true` if this is a user event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::User { - /// timestamp: 0, - /// window_id: 0, - /// type_: 0, - /// code: 0, - /// data1: ::std::ptr::null_mut(), - /// data2: ::std::ptr::null_mut(), - /// }; - /// assert!(ev.is_user()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_user() == false); // Not a user event! - /// ``` - pub fn is_user(&self) -> bool { - matches!(self, Self::User { .. }) - } - - /// Returns `true` if this is an unknown event. - /// - /// # Example - /// - /// ``` - /// use sdl3::event::Event; - /// - /// let ev = Event::Unknown { - /// timestamp: 0, - /// type_: 0, - /// }; - /// assert!(ev.is_unknown()); - /// - /// let another_ev = Event::Quit { - /// timestamp: 0, - /// }; - /// assert!(another_ev.is_unknown() == false); // Not an unknown event! - /// ``` - pub fn is_unknown(&self) -> bool { - matches!(self, Self::Unknown { .. }) + pub fn as_user_event_type(&self) -> Option { + let (type_id, data_ptr) = match self { + Event::User(u) => (u.type_id, u.data1), + _ => return None, + }; + let cet = CUSTOM_EVENT_TYPES.lock().unwrap(); + let expected_type_id = cet.sdl_id_to_type_id.get(&type_id)?; + if *expected_type_id != TypeId::of::>() { + return None; + } + // Safety: Stored as Box originally + let boxed: Box = unsafe { Box::from_raw(data_ptr as *mut T) }; + Some(*boxed) } - // Returns `None` if the event cannot be converted to its raw form (should not happen). pub fn get_converted_coords( &self, canvas: &crate::render::Canvas, @@ -2862,10 +2175,9 @@ impl Event { unsafe { sys::render::SDL_ConvertEventToRenderCoordinates(canvas.raw(), &mut raw); } - Some(Self::from_ll(raw)) + Some(Event::from_ll(raw)) } - // Returns `true` on success and false if the event cannot be converted to its raw form (should not happen) pub fn convert_coords( &mut self, canvas: &crate::render::Canvas, @@ -2874,7 +2186,7 @@ impl Event { unsafe { sys::render::SDL_ConvertEventToRenderCoordinates(canvas.raw(), &mut raw); } - *self = Self::from_ll(raw); + *self = Event::from_ll(raw); true } else { false @@ -2882,33 +2194,151 @@ impl Event { } } -unsafe fn poll_event() -> Option { - let mut raw = mem::MaybeUninit::uninit(); - let has_pending = sys::events::SDL_PollEvent(raw.as_mut_ptr()); +/* --------------------------- Window Kind Helper --------------------------- */ + +fn window_kind_to_ll(kind: &WindowEventKind) -> (EventType, i32, i32) { + match kind { + WindowEventKind::Shown => (EventType::WindowShown, 0, 0), + WindowEventKind::Hidden => (EventType::WindowHidden, 0, 0), + WindowEventKind::Exposed => (EventType::WindowExposed, 0, 0), + WindowEventKind::Moved { x, y } => (EventType::WindowMoved, *x, *y), + WindowEventKind::Resized { w, h } => (EventType::WindowResized, *w, *h), + WindowEventKind::PixelSizeChanged { w, h } => (EventType::WindowPixelSizeChanged, *w, *h), + WindowEventKind::Minimized => (EventType::WindowMinimized, 0, 0), + WindowEventKind::Maximized => (EventType::WindowMaximized, 0, 0), + WindowEventKind::Restored => (EventType::WindowRestored, 0, 0), + WindowEventKind::MouseEnter => (EventType::WindowMouseEnter, 0, 0), + WindowEventKind::MouseLeave => (EventType::WindowMouseLeave, 0, 0), + WindowEventKind::FocusGained => (EventType::WindowFocusGained, 0, 0), + WindowEventKind::FocusLost => (EventType::WindowFocusLost, 0, 0), + WindowEventKind::CloseRequested => (EventType::WindowCloseRequested, 0, 0), + WindowEventKind::HitTest { data1, data2 } => (EventType::WindowHitTest, *data1, *data2), + WindowEventKind::ICCProfileChanged => (EventType::WindowICCProfileChanged, 0, 0), + WindowEventKind::DisplayChanged { display_index } => { + (EventType::WindowDisplayChanged, *display_index, 0) + } + } +} + +/* --------------------------- Event Subsystem API --------------------------- */ + +impl crate::EventSubsystem { + #[doc(alias = "SDL_FlushEvent")] + pub fn flush_event(&self, event_type: EventType) { + unsafe { sys::events::SDL_FlushEvent(event_type.into()) }; + } + + #[doc(alias = "SDL_FlushEvents")] + pub fn flush_events(&self, min_type: u32, max_type: u32) { + unsafe { sys::events::SDL_FlushEvents(min_type, max_type) }; + } + + #[doc(alias = "SDL_PeepEvents")] + pub fn peek_events(&self, max_amount: u32) -> B + where + B: std::iter::FromIterator, + { + unsafe { + let mut sdl_events = Vec::with_capacity(max_amount as usize); + let result = { + sys::events::SDL_PeepEvents( + sdl_events.as_mut_ptr(), + max_amount as c_int, + sys::events::SDL_PEEKEVENT, + sys::events::SDL_EVENT_FIRST.into(), + sys::events::SDL_EVENT_LAST.into(), + ) + }; + if result < 0 { + panic!("{}", get_error()); + } + sdl_events.set_len(result as usize); + sdl_events.into_iter().map(Event::from_ll).collect() + } + } + + pub fn push_event(&self, event: Event) -> Result<(), Error> { + self.event_sender().push_event(event) + } + + #[inline(always)] + pub unsafe fn register_event(&self) -> Result { + Ok(*self.register_events(1)?.first().unwrap()) + } + + pub unsafe fn register_events(&self, nr: u32) -> Result, Error> { + let result = sys::events::SDL_RegisterEvents(nr as c_int); + const ERR_NR: u32 = u32::MAX - 1; + match result { + ERR_NR => Err(Error( + "No more user events can be created; SDL_EVENT_LAST reached".into(), + )), + _ => Ok((result..(result + nr)).collect()), + } + } + + pub fn register_custom_event(&self) -> Result<(), Error> { + let event_id = *(unsafe { self.register_events(1) })?.first().unwrap(); + let mut cet = CUSTOM_EVENT_TYPES.lock().unwrap(); + let type_id = TypeId::of::>(); + if cet.type_id_to_sdl_id.contains_key(&type_id) { + return Err(Error( + "The same event type can not be registered twice!".into(), + )); + } + cet.sdl_id_to_type_id.insert(event_id, type_id); + cet.type_id_to_sdl_id.insert(type_id, event_id); + Ok(()) + } + + pub fn push_custom_event(&self, event: T) -> Result<(), Error> { + self.event_sender().push_custom_event(event) + } + + pub fn event_sender(&self) -> EventSender { + EventSender { _priv: () } + } + + pub fn add_event_watch<'a, CB: EventWatchCallback + 'a>( + &self, + callback: CB, + ) -> EventWatch<'a, CB> { + EventWatch::add(callback) + } + + #[doc(alias = "SDL_SetEventEnabled")] + pub fn set_event_enabled(event_type: EventType, enabled: bool) { + unsafe { sys::events::SDL_SetEventEnabled(event_type.into(), enabled) }; + } + + #[doc(alias = "SDL_EventEnabled")] + pub fn event_enabled(event_type: EventType) -> bool { + unsafe { sys::events::SDL_EventEnabled(event_type.into()) } + } +} + +/* --------------------------- Poll/Wait Core --------------------------- */ - if has_pending { +unsafe fn poll_event() -> Option { + let mut raw = mem::MaybeUninit::::uninit(); + let has = sys::events::SDL_PollEvent(raw.as_mut_ptr()); + if has { Some(Event::from_ll(raw.assume_init())) } else { None } } - unsafe fn wait_event() -> Event { - let mut raw = mem::MaybeUninit::uninit(); - let success = sys::events::SDL_WaitEvent(raw.as_mut_ptr()); - - if success { + let mut raw = mem::MaybeUninit::::uninit(); + if sys::events::SDL_WaitEvent(raw.as_mut_ptr()) { Event::from_ll(raw.assume_init()) } else { panic!("{}", get_error()) } } - unsafe fn wait_event_timeout(timeout: u32) -> Option { - let mut raw = mem::MaybeUninit::uninit(); - let success = sys::events::SDL_WaitEventTimeout(raw.as_mut_ptr(), timeout as c_int); - - if success { + let mut raw = mem::MaybeUninit::::uninit(); + if sys::events::SDL_WaitEventTimeout(raw.as_mut_ptr(), timeout as c_int) { Some(Event::from_ll(raw.assume_init())) } else { None @@ -2916,222 +2346,118 @@ unsafe fn wait_event_timeout(timeout: u32) -> Option { } impl crate::EventPump { - /// Polls for currently pending events. - /// - /// If no events are pending, `None` is returned. pub fn poll_event(&mut self) -> Option { unsafe { poll_event() } } - - /// Returns a polling iterator that calls `poll_event()`. - /// The iterator will terminate once there are no more pending events. - /// - /// # Example - /// ```no_run - /// let sdl_context = sdl3::init().unwrap(); - /// let mut event_pump = sdl_context.event_pump().unwrap(); - /// - /// for event in event_pump.poll_iter() { - /// use sdl3::event::Event; - /// match event { - /// Event::KeyDown {..} => { /*...*/ } - /// _ => () - /// } - /// } - /// ``` pub fn poll_iter(&mut self) -> EventPollIterator { - EventPollIterator { - _marker: PhantomData, - } + EventPollIterator } - - /// Pumps the event loop, gathering events from the input devices. #[doc(alias = "SDL_PumpEvents")] pub fn pump_events(&mut self) { unsafe { sys::events::SDL_PumpEvents(); - }; + } } - - /// Waits indefinitely for the next available event. pub fn wait_event(&mut self) -> Event { unsafe { wait_event() } } - - /// Waits until the specified timeout (in milliseconds) for the next available event. pub fn wait_event_timeout(&mut self, timeout: u32) -> Option { unsafe { wait_event_timeout(timeout) } } - - /// Returns a waiting iterator that calls `wait_event()`. - /// - /// Note: The iterator will never terminate. pub fn wait_iter(&mut self) -> EventWaitIterator { - EventWaitIterator { - _marker: PhantomData, - } + EventWaitIterator } - - /// Returns a waiting iterator that calls `wait_event_timeout()`. - /// - /// Note: The iterator will never terminate, unless waiting for an event - /// exceeds the specified timeout. pub fn wait_timeout_iter(&mut self, timeout: u32) -> EventWaitTimeoutIterator { - EventWaitTimeoutIterator { - _marker: PhantomData, - timeout, - } + EventWaitTimeoutIterator { timeout } } - - #[inline] pub fn keyboard_state(&self) -> crate::keyboard::KeyboardState { crate::keyboard::KeyboardState::new(self) } - - #[inline] pub fn mouse_state(&self) -> crate::mouse::MouseState { crate::mouse::MouseState::new(self) } - - #[inline] pub fn relative_mouse_state(&self) -> crate::mouse::RelativeMouseState { crate::mouse::RelativeMouseState::new(self) } } -/// An iterator that calls `EventPump::poll_event()`. -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct EventPollIterator<'a> { - _marker: PhantomData<&'a ()>, -} +/* --------------------------- Iterators --------------------------- */ -impl Iterator for EventPollIterator<'_> { +pub struct EventPollIterator; +impl Iterator for EventPollIterator { type Item = Event; - fn next(&mut self) -> Option { unsafe { poll_event() } } } -/// An iterator that calls `EventPump::wait_event()`. -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct EventWaitIterator<'a> { - _marker: PhantomData<&'a ()>, -} - -impl Iterator for EventWaitIterator<'_> { +pub struct EventWaitIterator; +impl Iterator for EventWaitIterator { type Item = Event; fn next(&mut self) -> Option { - unsafe { Some(wait_event()) } + Some(unsafe { wait_event() }) } } -/// An iterator that calls `EventPump::wait_event_timeout()`. -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct EventWaitTimeoutIterator<'a> { - _marker: PhantomData<&'a ()>, +pub struct EventWaitTimeoutIterator { timeout: u32, } - -impl Iterator for EventWaitTimeoutIterator<'_> { +impl Iterator for EventWaitTimeoutIterator { type Item = Event; fn next(&mut self) -> Option { unsafe { wait_event_timeout(self.timeout) } } } -/// A sendible type that can push events to the event queue. +/* --------------------------- Event Sender --------------------------- */ + pub struct EventSender { _priv: (), } impl EventSender { - /// Pushes an event to the event queue. - #[doc(alias = "SDL_PushEvent")] pub fn push_event(&self, event: Event) -> Result<(), Error> { match event.to_ll() { - Some(mut raw_event) => { - let ok = unsafe { sys::events::SDL_PushEvent(&mut raw_event) }; - if ok { + Some(mut raw) => { + if unsafe { sys::events::SDL_PushEvent(&mut raw) } { Ok(()) } else { Err(get_error()) } } None => Err(Error( - "Cannot push unsupported event type to the queue".to_owned(), + "Cannot push unsupported event type to the queue".into(), )), } } - /// Push a custom event - /// - /// If the event type ``T`` was not registered using - /// [EventSubsystem::register_custom_event] - /// (../struct.EventSubsystem.html#method.register_custom_event), - /// this method will panic. - /// - /// # Example: pushing and receiving a custom event - /// ``` - /// struct SomeCustomEvent { - /// a: i32 - /// } - /// - /// let sdl = sdl3::init().unwrap(); - /// let ev = sdl.event().unwrap(); - /// let mut ep = sdl.event_pump().unwrap(); - /// - /// ev.register_custom_event::().unwrap(); - /// - /// let event = SomeCustomEvent { a: 42 }; - /// - /// ev.push_custom_event(event); - /// - /// let received = ep.poll_event().unwrap(); // or within a for event in ep.poll_iter() - /// if received.is_user_event() { - /// let e2 = received.as_user_event_type::().unwrap(); - /// assert_eq!(e2.a, 42); - /// } - /// ``` - pub fn push_custom_event(&self, event: T) -> Result<(), Error> { - use std::any::TypeId; + pub fn push_custom_event(&self, event: T) -> Result<(), Error> { let cet = CUSTOM_EVENT_TYPES.lock().unwrap(); let type_id = TypeId::of::>(); - - let user_event_id = *match cet.type_id_to_sdl_id.get(&type_id) { - Some(id) => id, - None => { - return Err(Error( - "Type is not registered as a custom event type!".to_owned(), - )); - } - }; - - let event_box = Box::new(event); - let event = Event::User { + let user_event_id = *cet + .type_id_to_sdl_id + .get(&type_id) + .ok_or_else(|| Error("Type is not registered as a custom event type!".into()))?; + let boxed = Box::new(event); + let ev = Event::User(UserEvent { timestamp: 0, window_id: 0, - type_: user_event_id, + type_id: user_event_id, code: 0, - data1: Box::into_raw(event_box) as *mut c_void, - data2: ::std::ptr::null_mut(), - }; + data1: Box::into_raw(boxed) as *mut c_void, + data2: ptr::null_mut(), + }); drop(cet); - - self.push_event(event)?; - - Ok(()) + self.push_event(ev) } } -/// A callback trait for [`EventSubsystem::add_event_watch`]. +/* --------------------------- Event Watch --------------------------- */ + pub trait EventWatchCallback: Send + Sync { fn callback(&mut self, event: Event); } -/// An handler for the event watch callback. -/// One must bind this struct in a variable as long as you want to keep the callback active. -/// For further information, see [`EventSubsystem::add_event_watch`]. pub struct EventWatch<'a, CB: EventWatchCallback + 'a> { activated: bool, callback: Box, @@ -3139,54 +2465,43 @@ pub struct EventWatch<'a, CB: EventWatchCallback + 'a> { } impl<'a, CB: EventWatchCallback + 'a> EventWatch<'a, CB> { - fn add(callback: CB) -> EventWatch<'a, CB> { - let f = Box::new(callback); - let mut watch = EventWatch { + fn add(callback: CB) -> Self { + let mut w = EventWatch { activated: false, - callback: f, + callback: Box::new(callback), _phantom: PhantomData, }; - watch.activate(); - watch + w.activate(); + w } - /// Activates the event watch. - /// Does nothing if it is already activated. pub fn activate(&mut self) { if !self.activated { self.activated = true; - unsafe { sys::events::SDL_AddEventWatch(self.filter(), self.callback()) }; + unsafe { sys::events::SDL_AddEventWatch(self.filter(), self.callback_ptr()) }; } } - - /// Deactivates the event watch. - /// Does nothing if it is already activated. pub fn deactivate(&mut self) { if self.activated { self.activated = false; - unsafe { sys::events::SDL_RemoveEventWatch(self.filter(), self.callback()) }; + unsafe { sys::events::SDL_RemoveEventWatch(self.filter(), self.callback_ptr()) }; } } - - /// Returns if the event watch is activated. pub fn activated(&self) -> bool { self.activated } - - /// Set the activation state of the event watch. pub fn set_activated(&mut self, activate: bool) { if activate { - self.activate(); + self.activate() } else { - self.deactivate(); + self.deactivate() } } - fn filter(&self) -> SDL_EventFilter { + fn filter(&self) -> sys::events::SDL_EventFilter { Some(event_callback_marshall::) } - - fn callback(&mut self) -> *mut c_void { + fn callback_ptr(&mut self) -> *mut c_void { &mut *self.callback as *mut _ as *mut c_void } } @@ -3199,11 +2514,11 @@ impl<'a, CB: EventWatchCallback + 'a> Drop for EventWatch<'a, CB> { extern "C" fn event_callback_marshall( user_data: *mut c_void, - event: *mut sdl3_sys::events::SDL_Event, + event: *mut SDL_Event, ) -> bool { - let f: &mut CB = unsafe { &mut *(user_data as *mut _) }; - let event = Event::from_ll(unsafe { *event }); - f.callback(event); + let cb: &mut CB = unsafe { &mut *(user_data as *mut CB) }; + let ev = Event::from_ll(unsafe { *event }); + cb.callback(ev); false } @@ -3213,287 +2528,222 @@ impl EventWatchCallback for F { } } +/* --------------------------- Tests (basic smoke) --------------------------- */ + +// PenAxis::to_ll moved to pen.rs; duplicate impl removed. + #[cfg(test)] -mod test { - use crate::video::Display; - - use super::super::gamepad::{Axis, Button}; - use super::super::joystick::HatState; - use super::super::keyboard::{Keycode, Mod, Scancode}; - use super::super::mouse::{MouseButton, MouseState, MouseWheelDirection}; - use super::super::video::Orientation; - use super::DisplayEvent; - use super::Event; - use super::WindowEvent; - - // Tests a round-trip conversion from an Event type to - // the SDL event type and back, to make sure it's sane. +mod tests { + #![allow(unused_imports, unused_variables, dead_code)] + + use super::*; + use crate::keyboard::{Keycode, Scancode}; + use crate::mouse::MouseWheelDirection; + #[test] - fn test_to_from_ll() { - { - let e = Event::Quit { timestamp: 0 }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::Display { - timestamp: 0, - display: Display::from_ll(1), - display_event: DisplayEvent::Orientation(Orientation::LandscapeFlipped), - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::Window { - timestamp: 0, - window_id: 0, - win_event: WindowEvent::Resized(1, 2), - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::KeyDown { - timestamp: 0, - window_id: 1, - keycode: Some(Keycode::Q), - scancode: Some(Scancode::Q), - keymod: Mod::all(), - repeat: false, - which: 0, - raw: 0, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::KeyUp { - timestamp: 123, - window_id: 0, - keycode: Some(Keycode::R), - scancode: Some(Scancode::R), - keymod: Mod::empty(), - repeat: true, - which: 0, - raw: 0, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::MouseMotion { - timestamp: 0, - window_id: 0, - which: 1, - mousestate: MouseState::from_sdl_state(1), - x: 3., - y: 91., - xrel: -1., - yrel: 43., - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::MouseButtonDown { - timestamp: 5634, - window_id: 2, - which: 0, - mouse_btn: MouseButton::Left, - clicks: 1, - x: 543., - y: 345., - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::MouseButtonUp { - timestamp: 0, - window_id: 2, - which: 0, - mouse_btn: MouseButton::Left, - clicks: 1, - x: 543., - y: 345., - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::MouseWheel { - timestamp: 1, - window_id: 0, - which: 32, - x: 23., - y: 91., - direction: MouseWheelDirection::Flipped, - mouse_x: 2., - mouse_y: 3., - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::JoyAxisMotion { - timestamp: 0, - which: 1, - axis_idx: 1, - value: 12, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::JoyHatMotion { - timestamp: 0, - which: 3, - hat_idx: 1, - state: HatState::Left, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::JoyButtonDown { - timestamp: 0, - which: 0, - button_idx: 3, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::JoyButtonUp { - timestamp: 9876, - which: 1, - button_idx: 2, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::JoyDeviceAdded { - timestamp: 0, - which: 1, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::JoyDeviceRemoved { - timestamp: 0, - which: 2, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::ControllerAxisMotion { - timestamp: 53, - which: 0, - axis: Axis::LeftX, - value: 3, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::ControllerButtonDown { - timestamp: 0, - which: 1, - button: Button::Guide, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::ControllerButtonUp { - timestamp: 654214, - which: 0, - button: Button::DPadRight, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::ControllerDeviceAdded { - timestamp: 543, - which: 3, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::ControllerDeviceRemoved { - timestamp: 555, - which: 3, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } - { - let e = Event::ControllerDeviceRemapped { - timestamp: 654, - which: 0, - }; - let e2 = Event::from_ll(e.clone().to_ll().unwrap()); - assert_eq!(e, e2); - } + fn keyboard_round_trip_basic() { + let ev = Event::Keyboard(KeyboardEvent { + timestamp: 123, + window_id: 3, + state: KeyState::Down, + keycode: Some(Keycode::A), + scancode: Some(Scancode::A), + keymod: Mod::all(), + repeat: false, + which: 1, + raw: 0, + }); + let raw = ev.to_ll().expect("convertable"); + let ev2 = Event::from_ll(raw); + assert!(matches!(ev2, Event::Keyboard(_))); + assert_eq!(ev.get_timestamp(), ev2.get_timestamp()); + } + + #[test] + fn mouse_button_round_trip() { + let ev = Event::Mouse(MouseEvent::Button { + timestamp: 5, + window_id: 2, + which: 0, + button: MouseButton::Left, + clicks: 2, + state: MouseButtonState::Down, + x: 10.0, + y: 11.0, + }); + let raw = ev.to_ll().unwrap(); + let back = Event::from_ll(raw); + assert!(back.is_mouse()); } #[test] - fn test_from_ll_keymod_keydown_unknown_bits() { - let mut raw_event = Event::KeyDown { + fn wheel_not_equal_button() { + let wheel = Event::Mouse(MouseEvent::Wheel { + timestamp: 1, + window_id: 0, + which: 0, + x: 0.0, + y: -1.0, + direction: MouseWheelDirection::Normal, + mouse_x: 100.0, + mouse_y: 200.0, + }); + let btn = Event::Mouse(MouseEvent::Button { + timestamp: 1, + window_id: 0, + which: 0, + button: MouseButton::Left, + clicks: 1, + state: MouseButtonState::Down, + x: 0.0, + y: 0.0, + }); + assert!(!wheel.is_same_kind_as(&Event::Keyboard(KeyboardEvent { timestamp: 0, - window_id: 1, - keycode: Some(Keycode::Q), - scancode: Some(Scancode::Q), + window_id: 0, + state: KeyState::Down, + keycode: None, + scancode: None, keymod: Mod::empty(), repeat: false, which: 0, - raw: 0, - } - .to_ll() - .unwrap(); + raw: 0 + }))); + assert!(wheel.is_same_kind_as(&btn)); // Both Mouse category + } - // Simulate SDL setting bits unknown to us, see PR #780 - unsafe { - raw_event.key.r#mod = 0xffff; + #[test] + fn joystick_axis_round_trip() { + let ev = Event::Joystick(JoystickEvent::Axis { + timestamp: 7, + which: 11, + axis_index: 2, + value: 1234, + }); + let raw = ev.to_ll().expect("joystick axis convertible"); + let back = Event::from_ll(raw); + match back { + Event::Joystick(JoystickEvent::Axis { + timestamp, + which, + axis_index, + value, + }) => { + assert_eq!(timestamp, 7); + assert_eq!(which, 11); + assert_eq!(axis_index, 2); + assert_eq!(value, 1234); + } + _ => panic!("Unexpected event variant on joystick axis round trip"), } + } - if let Event::KeyDown { keymod, .. } = Event::from_ll(raw_event) { - assert_eq!(keymod, Mod::all()); - } else { - panic!() + #[test] + fn controller_button_round_trip() { + let ev = Event::Controller(ControllerEvent::Button { + timestamp: 9, + which: 22, + button: crate::gamepad::Button::South, + state: ControllerButtonState::Down, + }); + let raw = ev.to_ll().expect("controller button convertible"); + let back = Event::from_ll(raw); + match back { + Event::Controller(ControllerEvent::Button { + timestamp, + which, + button, + state, + }) => { + assert_eq!(timestamp, 9); + assert_eq!(which, 22); + assert_eq!(button, crate::gamepad::Button::South); + assert!(matches!(state, ControllerButtonState::Down)); + } + _ => panic!("Unexpected event variant on controller button round trip"), } } #[test] - fn test_from_ll_keymod_keyup_unknown_bits() { - let mut raw_event = Event::KeyUp { - timestamp: 0, - window_id: 1, - keycode: Some(Keycode::Q), - scancode: Some(Scancode::Q), - keymod: Mod::empty(), - repeat: false, - which: 0, - raw: 0, + fn pen_axis_round_trip() { + let ev = Event::Pen(PenEvent::Axis { + timestamp: 42, + which: 5, + window_id: 99, + x: 10.0, + y: 20.0, + axis: PenAxis::Pressure, + value: 0.5, + }); + let raw = ev.to_ll().expect("pen axis convertible"); + let back = Event::from_ll(raw); + match back { + Event::Pen(PenEvent::Axis { + timestamp, + which, + window_id, + x, + y, + axis, + value, + }) => { + assert_eq!(timestamp, 42); + assert_eq!(which, 5); + assert_eq!(window_id, 99); + assert_eq!(x, 10.0); + assert_eq!(y, 20.0); + assert_eq!(axis, PenAxis::Pressure); + assert_eq!(value, 0.5); + } + _ => panic!("Unexpected event variant on pen axis round trip"), } - .to_ll() - .unwrap(); + } - // Simulate SDL setting bits unknown to us, see PR #780 - unsafe { - raw_event.key.r#mod = 0xffff; + #[test] + fn text_input_owned_conversion() { + let original_text = "Hello"; + let ev = Event::Text(TextEvent::Input { + timestamp: 1, + window_id: 2, + text: original_text.into(), + }); + let owned = ev.to_ll_owned().expect("owned text convertible"); + let back = Event::from_ll(owned.event); + match back { + Event::Text(TextEvent::Input { + timestamp, + window_id, + text, + }) => { + assert_eq!(timestamp, 1); + assert_eq!(window_id, 2); + assert_eq!(text, original_text); + } + _ => panic!("Unexpected event variant on text input owned conversion"), } + } - if let Event::KeyUp { keymod, .. } = Event::from_ll(raw_event) { - assert_eq!(keymod, Mod::all()); - } else { - panic!() + #[test] + fn drop_file_owned_conversion() { + let filename = "/tmp/example.txt"; + let ev = Event::Drop(DropEvent::File { + timestamp: 5, + window_id: 3, + filename: filename.into(), + }); + let owned = ev.to_ll_owned().expect("owned drop file convertible"); + let back = Event::from_ll(owned.event); + match back { + Event::Drop(DropEvent::File { + timestamp, + window_id, + filename: f, + }) => { + assert_eq!(timestamp, 5); + assert_eq!(window_id, 3); + assert_eq!(f, filename); + } + _ => panic!("Unexpected event variant on drop file owned conversion"), } } } diff --git a/src/sdl3/keyboard/keycode.rs b/src/sdl3/keyboard/keycode.rs index e37e5ed1..45a4beb1 100644 --- a/src/sdl3/keyboard/keycode.rs +++ b/src/sdl3/keyboard/keycode.rs @@ -523,7 +523,7 @@ impl Keycode { } pub fn to_ll(self) -> SDL_Keycode { - unsafe { i32::cast_unsigned(self as i32) } + i32::cast_unsigned(self as i32) } } diff --git a/src/sdl3/pen.rs b/src/sdl3/pen.rs index 54414208..56e574cd 100644 --- a/src/sdl3/pen.rs +++ b/src/sdl3/pen.rs @@ -36,4 +36,8 @@ impl PenAxis { _ => PenAxis::Unknown, } } + #[inline] + pub fn to_ll(self) -> sys::pen::SDL_PenAxis { + sys::pen::SDL_PenAxis(self as i32) + } } diff --git a/src/sdl3/sensor.rs b/src/sdl3/sensor.rs index 6d152716..0236b4a0 100644 --- a/src/sdl3/sensor.rs +++ b/src/sdl3/sensor.rs @@ -96,6 +96,12 @@ impl SensorType { _ => SensorType::Unknown, } } + + /// Convert the high-level SensorType into its low-level SDL_SensorType. + #[inline] + pub fn to_ll(self) -> SDL_SensorType { + self.into() + } } impl Into for SensorType { diff --git a/tests/events.rs b/tests/events.rs index e4f8ef8c..46abdc5b 100644 --- a/tests/events.rs +++ b/tests/events.rs @@ -2,7 +2,7 @@ extern crate sdl3; #[macro_use] extern crate lazy_static; -use sdl3::event; +use sdl3::event::*; use std::sync::Mutex; // Since only one `Sdl` context instance can be created at a time, running tests in parallel causes @@ -42,24 +42,24 @@ fn test1(ev: &sdl3::EventSubsystem) { fn test2(ev: &sdl3::EventSubsystem, ep: &mut sdl3::EventPump) { let user_event_id = unsafe { ev.register_event().unwrap() }; - let event = event::Event::User { + let event = Event::User(UserEvent { + type_id: user_event_id, timestamp: 0, window_id: 0, - type_: user_event_id, code: 456, data1: 0x12_34 as *mut libc::c_void, data2: 0x56_78 as *mut libc::c_void, - }; + }); let (w1, t1, c1, a1, a2) = match event { - event::Event::User { + Event::User(UserEvent { window_id: w1, - type_: t1, + type_id: t1, code: c1, data1: a1, data2: a2, .. - } => (w1, t1, c1, a1, a2), + }) => (w1, t1, c1, a1, a2), _ => panic!("expected user event"), }; ev.push_event(event.clone()).unwrap(); @@ -67,14 +67,14 @@ fn test2(ev: &sdl3::EventSubsystem, ep: &mut sdl3::EventPump) { // Do not check for timestamp here because it is always modified by // SDL_PushEvent. match &received { - &event::Event::User { + &Event::User(UserEvent { window_id: w2, - type_: t2, + type_id: t2, code: c2, data1: b1, data2: b2, .. - } => { + }) => { assert_eq!(w1, w2); assert_eq!(t1, t2); assert_eq!(c1, c2); @@ -127,21 +127,21 @@ fn test_event_sender_no_subsystem() { let tx = ev.event_sender(); assert!(tx - .push_event(sdl3::event::Event::Window { + .push_event(Event::Window(WindowEvent { timestamp: 0, window_id: 0, - win_event: sdl3::event::WindowEvent::Shown, - }) + kind: WindowEventKind::Shown, + })) .is_ok()); drop(ev); // Should return an error now the evet subsystem has been shut down assert!(tx - .push_event(sdl3::event::Event::Window { + .push_event(Event::Window(WindowEvent { timestamp: 0, window_id: 0, - win_event: sdl3::event::WindowEvent::Hidden, - }) + kind: WindowEventKind::Hidden, + })) .is_err()); }