1use instant::Instant;
2use winit::event::{
3 ElementState, KeyboardInput, MouseButton, MouseScrollDelta, VirtualKeyCode, WindowEvent,
4};
5
6use geom::Duration;
7
8use crate::{EventCtx, Line, ScreenDims, ScreenPt, TextSpan};
9
10const MAX_DOUBLE_CLICK_DURATION: instant::Duration = instant::Duration::from_millis(300);
15
16#[derive(Debug, Clone, Copy, PartialEq)]
17pub enum Event {
18 NoOp,
21 LeftMouseButtonDown,
22 LeftMouseButtonUp {
34 is_double_click: bool,
35 },
36 RightMouseButtonDown,
37 RightMouseButtonUp,
38 KeyPress(Key),
41 KeyRelease(Key),
42 Update(Duration),
44 MouseMovedTo(ScreenPt),
45 WindowLostCursor,
46 WindowGainedCursor,
47 MouseWheelScroll(f64, f64),
48 WindowResized(ScreenDims),
49}
50
51impl Event {
52 pub fn from_winit_event(
53 ev: WindowEvent,
54 scale_factor: f64,
55 previous_click: Instant,
56 ) -> Option<Event> {
57 match ev {
58 WindowEvent::MouseInput { state, button, .. } => match (button, state) {
59 (MouseButton::Left, ElementState::Pressed) => Some(Event::LeftMouseButtonDown),
60 (MouseButton::Left, ElementState::Released) => {
61 let is_double_click = previous_click.elapsed().le(&MAX_DOUBLE_CLICK_DURATION);
62 Some(Event::LeftMouseButtonUp { is_double_click })
63 }
64 (MouseButton::Right, ElementState::Pressed) => Some(Event::RightMouseButtonDown),
65 (MouseButton::Right, ElementState::Released) => Some(Event::RightMouseButtonUp),
66 _ => None,
67 },
68 WindowEvent::KeyboardInput { input, .. } => {
69 if let Some(key) = Key::from_winit_key(input) {
70 if input.state == ElementState::Pressed {
71 Some(Event::KeyPress(key))
72 } else {
73 Some(Event::KeyRelease(key))
74 }
75 } else {
76 None
77 }
78 }
79 WindowEvent::CursorMoved { position, .. } => Some(Event::MouseMovedTo(
80 position.to_logical(scale_factor).into(),
81 )),
82 WindowEvent::MouseWheel { delta, .. } => match delta {
83 MouseScrollDelta::LineDelta(dx, dy) => {
106 if dx == 0.0 && dy == 0.0 {
107 None
108 } else {
109 Some(Event::MouseWheelScroll(f64::from(dx), f64::from(dy)))
110 }
111 }
112 MouseScrollDelta::PixelDelta(pos) => {
113 let scale_factor = 0.01;
118
119 Some(Event::MouseWheelScroll(
120 scale_factor * pos.x,
121 scale_factor * pos.y,
122 ))
123 }
124 },
125 WindowEvent::Resized(size) => {
126 Some(Event::WindowResized(size.to_logical(scale_factor).into()))
127 }
128 WindowEvent::Focused(gained) => Some(if gained {
129 Event::WindowGainedCursor
130 } else {
131 Event::WindowLostCursor
132 }),
133 _ => None,
134 }
135 }
136}
137
138#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
139pub enum Key {
140 A,
144 B,
145 C,
146 D,
147 E,
148 F,
149 G,
150 H,
151 I,
152 J,
153 K,
154 L,
155 M,
156 N,
157 O,
158 P,
159 Q,
160 R,
161 S,
162 T,
163 U,
164 V,
165 W,
166 X,
167 Y,
168 Z,
169 Num1,
171 Num2,
172 Num3,
173 Num4,
174 Num5,
175 Num6,
176 Num7,
177 Num8,
178 Num9,
179 Num0,
180 LeftBracket,
183 RightBracket,
184 Space,
185 Slash,
186 Dot,
187 Comma,
188 Semicolon,
189 Colon,
190 Equals,
191 SingleQuote,
192 Minus,
193 Escape,
195 Enter,
196 Tab,
197 Backspace,
198 LeftShift,
199 LeftControl,
200 LeftAlt,
201 RightAlt,
202 LeftArrow,
203 RightArrow,
204 UpArrow,
205 DownArrow,
206 F1,
207 F2,
208 F3,
209 F4,
210 F5,
211 F6,
212 F7,
213 F8,
214 F9,
215 F10,
216 F11,
217 F12,
218}
219
220impl Key {
221 pub const NUM_KEYS: [Key; 9] = [
222 Key::Num1,
223 Key::Num2,
224 Key::Num3,
225 Key::Num4,
226 Key::Num5,
227 Key::Num6,
228 Key::Num7,
229 Key::Num8,
230 Key::Num9,
231 ];
232
233 pub fn to_char(self, shift_pressed: bool) -> Option<char> {
234 match self {
235 Key::A => Some(if shift_pressed { 'A' } else { 'a' }),
236 Key::B => Some(if shift_pressed { 'B' } else { 'b' }),
237 Key::C => Some(if shift_pressed { 'C' } else { 'c' }),
238 Key::D => Some(if shift_pressed { 'D' } else { 'd' }),
239 Key::E => Some(if shift_pressed { 'E' } else { 'e' }),
240 Key::F => Some(if shift_pressed { 'F' } else { 'f' }),
241 Key::G => Some(if shift_pressed { 'G' } else { 'g' }),
242 Key::H => Some(if shift_pressed { 'H' } else { 'h' }),
243 Key::I => Some(if shift_pressed { 'I' } else { 'i' }),
244 Key::J => Some(if shift_pressed { 'J' } else { 'j' }),
245 Key::K => Some(if shift_pressed { 'K' } else { 'k' }),
246 Key::L => Some(if shift_pressed { 'L' } else { 'l' }),
247 Key::M => Some(if shift_pressed { 'M' } else { 'm' }),
248 Key::N => Some(if shift_pressed { 'N' } else { 'n' }),
249 Key::O => Some(if shift_pressed { 'O' } else { 'o' }),
250 Key::P => Some(if shift_pressed { 'P' } else { 'p' }),
251 Key::Q => Some(if shift_pressed { 'Q' } else { 'q' }),
252 Key::R => Some(if shift_pressed { 'R' } else { 'r' }),
253 Key::S => Some(if shift_pressed { 'S' } else { 's' }),
254 Key::T => Some(if shift_pressed { 'T' } else { 't' }),
255 Key::U => Some(if shift_pressed { 'U' } else { 'u' }),
256 Key::V => Some(if shift_pressed { 'V' } else { 'v' }),
257 Key::W => Some(if shift_pressed { 'W' } else { 'w' }),
258 Key::X => Some(if shift_pressed { 'X' } else { 'x' }),
259 Key::Y => Some(if shift_pressed { 'Y' } else { 'y' }),
260 Key::Z => Some(if shift_pressed { 'Z' } else { 'z' }),
261 Key::Num1 => Some(if shift_pressed { '!' } else { '1' }),
262 Key::Num2 => Some(if shift_pressed { '@' } else { '2' }),
263 Key::Num3 => Some(if shift_pressed { '#' } else { '3' }),
264 Key::Num4 => Some(if shift_pressed { '$' } else { '4' }),
265 Key::Num5 => Some(if shift_pressed { '%' } else { '5' }),
266 Key::Num6 => Some(if shift_pressed { '^' } else { '6' }),
267 Key::Num7 => Some(if shift_pressed { '&' } else { '7' }),
268 Key::Num8 => Some(if shift_pressed { '*' } else { '8' }),
269 Key::Num9 => Some(if shift_pressed { '(' } else { '9' }),
270 Key::Num0 => Some(if shift_pressed { ')' } else { '0' }),
271 Key::LeftBracket => Some(if shift_pressed { '{' } else { '[' }),
272 Key::RightBracket => Some(if shift_pressed { '}' } else { ']' }),
273 Key::Space => Some(' '),
274 Key::Slash => Some(if shift_pressed { '?' } else { '/' }),
275 Key::Dot => Some(if shift_pressed { '>' } else { '.' }),
276 Key::Comma => Some(if shift_pressed { '<' } else { ',' }),
277 Key::Semicolon => Some(';'),
278 Key::Colon => Some(':'),
279 Key::Equals => Some(if shift_pressed { '+' } else { '=' }),
280 Key::SingleQuote => Some(if shift_pressed { '"' } else { '\'' }),
281 Key::Minus => Some(if shift_pressed { '_' } else { '-' }),
282 Key::Escape
283 | Key::Enter
284 | Key::Tab
285 | Key::Backspace
286 | Key::LeftShift
287 | Key::LeftControl
288 | Key::LeftAlt
289 | Key::RightAlt
290 | Key::LeftArrow
291 | Key::RightArrow
292 | Key::UpArrow
293 | Key::DownArrow
294 | Key::F1
295 | Key::F2
296 | Key::F3
297 | Key::F4
298 | Key::F5
299 | Key::F6
300 | Key::F7
301 | Key::F8
302 | Key::F9
303 | Key::F10
304 | Key::F11
305 | Key::F12 => None,
306 }
307 }
308
309 pub fn describe(self) -> String {
310 match self {
311 Key::Escape => "Escape".to_string(),
312 Key::Enter => "Enter".to_string(),
313 Key::Tab => "Tab".to_string(),
314 Key::Backspace => "Backspace".to_string(),
315 Key::LeftShift => "Shift".to_string(),
316 Key::LeftControl => "left Control".to_string(),
317 Key::LeftAlt => "left Alt".to_string(),
318 Key::RightAlt => "right Alt".to_string(),
319 Key::LeftArrow => "← arrow".to_string(),
320 Key::RightArrow => "→ arrow".to_string(),
321 Key::UpArrow => "↑".to_string(),
322 Key::DownArrow => "↓".to_string(),
323 Key::F1 => "F1".to_string(),
324 Key::F2 => "F2".to_string(),
325 Key::F3 => "F3".to_string(),
326 Key::F4 => "F4".to_string(),
327 Key::F5 => "F5".to_string(),
328 Key::F6 => "F6".to_string(),
329 Key::F7 => "F7".to_string(),
330 Key::F8 => "F8".to_string(),
331 Key::F9 => "F9".to_string(),
332 Key::F10 => "F10".to_string(),
333 Key::F11 => "F11".to_string(),
334 Key::F12 => "F12".to_string(),
335 Key::Space => "Space".to_string(),
337 _ => self.to_char(false).unwrap().to_string(),
338 }
339 }
340
341 fn from_winit_key(input: KeyboardInput) -> Option<Key> {
342 let key = input.virtual_keycode?;
343 Some(match key {
344 VirtualKeyCode::A => Key::A,
345 VirtualKeyCode::B => Key::B,
346 VirtualKeyCode::C => Key::C,
347 VirtualKeyCode::D => Key::D,
348 VirtualKeyCode::E => Key::E,
349 VirtualKeyCode::F => Key::F,
350 VirtualKeyCode::G => Key::G,
351 VirtualKeyCode::H => Key::H,
352 VirtualKeyCode::I => Key::I,
353 VirtualKeyCode::J => Key::J,
354 VirtualKeyCode::K => Key::K,
355 VirtualKeyCode::L => Key::L,
356 VirtualKeyCode::M => Key::M,
357 VirtualKeyCode::N => Key::N,
358 VirtualKeyCode::O => Key::O,
359 VirtualKeyCode::P => Key::P,
360 VirtualKeyCode::Q => Key::Q,
361 VirtualKeyCode::R => Key::R,
362 VirtualKeyCode::S => Key::S,
363 VirtualKeyCode::T => Key::T,
364 VirtualKeyCode::U => Key::U,
365 VirtualKeyCode::V => Key::V,
366 VirtualKeyCode::W => Key::W,
367 VirtualKeyCode::X => Key::X,
368 VirtualKeyCode::Y => Key::Y,
369 VirtualKeyCode::Z => Key::Z,
370 VirtualKeyCode::Key1 | VirtualKeyCode::Numpad1 => Key::Num1,
371 VirtualKeyCode::Key2 | VirtualKeyCode::Numpad2 => Key::Num2,
372 VirtualKeyCode::Key3 | VirtualKeyCode::Numpad3 => Key::Num3,
373 VirtualKeyCode::Key4 | VirtualKeyCode::Numpad4 => Key::Num4,
374 VirtualKeyCode::Key5 | VirtualKeyCode::Numpad5 => Key::Num5,
375 VirtualKeyCode::Key6 | VirtualKeyCode::Numpad6 => Key::Num6,
376 VirtualKeyCode::Key7 | VirtualKeyCode::Numpad7 => Key::Num7,
377 VirtualKeyCode::Key8 | VirtualKeyCode::Numpad8 => Key::Num8,
378 VirtualKeyCode::Key9 | VirtualKeyCode::Numpad9 => Key::Num9,
379 VirtualKeyCode::Key0 | VirtualKeyCode::Numpad0 => Key::Num0,
380 VirtualKeyCode::LBracket => Key::LeftBracket,
381 VirtualKeyCode::RBracket => Key::RightBracket,
382 VirtualKeyCode::Space => Key::Space,
383 VirtualKeyCode::Slash => Key::Slash,
384 VirtualKeyCode::Period => Key::Dot,
385 VirtualKeyCode::Comma => Key::Comma,
386 VirtualKeyCode::Semicolon => Key::Semicolon,
387 VirtualKeyCode::Colon => Key::Colon,
388 VirtualKeyCode::Equals => Key::Equals,
389 VirtualKeyCode::Apostrophe => Key::SingleQuote,
390 VirtualKeyCode::Minus => Key::Minus,
391 VirtualKeyCode::Escape => Key::Escape,
392 VirtualKeyCode::Return => Key::Enter,
393 VirtualKeyCode::Tab => Key::Tab,
394 VirtualKeyCode::Back => Key::Backspace,
395 VirtualKeyCode::LShift => Key::LeftShift,
396 VirtualKeyCode::LControl => Key::LeftControl,
397 VirtualKeyCode::LAlt => Key::LeftAlt,
398 VirtualKeyCode::RAlt => Key::RightAlt,
399 VirtualKeyCode::Left => Key::LeftArrow,
400 VirtualKeyCode::Right => Key::RightArrow,
401 VirtualKeyCode::Up => Key::UpArrow,
402 VirtualKeyCode::Down => Key::DownArrow,
403 VirtualKeyCode::F1 => Key::F1,
404 VirtualKeyCode::F2 => Key::F2,
405 VirtualKeyCode::F3 => Key::F3,
406 VirtualKeyCode::F4 => Key::F4,
407 VirtualKeyCode::F5 => Key::F5,
408 VirtualKeyCode::F6 => Key::F6,
409 VirtualKeyCode::F7 => Key::F7,
410 VirtualKeyCode::F8 => Key::F8,
411 VirtualKeyCode::F9 => Key::F9,
412 VirtualKeyCode::F10 => Key::F10,
413 VirtualKeyCode::F11 => Key::F11,
414 VirtualKeyCode::F12 => Key::F12,
415 _ => {
416 println!("Unknown winit key {:?}", key);
417 return None;
418 }
419 })
420 }
421
422 pub fn txt(self, ctx: &EventCtx) -> TextSpan {
423 Line(self.describe()).fg(ctx.style().text_hotkey_color)
424 }
425}
426
427#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
429pub enum MultiKey {
430 Normal(Key),
431 LCtrl(Key),
432 Any(Vec<Key>),
433}
434
435impl MultiKey {
436 pub fn describe(&self) -> String {
437 match self {
438 MultiKey::Normal(key) => key.describe(),
439 MultiKey::LCtrl(key) => format!("Ctrl+{}", key.describe()),
440 MultiKey::Any(ref keys) => keys
441 .iter()
442 .map(|k| k.describe())
443 .collect::<Vec<_>>()
444 .join(", "),
445 }
446 }
447
448 pub fn txt(&self, ctx: &EventCtx) -> TextSpan {
449 Line(self.describe()).fg(ctx.style().text_hotkey_color)
450 }
451}
452
453pub fn lctrl(key: Key) -> MultiKey {
454 MultiKey::LCtrl(key)
455}
456
457pub fn hotkeys(keys: Vec<Key>) -> MultiKey {
458 MultiKey::Any(keys)
459}
460
461impl std::convert::From<Key> for Option<MultiKey> {
462 fn from(key: Key) -> Option<MultiKey> {
463 Some(MultiKey::Normal(key))
464 }
465}
466
467impl std::convert::From<Key> for MultiKey {
468 fn from(key: Key) -> MultiKey {
469 MultiKey::Normal(key)
470 }
471}