1 use {ControlFlow, EventsLoopClosed};
2 use cocoa::{self, appkit, foundation};
3 use cocoa::appkit::{NSApplication, NSEvent, NSEventMask, NSEventModifierFlags, NSEventPhase, NSView, NSWindow};
4 use events::{self, ElementState, Event, TouchPhase, WindowEvent, DeviceEvent, ModifiersState, KeyboardInput};
5 use std::collections::VecDeque;
6 use std::sync::{Arc, Mutex, Weak};
7 use super::window::Window2;
8 use std;
9 use std::os::raw::*;
10 use super::DeviceId;
11 
12 pub struct EventsLoop {
13     modifiers: Modifiers,
14     pub shared: Arc<Shared>,
15 }
16 
17 // State shared between the `EventsLoop` and its registered windows.
18 pub struct Shared {
19     pub windows: Mutex<Vec<Weak<Window2>>>,
20     pub pending_events: Mutex<VecDeque<Event>>,
21     // The user event callback given via either of the `poll_events` or `run_forever` methods.
22     //
23     // We store the user's callback here so that it may be accessed by each of the window delegate
24     // callbacks (e.g. resize, close, etc) for the duration of a call to either of the
25     // `poll_events` or `run_forever` methods.
26     //
27     // This is *only* `Some` for the duration of a call to either of these methods and will be
28     // `None` otherwise.
29     user_callback: UserCallback,
30 }
31 
32 #[derive(Clone)]
33 pub struct Proxy {}
34 
35 struct Modifiers {
36     shift_pressed: bool,
37     ctrl_pressed: bool,
38     win_pressed: bool,
39     alt_pressed: bool,
40 }
41 
42 // Wrapping the user callback in a type allows us to:
43 //
44 // - ensure the callback pointer is never accidentally cloned
45 // - ensure that only the `EventsLoop` can `store` and `drop` the callback pointer
46 // - Share access to the user callback with the NSWindow callbacks.
47 pub struct UserCallback {
48     mutex: Mutex<Option<*mut FnMut(Event)>>,
49 }
50 
51 
52 impl Shared {
53 
new() -> Self54     pub fn new() -> Self {
55         Shared {
56             windows: Mutex::new(Vec::new()),
57             pending_events: Mutex::new(VecDeque::new()),
58             user_callback: UserCallback { mutex: Mutex::new(None) },
59         }
60     }
61 
call_user_callback_with_pending_events(&self)62     fn call_user_callback_with_pending_events(&self) {
63         loop {
64             let event = match self.pending_events.lock().unwrap().pop_front() {
65                 Some(event) => event,
66                 None => return,
67             };
68             unsafe {
69                 self.user_callback.call_with_event(event);
70             }
71         }
72     }
73 
74     // Calls the user callback if one exists.
75     //
76     // Otherwise, stores the event in the `pending_events` queue.
77     //
78     // This is necessary for the case when `WindowDelegate` callbacks are triggered during a call
79     // to the user's callback.
call_user_callback_with_event_or_store_in_pending(&self, event: Event)80     pub fn call_user_callback_with_event_or_store_in_pending(&self, event: Event) {
81         if self.user_callback.mutex.lock().unwrap().is_some() {
82             unsafe {
83                 self.user_callback.call_with_event(event);
84             }
85         } else {
86             self.pending_events.lock().unwrap().push_back(event);
87         }
88     }
89 
90     // Removes the window with the given `Id` from the `windows` list.
91     //
92     // This is called in response to `windowWillClose`.
find_and_remove_window(&self, id: super::window::Id)93     pub fn find_and_remove_window(&self, id: super::window::Id) {
94         if let Ok(mut windows) = self.windows.lock() {
95             windows.retain(|w| match w.upgrade() {
96                 Some(w) => w.id() != id,
97                 None => false,
98             });
99         }
100     }
101 
102 }
103 
104 
105 impl Modifiers {
new() -> Self106     pub fn new() -> Self {
107         Modifiers {
108             shift_pressed: false,
109             ctrl_pressed: false,
110             win_pressed: false,
111             alt_pressed: false,
112         }
113     }
114 }
115 
116 
117 impl UserCallback {
118 
119     // Here we store user's `callback` behind the mutex so that they may be safely shared between
120     // each of the window delegates.
121     //
122     // In order to make sure that the pointer is always valid, we must manually guarantee that it
123     // is dropped before the callback itself is dropped. Thus, this should *only* be called at the
124     // beginning of a call to `poll_events` and `run_forever`, both of which *must* drop the
125     // callback at the end of their scope using the `drop` method.
store<F>(&self, callback: &mut F) where F: FnMut(Event)126     fn store<F>(&self, callback: &mut F)
127         where F: FnMut(Event)
128     {
129         let trait_object = callback as &mut FnMut(Event);
130         let trait_object_ptr = trait_object as *const FnMut(Event) as *mut FnMut(Event);
131         *self.mutex.lock().unwrap() = Some(trait_object_ptr);
132     }
133 
134     // Emits the given event via the user-given callback.
135     //
136     // This is unsafe as it requires dereferencing the pointer to the user-given callback. We
137     // guarantee this is safe by ensuring the `UserCallback` never lives longer than the user-given
138     // callback.
139     //
140     // Note that the callback may not always be `Some`. This is because some `NSWindowDelegate`
141     // callbacks can be triggered by means other than `NSApp().sendEvent`. For example, if a window
142     // is destroyed or created during a call to the user's callback, the `WindowDelegate` methods
143     // may be called with `windowShouldClose` or `windowDidResignKey`.
call_with_event(&self, event: Event)144     unsafe fn call_with_event(&self, event: Event) {
145         let callback = match self.mutex.lock().unwrap().take() {
146             Some(callback) => callback,
147             None => return,
148         };
149         (*callback)(event);
150         *self.mutex.lock().unwrap() = Some(callback);
151     }
152 
153     // Used to drop the user callback pointer at the end of the `poll_events` and `run_forever`
154     // methods. This is done to enforce our guarantee that the top callback will never live longer
155     // than the call to either `poll_events` or `run_forever` to which it was given.
drop(&self)156     fn drop(&self) {
157         self.mutex.lock().unwrap().take();
158     }
159 
160 }
161 
162 
163 impl EventsLoop {
164 
new() -> Self165     pub fn new() -> Self {
166         // Mark this thread as the main thread of the Cocoa event system.
167         //
168         // This must be done before any worker threads get a chance to call it
169         // (e.g., via `EventsLoopProxy::wakeup()`), causing a wrong thread to be
170         // marked as the main thread.
171         unsafe { appkit::NSApp(); }
172 
173         EventsLoop {
174             shared: Arc::new(Shared::new()),
175             modifiers: Modifiers::new(),
176         }
177     }
178 
poll_events<F>(&mut self, mut callback: F) where F: FnMut(Event),179     pub fn poll_events<F>(&mut self, mut callback: F)
180         where F: FnMut(Event),
181     {
182         unsafe {
183             if !msg_send![class!(NSThread), isMainThread] {
184                 panic!("Events can only be polled from the main thread on macOS");
185             }
186         }
187 
188         self.shared.user_callback.store(&mut callback);
189 
190         // Loop as long as we have pending events to return.
191         loop {
192             unsafe {
193                 // First, yield all pending events.
194                 self.shared.call_user_callback_with_pending_events();
195 
196                 let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
197 
198                 // Poll for the next event, returning `nil` if there are none.
199                 let ns_event = appkit::NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
200                     NSEventMask::NSAnyEventMask.bits() | NSEventMask::NSEventMaskPressure.bits(),
201                     foundation::NSDate::distantPast(cocoa::base::nil),
202                     foundation::NSDefaultRunLoopMode,
203                     cocoa::base::YES);
204 
205                 let event = self.ns_event_to_event(ns_event);
206 
207                 let _: () = msg_send![pool, release];
208 
209                 match event {
210                     // Call the user's callback.
211                     Some(event) => self.shared.user_callback.call_with_event(event),
212                     None => break,
213                 }
214             }
215         }
216 
217         self.shared.user_callback.drop();
218     }
219 
run_forever<F>(&mut self, mut callback: F) where F: FnMut(Event) -> ControlFlow220     pub fn run_forever<F>(&mut self, mut callback: F)
221         where F: FnMut(Event) -> ControlFlow
222     {
223         unsafe {
224             if !msg_send![class!(NSThread), isMainThread] {
225                 panic!("Events can only be polled from the main thread on macOS");
226             }
227         }
228 
229         // Track whether or not control flow has changed.
230         let control_flow = std::cell::Cell::new(ControlFlow::Continue);
231 
232         let mut callback = |event| {
233             if let ControlFlow::Break = callback(event) {
234                 control_flow.set(ControlFlow::Break);
235             }
236         };
237 
238         self.shared.user_callback.store(&mut callback);
239 
240         loop {
241             unsafe {
242                 // First, yield all pending events.
243                 self.shared.call_user_callback_with_pending_events();
244                 if let ControlFlow::Break = control_flow.get() {
245                     break;
246                 }
247 
248                 let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
249 
250                 // Wait for the next event. Note that this function blocks during resize.
251                 let ns_event = appkit::NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
252                     NSEventMask::NSAnyEventMask.bits() | NSEventMask::NSEventMaskPressure.bits(),
253                     foundation::NSDate::distantFuture(cocoa::base::nil),
254                     foundation::NSDefaultRunLoopMode,
255                     cocoa::base::YES);
256 
257                 let maybe_event = self.ns_event_to_event(ns_event);
258 
259                 // Release the pool before calling the top callback in case the user calls either
260                 // `run_forever` or `poll_events` within the callback.
261                 let _: () = msg_send![pool, release];
262 
263                 if let Some(event) = maybe_event {
264                     self.shared.user_callback.call_with_event(event);
265                     if let ControlFlow::Break = control_flow.get() {
266                         break;
267                     }
268                 }
269             }
270         }
271 
272         self.shared.user_callback.drop();
273     }
274 
275     // Convert some given `NSEvent` into a winit `Event`.
ns_event_to_event(&mut self, ns_event: cocoa::base::id) -> Option<Event>276     unsafe fn ns_event_to_event(&mut self, ns_event: cocoa::base::id) -> Option<Event> {
277         if ns_event == cocoa::base::nil {
278             return None;
279         }
280 
281         // FIXME: Despite not being documented anywhere, an `NSEvent` is produced when a user opens
282         // Spotlight while the NSApplication is in focus. This `NSEvent` produces a `NSEventType`
283         // with value `21`. This causes a SEGFAULT as soon as we try to match on the `NSEventType`
284         // enum as there is no variant associated with the value. Thus, we return early if this
285         // sneaky event occurs. If someone does find some documentation on this, please fix this by
286         // adding an appropriate variant to the `NSEventType` enum in the cocoa-rs crate.
287         if ns_event.eventType() as u64 == 21 {
288             return None;
289         }
290 
291         let event_type = ns_event.eventType();
292         let ns_window = ns_event.window();
293         let window_id = super::window::get_window_id(ns_window);
294 
295         // FIXME: Document this. Why do we do this? Seems like it passes on events to window/app.
296         // If we don't do this, window does not become main for some reason.
297         appkit::NSApp().sendEvent_(ns_event);
298 
299         let windows = self.shared.windows.lock().unwrap();
300         let maybe_window = windows.iter()
301             .filter_map(Weak::upgrade)
302             .find(|window| window_id == window.id());
303 
304         let into_event = |window_event| Event::WindowEvent {
305             window_id: ::WindowId(window_id),
306             event: window_event,
307         };
308 
309         // Returns `Some` window if one of our windows is the key window.
310         let maybe_key_window = || windows.iter()
311             .filter_map(Weak::upgrade)
312             .find(|window| {
313                 let is_key_window: cocoa::base::BOOL = msg_send![*window.window, isKeyWindow];
314                 is_key_window == cocoa::base::YES
315             });
316 
317         match event_type {
318             // https://github.com/glfw/glfw/blob/50eccd298a2bbc272b4977bd162d3e4b55f15394/src/cocoa_window.m#L881
319             appkit::NSKeyUp  => {
320                 if let Some(key_window) = maybe_key_window() {
321                     if event_mods(ns_event).logo {
322                         let _: () = msg_send![*key_window.window, sendEvent:ns_event];
323                     }
324                 }
325                 None
326             },
327             // similar to above, but for `<Cmd-.>`, the keyDown is suppressed instead of the
328             // KeyUp, and the above trick does not appear to work.
329             appkit::NSKeyDown => {
330                 let modifiers = event_mods(ns_event);
331                 let keycode = NSEvent::keyCode(ns_event);
332                 if modifiers.logo && keycode == 47 {
333                     modifier_event(ns_event, NSEventModifierFlags::NSCommandKeyMask, false)
334                         .map(into_event)
335                 } else {
336                     None
337                 }
338             },
339             appkit::NSFlagsChanged => {
340                 let mut events = std::collections::VecDeque::new();
341 
342                 if let Some(window_event) = modifier_event(
343                     ns_event,
344                     NSEventModifierFlags::NSShiftKeyMask,
345                     self.modifiers.shift_pressed,
346                 ) {
347                     self.modifiers.shift_pressed = !self.modifiers.shift_pressed;
348                     events.push_back(into_event(window_event));
349                 }
350 
351                 if let Some(window_event) = modifier_event(
352                     ns_event,
353                     NSEventModifierFlags::NSControlKeyMask,
354                     self.modifiers.ctrl_pressed,
355                 ) {
356                     self.modifiers.ctrl_pressed = !self.modifiers.ctrl_pressed;
357                     events.push_back(into_event(window_event));
358                 }
359 
360                 if let Some(window_event) = modifier_event(
361                     ns_event,
362                     NSEventModifierFlags::NSCommandKeyMask,
363                     self.modifiers.win_pressed,
364                 ) {
365                     self.modifiers.win_pressed = !self.modifiers.win_pressed;
366                     events.push_back(into_event(window_event));
367                 }
368 
369                 if let Some(window_event) = modifier_event(
370                     ns_event,
371                     NSEventModifierFlags::NSAlternateKeyMask,
372                     self.modifiers.alt_pressed,
373                 ) {
374                     self.modifiers.alt_pressed = !self.modifiers.alt_pressed;
375                     events.push_back(into_event(window_event));
376                 }
377 
378                 let event = events.pop_front();
379                 self.shared.pending_events
380                     .lock()
381                     .unwrap()
382                     .extend(events.into_iter());
383                 event
384             },
385 
386             appkit::NSMouseEntered => {
387                 let window = match maybe_window.or_else(maybe_key_window) {
388                     Some(window) => window,
389                     None => return None,
390                 };
391 
392                 let window_point = ns_event.locationInWindow();
393                 let view_point = if ns_window == cocoa::base::nil {
394                     let ns_size = foundation::NSSize::new(0.0, 0.0);
395                     let ns_rect = foundation::NSRect::new(window_point, ns_size);
396                     let window_rect = window.window.convertRectFromScreen_(ns_rect);
397                     window.view.convertPoint_fromView_(window_rect.origin, cocoa::base::nil)
398                 } else {
399                     window.view.convertPoint_fromView_(window_point, cocoa::base::nil)
400                 };
401 
402                 let view_rect = NSView::frame(*window.view);
403                 let x = view_point.x as f64;
404                 let y = (view_rect.size.height - view_point.y) as f64;
405                 let window_event = WindowEvent::CursorMoved {
406                     device_id: DEVICE_ID,
407                     position: (x, y).into(),
408                     modifiers: event_mods(ns_event),
409                 };
410                 let event = Event::WindowEvent { window_id: ::WindowId(window.id()), event: window_event };
411                 self.shared.pending_events.lock().unwrap().push_back(event);
412                 Some(into_event(WindowEvent::CursorEntered { device_id: DEVICE_ID }))
413             },
414             appkit::NSMouseExited => { Some(into_event(WindowEvent::CursorLeft { device_id: DEVICE_ID })) },
415 
416             appkit::NSMouseMoved |
417             appkit::NSLeftMouseDragged |
418             appkit::NSOtherMouseDragged |
419             appkit::NSRightMouseDragged => {
420                 // If the mouse movement was on one of our windows, use it.
421                 // Otherwise, if one of our windows is the key window (receiving input), use it.
422                 // Otherwise, return `None`.
423                 match maybe_window.or_else(maybe_key_window) {
424                     Some(_window) => (),
425                     None => return None,
426                 }
427 
428                 let mut events = std::collections::VecDeque::with_capacity(3);
429 
430                 let delta_x = ns_event.deltaX() as f64;
431                 if delta_x != 0.0 {
432                     let motion_event = DeviceEvent::Motion { axis: 0, value: delta_x };
433                     let event = Event::DeviceEvent { device_id: DEVICE_ID, event: motion_event };
434                     events.push_back(event);
435                 }
436 
437                 let delta_y = ns_event.deltaY() as f64;
438                 if delta_y != 0.0 {
439                     let motion_event = DeviceEvent::Motion { axis: 1, value: delta_y };
440                     let event = Event::DeviceEvent { device_id: DEVICE_ID, event: motion_event };
441                     events.push_back(event);
442                 }
443 
444                 if delta_x != 0.0 || delta_y != 0.0 {
445                     let motion_event = DeviceEvent::MouseMotion { delta: (delta_x, delta_y) };
446                     let event = Event::DeviceEvent { device_id: DEVICE_ID, event: motion_event };
447                     events.push_back(event);
448                 }
449 
450                 let event = events.pop_front();
451                 self.shared.pending_events.lock().unwrap().extend(events.into_iter());
452                 event
453             },
454 
455             appkit::NSScrollWheel => {
456                 // If none of the windows received the scroll, return `None`.
457                 if maybe_window.is_none() {
458                     return None;
459                 }
460 
461                 use events::MouseScrollDelta::{LineDelta, PixelDelta};
462                 let delta = if ns_event.hasPreciseScrollingDeltas() == cocoa::base::YES {
463                     PixelDelta((
464                         ns_event.scrollingDeltaX() as f64,
465                         ns_event.scrollingDeltaY() as f64,
466                     ).into())
467                 } else {
468                     // TODO: This is probably wrong
469                     LineDelta(
470                         ns_event.scrollingDeltaX() as f32,
471                         ns_event.scrollingDeltaY() as f32,
472                     )
473                 };
474                 let phase = match ns_event.phase() {
475                     NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => TouchPhase::Started,
476                     NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended,
477                     _ => TouchPhase::Moved,
478                 };
479                 self.shared.pending_events.lock().unwrap().push_back(Event::DeviceEvent {
480                     device_id: DEVICE_ID,
481                     event: DeviceEvent::MouseWheel {
482                         delta: if ns_event.hasPreciseScrollingDeltas() == cocoa::base::YES {
483                             PixelDelta((
484                                 ns_event.scrollingDeltaX() as f64,
485                                 ns_event.scrollingDeltaY() as f64,
486                             ).into())
487                         } else {
488                             LineDelta(
489                                 ns_event.scrollingDeltaX() as f32,
490                                 ns_event.scrollingDeltaY() as f32,
491                             )
492                         },
493                     }
494                 });
495                 let window_event = WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: delta, phase: phase, modifiers: event_mods(ns_event) };
496                 Some(into_event(window_event))
497             },
498 
499             appkit::NSEventTypePressure => {
500                 let pressure = ns_event.pressure();
501                 let stage = ns_event.stage();
502                 let window_event = WindowEvent::TouchpadPressure { device_id: DEVICE_ID, pressure: pressure, stage: stage };
503                 Some(into_event(window_event))
504             },
505 
506             appkit::NSApplicationDefined => match ns_event.subtype() {
507                 appkit::NSEventSubtype::NSApplicationActivatedEventType => {
508                     Some(Event::Awakened)
509                 },
510                 _ => None,
511             },
512 
513             _  => None,
514         }
515     }
516 
create_proxy(&self) -> Proxy517     pub fn create_proxy(&self) -> Proxy {
518         Proxy {}
519     }
520 
521 }
522 
523 impl Proxy {
wakeup(&self) -> Result<(), EventsLoopClosed>524     pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
525         // Awaken the event loop by triggering `NSApplicationActivatedEventType`.
526         unsafe {
527             let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
528             let event =
529                 NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
530                     cocoa::base::nil,
531                     appkit::NSApplicationDefined,
532                     foundation::NSPoint::new(0.0, 0.0),
533                     appkit::NSEventModifierFlags::empty(),
534                     0.0,
535                     0,
536                     cocoa::base::nil,
537                     appkit::NSEventSubtype::NSApplicationActivatedEventType,
538                     0,
539                     0);
540             appkit::NSApp().postEvent_atStart_(event, cocoa::base::NO);
541             foundation::NSAutoreleasePool::drain(pool);
542         }
543         Ok(())
544     }
545 }
546 
char_to_keycode(c: char) -> Option<events::VirtualKeyCode>547 pub fn char_to_keycode(c: char) -> Option<events::VirtualKeyCode> {
548     // We only translate keys that are affected by keyboard layout.
549     //
550     // Note that since keys are translated in a somewhat "dumb" way (reading character)
551     // there is a concern that some combination, i.e. Cmd+char, causes the wrong
552     // letter to be received, and so we receive the wrong key.
553     //
554     // Implementation reference: https://github.com/WebKit/webkit/blob/82bae82cf0f329dbe21059ef0986c4e92fea4ba6/Source/WebCore/platform/cocoa/KeyEventCocoa.mm#L626
555     Some(match c {
556         'a' | 'A' => events::VirtualKeyCode::A,
557         'b' | 'B' => events::VirtualKeyCode::B,
558         'c' | 'C' => events::VirtualKeyCode::C,
559         'd' | 'D' => events::VirtualKeyCode::D,
560         'e' | 'E' => events::VirtualKeyCode::E,
561         'f' | 'F' => events::VirtualKeyCode::F,
562         'g' | 'G' => events::VirtualKeyCode::G,
563         'h' | 'H' => events::VirtualKeyCode::H,
564         'i' | 'I' => events::VirtualKeyCode::I,
565         'j' | 'J' => events::VirtualKeyCode::J,
566         'k' | 'K' => events::VirtualKeyCode::K,
567         'l' | 'L' => events::VirtualKeyCode::L,
568         'm' | 'M' => events::VirtualKeyCode::M,
569         'n' | 'N' => events::VirtualKeyCode::N,
570         'o' | 'O' => events::VirtualKeyCode::O,
571         'p' | 'P' => events::VirtualKeyCode::P,
572         'q' | 'Q' => events::VirtualKeyCode::Q,
573         'r' | 'R' => events::VirtualKeyCode::R,
574         's' | 'S' => events::VirtualKeyCode::S,
575         't' | 'T' => events::VirtualKeyCode::T,
576         'u' | 'U' => events::VirtualKeyCode::U,
577         'v' | 'V' => events::VirtualKeyCode::V,
578         'w' | 'W' => events::VirtualKeyCode::W,
579         'x' | 'X' => events::VirtualKeyCode::X,
580         'y' | 'Y' => events::VirtualKeyCode::Y,
581         'z' | 'Z' => events::VirtualKeyCode::Z,
582         '1' | '!' => events::VirtualKeyCode::Key1,
583         '2' | '@' => events::VirtualKeyCode::Key2,
584         '3' | '#' => events::VirtualKeyCode::Key3,
585         '4' | '$' => events::VirtualKeyCode::Key4,
586         '5' | '%' => events::VirtualKeyCode::Key5,
587         '6' | '^' => events::VirtualKeyCode::Key6,
588         '7' | '&' => events::VirtualKeyCode::Key7,
589         '8' | '*' => events::VirtualKeyCode::Key8,
590         '9' | '(' => events::VirtualKeyCode::Key9,
591         '0' | ')' => events::VirtualKeyCode::Key0,
592         '=' | '+' => events::VirtualKeyCode::Equals,
593         '-' | '_' => events::VirtualKeyCode::Minus,
594         ']' | '}' => events::VirtualKeyCode::RBracket,
595         '[' | '{' => events::VirtualKeyCode::LBracket,
596         '\''| '"' => events::VirtualKeyCode::Apostrophe,
597         ';' | ':' => events::VirtualKeyCode::Semicolon,
598         '\\'| '|' => events::VirtualKeyCode::Backslash,
599         ',' | '<' => events::VirtualKeyCode::Comma,
600         '/' | '?' => events::VirtualKeyCode::Slash,
601         '.' | '>' => events::VirtualKeyCode::Period,
602         '`' | '~' => events::VirtualKeyCode::Grave,
603         _ => return None,
604     })
605 }
606 
scancode_to_keycode(code: c_ushort) -> Option<events::VirtualKeyCode>607 pub fn scancode_to_keycode(code: c_ushort) -> Option<events::VirtualKeyCode> {
608     Some(match code {
609         0x00 => events::VirtualKeyCode::A,
610         0x01 => events::VirtualKeyCode::S,
611         0x02 => events::VirtualKeyCode::D,
612         0x03 => events::VirtualKeyCode::F,
613         0x04 => events::VirtualKeyCode::H,
614         0x05 => events::VirtualKeyCode::G,
615         0x06 => events::VirtualKeyCode::Z,
616         0x07 => events::VirtualKeyCode::X,
617         0x08 => events::VirtualKeyCode::C,
618         0x09 => events::VirtualKeyCode::V,
619         //0x0a => World 1,
620         0x0b => events::VirtualKeyCode::B,
621         0x0c => events::VirtualKeyCode::Q,
622         0x0d => events::VirtualKeyCode::W,
623         0x0e => events::VirtualKeyCode::E,
624         0x0f => events::VirtualKeyCode::R,
625         0x10 => events::VirtualKeyCode::Y,
626         0x11 => events::VirtualKeyCode::T,
627         0x12 => events::VirtualKeyCode::Key1,
628         0x13 => events::VirtualKeyCode::Key2,
629         0x14 => events::VirtualKeyCode::Key3,
630         0x15 => events::VirtualKeyCode::Key4,
631         0x16 => events::VirtualKeyCode::Key6,
632         0x17 => events::VirtualKeyCode::Key5,
633         0x18 => events::VirtualKeyCode::Equals,
634         0x19 => events::VirtualKeyCode::Key9,
635         0x1a => events::VirtualKeyCode::Key7,
636         0x1b => events::VirtualKeyCode::Minus,
637         0x1c => events::VirtualKeyCode::Key8,
638         0x1d => events::VirtualKeyCode::Key0,
639         0x1e => events::VirtualKeyCode::RBracket,
640         0x1f => events::VirtualKeyCode::O,
641         0x20 => events::VirtualKeyCode::U,
642         0x21 => events::VirtualKeyCode::LBracket,
643         0x22 => events::VirtualKeyCode::I,
644         0x23 => events::VirtualKeyCode::P,
645         0x24 => events::VirtualKeyCode::Return,
646         0x25 => events::VirtualKeyCode::L,
647         0x26 => events::VirtualKeyCode::J,
648         0x27 => events::VirtualKeyCode::Apostrophe,
649         0x28 => events::VirtualKeyCode::K,
650         0x29 => events::VirtualKeyCode::Semicolon,
651         0x2a => events::VirtualKeyCode::Backslash,
652         0x2b => events::VirtualKeyCode::Comma,
653         0x2c => events::VirtualKeyCode::Slash,
654         0x2d => events::VirtualKeyCode::N,
655         0x2e => events::VirtualKeyCode::M,
656         0x2f => events::VirtualKeyCode::Period,
657         0x30 => events::VirtualKeyCode::Tab,
658         0x31 => events::VirtualKeyCode::Space,
659         0x32 => events::VirtualKeyCode::Grave,
660         0x33 => events::VirtualKeyCode::Back,
661         //0x34 => unkown,
662         0x35 => events::VirtualKeyCode::Escape,
663         0x36 => events::VirtualKeyCode::RWin,
664         0x37 => events::VirtualKeyCode::LWin,
665         0x38 => events::VirtualKeyCode::LShift,
666         //0x39 => Caps lock,
667         0x3a => events::VirtualKeyCode::LAlt,
668         0x3b => events::VirtualKeyCode::LControl,
669         0x3c => events::VirtualKeyCode::RShift,
670         0x3d => events::VirtualKeyCode::RAlt,
671         0x3e => events::VirtualKeyCode::RControl,
672         //0x3f => Fn key,
673         0x40 => events::VirtualKeyCode::F17,
674         0x41 => events::VirtualKeyCode::Decimal,
675         //0x42 -> unkown,
676         0x43 => events::VirtualKeyCode::Multiply,
677         //0x44 => unkown,
678         0x45 => events::VirtualKeyCode::Add,
679         //0x46 => unkown,
680         0x47 => events::VirtualKeyCode::Numlock,
681         //0x48 => KeypadClear,
682         0x49 => events::VirtualKeyCode::VolumeUp,
683         0x4a => events::VirtualKeyCode::VolumeDown,
684         0x4b => events::VirtualKeyCode::Divide,
685         0x4c => events::VirtualKeyCode::NumpadEnter,
686         0x4e => events::VirtualKeyCode::Subtract,
687         //0x4d => unkown,
688         0x4e => events::VirtualKeyCode::Subtract,
689         0x4f => events::VirtualKeyCode::F18,
690         0x50 => events::VirtualKeyCode::F19,
691         0x51 => events::VirtualKeyCode::NumpadEquals,
692         0x52 => events::VirtualKeyCode::Numpad0,
693         0x53 => events::VirtualKeyCode::Numpad1,
694         0x54 => events::VirtualKeyCode::Numpad2,
695         0x55 => events::VirtualKeyCode::Numpad3,
696         0x56 => events::VirtualKeyCode::Numpad4,
697         0x57 => events::VirtualKeyCode::Numpad5,
698         0x58 => events::VirtualKeyCode::Numpad6,
699         0x59 => events::VirtualKeyCode::Numpad7,
700         0x5a => events::VirtualKeyCode::F20,
701         0x5b => events::VirtualKeyCode::Numpad8,
702         0x5c => events::VirtualKeyCode::Numpad9,
703         0x5d => events::VirtualKeyCode::Yen,
704         //0x5e => JIS Ro,
705         //0x5f => unkown,
706         0x60 => events::VirtualKeyCode::F5,
707         0x61 => events::VirtualKeyCode::F6,
708         0x62 => events::VirtualKeyCode::F7,
709         0x63 => events::VirtualKeyCode::F3,
710         0x64 => events::VirtualKeyCode::F8,
711         0x65 => events::VirtualKeyCode::F9,
712         //0x66 => JIS Eisuu (macOS),
713         0x67 => events::VirtualKeyCode::F11,
714         //0x68 => JIS Kana (macOS),
715         0x69 => events::VirtualKeyCode::F13,
716         0x6a => events::VirtualKeyCode::F16,
717         0x6b => events::VirtualKeyCode::F14,
718         //0x6c => unkown,
719         0x6d => events::VirtualKeyCode::F10,
720         //0x6e => unkown,
721         0x6f => events::VirtualKeyCode::F12,
722         //0x70 => unkown,
723         0x71 => events::VirtualKeyCode::F15,
724         0x72 => events::VirtualKeyCode::Insert,
725         0x73 => events::VirtualKeyCode::Home,
726         0x74 => events::VirtualKeyCode::PageUp,
727         0x75 => events::VirtualKeyCode::Delete,
728         0x76 => events::VirtualKeyCode::F4,
729         0x77 => events::VirtualKeyCode::End,
730         0x78 => events::VirtualKeyCode::F2,
731         0x79 => events::VirtualKeyCode::PageDown,
732         0x7a => events::VirtualKeyCode::F1,
733         0x7b => events::VirtualKeyCode::Left,
734         0x7c => events::VirtualKeyCode::Right,
735         0x7d => events::VirtualKeyCode::Down,
736         0x7e => events::VirtualKeyCode::Up,
737         //0x7f =>  unkown,
738 
739         0xa => events::VirtualKeyCode::Caret,
740         _ => return None,
741     })
742 }
743 
check_function_keys( s: &String ) -> Option<events::VirtualKeyCode>744 pub fn check_function_keys(
745     s: &String
746 ) -> Option<events::VirtualKeyCode> {
747     if let Some(ch) = s.encode_utf16().next() {
748         return Some(match ch {
749             0xf718 => events::VirtualKeyCode::F21,
750             0xf719 => events::VirtualKeyCode::F22,
751             0xf71a => events::VirtualKeyCode::F23,
752             0xf71b => events::VirtualKeyCode::F24,
753             _ => return None,
754         })
755     }
756 
757     None
758 }
759 
event_mods(event: cocoa::base::id) -> ModifiersState760 pub fn event_mods(event: cocoa::base::id) -> ModifiersState {
761     let flags = unsafe {
762         NSEvent::modifierFlags(event)
763     };
764     ModifiersState {
765         shift: flags.contains(NSEventModifierFlags::NSShiftKeyMask),
766         ctrl: flags.contains(NSEventModifierFlags::NSControlKeyMask),
767         alt: flags.contains(NSEventModifierFlags::NSAlternateKeyMask),
768         logo: flags.contains(NSEventModifierFlags::NSCommandKeyMask),
769     }
770 }
771 
get_scancode(event: cocoa::base::id) -> c_ushort772 pub fn get_scancode(event: cocoa::base::id) -> c_ushort {
773     // In AppKit, `keyCode` refers to the position (scancode) of a key rather than its character,
774     // and there is no easy way to navtively retrieve the layout-dependent character.
775     // In winit, we use keycode to refer to the key's character, and so this function aligns
776     // AppKit's terminology with ours.
777     unsafe {
778         msg_send![event, keyCode]
779     }
780 }
781 
modifier_event( ns_event: cocoa::base::id, keymask: NSEventModifierFlags, was_key_pressed: bool, ) -> Option<WindowEvent>782 unsafe fn modifier_event(
783     ns_event: cocoa::base::id,
784     keymask: NSEventModifierFlags,
785     was_key_pressed: bool,
786 ) -> Option<WindowEvent> {
787     if !was_key_pressed && NSEvent::modifierFlags(ns_event).contains(keymask)
788     || was_key_pressed && !NSEvent::modifierFlags(ns_event).contains(keymask) {
789         let state = if was_key_pressed {
790             ElementState::Released
791         } else {
792             ElementState::Pressed
793         };
794 
795         let scancode = get_scancode(ns_event);
796         let virtual_keycode = scancode_to_keycode(scancode);
797         Some(WindowEvent::KeyboardInput {
798             device_id: DEVICE_ID,
799             input: KeyboardInput {
800                 state,
801                 scancode: scancode as u32,
802                 virtual_keycode,
803                 modifiers: event_mods(ns_event),
804             },
805         })
806     } else {
807         None
808     }
809 }
810 
811 // Constant device ID, to be removed when this backend is updated to report real device IDs.
812 pub const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);
813