sylasteven_system_input_default/
lib.rs

1#![deny(missing_docs)]
2/*!
3See [README.md](https://crates.io/crates/sylasteven-system-input-default)
4**/
5
6use sylasteven as engine;
7
8use glutin::{EventsLoop, GlContext, GlWindow};
9
10pub use glutin::{ModifiersState as Modifiers, MouseButton, VirtualKeyCode as KeyCode};
11
12/// An event representing input.
13pub enum InputEvent {
14    /// The event when the window is resized.
15    Resize {
16        /// The new window width.
17        width: u32,
18        /// The new window height.
19        height: u32,
20    },
21    /// The event when a key is pressed or released.
22    Key {
23        /// The code of the pressed or released key.
24        keycode: KeyCode,
25        /// The pressed modifiers.
26        modifiers: Modifiers,
27        /// A flag if the key is pressed, not released.
28        down: bool,
29    },
30    /// The event for text input.
31    TextInput(char),
32    /// The event when a mouse button is clicked or released.
33    MouseClick {
34        /// The clicked or released button.
35        button: MouseButton,
36        /// The pressed modifiers.
37        modifiers: Modifiers,
38        /// A flag if the key is clicked, not released.
39        down: bool,
40    },
41    /// The event when the mouse is moved.
42    MouseMove {
43        /// The new horizonal posiiton of the mouse.
44        x: f32,
45        /// The new vertical posiiton of the mouse.
46        y: f32,
47    },
48    /// The event when the mouse wheel is rotated.
49    MouseWheel(f32),
50    /// The event for files dragged or dropped over the window.
51    File {
52        /// A flag, if the file is dropped, not just hovered.
53        dropped: bool,
54        /// The path of the file.
55        path: std::path::PathBuf,
56    },
57    /// The quit event.
58    Quit,
59}
60
61/// The input system
62pub struct Input {
63    events_loop: EventsLoop,
64}
65
66impl Input {
67    /// Creates a new input window of specified size
68    pub fn new(name: &str, w: u32, h: u32) -> (Self, GlWindow) {
69        let events_loop = glutin::EventsLoop::new();
70        let window = glutin::WindowBuilder::new()
71            .with_title(name)
72            .with_dimensions(w, h);
73        let context = glutin::ContextBuilder::new()
74            .with_vsync(true)
75            .with_multisampling(4)
76            .with_srgb(false);
77        let gl_window = GlWindow::new(window, context, &events_loop).unwrap();
78
79        unsafe {
80            gl_window.make_current().unwrap();
81            gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _);
82            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
83        }
84
85        (Self { events_loop }, gl_window)
86    }
87}
88
89use crate::engine::{Handler, System};
90
91impl<H: Handler> System<H> for Input
92where
93    H::Event: From<InputEvent>,
94{
95    fn process(&mut self, handler: &mut H) {
96        let Self { events_loop } = self;
97        events_loop.poll_events(|event| {
98            if let Some(event) = match event {
99                glutin::Event::WindowEvent { event, .. } => match event {
100                    glutin::WindowEvent::CloseRequested => Some(InputEvent::Quit),
101                    glutin::WindowEvent::Resized(width, height) => {
102                        Some(InputEvent::Resize { width, height })
103                    }
104                    glutin::WindowEvent::KeyboardInput {
105                        input:
106                            glutin::KeyboardInput {
107                                state,
108                                virtual_keycode: Some(keycode),
109                                modifiers,
110                                ..
111                            },
112                        ..
113                    } => {
114                        use glutin::ElementState::*;
115                        let down = match state {
116                            Pressed => true,
117                            Released => false,
118                        };
119                        Some(InputEvent::Key {
120                            keycode,
121                            down,
122                            modifiers,
123                        })
124                    }
125
126                    glutin::WindowEvent::ReceivedCharacter(char) => {
127                        Some(InputEvent::TextInput(char))
128                    }
129
130                    glutin::WindowEvent::DroppedFile(path) => Some(InputEvent::File {
131                        dropped: true,
132                        path,
133                    }),
134
135                    glutin::WindowEvent::HoveredFile(path) => Some(InputEvent::File {
136                        dropped: false,
137                        path,
138                    }),
139
140                    glutin::WindowEvent::MouseInput {
141                        state,
142                        button,
143                        modifiers,
144                        ..
145                    } => {
146                        use glutin::ElementState::*;
147                        let down = match state {
148                            Pressed => true,
149                            Released => false,
150                        };
151                        Some(InputEvent::MouseClick {
152                            button,
153                            down,
154                            modifiers,
155                        })
156                    }
157                    glutin::WindowEvent::MouseWheel { delta, .. } => {
158                        use glutin::MouseScrollDelta::*;
159                        let delta = match delta {
160                            LineDelta(_, delta) => delta,
161                            PixelDelta(_, delta) => delta,
162                        };
163                        Some(InputEvent::MouseWheel(delta))
164                    }
165                    glutin::WindowEvent::CursorMoved { position, .. } => {
166                        Some(InputEvent::MouseMove {
167                            x: position.0 as f32,
168                            y: position.1 as f32,
169                        })
170                    }
171                    _ => None,
172                },
173                _ => None,
174            } {
175                handler.handle(event.into());
176            }
177        });
178    }
179}