event.rs

  1use crate::{geometry::vector::vec2f, keymap::Keystroke, platform::Event};
  2use cocoa::{
  3    appkit::{NSEvent, NSEventModifierFlags, NSEventType},
  4    base::{id, nil, YES},
  5    foundation::NSString as _,
  6};
  7use std::{ffi::CStr, os::raw::c_char};
  8
  9impl Event {
 10    pub unsafe fn from_native(native_event: id, window_height: Option<f32>) -> Option<Self> {
 11        let event_type = native_event.eventType();
 12
 13        // Filter out event types that aren't in the NSEventType enum.
 14        // See https://github.com/servo/cocoa-rs/issues/155#issuecomment-323482792 for details.
 15        match event_type as u64 {
 16            0 | 21 | 32 | 33 | 35 | 36 | 37 => {
 17                return None;
 18            }
 19            _ => {}
 20        }
 21
 22        match event_type {
 23            NSEventType::NSKeyDown => {
 24                let modifiers = native_event.modifierFlags();
 25                let ctrl = modifiers.contains(NSEventModifierFlags::NSControlKeyMask);
 26                let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask);
 27                let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask);
 28                let cmd = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask);
 29
 30                let unmodified_chars = CStr::from_ptr(
 31                    native_event.charactersIgnoringModifiers().UTF8String() as *mut c_char,
 32                )
 33                .to_str()
 34                .unwrap();
 35
 36                let mut input = None;
 37                let unmodified_chars = if let Some(first_char) = unmodified_chars.chars().next() {
 38                    use cocoa::appkit::*;
 39                    const BACKSPACE_KEY: u16 = 0x7f;
 40                    const ENTER_KEY: u16 = 0x0d;
 41                    const ESCAPE_KEY: u16 = 0x1b;
 42                    const TAB_KEY: u16 = 0x09;
 43                    const SHIFT_TAB_KEY: u16 = 0x19;
 44                    const SPACE_KEY: u16 = b' ' as u16;
 45
 46                    #[allow(non_upper_case_globals)]
 47                    match first_char as u16 {
 48                        SPACE_KEY => {
 49                            input = Some(" ".to_string());
 50                            "space"
 51                        }
 52                        BACKSPACE_KEY => "backspace",
 53                        ENTER_KEY => "enter",
 54                        ESCAPE_KEY => "escape",
 55                        TAB_KEY => "tab",
 56                        SHIFT_TAB_KEY => "tab",
 57
 58                        NSUpArrowFunctionKey => "up",
 59                        NSDownArrowFunctionKey => "down",
 60                        NSLeftArrowFunctionKey => "left",
 61                        NSRightArrowFunctionKey => "right",
 62                        NSPageUpFunctionKey => "pageup",
 63                        NSPageDownFunctionKey => "pagedown",
 64                        NSDeleteFunctionKey => "delete",
 65                        NSF1FunctionKey => "f1",
 66                        NSF2FunctionKey => "f2",
 67                        NSF3FunctionKey => "f3",
 68                        NSF4FunctionKey => "f4",
 69                        NSF5FunctionKey => "f5",
 70                        NSF6FunctionKey => "f6",
 71                        NSF7FunctionKey => "f7",
 72                        NSF8FunctionKey => "f8",
 73                        NSF9FunctionKey => "f9",
 74                        NSF10FunctionKey => "f10",
 75                        NSF11FunctionKey => "f11",
 76                        NSF12FunctionKey => "f12",
 77
 78                        _ => {
 79                            if !cmd && !ctrl {
 80                                input = Some(
 81                                    CStr::from_ptr(
 82                                        native_event.characters().UTF8String() as *mut c_char
 83                                    )
 84                                    .to_str()
 85                                    .unwrap()
 86                                    .into(),
 87                                );
 88                            }
 89                            unmodified_chars
 90                        }
 91                    }
 92                } else {
 93                    return None;
 94                };
 95
 96                Some(Self::KeyDown {
 97                    keystroke: Keystroke {
 98                        ctrl,
 99                        alt,
100                        shift,
101                        cmd,
102                        key: unmodified_chars.into(),
103                    },
104                    input,
105                    is_held: native_event.isARepeat() == YES,
106                })
107            }
108            NSEventType::NSLeftMouseDown => {
109                let modifiers = native_event.modifierFlags();
110                window_height.map(|window_height| Self::LeftMouseDown {
111                    position: vec2f(
112                        native_event.locationInWindow().x as f32,
113                        window_height - native_event.locationInWindow().y as f32,
114                    ),
115                    ctrl: modifiers.contains(NSEventModifierFlags::NSControlKeyMask),
116                    alt: modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask),
117                    shift: modifiers.contains(NSEventModifierFlags::NSShiftKeyMask),
118                    cmd: modifiers.contains(NSEventModifierFlags::NSCommandKeyMask),
119                    click_count: native_event.clickCount() as usize,
120                })
121            }
122            NSEventType::NSLeftMouseUp => window_height.map(|window_height| Self::LeftMouseUp {
123                position: vec2f(
124                    native_event.locationInWindow().x as f32,
125                    window_height - native_event.locationInWindow().y as f32,
126                ),
127            }),
128            NSEventType::NSLeftMouseDragged => {
129                window_height.map(|window_height| Self::LeftMouseDragged {
130                    position: vec2f(
131                        native_event.locationInWindow().x as f32,
132                        window_height - native_event.locationInWindow().y as f32,
133                    ),
134                })
135            }
136            NSEventType::NSScrollWheel => window_height.map(|window_height| Self::ScrollWheel {
137                position: vec2f(
138                    native_event.locationInWindow().x as f32,
139                    window_height - native_event.locationInWindow().y as f32,
140                ),
141                delta: vec2f(
142                    native_event.scrollingDeltaX() as f32,
143                    native_event.scrollingDeltaY() as f32,
144                ),
145                precise: native_event.hasPreciseScrollingDeltas() == YES,
146            }),
147            NSEventType::NSMouseMoved => window_height.map(|window_height| Self::MouseMoved {
148                position: vec2f(
149                    native_event.locationInWindow().x as f32,
150                    window_height - native_event.locationInWindow().y as f32,
151                ),
152                left_mouse_down: NSEvent::pressedMouseButtons(nil) & 1 != 0,
153            }),
154            _ => None,
155        }
156    }
157}