1use crate::NSTDEvent::*;
2use nstd_input::{
3 deps::{winit, winit_input_helper},
4 key::*,
5 mouse::*,
6 touch::NSTDTouchState,
7 NSTDRawInput,
8};
9use std::{
10 os::raw::{c_double, c_int},
11 ptr::{self, addr_of_mut},
12};
13#[cfg(any(
14 target_os = "windows",
15 target_os = "linux",
16 target_os = "macos",
17 target_os = "android"
18))]
19use winit::platform::run_return::EventLoopExtRunReturn;
20#[cfg(target_os = "linux")]
21use winit::platform::unix::EventLoopExtUnix;
22#[cfg(target_os = "windows")]
23use winit::platform::windows::EventLoopExtWindows;
24use winit::{
25 event::*,
26 event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
27 window::WindowId,
28};
29use winit_input_helper::WinitInputHelper;
30#[cfg(feature = "deps")]
31pub mod deps {
32 pub use nstd_input;
33}
34
35pub type NSTDEventLoop = *mut EventLoop<()>;
37
38pub type NSTDWindowID = *mut WindowId;
40
41#[repr(C)]
43#[allow(non_camel_case_types)]
44pub enum NSTDEventLoopControlFlow {
45 NSTD_EVENT_LOOP_CONTROL_FLOW_POLL,
46 NSTD_EVENT_LOOP_CONTROL_FLOW_WAIT,
47 NSTD_EVENT_LOOP_CONTROL_FLOW_EXIT,
48}
49impl Into<ControlFlow> for NSTDEventLoopControlFlow {
50 #[inline]
51 fn into(self) -> ControlFlow {
52 match self {
53 Self::NSTD_EVENT_LOOP_CONTROL_FLOW_POLL => ControlFlow::Poll,
54 Self::NSTD_EVENT_LOOP_CONTROL_FLOW_WAIT => ControlFlow::Wait,
55 Self::NSTD_EVENT_LOOP_CONTROL_FLOW_EXIT => ControlFlow::Exit,
56 }
57 }
58}
59
60#[repr(C)]
62#[allow(non_camel_case_types)]
63pub enum NSTDEvent {
64 NSTD_EVENT_NONE,
65 NSTD_EVENT_LOOP_DESTROYED,
66 NSTD_EVENT_EVENTS_CLEARED,
67 NSTD_EVENT_DEVICE_ADDED,
68 NSTD_EVENT_DEVICE_REMOVED,
69 NSTD_EVENT_MOUSE_MOVED,
70 NSTD_EVENT_SCROLL_PIXEL,
71 NSTD_EVENT_SCROLL_LINE,
72 NSTD_EVENT_WINDOW_REDRAW_REQUESTED,
73 NSTD_EVENT_WINDOW_RESIZED,
74 NSTD_EVENT_WINDOW_MOVED,
75 NSTD_EVENT_WINDOW_FOCUS_CHANGED,
76 NSTD_EVENT_WINDOW_KEY,
77 NSTD_EVENT_WINDOW_MOD_KEY,
78 NSTD_EVENT_WINDOW_MOUSE_MOVED,
79 NSTD_EVENT_WINDOW_MOUSE_ENTERED,
80 NSTD_EVENT_WINDOW_MOUSE_LEFT,
81 NSTD_EVENT_WINDOW_SCROLL,
82 NSTD_EVENT_WINDOW_MOUSE_BUTTON,
83 NSTD_EVENT_WINDOW_CLOSE_REQUESTED,
84}
85
86#[repr(C)]
88pub struct NSTDEventData {
89 pub event: NSTDEvent,
90 pub mouse_delta: [c_double; 2],
91 pub size: [u32; 2],
92 pub pos: [i32; 2],
93 pub window_id: NSTDWindowID,
94 pub raw_input: NSTDRawInput,
95 pub touch_state: NSTDTouchState,
96 pub mouse_button_event: NSTDMouseButtonEvent,
97 pub key: NSTDKeyEvent,
98 pub mod_keys: u8,
99 pub has_focus: i8,
100}
101impl Default for NSTDEventData {
102 fn default() -> Self {
103 Self {
104 event: NSTD_EVENT_NONE,
105 mouse_delta: [0.0, 0.0],
106 size: [0, 0],
107 pos: [0, 0],
108 window_id: ptr::null_mut(),
109 raw_input: ptr::null_mut(),
110 touch_state: NSTDTouchState::default(),
111 mouse_button_event: NSTDMouseButtonEvent::default(),
112 key: NSTDKeyEvent::default(),
113 mod_keys: 0,
114 has_focus: 0,
115 }
116 }
117}
118
119#[inline]
122#[cfg_attr(feature = "clib", no_mangle)]
123pub unsafe extern "C" fn nstd_events_event_loop_new() -> NSTDEventLoop {
124 #[cfg(not(any(target_os = "windows", target_os = "linux")))]
125 return Box::into_raw(Box::new(EventLoop::new()));
126 #[cfg(any(target_os = "windows", target_os = "linux"))]
127 return Box::into_raw(Box::new(EventLoop::<()>::new_any_thread()));
128}
129
130#[cfg_attr(feature = "clib", no_mangle)]
140pub unsafe extern "C" fn nstd_events_event_loop_run(
141 event_loop: *mut NSTDEventLoop,
142 callback: extern "C" fn(*mut NSTDEventData) -> NSTDEventLoopControlFlow,
143 should_return: c_int,
144) {
145 let mut winit_event_loop = Box::from_raw(*event_loop);
146 *event_loop = ptr::null_mut();
147 let mut winput = Box::new(WinitInputHelper::new());
148 let mut event_data = NSTDEventData::default();
149 event_data.raw_input = winput.as_mut();
150 let closure =
151 move |event: Event<()>, _: &EventLoopWindowTarget<()>, control_flow: &mut ControlFlow| {
152 winput.update(&event);
153 event_data.event = match event {
154 Event::LoopDestroyed => NSTD_EVENT_LOOP_DESTROYED,
155 Event::MainEventsCleared => NSTD_EVENT_EVENTS_CLEARED,
156 Event::RedrawRequested(window_id) => {
157 event_data.window_id = Box::into_raw(Box::new(window_id));
158 NSTD_EVENT_WINDOW_REDRAW_REQUESTED
159 }
160 Event::WindowEvent { window_id, event } => {
161 event_data.window_id = Box::into_raw(Box::new(window_id));
162 match event {
163 WindowEvent::Resized(size) => {
164 event_data.size = [size.width, size.height];
165 NSTD_EVENT_WINDOW_RESIZED
166 }
167 WindowEvent::Moved(pos) => {
168 event_data.pos = [pos.x, pos.y];
169 NSTD_EVENT_WINDOW_MOVED
170 }
171 WindowEvent::Focused(focused) => {
172 event_data.has_focus = focused as i8;
173 NSTD_EVENT_WINDOW_FOCUS_CHANGED
174 }
175 WindowEvent::KeyboardInput { input, .. } => {
176 event_data.key.state = match input.state {
177 ElementState::Pressed => NSTDKeyState::NSTD_KEY_STATE_PRESSED,
178 ElementState::Released => NSTDKeyState::NSTD_KEY_STATE_RELEASED,
179 };
180 event_data.key.scan_code = input.scancode;
181 event_data.key.key = match input.virtual_keycode {
182 Some(key) => NSTDKey::from(key),
183 _ => NSTDKey::NSTD_KEY_NONE,
184 };
185 NSTD_EVENT_WINDOW_KEY
186 }
187 WindowEvent::ModifiersChanged(mods) => {
188 event_data.mod_keys = 0
189 | NSTD_INPUT_KEY_SHIFT_BIT * mods.shift() as u8
190 | NSTD_INPUT_KEY_CTRL_BIT * mods.ctrl() as u8
191 | NSTD_INPUT_KEY_ALT_BIT * mods.alt() as u8
192 | NSTD_INPUT_KEY_LOGO_BIT * mods.logo() as u8;
193 NSTD_EVENT_WINDOW_MOD_KEY
194 }
195 WindowEvent::CursorMoved { position, .. } => {
196 event_data.mouse_delta = [position.x, position.y];
197 NSTD_EVENT_WINDOW_MOUSE_MOVED
198 }
199 WindowEvent::CursorEntered { .. } => NSTD_EVENT_WINDOW_MOUSE_ENTERED,
200 WindowEvent::CursorLeft { .. } => NSTD_EVENT_WINDOW_MOUSE_LEFT,
201 WindowEvent::MouseWheel { delta, phase, .. } => {
202 event_data.mouse_delta = match delta {
203 MouseScrollDelta::PixelDelta(delta) => [delta.x, delta.y],
204 MouseScrollDelta::LineDelta(x, y) => [x as c_double, y as c_double],
205 };
206 event_data.touch_state = match phase {
207 TouchPhase::Started => NSTDTouchState::NSTD_TOUCH_STATE_STARTED,
208 TouchPhase::Moved => NSTDTouchState::NSTD_TOUCH_STATE_MOVED,
209 TouchPhase::Ended => NSTDTouchState::NSTD_TOUCH_STATE_ENDED,
210 TouchPhase::Cancelled => NSTDTouchState::NSTD_TOUCH_STATE_CANCELLED,
211 };
212 NSTD_EVENT_WINDOW_SCROLL
213 }
214 WindowEvent::MouseInput { state, button, .. } => {
215 event_data.mouse_button_event.state = match state {
216 ElementState::Pressed => {
217 NSTDMouseButtonState::NSTD_MOUSE_BUTTON_PRESSED
218 }
219 ElementState::Released => {
220 NSTDMouseButtonState::NSTD_MOUSE_BUTTON_RELEASED
221 }
222 };
223 event_data.mouse_button_event.button = match button {
224 MouseButton::Left => NSTDMouseButton::NSTD_MOUSE_BUTTON_LEFT,
225 MouseButton::Right => NSTDMouseButton::NSTD_MOUSE_BUTTON_RIGHT,
226 MouseButton::Middle => NSTDMouseButton::NSTD_MOUSE_BUTTON_MIDDLE,
227 MouseButton::Other(other) => {
228 event_data.mouse_button_event.extra_button = other;
229 NSTDMouseButton::NSTD_MOUSE_BUTTON_OTHER
230 }
231 };
232 NSTD_EVENT_WINDOW_MOUSE_BUTTON
233 }
234 WindowEvent::CloseRequested => NSTD_EVENT_WINDOW_CLOSE_REQUESTED,
235 _ => NSTD_EVENT_NONE,
236 }
237 }
238 Event::DeviceEvent { event, .. } => match event {
239 DeviceEvent::Added => NSTD_EVENT_DEVICE_ADDED,
240 DeviceEvent::Removed => NSTD_EVENT_DEVICE_REMOVED,
241 DeviceEvent::MouseMotion { delta } => {
242 event_data.mouse_delta = [delta.0, delta.1];
243 NSTD_EVENT_MOUSE_MOVED
244 }
245 DeviceEvent::MouseWheel { delta } => match delta {
246 MouseScrollDelta::PixelDelta(delta) => {
247 event_data.mouse_delta = [delta.x, delta.y];
248 NSTD_EVENT_SCROLL_PIXEL
249 }
250 MouseScrollDelta::LineDelta(x, y) => {
251 event_data.mouse_delta = [x as c_double, y as c_double];
252 NSTD_EVENT_SCROLL_LINE
253 }
254 },
255 _ => NSTD_EVENT_NONE,
256 },
257 _ => NSTD_EVENT_NONE,
258 };
259 *control_flow = callback(addr_of_mut!(event_data)).into();
260 if !event_data.window_id.is_null() {
261 Box::from_raw(event_data.window_id);
262 event_data.window_id = ptr::null_mut();
263 }
264 };
265 #[cfg(not(any(
266 target_os = "windows",
267 target_os = "linux",
268 target_os = "macos",
269 target_os = "android"
270 )))]
271 event_loop.run(closure);
272 #[cfg(any(
273 target_os = "windows",
274 target_os = "linux",
275 target_os = "macos",
276 target_os = "android"
277 ))]
278 if should_return != 0 {
279 winit_event_loop.run_return(closure);
280 } else {
281 winit_event_loop.run(closure);
282 }
283}
284
285#[inline]
289#[cfg_attr(feature = "clib", no_mangle)]
290pub unsafe extern "C" fn nstd_events_event_loop_free(event_loop: *mut NSTDEventLoop) {
291 Box::from_raw(*event_loop);
292 *event_loop = ptr::null_mut();
293}