1#![deny(missing_docs)]
2
3extern crate glutin;
6extern crate gl;
7extern crate glutin_winit;
8extern crate input;
9extern crate raw_window_handle;
10extern crate window;
11extern crate winit;
12extern crate shader_version;
13extern crate rustc_hash;
14
15use rustc_hash::FxHashMap;
16
17use std::collections::VecDeque;
18use std::error::Error;
19
20use input::{
22 ButtonArgs,
23 ButtonState,
24 CloseArgs,
25 Event,
26 Key,
27 Motion,
28 MouseButton,
29 Button,
30 Input,
31 ResizeArgs,
32};
33use window::{
34 BuildFromWindowSettings,
35 OpenGLWindow,
36 Window,
37 AdvancedWindow,
38 ProcAddress,
39 WindowSettings,
40 Size,
41 Position,
42 Api,
43 UnsupportedGraphicsApiError,
44};
45use winit::{
46 application::ApplicationHandler,
47 dpi::{LogicalPosition, LogicalSize},
48 event_loop::{ActiveEventLoop, EventLoop},
49 event::{DeviceId, ElementState, MouseScrollDelta, WindowEvent},
50 window::WindowId,
51};
52use glutin::context::PossiblyCurrentGlContext;
53use glutin::display::GlDisplay;
54use glutin::prelude::GlSurface;
55use std::time::Duration;
56use std::sync::Arc;
57
58pub use shader_version::OpenGL;
59
60
61#[derive(Copy, Clone, PartialEq, Eq, Debug)]
71pub enum KeyboardIgnoreModifiers {
72 None,
82 AbcKeyCode,
104}
105
106pub struct GlutinWindow {
108 pub ctx: Option<glutin::context::PossiblyCurrentContext>,
110 pub surface: Option<glutin::surface::Surface<glutin::surface::WindowSurface>>,
112 pub display: Option<glutin::display::Display>,
114 pub event_loop: Option<EventLoop<UserEvent>>,
119 pub keyboard_ignore_modifiers: KeyboardIgnoreModifiers,
123 pub window: Option<Arc<winit::window::Window>>,
132 pub devices: u32,
134 pub device_id_map: FxHashMap<DeviceId, u32>,
136 settings: WindowSettings,
138 title: String,
140 exit_on_esc: bool,
141 should_close: bool,
142 automatic_close: bool,
143 is_capturing_cursor: bool,
146 last_cursor_pos: Option<[f64; 2]>,
148 mouse_relative: Option<(f64, f64)>,
150 cursor_pos: Option<[f64; 2]>,
152 last_key_pressed: Option<input::Key>,
154 events: VecDeque<Event>,
156}
157
158fn graphics_api_from_settings(settings: &WindowSettings) -> Result<Api, Box<dyn Error>> {
159 let api = settings.get_maybe_graphics_api().unwrap_or(Api::opengl(3, 2));
160 if api.api != "OpenGL" {
161 return Err(UnsupportedGraphicsApiError {
162 found: api.api,
163 expected: vec!["OpenGL".into()]
164 }.into());
165 };
166 Ok(api)
167}
168
169fn surface_attributes_builder_from_settings(
170 settings: &WindowSettings
171) -> glutin::surface::SurfaceAttributesBuilder<glutin::surface::WindowSurface> {
172 glutin::surface::SurfaceAttributesBuilder::<glutin::surface::WindowSurface>::new()
173 .with_srgb(Some(settings.get_srgb()))
174}
175
176fn config_template_builder_from_settings(
177 settings: &WindowSettings
178) -> glutin::config::ConfigTemplateBuilder {
179 let x = glutin::config::ConfigTemplateBuilder::new()
180 .with_transparency(settings.get_transparent());
181 let samples = settings.get_samples();
182 if samples == 0 {x} else {
183 x.with_multisampling(samples)
184 }
185}
186
187impl GlutinWindow {
188
189 pub fn new(settings: &WindowSettings) -> Result<Self, Box<dyn Error>> {
191 let event_loop = winit::event_loop::EventLoop::with_user_event().build()?;
192 Self::from_event_loop(settings, event_loop)
193 }
194
195 pub fn from_event_loop(
197 settings: &WindowSettings,
198 event_loop: winit::event_loop::EventLoop<UserEvent>,
199 ) -> Result<Self, Box<dyn Error>> {
200 let title = settings.get_title();
201 let exit_on_esc = settings.get_exit_on_esc();
202
203 let mut w = GlutinWindow {
204 ctx: None,
205 display: None,
206 surface: None,
207 window: None,
208 title,
209 exit_on_esc,
210 settings: settings.clone(),
211 should_close: false,
212 automatic_close: settings.get_automatic_close(),
213 cursor_pos: None,
214 is_capturing_cursor: false,
215 last_cursor_pos: None,
216 mouse_relative: None,
217 last_key_pressed: None,
218 event_loop: Some(event_loop),
219 keyboard_ignore_modifiers: KeyboardIgnoreModifiers::None,
220 events: VecDeque::new(),
221
222 devices: 0,
223 device_id_map: FxHashMap::default(),
224 };
225 if let Some(e) = w.poll_event() {w.events.push_front(e)}
227 Ok(w)
228 }
229
230 pub fn get_window_ref(&self) -> &winit::window::Window {
234 self.window.as_ref().unwrap()
235 }
236
237 pub fn get_window(&self) -> Arc<winit::window::Window> {
239 self.window.as_ref().unwrap().clone()
240 }
241
242 fn pre_pop_front_event(&mut self) -> Option<Input> {
245 use input::Motion;
246
247 if let Some(pos) = self.cursor_pos {
249 self.cursor_pos = None;
250 return Some(Input::Move(Motion::MouseCursor(pos)));
251 }
252
253 if let Some((x, y)) = self.mouse_relative {
255 self.mouse_relative = None;
256 return Some(Input::Move(Motion::MouseRelative([x, y])));
257 }
258
259 None
260 }
261
262 fn handle_event(
269 &mut self,
270 event: winit::event::WindowEvent,
271 unknown: &mut bool,
272 ) -> Option<Input> {
273 use winit::keyboard::{Key, NamedKey};
274
275 match event {
276 WindowEvent::KeyboardInput { event: ref ev, .. } => {
277 if self.exit_on_esc {
278 if let Key::Named(NamedKey::Escape) = ev.logical_key {
279 self.set_should_close(true);
280 return None;
281 }
282 }
283 if let Some(s) = &ev.text {
284 let s = s.to_string();
285 let repeat = ev.repeat;
286 if !repeat {
287 if let Some(input) = map_window_event(
288 event,
289 self.get_window_ref().scale_factor(),
290 self.keyboard_ignore_modifiers,
291 unknown,
292 &mut self.last_key_pressed,
293 &mut self.devices,
294 &mut self.device_id_map,
295 ) {
296 self.events.push_back(Event::Input(input, None));
297 }
298 }
299
300 return Some(Input::Text(s));
301 }
302 }
303 WindowEvent::CursorMoved { position, .. } => {
304 let scale = self.get_window_ref().scale_factor();
305 let position = position.to_logical::<f64>(scale);
306 let x = f64::from(position.x);
307 let y = f64::from(position.y);
308
309 let pre_event = self.pre_pop_front_event();
310 let mut input = || {
311 if let Some(pos) = self.last_cursor_pos {
312 let dx = x - pos[0];
313 let dy = y - pos[1];
314 if self.is_capturing_cursor {
315 self.last_cursor_pos = Some([x, y]);
316 self.fake_capture();
317 return Some(Input::Move(Motion::MouseRelative([dx as f64, dy as f64])));
319 }
320 self.mouse_relative = Some((dx as f64, dy as f64));
322 } else if self.is_capturing_cursor {
323 self.last_cursor_pos = Some([x, y]);
326 return None;
327 }
328
329 self.last_cursor_pos = Some([x, y]);
330 return Some(Input::Move(Motion::MouseCursor([x, y])))
331 };
332
333 let input = input();
334 return if pre_event.is_some() {
335 if let Some(input) = input {
336 self.events.push_back(Event::Input(input, None));
337 }
338 pre_event
339 } else {input}
340 }
341 _ => {}
342 }
343
344 let input = map_window_event(
346 event,
347 self.get_window_ref().scale_factor(),
348 self.keyboard_ignore_modifiers,
349 unknown,
350 &mut self.last_key_pressed,
351 &mut self.devices,
352 &mut self.device_id_map,
353 );
354
355 let pre_event = self.pre_pop_front_event();
356 if pre_event.is_some() {
357 if let Some(input) = input {
358 self.events.push_back(Event::Input(input, None));
359 }
360 pre_event
361 } else {input}
362 }
363
364 fn fake_capture(&mut self) {
365 if let Some(pos) = self.last_cursor_pos {
366 let size = self.size();
368 let cx = size.width / 2.0;
369 let cy = size.height / 2.0;
370 let dx = cx - pos[0];
371 let dy = cy - pos[1];
372 if dx != 0.0 || dy != 0.0 {
373 let pos = winit::dpi::LogicalPosition::new(cx, cy);
374 if let Ok(_) = self.get_window_ref().set_cursor_position(pos) {
375 self.last_cursor_pos = Some([cx, cy]);
376 }
377 }
378 }
379 }
380}
381
382impl ApplicationHandler<UserEvent> for GlutinWindow {
383 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
384 use glutin::display::GetGlDisplay;
385 use glutin::config::GlConfig;
386 use glutin::context::ContextApi;
387 use glutin::context::NotCurrentGlContext;
388 use raw_window_handle::HasRawWindowHandle;
389 use std::num::NonZeroU32;
390
391 let settings = &self.settings;
392
393 let template = config_template_builder_from_settings(settings);
394 let display_builder = glutin_winit::DisplayBuilder::new();
395 let (_, gl_config) = display_builder
396 .build(event_loop, template, |configs| {
397 configs.reduce(|accum, config| {
398 let transparency_check = config.supports_transparency().unwrap_or(false)
399 & !accum.supports_transparency().unwrap_or(false);
400
401 if transparency_check || config.num_samples() > accum.num_samples() {
402 config
403 } else {
404 accum
405 }
406 })
407 .unwrap()
408 }).unwrap();
409
410 let window = event_loop.create_window(winit::window::Window::default_attributes()
411 .with_inner_size(LogicalSize::<f64>::new(
412 settings.get_size().width.into(),
413 settings.get_size().height.into(),
414 ))
415 .with_title(settings.get_title())
416 ).unwrap();
417
418 let raw_window_handle = window.raw_window_handle().unwrap();
419 let draw_size = window.inner_size();
420 let dw = NonZeroU32::new(draw_size.width).unwrap();
421 let dh = NonZeroU32::new(draw_size.height).unwrap();
422 let surface_attributes = surface_attributes_builder_from_settings(settings)
423 .build(raw_window_handle, dw, dh);
424
425 let display: glutin::display::Display = gl_config.display();
426 let surface = unsafe {display.create_window_surface(&gl_config, &surface_attributes).unwrap()};
427
428 let api = graphics_api_from_settings(settings).unwrap();
429 let context_attributes = glutin::context::ContextAttributesBuilder::new()
430 .with_context_api(glutin::context::ContextApi::OpenGl(Some(glutin::context::Version::new(api.major as u8, api.minor as u8))))
431 .build(Some(raw_window_handle));
432
433 let fallback_context_attributes = glutin::context::ContextAttributesBuilder::new()
434 .with_context_api(ContextApi::Gles(None))
435 .build(Some(raw_window_handle));
436
437 let legacy_context_attributes = glutin::context::ContextAttributesBuilder::new()
438 .with_context_api(glutin::context::ContextApi::OpenGl(Some(glutin::context::Version::new(2, 1))))
439 .build(Some(raw_window_handle));
440
441 let mut not_current_gl_context = Some(unsafe {
442 if let Ok(x) = display.create_context(&gl_config, &context_attributes) {x}
443 else if let Ok(x) = display.create_context(&gl_config, &fallback_context_attributes) {x}
444 else {
445 display.create_context(&gl_config, &legacy_context_attributes).unwrap()
446 }
447 });
448
449 let ctx: glutin::context::PossiblyCurrentContext = not_current_gl_context.take().unwrap()
450 .make_current(&surface).unwrap();
451
452 if settings.get_vsync() {
453 surface.set_swap_interval(&ctx,
454 glutin::surface::SwapInterval::Wait(NonZeroU32::new(1).unwrap())).unwrap();
455 }
456
457 gl::load_with(|s| {
459 use std::ffi::CString;
460
461 let s = CString::new(s).expect("CString::new failed");
462 display.get_proc_address(&s) as *const _
463 });
464
465 self.ctx = Some(ctx);
466 self.surface = Some(surface);
467 self.display = Some(display);
468 self.window = Some(Arc::new(window));
469 }
470
471 fn window_event(
472 &mut self,
473 event_loop: &ActiveEventLoop,
474 _window_id: WindowId,
475 event: WindowEvent,
476 ) {
477 let window = &self.get_window_ref();
478
479 match event {
480 WindowEvent::CloseRequested => {
481 if self.automatic_close {
482 self.should_close = true;
483 event_loop.exit();
484 }
485 }
486 WindowEvent::RedrawRequested => {
487 window.request_redraw();
488 },
489 event => {
490 let mut unknown = false;
491 if let Some(ev) = self.handle_event(event, &mut unknown) {
492 if !unknown {
493 self.events.push_back(Event::Input(ev, None));
494 }
495 }
496 }
497 }
498 }
499}
500
501impl Window for GlutinWindow {
502 fn size(&self) -> Size {
503 let window = self.get_window_ref();
504 let (w, h): (u32, u32) = window.inner_size().into();
505 let hidpi = window.scale_factor();
506 ((w as f64 / hidpi) as u32, (h as f64 / hidpi) as u32).into()
507 }
508
509 fn should_close(&self) -> bool { self.should_close }
510
511 fn set_should_close(&mut self, value: bool) { self.should_close = value; }
512
513 fn swap_buffers(&mut self) {
514 if let (Some(ctx), Some(surface)) = (&self.ctx, &self.surface) {
515 let _ = surface.swap_buffers(ctx);
516 }
517 }
518
519 fn wait_event(&mut self) -> Event {
520 use winit::platform::pump_events::EventLoopExtPumpEvents;
521 use input::{IdleArgs, Loop};
522
523 if let Some(mut event_loop) = std::mem::replace(&mut self.event_loop, None) {
526 let event_loop_proxy = event_loop.create_proxy();
527 event_loop_proxy
528 .send_event(UserEvent::WakeUp)
529 .expect("Event loop is closed before property handling all events.");
530 event_loop.pump_app_events(None, self);
531 self.event_loop = Some(event_loop);
532 }
533
534 let event = self.events.pop_front();
536
537 if let &Some(Event::Input(Input::Close(_), ..)) = &event {
539 self.set_should_close(true);
540 }
541
542 event.unwrap_or(Event::Loop(Loop::Idle(IdleArgs {dt: 0.0})))
543 }
544 fn wait_event_timeout(&mut self, timeout: Duration) -> Option<Event> {
545 use winit::platform::pump_events::EventLoopExtPumpEvents;
546
547 if let Some(mut event_loop) = std::mem::replace(&mut self.event_loop, None) {
550 let event_loop_proxy = event_loop.create_proxy();
551 event_loop_proxy
552 .send_event(UserEvent::WakeUp)
553 .expect("Event loop is closed before property handling all events.");
554 event_loop.pump_app_events(Some(timeout), self);
555 self.event_loop = Some(event_loop);
556 }
557
558 let event = self.events.pop_front();
560
561 if let &Some(Event::Input(Input::Close(_), ..)) = &event {
563 self.set_should_close(true);
564 }
565
566 event
567 }
568 fn poll_event(&mut self) -> Option<Event> {
569 use winit::platform::pump_events::EventLoopExtPumpEvents;
570
571 if let Some(mut event_loop) = std::mem::replace(&mut self.event_loop, None) {
574 let event_loop_proxy = event_loop.create_proxy();
575 event_loop_proxy
576 .send_event(UserEvent::WakeUp)
577 .expect("Event loop is closed before property handling all events.");
578 event_loop.pump_app_events(Some(Duration::ZERO), self);
579 self.event_loop = Some(event_loop);
580 }
581
582 let event = self.events.pop_front();
584
585 if let &Some(Event::Input(Input::Close(_), ..)) = &event {
587 self.set_should_close(true);
588 }
589
590 event
591 }
592
593 fn draw_size(&self) -> Size {
594 let size: (f64, f64) = self.get_window_ref().inner_size().into();
595 size.into()
596 }
597}
598
599impl BuildFromWindowSettings for GlutinWindow {
600 fn build_from_window_settings(settings: &WindowSettings)
601 -> Result<Self, Box<dyn Error>> {
602 GlutinWindow::new(settings)
603 }
604}
605
606impl AdvancedWindow for GlutinWindow {
607 fn get_title(&self) -> String {
608 self.title.clone()
609 }
610
611 fn set_title(&mut self, value: String) {
612 self.get_window_ref().set_title(&value);
613 self.title = value;
614 }
615
616 fn get_exit_on_esc(&self) -> bool {
617 self.exit_on_esc
618 }
619
620 fn set_exit_on_esc(&mut self, value: bool) {
621 self.exit_on_esc = value
622 }
623
624 fn set_capture_cursor(&mut self, value: bool) {
625 self.is_capturing_cursor = value;
631 self.get_window_ref().set_cursor_visible(!value);
632 if value {
633 self.fake_capture();
634 }
635 }
636
637 fn get_automatic_close(&self) -> bool {self.automatic_close}
638
639 fn set_automatic_close(&mut self, value: bool) {self.automatic_close = value}
640
641 fn show(&mut self) {
642 self.get_window_ref().set_visible(true);
643 }
644
645 fn hide(&mut self) {
646 self.get_window_ref().set_visible(false);
647 }
648
649 fn get_position(&self) -> Option<Position> {
650 self.get_window_ref()
651 .outer_position()
652 .map(|p| Position { x: p.x, y: p.y })
653 .ok()
654 }
655
656 fn set_position<P: Into<Position>>(&mut self, val: P) {
657 let val = val.into();
658 self.get_window_ref()
659 .set_outer_position(LogicalPosition::new(val.x as f64, val.y as f64))
660 }
661
662 fn set_size<S: Into<Size>>(&mut self, size: S) {
663 let size: Size = size.into();
664 let w = self.get_window_ref();
665 let _ = w.request_inner_size(LogicalSize::new(
666 size.width as f64,
667 size.height as f64,
668 ));
669 }
670}
671
672impl OpenGLWindow for GlutinWindow {
673 fn get_proc_address(&mut self, proc_name: &str) -> ProcAddress {
674 use std::ffi::CString;
675
676 let s = CString::new(proc_name).expect("CString::new failed");
677 self.display.as_ref().expect("No display").get_proc_address(&s) as *const _
678 }
679
680 fn is_current(&self) -> bool {
681 if let Some(ctx) = &self.ctx {
682 ctx.is_current()
683 } else {false}
684 }
685
686 fn make_current(&mut self) {
687 if let (Some(ctx), Some(surface)) = (&self.ctx, &self.surface) {
688 let _ = ctx.make_current(surface);
689 }
690 }
691}
692
693fn map_key(input: &winit::event::KeyEvent, kim: KeyboardIgnoreModifiers) -> Key {
694 use winit::keyboard::NamedKey::*;
695 use winit::keyboard::Key::*;
696 use KeyboardIgnoreModifiers as KIM;
697
698 match input.logical_key {
699 Character(ref ch) => match ch.as_str() {
700 "0" | ")" if kim == KIM::AbcKeyCode => Key::D0,
701 "0" => Key::D0,
702 ")" => Key::RightParen,
703 "1" | "!" if kim == KIM::AbcKeyCode => Key::D1,
704 "1" => Key::D1,
705 "!" => Key::NumPadExclam,
706 "2" | "@" if kim == KIM::AbcKeyCode => Key::D2,
707 "2" => Key::D2,
708 "@" => Key::At,
709 "3" | "#" if kim == KIM::AbcKeyCode => Key::D3,
710 "3" => Key::D3,
711 "#" => Key::Hash,
712 "4" | "$" if kim == KIM::AbcKeyCode => Key::D4,
713 "4" => Key::D4,
714 "$" => Key::Dollar,
715 "5" | "%" if kim == KIM::AbcKeyCode => Key::D5,
716 "5" => Key::D5,
717 "%" => Key::Percent,
718 "6" | "^" if kim == KIM::AbcKeyCode => Key::D6,
719 "6" => Key::D6,
720 "^" => Key::Caret,
721 "7" | "&" if kim == KIM::AbcKeyCode => Key::D7,
722 "7" => Key::D7,
723 "&" => Key::Ampersand,
724 "8" | "*" if kim == KIM::AbcKeyCode => Key::D8,
725 "8" => Key::D8,
726 "*" => Key::Asterisk,
727 "9" | "(" if kim == KIM::AbcKeyCode => Key::D9,
728 "9" => Key::D9,
729 "(" => Key::LeftParen,
730 "a" | "A" => Key::A,
731 "b" | "B" => Key::B,
732 "c" | "C" => Key::C,
733 "d" | "D" => Key::D,
734 "e" | "E" => Key::E,
735 "f" | "F" => Key::F,
736 "g" | "G" => Key::G,
737 "h" | "H" => Key::H,
738 "i" | "I" => Key::I,
739 "j" | "J" => Key::J,
740 "k" | "K" => Key::K,
741 "l" | "L" => Key::L,
742 "m" | "M" => Key::M,
743 "n" | "N" => Key::N,
744 "o" | "O" => Key::O,
745 "p" | "P" => Key::P,
746 "q" | "Q" => Key::Q,
747 "r" | "R" => Key::R,
748 "s" | "S" => Key::S,
749 "t" | "T" => Key::T,
750 "u" | "U" => Key::U,
751 "v" | "V" => Key::V,
752 "w" | "W" => Key::W,
753 "x" | "X" => Key::X,
754 "y" | "Y" => Key::Y,
755 "z" | "Z" => Key::Z,
756 "'" | "\"" if kim == KIM::AbcKeyCode => Key::Quote,
757 "'" => Key::Quote,
758 "\"" => Key::Quotedbl,
759 ";" | ":" if kim == KIM::AbcKeyCode => Key::Semicolon,
760 ";" => Key::Semicolon,
761 ":" => Key::Colon,
762 "[" | "{" if kim == KIM::AbcKeyCode => Key::LeftBracket,
763 "[" => Key::LeftBracket,
764 "{" => Key::NumPadLeftBrace,
765 "]" | "}" if kim == KIM::AbcKeyCode => Key::RightBracket,
766 "]" => Key::RightBracket,
767 "}" => Key::NumPadRightBrace,
768 "\\" | "|" if kim == KIM::AbcKeyCode => Key::Backslash,
769 "\\" => Key::Backslash,
770 "|" => Key::NumPadVerticalBar,
771 "," | "<" if kim == KIM::AbcKeyCode => Key::Comma,
772 "," => Key::Comma,
773 "<" => Key::Less,
774 "." | ">" if kim == KIM::AbcKeyCode => Key::Period,
775 "." => Key::Period,
776 ">" => Key::Greater,
777 "/" | "?" if kim == KIM::AbcKeyCode => Key::Slash,
778 "/" => Key::Slash,
779 "?" => Key::Question,
780 "`" | "~" if kim == KIM::AbcKeyCode => Key::Backquote,
781 "`" => Key::Backquote,
782 "~" => Key::Unknown,
786 _ => Key::Unknown,
787 }
788 Named(Escape) => Key::Escape,
789 Named(F1) => Key::F1,
790 Named(F2) => Key::F2,
791 Named(F3) => Key::F3,
792 Named(F4) => Key::F4,
793 Named(F5) => Key::F5,
794 Named(F6) => Key::F6,
795 Named(F7) => Key::F7,
796 Named(F8) => Key::F8,
797 Named(F9) => Key::F9,
798 Named(F10) => Key::F10,
799 Named(F11) => Key::F11,
800 Named(F12) => Key::F12,
801 Named(F13) => Key::F13,
802 Named(F14) => Key::F14,
803 Named(F15) => Key::F15,
804
805 Named(Delete) => Key::Delete,
806
807 Named(ArrowLeft) => Key::Left,
808 Named(ArrowUp) => Key::Up,
809 Named(ArrowRight) => Key::Right,
810 Named(ArrowDown) => Key::Down,
811
812 Named(Backspace) => Key::Backspace,
813 Named(Enter) => Key::Return,
814 Named(Space) => Key::Space,
815
816 Named(Alt) => Key::LAlt,
817 Named(AltGraph) => Key::RAlt,
818 Named(Control) => Key::LCtrl,
819 Named(Super) => Key::Menu,
820 Named(Shift) => Key::LShift,
821
822 Named(Tab) => Key::Tab,
823 _ => Key::Unknown,
824 }
825}
826
827fn map_keyboard_input(
828 input: &winit::event::KeyEvent,
829 kim: KeyboardIgnoreModifiers,
830 unknown: &mut bool,
831 last_key_pressed: &mut Option<Key>,
832) -> Option<Input> {
833 let key = map_key(input, kim);
834
835 let state = if input.state == ElementState::Pressed {
836 if let Some(last_key) = &*last_key_pressed {
838 if last_key == &key {
839 *unknown = true;
840 return None;
841 }
842 }
843 *last_key_pressed = Some(key);
844
845 ButtonState::Press
846 } else {
847 if let Some(last_key) = &*last_key_pressed {
848 if last_key == &key {
849 *last_key_pressed = None;
850 }
851 }
852 ButtonState::Release
853 };
854
855 Some(Input::Button(ButtonArgs {
856 state: state,
857 button: Button::Keyboard(key),
858 scancode: if let winit::keyboard::PhysicalKey::Code(code) = input.physical_key {
859 Some(code as i32)
860 } else {None},
861 }))
862}
863
864pub fn map_mouse(mouse_button: winit::event::MouseButton) -> MouseButton {
866 use winit::event::MouseButton as M;
867
868 match mouse_button {
869 M::Left => MouseButton::Left,
870 M::Right => MouseButton::Right,
871 M::Middle => MouseButton::Middle,
872 M::Other(0) => MouseButton::X1,
873 M::Other(1) => MouseButton::X2,
874 M::Other(2) => MouseButton::Button6,
875 M::Other(3) => MouseButton::Button7,
876 M::Other(4) => MouseButton::Button8,
877 _ => MouseButton::Unknown
878 }
879}
880
881fn map_window_event(
885 window_event: WindowEvent,
886 scale_factor: f64,
887 kim: KeyboardIgnoreModifiers,
888 unknown: &mut bool,
889 last_key_pressed: &mut Option<Key>,
890 devices: &mut u32,
891 device_id_map: &mut FxHashMap<DeviceId, u32>,
892) -> Option<Input> {
893 use input::FileDrag;
894
895 match window_event {
896 WindowEvent::DroppedFile(path) =>
897 Some(Input::FileDrag(FileDrag::Drop(path))),
898 WindowEvent::HoveredFile(path) =>
899 Some(Input::FileDrag(FileDrag::Hover(path))),
900 WindowEvent::HoveredFileCancelled =>
901 Some(Input::FileDrag(FileDrag::Cancel)),
902 WindowEvent::Resized(size) => Some(Input::Resize(ResizeArgs {
903 window_size: [size.width as f64, size.height as f64],
904 draw_size: Size {
905 width: size.width as f64,
906 height: size.height as f64,
907 }
908 .into(),
909 })),
910 WindowEvent::CloseRequested => Some(Input::Close(CloseArgs)),
911 WindowEvent::Destroyed => Some(Input::Close(CloseArgs)),
912 WindowEvent::Focused(focused) => Some(Input::Focus(focused)),
913 WindowEvent::KeyboardInput { ref event, .. } => {
914 map_keyboard_input(event, kim, unknown, last_key_pressed)
915 }
916 WindowEvent::CursorMoved { position, .. } => {
917 let position = position.to_logical(scale_factor);
918 Some(Input::Move(Motion::MouseCursor([position.x, position.y])))
919 }
920 WindowEvent::CursorEntered { .. } => Some(Input::Cursor(true)),
921 WindowEvent::CursorLeft { .. } => Some(Input::Cursor(false)),
922 WindowEvent::MouseWheel { delta, .. } => match delta {
923 MouseScrollDelta::PixelDelta(position) => {
924 let position = position.to_logical(scale_factor);
925 Some(Input::Move(Motion::MouseScroll([position.x, position.y])))
926 }
927 MouseScrollDelta::LineDelta(x, y) =>
928 Some(Input::Move(Motion::MouseScroll([x as f64, y as f64]))),
929 },
930 WindowEvent::MouseInput { state, button, .. } => {
931 let button = map_mouse(button);
932 let state = match state {
933 ElementState::Pressed => ButtonState::Press,
934 ElementState::Released => ButtonState::Release,
935 };
936
937 Some(Input::Button(ButtonArgs {
938 state,
939 button: Button::Mouse(button),
940 scancode: None,
941 }))
942 }
943 WindowEvent::AxisMotion { device_id, axis, value } => {
944 use input::ControllerAxisArgs;
945
946 Some(Input::Move(Motion::ControllerAxis(ControllerAxisArgs::new(
947 {
948 if let Some(id) = device_id_map.get(&device_id) {*id}
949 else {
950 let id = *devices;
951 *devices += 1;
952 device_id_map.insert(device_id, id);
953 id
954 }
955 },
956 axis as u8,
957 value,
958 ))))
959 }
960 WindowEvent::Touch(winit::event::Touch { phase, location, id, .. }) => {
961 use winit::event::TouchPhase;
962 use input::{Touch, TouchArgs};
963
964 let location = location.to_logical::<f64>(scale_factor);
965
966 Some(Input::Move(Motion::Touch(TouchArgs::new(
967 0, id as i64, [location.x, location.y], 1.0, match phase {
968 TouchPhase::Started => Touch::Start,
969 TouchPhase::Moved => Touch::Move,
970 TouchPhase::Ended => Touch::End,
971 TouchPhase::Cancelled => Touch::Cancel
972 }
973 ))))
974 }
975 WindowEvent::TouchpadPressure { .. } |
979 WindowEvent::PinchGesture { .. } |
980 WindowEvent::RotationGesture { .. } |
981 WindowEvent::PanGesture { .. } |
982 WindowEvent::DoubleTapGesture { .. } => None,
983 WindowEvent::ScaleFactorChanged { .. } => None,
984 WindowEvent::ActivationTokenDone { .. } => None,
985 WindowEvent::ThemeChanged(_) => None,
986 WindowEvent::Ime(_) => None,
987 WindowEvent::Occluded(_) => None,
988 WindowEvent::RedrawRequested { .. } => None,
989 WindowEvent::Moved(_) => None,
990 WindowEvent::ModifiersChanged(_) => None,
991 }
992}
993
994#[derive(Debug, Eq, PartialEq)]
995pub enum UserEvent {
997 WakeUp,
999}