event.rs

  1use crate::{geometry::vector::vec2f, keymap::Keystroke, platform::Event};
  2use cocoa::appkit::{
  3    NSDeleteFunctionKey as DELETE_KEY, NSDownArrowFunctionKey as ARROW_DOWN_KEY,
  4    NSLeftArrowFunctionKey as ARROW_LEFT_KEY, NSPageDownFunctionKey as PAGE_DOWN_KEY,
  5    NSPageUpFunctionKey as PAGE_UP_KEY, NSRightArrowFunctionKey as ARROW_RIGHT_KEY,
  6    NSUpArrowFunctionKey as ARROW_UP_KEY,
  7};
  8use cocoa::{
  9    appkit::{NSEvent, NSEventModifierFlags, NSEventType},
 10    base::{id, nil, YES},
 11    foundation::NSString as _,
 12};
 13use std::{ffi::CStr, os::raw::c_char};
 14
 15const BACKSPACE_KEY: u16 = 0x7f;
 16const ENTER_KEY: u16 = 0x0d;
 17const ESCAPE_KEY: u16 = 0x1b;
 18const TAB_KEY: u16 = 0x09;
 19
 20impl Event {
 21    pub unsafe fn from_native(native_event: id, window_height: Option<f32>) -> Option<Self> {
 22        let event_type = native_event.eventType();
 23
 24        // Filter out event types that aren't in the NSEventType enum.
 25        // See https://github.com/servo/cocoa-rs/issues/155#issuecomment-323482792 for details.
 26        match event_type as u64 {
 27            0 | 21 | 32 | 33 | 35 | 36 | 37 => {
 28                return None;
 29            }
 30            _ => {}
 31        }
 32
 33        match event_type {
 34            NSEventType::NSKeyDown => {
 35                let modifiers = native_event.modifierFlags();
 36                let unmodified_chars = native_event.charactersIgnoringModifiers();
 37                let unmodified_chars = CStr::from_ptr(unmodified_chars.UTF8String() as *mut c_char)
 38                    .to_str()
 39                    .unwrap();
 40
 41                let unmodified_chars = if let Some(first_char) = unmodified_chars.chars().next() {
 42                    match first_char as u16 {
 43                        ARROW_UP_KEY => "up",
 44                        ARROW_DOWN_KEY => "down",
 45                        ARROW_LEFT_KEY => "left",
 46                        ARROW_RIGHT_KEY => "right",
 47                        PAGE_UP_KEY => "pageup",
 48                        PAGE_DOWN_KEY => "pagedown",
 49                        BACKSPACE_KEY => "backspace",
 50                        ENTER_KEY => "enter",
 51                        DELETE_KEY => "delete",
 52                        ESCAPE_KEY => "escape",
 53                        TAB_KEY => "tab",
 54                        _ => unmodified_chars,
 55                    }
 56                } else {
 57                    return None;
 58                };
 59
 60                let chars = native_event.characters();
 61                let chars = CStr::from_ptr(chars.UTF8String() as *mut c_char)
 62                    .to_str()
 63                    .unwrap()
 64                    .into();
 65
 66                Some(Self::KeyDown {
 67                    keystroke: Keystroke {
 68                        ctrl: modifiers.contains(NSEventModifierFlags::NSControlKeyMask),
 69                        alt: modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask),
 70                        shift: modifiers.contains(NSEventModifierFlags::NSShiftKeyMask),
 71                        cmd: modifiers.contains(NSEventModifierFlags::NSCommandKeyMask),
 72                        key: unmodified_chars.into(),
 73                    },
 74                    chars,
 75                    is_held: native_event.isARepeat() == YES,
 76                })
 77            }
 78            NSEventType::NSLeftMouseDown => {
 79                window_height.map(|window_height| Self::LeftMouseDown {
 80                    position: vec2f(
 81                        native_event.locationInWindow().x as f32,
 82                        window_height - native_event.locationInWindow().y as f32,
 83                    ),
 84                    cmd: native_event
 85                        .modifierFlags()
 86                        .contains(NSEventModifierFlags::NSCommandKeyMask),
 87                })
 88            }
 89            NSEventType::NSLeftMouseUp => window_height.map(|window_height| Self::LeftMouseUp {
 90                position: vec2f(
 91                    native_event.locationInWindow().x as f32,
 92                    window_height - native_event.locationInWindow().y as f32,
 93                ),
 94            }),
 95            NSEventType::NSLeftMouseDragged => {
 96                window_height.map(|window_height| Self::LeftMouseDragged {
 97                    position: vec2f(
 98                        native_event.locationInWindow().x as f32,
 99                        window_height - native_event.locationInWindow().y as f32,
100                    ),
101                })
102            }
103            NSEventType::NSScrollWheel => window_height.map(|window_height| Self::ScrollWheel {
104                position: vec2f(
105                    native_event.locationInWindow().x as f32,
106                    window_height - native_event.locationInWindow().y as f32,
107                ),
108                delta: vec2f(
109                    native_event.scrollingDeltaX() as f32,
110                    native_event.scrollingDeltaY() as f32,
111                ),
112                precise: native_event.hasPreciseScrollingDeltas() == YES,
113            }),
114            NSEventType::NSMouseMoved => window_height.map(|window_height| Self::MouseMoved {
115                position: vec2f(
116                    native_event.locationInWindow().x as f32,
117                    window_height - native_event.locationInWindow().y as f32,
118                ),
119                left_mouse_down: NSEvent::pressedMouseButtons(nil) & 1 != 0,
120            }),
121            _ => None,
122        }
123    }
124}