You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
7.1 KiB

  1. use std::collections::HashSet;
  2. use glutin::{
  3. event::{
  4. ElementState, Event, KeyboardInput, MouseScrollDelta, WindowEvent as GlutinWindowEvent,
  5. },
  6. event_loop::{ControlFlow, EventLoop},
  7. platform::desktop::EventLoopExtDesktop,
  8. };
  9. use shrev::{EventChannel, ReaderId};
  10. use space_crush_common::misc::{LogResult, WorldHelper};
  11. use specs::World;
  12. use crate::{misc::Window, Error};
  13. pub use glutin::event::{MouseButton, VirtualKeyCode};
  14. pub struct Events {
  15. keys: HashSet<VirtualKeyCode>,
  16. event_loop: EventLoop<()>,
  17. mouse_pos: Option<(f64, f64)>,
  18. mouse_lock: Option<(f64, f64)>,
  19. control_event_id: ReaderId<ControlEvent>,
  20. }
  21. impl Events {
  22. pub fn new(world: &mut World) -> Result<Self, Error> {
  23. world.insert(EventChannel::<ControlEvent>::default());
  24. world.insert(EventChannel::<MouseEvent>::default());
  25. world.insert(EventChannel::<WindowEvent>::default());
  26. world.insert(EventChannel::<KeyboardEvent>::default());
  27. let control_event_id = world.register_event_reader::<ControlEvent>()?;
  28. Ok(Self {
  29. keys: HashSet::new(),
  30. event_loop: EventLoop::new(),
  31. mouse_pos: None,
  32. mouse_lock: None,
  33. control_event_id,
  34. })
  35. }
  36. }
  37. impl Events {
  38. pub fn handle(&self) -> &EventLoop<()> {
  39. &self.event_loop
  40. }
  41. pub fn process(&mut self, world: &World, window: &Window) {
  42. let control_events = world.fetch::<EventChannel<ControlEvent>>();
  43. let mut mouse_events = world.fetch_mut::<EventChannel<MouseEvent>>();
  44. let mut window_events = world.fetch_mut::<EventChannel<WindowEvent>>();
  45. let mut keyboard_events = world.fetch_mut::<EventChannel<KeyboardEvent>>();
  46. let keys = &mut self.keys;
  47. let mouse_pos = &mut self.mouse_pos;
  48. let event_loop = &mut self.event_loop;
  49. let mouse_lock = &mut self.mouse_lock;
  50. let events = control_events.read(&mut self.control_event_id);
  51. for event in events {
  52. match event {
  53. ControlEvent::LockMouse => {
  54. *mouse_lock = *mouse_pos;
  55. window
  56. .set_mouse_locked(true)
  57. .warn("Unable to lock mouse to window");
  58. }
  59. ControlEvent::UnlockMouse => {
  60. *mouse_lock = None;
  61. window
  62. .set_mouse_locked(false)
  63. .warn("Unable to lock mouse to window");
  64. }
  65. }
  66. }
  67. let mut has_mouse_moved = false;
  68. event_loop.run_return(|event, _target, flow_control| {
  69. *flow_control = ControlFlow::Poll;
  70. match event {
  71. Event::MainEventsCleared | Event::RedrawRequested(_) => {
  72. *flow_control = ControlFlow::Exit;
  73. }
  74. Event::WindowEvent { event, .. } => match event {
  75. /* Mouse Events */
  76. GlutinWindowEvent::CursorMoved { position, .. } => {
  77. if mouse_lock.is_none() {
  78. mouse_events
  79. .single_write(MouseEvent::Move(position.x as _, position.y as _));
  80. }
  81. if let Some((x, y)) = mouse_pos {
  82. let dx = position.x - *x;
  83. let dy = position.y - *y;
  84. mouse_events.single_write(MouseEvent::Delta(dx as _, dy as _));
  85. }
  86. has_mouse_moved = true;
  87. *mouse_pos = Some((position.x as _, position.y as _));
  88. }
  89. GlutinWindowEvent::MouseInput {
  90. state: ElementState::Pressed,
  91. button,
  92. ..
  93. } => {
  94. mouse_events.single_write(MouseEvent::ButtonDown(button));
  95. }
  96. GlutinWindowEvent::MouseInput {
  97. state: ElementState::Released,
  98. button,
  99. ..
  100. } => {
  101. mouse_events.single_write(MouseEvent::ButtonUp(button));
  102. }
  103. GlutinWindowEvent::MouseWheel {
  104. delta: MouseScrollDelta::LineDelta(x, y),
  105. ..
  106. } => {
  107. if x != 0.0 {
  108. mouse_events.single_write(MouseEvent::ScrollX(x));
  109. }
  110. if y != 0.0 {
  111. mouse_events.single_write(MouseEvent::ScrollY(y));
  112. }
  113. }
  114. GlutinWindowEvent::CursorLeft { .. } => {
  115. *mouse_pos = None;
  116. }
  117. /* Key Event */
  118. GlutinWindowEvent::KeyboardInput {
  119. input:
  120. KeyboardInput {
  121. state: ElementState::Pressed,
  122. virtual_keycode: Some(key),
  123. ..
  124. },
  125. ..
  126. } => {
  127. if keys.insert(key) {
  128. keyboard_events.single_write(KeyboardEvent::KeyDown(key));
  129. }
  130. keyboard_events.single_write(KeyboardEvent::KeyPress(key));
  131. }
  132. GlutinWindowEvent::KeyboardInput {
  133. input:
  134. KeyboardInput {
  135. state: ElementState::Released,
  136. virtual_keycode: Some(key),
  137. ..
  138. },
  139. ..
  140. } => {
  141. if keys.remove(&key) {
  142. keyboard_events.single_write(KeyboardEvent::KeyUp(key));
  143. }
  144. }
  145. /* Window Event */
  146. GlutinWindowEvent::Resized(pos) => {
  147. window_events.single_write(WindowEvent::Resize(pos.width, pos.height));
  148. }
  149. GlutinWindowEvent::CloseRequested => {
  150. window_events.single_write(WindowEvent::Close);
  151. }
  152. /* Ignore */
  153. _ => (),
  154. },
  155. _ => (),
  156. }
  157. });
  158. if let Some((x, y)) = self.mouse_lock {
  159. if has_mouse_moved {
  160. window.set_mouse_pos(x, y).warn("Unable to set mouse pos");
  161. self.mouse_pos = Some((x, y));
  162. }
  163. }
  164. }
  165. }
  166. pub enum ControlEvent {
  167. LockMouse,
  168. UnlockMouse,
  169. }
  170. pub enum WindowEvent {
  171. Resize(u32, u32),
  172. Close,
  173. }
  174. pub enum MouseEvent {
  175. Move(f32, f32),
  176. Delta(f32, f32),
  177. ButtonDown(MouseButton),
  178. ButtonUp(MouseButton),
  179. ScrollX(f32),
  180. ScrollY(f32),
  181. }
  182. pub enum KeyboardEvent {
  183. KeyUp(VirtualKeyCode),
  184. KeyDown(VirtualKeyCode),
  185. KeyPress(VirtualKeyCode),
  186. }