1mod utility;
3
4use std::{ffi::{c_uint, c_void}, num::NonZeroU32, os::raw::c_int, ptr::NonNull};
5
6use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
7
8#[cfg(target_os = "linux")]
9use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle};
10
11#[cfg(target_os = "linux")]
12use xcb::{x, Xid};
13
14#[cfg(target_os = "windows")]
15use raw_window_handle::{Win32WindowHandle, WindowsDisplayHandle};
16
17#[cfg(target_os = "windows")]
18use std::{mem::MaybeUninit, num::NonZeroIsize, ptr};
19
20#[cfg(target_os = "windows")]
21use windows_sys::Win32::{
22 Foundation::{HWND, HINSTANCE, LPARAM, LRESULT, RECT, WPARAM},
23 System::LibraryLoader::GetModuleHandleA,
24 UI::WindowsAndMessaging::{
25 AdjustWindowRectEx, LoadCursorW, LoadIconW, MessageBoxA, ShowWindow, CreateWindowExW, DestroyWindow,
26 DefWindowProcW, PeekMessageW, TranslateMessage, DispatchMessageW, GetClientRect,
27 RegisterClassW, WNDCLASSW, MSG,
28 CS_DBLCLKS, IDC_ARROW, IDI_APPLICATION, MB_ICONEXCLAMATION, MB_OK, SW_SHOW, SW_SHOWNOACTIVATE,
29 WS_CAPTION, WS_EX_APPWINDOW, WS_MAXIMIZEBOX, WS_MINIMIZEBOX, WS_OVERLAPPED, WS_SYSMENU, WS_THICKFRAME,
30 WM_DESTROY, PM_REMOVE, WM_CLOSE, WM_ERASEBKGND, WM_EXITSIZEMOVE, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDOWN,
31 WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_RBUTTONDOWN, WM_RBUTTONUP,
32 WM_SYSKEYDOWN, WM_SYSKEYUP, WM_USER
33 },
34};
35
36pub enum WindowEvent {
37 Close,
38 Resize(u32, u32),
39 Input(WindowInputEvent),
40}
41
42pub enum WindowInputEvent {
43 KeyDown(Keys),
44 KeyUp(Keys),
45 MouseDown(MouseButton),
46 MouseUp(MouseButton),
47 MouseMove(i16, i16),
48 MouseWheelMove(i16),
49}
50
51pub struct Window {
81 previous_size: (u32, u32),
82
83 #[cfg(target_os = "windows")]
84 h_instance: HINSTANCE,
85 #[cfg(target_os = "windows")]
86 hwnd: HWND,
87
88 #[cfg(target_os = "linux")]
89 connection: xcb::Connection,
90 #[cfg(target_os = "linux")]
91 window: u32,
92 #[cfg(target_os = "linux")]
93 screen: c_int,
94 #[cfg(target_os = "linux")]
95 wm_del_window: x::Atom,
96}
97
98#[cfg(target_os = "windows")]
99const CUSTOM_CLOSE_MESSAGE: u32 = WM_USER + 0;
100#[cfg(target_os = "windows")]
101const CUSTOM_SIZE_MESSAGE: u32 = WM_USER + 1;
102
103#[cfg(target_os = "windows")]
104extern "system" fn win32_process_message(hwnd: HWND, msg: u32, w_param: WPARAM, l_param: LPARAM) -> LRESULT {
105 use windows_sys::Win32::{Foundation::GetLastError, UI::WindowsAndMessaging::{PostMessageW, PostQuitMessage}};
106
107 match msg {
108 WM_ERASEBKGND => 1,
109 WM_CLOSE => {
110 unsafe { PostMessageW(hwnd, CUSTOM_CLOSE_MESSAGE, 0, 0); }
111 0
112 }
113 WM_DESTROY => {
114 unsafe { PostQuitMessage(0); }
115 0
116 },
117 WM_EXITSIZEMOVE => {
118 if unsafe { PostMessageW(hwnd, CUSTOM_SIZE_MESSAGE, 0, 0) } == 0 {
120 println!("Failed to post. {}", unsafe { GetLastError() });
121 }
122
123 unsafe { DefWindowProcW(hwnd, msg, w_param, l_param) }
124 },
125 _ => unsafe { DefWindowProcW(hwnd, msg, w_param, l_param) },
126 }
127}
128
129impl Window {
130 pub fn new(
132 window_name: &str,
133 x: i32, y: i32,
134 width: i32, height: i32,
135 ) -> Self {
136 #[cfg(target_os = "windows")]
137 { Self::new_win32(window_name, x, y, width, height) }
138
139 #[cfg(target_os = "linux")]
140 { Self::new_linux_x(window_name, x, y, width, height) }
141 }
142
143 pub fn poll_messages(&mut self, event_closure: impl FnMut(WindowEvent)) {
145 #[cfg(target_os = "windows")]
146 { self.poll_messages_win32(event_closure); }
147
148 #[cfg(target_os = "linux")]
149 { self.poll_messages_linux_x(event_closure); }
150 }
151
152 pub fn raw_window_handle(&self) -> RawWindowHandle {
153 #[cfg(target_os = "windows")]
154 { self.raw_window_handle_win32() }
155
156 #[cfg(target_os = "linux")]
157 { self.raw_window_handle_linux_x() }
158 }
159
160 pub fn raw_display_handle(&self) -> RawDisplayHandle {
161 #[cfg(target_os = "windows")]
162 { self.raw_display_handle_windows() }
163
164 #[cfg(target_os = "linux")]
165 { self.raw_display_handle_linux_x() }
166 }
167}
168
169#[cfg(target_os = "linux")]
170impl Window {
171 fn new_linux_x(
172 window_name: &str,
173 x: i32, y: i32,
174 width: i32, height: i32,
175 ) -> Self {
176 let (conn, screen_num) = xcb::Connection::connect_with_xlib_display().unwrap();
177
178 let setup = conn.get_setup();
179 let screen = setup.roots().nth(screen_num as usize).unwrap();
180
181 let window: x::Window = conn.generate_id();
182
183 let cookie = conn.send_request_checked(&x::CreateWindow {
184 depth: x::COPY_FROM_PARENT as u8,
185 wid: window,
186 parent: screen.root(),
187 x: x.try_into().unwrap(),
188 y: y.try_into().unwrap(),
189 width: width.try_into().unwrap(),
190 height: height.try_into().unwrap(),
191 border_width: 0,
192 class: x::WindowClass::InputOutput,
193 visual: screen.root_visual(),
194 value_list: &[
195 x::Cw::BackPixel(screen.white_pixel()),
196 x::Cw::EventMask(x::EventMask::BUTTON_PRESS | x::EventMask::BUTTON_RELEASE | x::EventMask::KEY_PRESS
197 | x::EventMask::KEY_RELEASE | x::EventMask::EXPOSURE | x::EventMask::POINTER_MOTION
198 | x::EventMask::STRUCTURE_NOTIFY
199 ),
200 ],
201 });
202 conn.check_request(cookie).unwrap();
203
204 let cookie = conn.send_request_checked(&x::ChangeProperty {
205 mode: x::PropMode::Replace,
206 window,
207 property: x::ATOM_WM_NAME,
208 r#type: x::ATOM_STRING,
209 data: window_name.as_bytes(),
210 });
211 conn.check_request(cookie).unwrap();
212
213 conn.send_request(&x::MapWindow {
214 window,
215 });
216
217 let (wm_protocols, wm_del_window) = {
219 let cookies = (
220 conn.send_request(&x::InternAtom {
221 only_if_exists: true,
222 name: b"WM_PROTOCOLS",
223 }),
224 conn.send_request(&x::InternAtom {
225 only_if_exists: true,
226 name: b"WM_DELETE_WINDOW",
227 }),
228 );
229
230 (
231 conn.wait_for_reply(cookies.0).unwrap().atom(),
232 conn.wait_for_reply(cookies.1).unwrap().atom(),
233 )
234 };
235
236 conn.check_request(conn.send_request_checked(&x::ChangeProperty {
237 mode: x::PropMode::Replace,
238 window,
239 property: wm_protocols,
240 r#type: x::ATOM_ATOM,
241 data: &[wm_del_window],
242 })).unwrap();
243
244 conn.flush().unwrap();
245
246 Self {
247 previous_size: (0, 0),
248 connection: conn,
249 screen: screen_num,
250 window: window.resource_id(),
251 wm_del_window,
252 }
253 }
254
255 fn poll_messages_linux_x(&mut self, mut event_closure: impl FnMut(WindowEvent)) {
256 while let Some(event) = self.connection.poll_for_event().unwrap() {
257 if let xcb::Event::X(event) = event { match event {
258 x::Event::KeyPress(event) => {
259 if let Some(key) = self.translate_key_code(event.detail()) {
260 (event_closure)(WindowEvent::Input(WindowInputEvent::KeyDown(key)));
261 }
262 },
263 x::Event::KeyRelease(event) => {
264 if let Some(key) = self.translate_key_code(event.detail()) {
265 (event_closure)(WindowEvent::Input(WindowInputEvent::KeyUp(key)));
266 }
267 },
268 x::Event::ButtonPress(event) => {
269 let button = match event.detail() as c_uint {
270 x11::xlib::Button1 => MouseButton::Left,
271 x11::xlib::Button2 => MouseButton::Middle,
272 x11::xlib::Button3 => MouseButton::Right,
273 x11::xlib::Button4 => continue,
274 x11::xlib::Button5 => continue,
275 _ => { log::warn!("Unrecognized mouse button pressed: {}.", event.detail()); continue; },
276 };
277
278 (event_closure)(WindowEvent::Input(WindowInputEvent::MouseDown(button)));
279 },
280 x::Event::ButtonRelease(event) => {
281 match event.detail() as c_uint{
282 event @ (x11::xlib::Button1 | x11::xlib::Button2 | x11::xlib::Button3) => {
283 let button = match event {
284 x11::xlib::Button1 => MouseButton::Left,
285 x11::xlib::Button2 => MouseButton::Middle,
286 x11::xlib::Button3 => MouseButton::Right,
287 _ => panic!("Unrecognized mouse button x keycode.")
288 };
289
290 (event_closure)(WindowEvent::Input(WindowInputEvent::MouseUp(button)));
291 },
292 event @ (x11::xlib::Button4 | x11::xlib::Button5) => {
293 let d = match event {
294 x11::xlib::Button4 => 1i16,
295 x11::xlib::Button5 => -1i16,
296 _ => panic!("Unrecognized mouse button x keycode.")
297 };
298
299 (event_closure)(WindowEvent::Input(WindowInputEvent::MouseWheelMove(d)));
300 },
301 _ => { log::warn!("Unrecognized mouse button released: {}.", event.detail()); continue; },
302 };
303 },
304 x::Event::MotionNotify(event) => {
305 let x = event.event_x();
306 let y = event.event_x();
307
308 (event_closure)(WindowEvent::Input(WindowInputEvent::MouseMove(x, y)));
309 },
310 x::Event::ConfigureNotify(event) => {
311 let x = event.width() as u32;
314 let y = event.height() as u32;
315
316 if self.previous_size != (x, y) {
317 self.previous_size = (x, y);
318
319 (event_closure)(WindowEvent::Resize(x, y));
320 }
321 },
322 x::Event::ClientMessage(event) => {
323 if let x::ClientMessageData::Data32([atom, ..]) = event.data() {
324 if atom == self.wm_del_window.resource_id() {
325 (event_closure)(WindowEvent::Close);
326 }
327 }
328 },
329 _ => {},
330 }
331 }
332 }
333 }
334
335 fn raw_window_handle_linux_x(&self) -> RawWindowHandle {
336 let handle = XcbWindowHandle::new(NonZeroU32::new(self.window).unwrap());
337
338 RawWindowHandle::Xcb(handle)
339 }
340
341 fn raw_display_handle_linux_x(&self) -> RawDisplayHandle {
342 let handle = XcbDisplayHandle::new(
343 Some(NonNull::new(self.connection.get_raw_conn() as *mut c_void).unwrap()), self.screen
344 );
345
346 RawDisplayHandle::Xcb(handle)
347 }
348
349 fn translate_key_code(&self, x_keycode: x::Keycode) -> Option<Keys> {
350
351 let key_sym = unsafe {
352 x11::xlib::XkbKeycodeToKeysym(
353 self.connection.get_raw_dpy(),
354 x_keycode as x11::xlib::KeyCode,
355 0,
356 if x_keycode as u32 & x11::xlib::ShiftMask == 0 { 1 } else { 0 }
357 )
358 };
359
360 match key_sym as c_uint {
361 x11::keysym::XK_BackSpace => Some(Keys::Backspace),
362 x11::keysym::XK_Return => Some(Keys::Enter),
363 x11::keysym::XK_Tab => Some(Keys::Tab),
364 x11::keysym::XK_Pause => Some(Keys::Pause),
368 x11::keysym::XK_Caps_Lock => Some(Keys::Capital),
369
370 x11::keysym::XK_Escape => Some(Keys::Escape),
371
372 x11::keysym::XK_Mode_switch => Some(Keys::Modechange),
378
379 x11::keysym::XK_space => Some(Keys::Space),
380 x11::keysym::XK_Prior => Some(Keys::Prior),
381 x11::keysym::XK_Next => Some(Keys::Next),
382 x11::keysym::XK_End => Some(Keys::End),
383 x11::keysym::XK_Home => Some(Keys::Home),
384 x11::keysym::XK_Left => Some(Keys::Left),
385 x11::keysym::XK_Up => Some(Keys::Up),
386 x11::keysym::XK_Right => Some(Keys::Right),
387 x11::keysym::XK_Down => Some(Keys::Down),
388 x11::keysym::XK_Select => Some(Keys::Select),
389 x11::keysym::XK_Print => Some(Keys::Print),
390 x11::keysym::XK_Execute => Some(Keys::Execute),
391 x11::keysym::XK_Insert => Some(Keys::Insert),
393 x11::keysym::XK_Delete => Some(Keys::Delete),
394 x11::keysym::XK_Help => Some(Keys::Help),
395
396 x11::keysym::XK_Super_L => Some(Keys::LWin),
397 x11::keysym::XK_Super_R => Some(Keys::RWin),
398 x11::keysym::XK_KP_0 => Some(Keys::Numpad0),
403 x11::keysym::XK_KP_1 => Some(Keys::Numpad1),
404 x11::keysym::XK_KP_2 => Some(Keys::Numpad2),
405 x11::keysym::XK_KP_3 => Some(Keys::Numpad3),
406 x11::keysym::XK_KP_4 => Some(Keys::Numpad4),
407 x11::keysym::XK_KP_5 => Some(Keys::Numpad5),
408 x11::keysym::XK_KP_6 => Some(Keys::Numpad6),
409 x11::keysym::XK_KP_7 => Some(Keys::Numpad7),
410 x11::keysym::XK_KP_8 => Some(Keys::Numpad8),
411 x11::keysym::XK_KP_9 => Some(Keys::Numpad9),
412 x11::keysym::XK_multiply => Some(Keys::Multiply),
413 x11::keysym::XK_KP_Add => Some(Keys::Add),
414 x11::keysym::XK_KP_Separator => Some(Keys::Separator),
415 x11::keysym::XK_KP_Subtract => Some(Keys::Subtract),
416 x11::keysym::XK_KP_Decimal => Some(Keys::Decimal),
417 x11::keysym::XK_KP_Divide => Some(Keys::Divide),
418 x11::keysym::XK_F1 => Some(Keys::F1),
419 x11::keysym::XK_F2 => Some(Keys::F2),
420 x11::keysym::XK_F3 => Some(Keys::F3),
421 x11::keysym::XK_F4 => Some(Keys::F4),
422 x11::keysym::XK_F5 => Some(Keys::F5),
423 x11::keysym::XK_F6 => Some(Keys::F6),
424 x11::keysym::XK_F7 => Some(Keys::F7),
425 x11::keysym::XK_F8 => Some(Keys::F8),
426 x11::keysym::XK_F9 => Some(Keys::F9),
427 x11::keysym::XK_F10 => Some(Keys::F10),
428 x11::keysym::XK_F11 => Some(Keys::F11),
429 x11::keysym::XK_F12 => Some(Keys::F12),
430 x11::keysym::XK_F13 => Some(Keys::F13),
431 x11::keysym::XK_F14 => Some(Keys::F14),
432 x11::keysym::XK_F15 => Some(Keys::F15),
433 x11::keysym::XK_F16 => Some(Keys::F16),
434 x11::keysym::XK_F17 => Some(Keys::F17),
435 x11::keysym::XK_F18 => Some(Keys::F18),
436 x11::keysym::XK_F19 => Some(Keys::F19),
437 x11::keysym::XK_F20 => Some(Keys::F20),
438 x11::keysym::XK_F21 => Some(Keys::F21),
439 x11::keysym::XK_F22 => Some(Keys::F22),
440 x11::keysym::XK_F23 => Some(Keys::F23),
441 x11::keysym::XK_F24 => Some(Keys::F24),
442
443 x11::keysym::XK_Num_Lock => Some(Keys::Numlock),
444 x11::keysym::XK_Scroll_Lock => Some(Keys::Scroll),
445
446 x11::keysym::XK_KP_Equal => Some(Keys::NumpadEqual),
447
448 x11::keysym::XK_Shift_L => Some(Keys::LShift),
449 x11::keysym::XK_Shift_R => Some(Keys::RShift),
450 x11::keysym::XK_Control_L => Some(Keys::LControl),
451 x11::keysym::XK_Control_R => Some(Keys::RControl),
452 x11::keysym::XK_Menu => Some(Keys::RMenu),
454
455 x11::keysym::XK_semicolon => Some(Keys::Semicolon),
456 x11::keysym::XK_plus => Some(Keys::Plus),
457 x11::keysym::XK_comma => Some(Keys::Comma),
458 x11::keysym::XK_minus => Some(Keys::Minus),
459 x11::keysym::XK_period => Some(Keys::Period),
460 x11::keysym::XK_slash => Some(Keys::Slash),
461 x11::keysym::XK_grave => Some(Keys::Grave),
462
463 x11::keysym::XK_a | x11::keysym::XK_A => Some(Keys::A),
464 x11::keysym::XK_b | x11::keysym::XK_B => Some(Keys::B),
465 x11::keysym::XK_c | x11::keysym::XK_C => Some(Keys::C),
466 x11::keysym::XK_d | x11::keysym::XK_D => Some(Keys::D),
467 x11::keysym::XK_e | x11::keysym::XK_E => Some(Keys::E),
468 x11::keysym::XK_f | x11::keysym::XK_F => Some(Keys::F),
469 x11::keysym::XK_g | x11::keysym::XK_G => Some(Keys::G),
470 x11::keysym::XK_h | x11::keysym::XK_H => Some(Keys::H),
471 x11::keysym::XK_i | x11::keysym::XK_I => Some(Keys::I),
472 x11::keysym::XK_j | x11::keysym::XK_J => Some(Keys::J),
473 x11::keysym::XK_k | x11::keysym::XK_K => Some(Keys::K),
474 x11::keysym::XK_l | x11::keysym::XK_L => Some(Keys::L),
475 x11::keysym::XK_m | x11::keysym::XK_M => Some(Keys::M),
476 x11::keysym::XK_n | x11::keysym::XK_N => Some(Keys::N),
477 x11::keysym::XK_o | x11::keysym::XK_O => Some(Keys::O),
478 x11::keysym::XK_p | x11::keysym::XK_P => Some(Keys::P),
479 x11::keysym::XK_q | x11::keysym::XK_Q => Some(Keys::Q),
480 x11::keysym::XK_r | x11::keysym::XK_R => Some(Keys::R),
481 x11::keysym::XK_s | x11::keysym::XK_S => Some(Keys::S),
482 x11::keysym::XK_t | x11::keysym::XK_T => Some(Keys::T),
483 x11::keysym::XK_u | x11::keysym::XK_U => Some(Keys::U),
484 x11::keysym::XK_v | x11::keysym::XK_V => Some(Keys::V),
485 x11::keysym::XK_w | x11::keysym::XK_W => Some(Keys::W),
486 x11::keysym::XK_x | x11::keysym::XK_X => Some(Keys::X),
487 x11::keysym::XK_y | x11::keysym::XK_Y => Some(Keys::Y),
488 x11::keysym::XK_z | x11::keysym::XK_Z => Some(Keys::Z),
489 _ => { log::warn!("Unrecognized x keysym: {}", key_sym); None }
490 }
491 }
492}
493
494
495#[cfg(target_os = "windows")]
496impl Window {
497 pub const WINDOW_CLASS_NAME: &'static str = "window_class";
498
499 fn new_win32(
500 window_name: &str,
501 x: i32, y: i32,
502 width: i32, height: i32,
503 ) -> Self {
504 let window_class_name_utf16 = Self::wide_null(Self::WINDOW_CLASS_NAME);
505 let application_name_utf16 = Self::wide_null(window_name);
506
507 let h_instance = unsafe { GetModuleHandleA(ptr::null()) };
508
509 let icon = unsafe { LoadIconW(h_instance, IDI_APPLICATION) };
510
511 let wc = WNDCLASSW {
512 style: CS_DBLCLKS,
513 lpfnWndProc: Some(win32_process_message),
514 cbClsExtra: 0,
515 cbWndExtra: 0,
516 hInstance: h_instance,
517 hIcon: icon,
518 hCursor: unsafe { LoadCursorW(0, IDC_ARROW) },
519 hbrBackground: 0,
520 lpszClassName: window_class_name_utf16.as_ptr(),
521 lpszMenuName: ptr::null(),
522 };
523
524 if unsafe { RegisterClassW(&wc) } == 0 {
525 unsafe {
526 MessageBoxA(
527 0,
528 "Window registration failed.".as_ptr(),
529 "Error".as_ptr(),
530 MB_ICONEXCLAMATION | MB_OK
531 );
532 }
533
534 log::error!("Window registration failed.");
535 panic!("Window registration failed.");
536 }
537
538 let client_x = x;
539 let client_y = y;
540 let client_width = width;
541 let client_height = height;
542
543 let mut window_x = client_x;
544 let mut window_y = client_y;
545 let mut window_width = client_width;
546 let mut window_height = client_height;
547
548 let window_style = WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME;
549 let window_ex_style = WS_EX_APPWINDOW;
550
551 let mut border_rect = RECT { left: 0, right: 0, top: 0, bottom: 0 };
552 unsafe { AdjustWindowRectEx(&mut border_rect, window_style, 0, window_ex_style); }
553
554 window_x += border_rect.left;
555 window_y += border_rect.top;
556 window_width += border_rect.right - border_rect.left;
557 window_height += border_rect.bottom - border_rect.top;
558
559 let handle = unsafe {
560 CreateWindowExW(
561 window_ex_style, window_class_name_utf16.as_ptr(), application_name_utf16.as_ptr(),
562 window_style, window_x, window_y, window_width, window_height,
563 0, 0, h_instance, ptr::null()
564 )
565 };
566
567 if handle == 0 {
568 unsafe {
569 MessageBoxA(
570 0,
571 "Window creation failed.".as_ptr(),
572 "Error".as_ptr(),
573 MB_ICONEXCLAMATION | MB_OK
574 );
575 }
576
577 log::error!("Window creation failed.");
578 panic!("Window creation failed.");
579 }
580
581 let should_activate = true;
583 let show_window_command_flags = if should_activate { SW_SHOW } else { SW_SHOWNOACTIVATE };
584
585 unsafe { ShowWindow(handle, show_window_command_flags); }
586
587 Self {
588 previous_size: (window_width as u32, window_height as u32),
589 h_instance,
590 hwnd: handle,
591 }
592 }
593
594 fn poll_messages_win32(&mut self, mut event_closure: impl FnMut(WindowEvent)) {
595 let mut message = MaybeUninit::<MSG>::uninit();
596
597 while unsafe { PeekMessageW(message.as_mut_ptr(), self.hwnd, 0, 0, PM_REMOVE) } != 0 {
598 unsafe {
599 if !(message.assume_init().message == CUSTOM_CLOSE_MESSAGE
600 || message.assume_init().message == CUSTOM_SIZE_MESSAGE) {
601 TranslateMessage(message.as_mut_ptr());
602 DispatchMessageW(message.as_mut_ptr());
603 }
604 }
605
606 match unsafe { message.assume_init().message } {
607 CUSTOM_CLOSE_MESSAGE => {
608 (event_closure)(WindowEvent::Close);
609 },
610 CUSTOM_SIZE_MESSAGE => {
611 let mut r = MaybeUninit::<RECT>::uninit();
612 unsafe { GetClientRect(self.hwnd, r.as_mut_ptr()); }
613
614
615 let width = unsafe { r.assume_init().right - r.assume_init().left } as u32;
616 let height = unsafe { r.assume_init().bottom - r.assume_init().top } as u32;
617
618 if self.previous_size != (width, height) {
619 self.previous_size = (width, height);
620 (event_closure)(WindowEvent::Resize(width, height));
621 }
622 },
623 WM_MOUSEMOVE => {
624 let mouse_pos = utility::get_x_y_lparam(unsafe{ message.assume_init().lParam });
625 (event_closure)(WindowEvent::Input(WindowInputEvent::MouseMove(mouse_pos.0, mouse_pos.1)));
626 },
627 WM_KEYDOWN | WM_SYSKEYDOWN => {
628 if ((unsafe { message.assume_init().lParam } >> 30) & 1) as u8 == 0 {
630 let key = Keys::from_usize(unsafe { message.assume_init().wParam });
631 (event_closure)(WindowEvent::Input(WindowInputEvent::KeyDown(key)));
632 }
633 },
634 WM_KEYUP | WM_SYSKEYUP => {
635 let key = Keys::from_usize(unsafe { message.assume_init().wParam });
636 (event_closure)(WindowEvent::Input(WindowInputEvent::KeyUp(key)));
637 },
638 WM_MOUSEWHEEL => {
639 let dz = if utility::get_wheel_delta_wparam(unsafe { message.assume_init().wParam }) < 0 {
640 -1i16
641 } else {
642 1i16
643 };
644
645 (event_closure)(WindowEvent::Input(WindowInputEvent::MouseWheelMove(dz)));
646 },
647 WM_LBUTTONDOWN => (event_closure)(WindowEvent::Input(WindowInputEvent::MouseDown(MouseButton::Left))),
648 WM_MBUTTONDOWN => (event_closure)(WindowEvent::Input(WindowInputEvent::MouseDown(MouseButton::Middle))),
649 WM_RBUTTONDOWN => (event_closure)(WindowEvent::Input(WindowInputEvent::MouseDown(MouseButton::Right))),
650 WM_LBUTTONUP => (event_closure)(WindowEvent::Input(WindowInputEvent::MouseUp(MouseButton::Left))),
651 WM_MBUTTONUP => (event_closure)(WindowEvent::Input(WindowInputEvent::MouseUp(MouseButton::Middle))),
652 WM_RBUTTONUP => (event_closure)(WindowEvent::Input(WindowInputEvent::MouseUp(MouseButton::Right))),
653 _ => (),
654 }
655
656 }
657 }
658
659 fn raw_window_handle_win32(&self) -> RawWindowHandle {
660 let mut handle = Win32WindowHandle::new(NonZeroIsize::new(self.hwnd).unwrap());
661 handle.hinstance = NonZeroIsize::new(self.h_instance);
662
663 RawWindowHandle::Win32(handle)
664 }
665
666 fn raw_display_handle_windows(&self) -> RawDisplayHandle {
667 RawDisplayHandle::Windows(WindowsDisplayHandle::new())
668 }
669
670 fn wide_null(s: &str) -> Vec<u16> {
671 s.encode_utf16().chain(Some(0)).collect()
672 }
673}
674
675#[cfg(target_os = "windows")]
676impl Drop for Window {
677 fn drop(&mut self) {
678 unsafe { DestroyWindow(self.hwnd); }
679 }
680}
681
682pub enum MouseButton {
683 Left,
684 Right,
685 Middle,
686}
687
688impl MouseButton {
689 pub fn as_str(&self) -> &str {
690 match self {
691 Self::Left => "Left",
692 Self::Middle => "Middle",
693 Self::Right => "Right",
694 }
695 }
696}
697
698pub enum Keys {
699 Backspace,
700 Enter,
701 Tab,
702 Shift,
703 Control,
704
705 Pause,
706 Capital,
707
708 Escape,
709
710 Convert,
711 Nonconvert,
712 Accept,
713 Modechange,
714
715 Space,
716 Prior,
717 Next,
718 End,
719 Home,
720 Left,
721 Up,
722 Right,
723 Down,
724 Select,
725 Print,
726 Execute,
727 Snapshot,
728 Insert,
729 Delete,
730 Help,
731
732 A,
733 B,
734 C,
735 D,
736 E,
737 F,
738 G,
739 H,
740 I,
741 J,
742 K,
743 L,
744 M,
745 N,
746 O,
747 P,
748 Q,
749 R,
750 S,
751 T,
752 U,
753 V,
754 W,
755 X,
756 Y,
757 Z,
758
759 LWin,
760 RWin,
761 Apps,
762
763 Sleep,
764
765 Numpad0,
766 Numpad1,
767 Numpad2,
768 Numpad3,
769 Numpad4,
770 Numpad5,
771 Numpad6,
772 Numpad7,
773 Numpad8,
774 Numpad9,
775 Multiply,
776 Add,
777 Separator,
778 Subtract,
779 Decimal,
780 Divide,
781 F1,
782 F2,
783 F3,
784 F4,
785 F5,
786 F6,
787 F7,
788 F8,
789 F9,
790 F10,
791 F11,
792 F12,
793 F13,
794 F14,
795 F15,
796 F16,
797 F17,
798 F18,
799 F19,
800 F20,
801 F21,
802 F22,
803 F23,
804 F24,
805
806 Numlock,
807 Scroll,
808
809 NumpadEqual,
810
811 LShift,
812 RShift,
813 LControl,
814 RControl,
815 LMenu,
816 RMenu,
817
818 Semicolon,
819 Plus,
820 Comma,
821 Minus,
822 Period,
823 Slash,
824 Grave,
825}
826
827impl Keys {
828 pub fn from_usize(s: usize) -> Self {
829 match s {
830 0x08 => Self::Backspace,
831 0x0D => Self::Enter,
832 0x09 => Self::Tab,
833 0x10 => Self::Shift,
834 0x11 => Self::Control,
835
836 0x13 => Self::Pause,
837 0x14 => Self::Capital,
838
839 0x1B => Self::Escape,
840
841 0x1C => Self::Convert,
842 0x1D => Self::Nonconvert,
843 0x1E => Self::Accept,
844 0x1F => Self::Modechange,
845
846 0x20 => Self::Space,
847 0x21 => Self::Prior,
848 0x22 => Self::Next,
849 0x23 => Self::End,
850 0x24 => Self::Home,
851 0x25 => Self::Left,
852 0x26 => Self::Up,
853 0x27 => Self::Right,
854 0x28 => Self::Down,
855 0x29 => Self::Select,
856 0x2A => Self::Print,
857 0x2B => Self::Execute,
858 0x2C => Self::Snapshot,
859 0x2D => Self::Insert,
860 0x2E => Self::Delete,
861 0x2F => Self::Help,
862
863 0x41 => Self::A,
864 0x42 => Self::B,
865 0x43 => Self::C,
866 0x44 => Self::D,
867 0x45 => Self::E,
868 0x46 => Self::F,
869 0x47 => Self::G,
870 0x48 => Self::H,
871 0x49 => Self::I,
872 0x4A => Self::J,
873 0x4B => Self::K,
874 0x4C => Self::L,
875 0x4D => Self::M,
876 0x4E => Self::N,
877 0x4F => Self::O,
878 0x50 => Self::P,
879 0x51 => Self::Q,
880 0x52 => Self::R,
881 0x53 => Self::S,
882 0x54 => Self::T,
883 0x55 => Self::U,
884 0x56 => Self::V,
885 0x57 => Self::W,
886 0x58 => Self::X,
887 0x59 => Self::Y,
888 0x5A => Self::Z,
889
890 0x5B => Self::LWin,
891 0x5C => Self::RWin,
892 0x5D => Self::Apps,
893
894 0x5F => Self::Sleep,
895
896 0x60 => Self::Numpad0,
897 0x61 => Self::Numpad1,
898 0x62 => Self::Numpad2,
899 0x63 => Self::Numpad3,
900 0x64 => Self::Numpad4,
901 0x65 => Self::Numpad5,
902 0x66 => Self::Numpad6,
903 0x67 => Self::Numpad7,
904 0x68 => Self::Numpad8,
905 0x69 => Self::Numpad9,
906 0x6A => Self::Multiply,
907 0x6B => Self::Add,
908 0x6C => Self::Separator,
909 0x6D => Self::Subtract,
910 0x6E => Self::Decimal,
911 0x6F => Self::Divide,
912 0x70 => Self::F1,
913 0x71 => Self::F2,
914 0x72 => Self::F3,
915 0x73 => Self::F4,
916 0x74 => Self::F5,
917 0x75 => Self::F6,
918 0x76 => Self::F7,
919 0x77 => Self::F8,
920 0x78 => Self::F9,
921 0x79 => Self::F10,
922 0x7A => Self::F11,
923 0x7B => Self::F12,
924 0x7C => Self::F13,
925 0x7D => Self::F14,
926 0x7E => Self::F15,
927 0x7F => Self::F16,
928 0x80 => Self::F17,
929 0x81 => Self::F18,
930 0x82 => Self::F19,
931 0x83 => Self::F20,
932 0x84 => Self::F21,
933 0x85 => Self::F22,
934 0x86 => Self::F23,
935 0x87 => Self::F24,
936
937 0x90 => Self::Numlock,
938 0x91 => Self::Scroll,
939
940 0x92 => Self::NumpadEqual,
941
942 0xA0 => Self::LShift,
943 0xA1 => Self::RShift,
944 0xA2 => Self::LControl,
945 0xA3 => Self::RControl,
946 0xA4 => Self::LMenu,
947 0xA5 => Self::RMenu,
948
949 0xBA => Self::Semicolon,
950 0xBB => Self::Plus,
951 0xBC => Self::Comma,
952 0xBD => Self::Minus,
953 0xBE => Self::Period,
954 0xBF => Self::Slash,
955 0xC0 => Self::Grave,
956 _ => panic!("Provided usize does not corrospond to a valid Key."),
957 }
958 }
959
960 pub fn as_str(&self) -> &str {
961 match self {
962 Self::Backspace => "Backspace",
963 Self::Enter => "Enter",
964 Self::Tab => "Tab",
965 Self::Shift => "Shift",
966 Self::Control => "Control",
967
968 Self::Pause => "Pause",
969 Self::Capital => "Capital",
970
971 Self::Escape => "Escape",
972
973 Self::Convert => "Convert",
974 Self::Nonconvert => "Nonconvert",
975 Self::Accept => "Accept",
976 Self::Modechange => "Modechange",
977
978 Self::Space => "Space",
979 Self::Prior => "Prior",
980 Self::Next => "Next",
981 Self::End => "End",
982 Self::Home => "Home",
983 Self::Left => "Left",
984 Self::Up => "Up",
985 Self::Right => "Right",
986 Self::Down => "Down",
987 Self::Select => "Select",
988 Self::Print => "Print",
989 Self::Execute => "Execute",
990 Self::Snapshot => "Snapshot",
991 Self::Insert => "Insert",
992 Self::Delete => "Delete",
993 Self::Help => "Help",
994
995 Self::A => "A",
996 Self::B => "B",
997 Self::C => "C",
998 Self::D => "D",
999 Self::E => "E",
1000 Self::F => "F",
1001 Self::G => "G",
1002 Self::H => "H",
1003 Self::I => "I",
1004 Self::J => "J",
1005 Self::K => "K",
1006 Self::L => "L",
1007 Self::M => "M",
1008 Self::N => "N",
1009 Self::O => "O",
1010 Self::P => "P",
1011 Self::Q => "Q",
1012 Self::R => "R",
1013 Self::S => "S",
1014 Self::T => "T",
1015 Self::U => "U",
1016 Self::V => "V",
1017 Self::W => "W",
1018 Self::X => "X",
1019 Self::Y => "Y",
1020 Self::Z => "Z",
1021
1022 Self::LWin => "LWin",
1023 Self::RWin => "RWin",
1024 Self::Apps => "Apps",
1025
1026 Self::Sleep => "Sleep",
1027
1028 Self::Numpad0 => "Numpad0",
1029 Self::Numpad1 => "Numpad1",
1030 Self::Numpad2 => "Numpad2",
1031 Self::Numpad3 => "Numpad3",
1032 Self::Numpad4 => "Numpad4",
1033 Self::Numpad5 => "Numpad5",
1034 Self::Numpad6 => "Numpad6",
1035 Self::Numpad7 => "Numpad7",
1036 Self::Numpad8 => "Numpad8",
1037 Self::Numpad9 => "Numpad9",
1038 Self::Multiply => "Multiply",
1039 Self::Add => "Add",
1040 Self::Separator => "Separator",
1041 Self::Subtract => "Subtract",
1042 Self::Decimal => "Decimal",
1043 Self::Divide => "Divide",
1044 Self::F1 => "F1",
1045 Self::F2 => "F2",
1046 Self::F3 => "F3",
1047 Self::F4 => "F4",
1048 Self::F5 => "F5",
1049 Self::F6 => "F6",
1050 Self::F7 => "F7",
1051 Self::F8 => "F8",
1052 Self::F9 => "F9",
1053 Self::F10 => "F10",
1054 Self::F11 => "F11",
1055 Self::F12 => "F12",
1056 Self::F13 => "F13",
1057 Self::F14 => "F14",
1058 Self::F15 => "F15",
1059 Self::F16 => "F16",
1060 Self::F17 => "F17",
1061 Self::F18 => "F18",
1062 Self::F19 => "F19",
1063 Self::F20 => "F20",
1064 Self::F21 => "F21",
1065 Self::F22 => "F22",
1066 Self::F23 => "F23",
1067 Self::F24 => "F24",
1068
1069 Self::Numlock => "Numlock",
1070 Self::Scroll => "Scroll",
1071
1072 Self::NumpadEqual => "NumpadEqual",
1073
1074 Self::LShift => "LShift",
1075 Self::RShift => "RShift",
1076 Self::LControl => "LControl",
1077 Self::RControl => "RControl",
1078 Self::LMenu => "LMenu",
1079 Self::RMenu => "RMenu",
1080
1081 Self::Semicolon => "Semicolon",
1082 Self::Plus => "Plus",
1083 Self::Comma => "Comma",
1084 Self::Minus => "Minus",
1085 Self::Period => "Period",
1086 Self::Slash => "Slash",
1087 Self::Grave => "Grave",
1088 }
1089 }
1090}
1091