core_graphics/
event.rs

1#![allow(non_upper_case_globals)]
2use crate::event_source::CGEventSource;
3use crate::geometry::CGPoint;
4
5use bitflags::bitflags;
6use core::ffi::{c_ulong, c_void};
7use core_foundation::{
8    base::{CFRelease, CFRetain, CFTypeID, TCFType},
9    mach_port::{CFMachPort, CFMachPortInvalidate, CFMachPortRef},
10    runloop::{kCFRunLoopCommonModes, CFRunLoop},
11};
12use foreign_types::{foreign_type, ForeignType};
13use std::{mem::ManuallyDrop, ptr};
14
15pub type CGEventField = u32;
16pub type CGKeyCode = u16;
17pub type CGScrollEventUnit = u32;
18
19bitflags! {
20    /// Flags for events
21    ///
22    /// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
23    #[repr(C)]
24    #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
25    pub struct CGEventFlags: u64 {
26        const CGEventFlagNull = 0;
27
28        // Device-independent modifier key bits.
29        const CGEventFlagAlphaShift = 0x00010000;
30        const CGEventFlagShift = 0x00020000;
31        const CGEventFlagControl = 0x00040000;
32        const CGEventFlagAlternate = 0x00080000;
33        const CGEventFlagCommand = 0x00100000;
34
35        // Special key identifiers.
36        const CGEventFlagHelp = 0x00400000;
37        const CGEventFlagSecondaryFn = 0x00800000;
38
39        // Identifies key events from numeric keypad area on extended keyboards.
40        const CGEventFlagNumericPad = 0x00200000;
41
42        // Indicates if mouse/pen movement events are not being coalesced
43        const CGEventFlagNonCoalesced = 0x00000100;
44    }
45}
46
47/// Constants for the virtual key codes
48///
49/// These constants are the virtual keycodes defined originally in
50/// Inside Mac Volume V, pg. V-191. They identify physical keys on a
51/// keyboard. The struct contains the values of the `ANSIKeyCode`,
52/// `KeyCode`, `ISOKeyCode` and `JISKeyCode` of the original Carbon headers.
53///
54/// Those constants with "ANSI" in the name are labeled
55/// according to the key position on an ANSI-standard US keyboard.
56/// For example, `ANSI_A` indicates the virtual keycode for the key
57/// with the letter 'A' in the US keyboard layout. Other keyboard
58/// layouts may have the 'A' key label on a different physical key;
59/// in this case, pressing 'A' will generate a different virtual
60/// keycode. Constants with the 'JIS_' or 'ISO_' prefix behave
61/// analogously. Keys without a prefix are independent of the
62/// keyboard layout.
63///
64/// [Ref](https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.13.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h#L197-L327)
65#[repr(C)]
66pub struct KeyCode;
67impl KeyCode {
68    pub const ANSI_A: CGKeyCode = 0x00;
69    pub const ANSI_S: CGKeyCode = 0x01;
70    pub const ANSI_D: CGKeyCode = 0x02;
71    pub const ANSI_F: CGKeyCode = 0x03;
72    pub const ANSI_H: CGKeyCode = 0x04;
73    pub const ANSI_G: CGKeyCode = 0x05;
74    pub const ANSI_Z: CGKeyCode = 0x06;
75    pub const ANSI_X: CGKeyCode = 0x07;
76    pub const ANSI_C: CGKeyCode = 0x08;
77    pub const ANSI_V: CGKeyCode = 0x09;
78    pub const ANSI_B: CGKeyCode = 0x0B;
79    pub const ANSI_Q: CGKeyCode = 0x0C;
80    pub const ANSI_W: CGKeyCode = 0x0D;
81    pub const ANSI_E: CGKeyCode = 0x0E;
82    pub const ANSI_R: CGKeyCode = 0x0F;
83    pub const ANSI_Y: CGKeyCode = 0x10;
84    pub const ANSI_T: CGKeyCode = 0x11;
85    pub const ANSI_1: CGKeyCode = 0x12;
86    pub const ANSI_2: CGKeyCode = 0x13;
87    pub const ANSI_3: CGKeyCode = 0x14;
88    pub const ANSI_4: CGKeyCode = 0x15;
89    pub const ANSI_6: CGKeyCode = 0x16;
90    pub const ANSI_5: CGKeyCode = 0x17;
91    pub const ANSI_EQUAL: CGKeyCode = 0x18;
92    pub const ANSI_9: CGKeyCode = 0x19;
93    pub const ANSI_7: CGKeyCode = 0x1A;
94    pub const ANSI_MINUS: CGKeyCode = 0x1B;
95    pub const ANSI_8: CGKeyCode = 0x1C;
96    pub const ANSI_0: CGKeyCode = 0x1D;
97    pub const ANSI_RIGHT_BRACKET: CGKeyCode = 0x1E;
98    pub const ANSI_O: CGKeyCode = 0x1F;
99    pub const ANSI_U: CGKeyCode = 0x20;
100    pub const ANSI_LEFT_BRACKET: CGKeyCode = 0x21;
101    pub const ANSI_I: CGKeyCode = 0x22;
102    pub const ANSI_P: CGKeyCode = 0x23;
103    pub const ANSI_L: CGKeyCode = 0x25;
104    pub const ANSI_J: CGKeyCode = 0x26;
105    pub const ANSI_QUOTE: CGKeyCode = 0x27;
106    pub const ANSI_K: CGKeyCode = 0x28;
107    pub const ANSI_SEMICOLON: CGKeyCode = 0x29;
108    pub const ANSI_BACKSLASH: CGKeyCode = 0x2A;
109    pub const ANSI_COMMA: CGKeyCode = 0x2B;
110    pub const ANSI_SLASH: CGKeyCode = 0x2C;
111    pub const ANSI_N: CGKeyCode = 0x2D;
112    pub const ANSI_M: CGKeyCode = 0x2E;
113    pub const ANSI_PERIOD: CGKeyCode = 0x2F;
114    pub const ANSI_GRAVE: CGKeyCode = 0x32;
115    pub const ANSI_KEYPAD_DECIMAL: CGKeyCode = 0x41;
116    pub const ANSI_KEYPAD_MULTIPLY: CGKeyCode = 0x43;
117    pub const ANSI_KEYPAD_PLUS: CGKeyCode = 0x45;
118    pub const ANSI_KEYPAD_CLEAR: CGKeyCode = 0x47;
119    pub const ANSI_KEYPAD_DIVIDE: CGKeyCode = 0x4B;
120    pub const ANSI_KEYPAD_ENTER: CGKeyCode = 0x4C;
121    pub const ANSI_KEYPAD_MINUS: CGKeyCode = 0x4E;
122    pub const ANSI_KEYPAD_EQUAL: CGKeyCode = 0x51;
123    pub const ANSI_KEYPAD_0: CGKeyCode = 0x52;
124    pub const ANSI_KEYPAD_1: CGKeyCode = 0x53;
125    pub const ANSI_KEYPAD_2: CGKeyCode = 0x54;
126    pub const ANSI_KEYPAD_3: CGKeyCode = 0x55;
127    pub const ANSI_KEYPAD_4: CGKeyCode = 0x56;
128    pub const ANSI_KEYPAD_5: CGKeyCode = 0x57;
129    pub const ANSI_KEYPAD_6: CGKeyCode = 0x58;
130    pub const ANSI_KEYPAD_7: CGKeyCode = 0x59;
131    pub const ANSI_KEYPAD_8: CGKeyCode = 0x5B;
132    pub const ANSI_KEYPAD_9: CGKeyCode = 0x5C;
133    pub const RETURN: CGKeyCode = 0x24;
134    pub const TAB: CGKeyCode = 0x30;
135    pub const SPACE: CGKeyCode = 0x31;
136    pub const DELETE: CGKeyCode = 0x33;
137    pub const ESCAPE: CGKeyCode = 0x35;
138    pub const COMMAND: CGKeyCode = 0x37;
139    pub const SHIFT: CGKeyCode = 0x38;
140    pub const CAPS_LOCK: CGKeyCode = 0x39;
141    pub const OPTION: CGKeyCode = 0x3A;
142    pub const CONTROL: CGKeyCode = 0x3B;
143    pub const RIGHT_COMMAND: CGKeyCode = 0x36;
144    pub const RIGHT_SHIFT: CGKeyCode = 0x3C;
145    pub const RIGHT_OPTION: CGKeyCode = 0x3D;
146    pub const RIGHT_CONTROL: CGKeyCode = 0x3E;
147    pub const FUNCTION: CGKeyCode = 0x3F;
148    pub const F17: CGKeyCode = 0x40;
149    pub const VOLUME_UP: CGKeyCode = 0x48;
150    pub const VOLUME_DOWN: CGKeyCode = 0x49;
151    pub const MUTE: CGKeyCode = 0x4A;
152    pub const F18: CGKeyCode = 0x4F;
153    pub const F19: CGKeyCode = 0x50;
154    pub const F20: CGKeyCode = 0x5A;
155    pub const F5: CGKeyCode = 0x60;
156    pub const F6: CGKeyCode = 0x61;
157    pub const F7: CGKeyCode = 0x62;
158    pub const F3: CGKeyCode = 0x63;
159    pub const F8: CGKeyCode = 0x64;
160    pub const F9: CGKeyCode = 0x65;
161    pub const F11: CGKeyCode = 0x67;
162    pub const F13: CGKeyCode = 0x69;
163    pub const F16: CGKeyCode = 0x6A;
164    pub const F14: CGKeyCode = 0x6B;
165    pub const F10: CGKeyCode = 0x6D;
166    pub const F12: CGKeyCode = 0x6F;
167    pub const F15: CGKeyCode = 0x71;
168    pub const HELP: CGKeyCode = 0x72;
169    pub const HOME: CGKeyCode = 0x73;
170    pub const PAGE_UP: CGKeyCode = 0x74;
171    pub const FORWARD_DELETE: CGKeyCode = 0x75;
172    pub const F4: CGKeyCode = 0x76;
173    pub const END: CGKeyCode = 0x77;
174    pub const F2: CGKeyCode = 0x78;
175    pub const PAGE_DOWN: CGKeyCode = 0x79;
176    pub const F1: CGKeyCode = 0x7A;
177    pub const LEFT_ARROW: CGKeyCode = 0x7B;
178    pub const RIGHT_ARROW: CGKeyCode = 0x7C;
179    pub const DOWN_ARROW: CGKeyCode = 0x7D;
180    pub const UP_ARROW: CGKeyCode = 0x7E;
181    pub const ISO_SECTION: CGKeyCode = 0x0A;
182    pub const JIS_YEN: CGKeyCode = 0x5D;
183    pub const JIS_UNDERSCORE: CGKeyCode = 0x5E;
184    pub const JIS_KEYPAD_COMMA: CGKeyCode = 0x5F;
185    pub const JIS_EISU: CGKeyCode = 0x66;
186    pub const JIS_KANA: CGKeyCode = 0x68;
187}
188
189#[repr(C)]
190pub struct ScrollEventUnit {}
191impl ScrollEventUnit {
192    pub const PIXEL: CGScrollEventUnit = 0;
193    pub const LINE: CGScrollEventUnit = 1;
194}
195
196/// Constants that specify the different types of input events.
197///
198/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
199#[repr(u32)]
200#[derive(Clone, Copy, Debug)]
201pub enum CGEventType {
202    Null = 0,
203
204    // Mouse events.
205    LeftMouseDown = 1,
206    LeftMouseUp = 2,
207    RightMouseDown = 3,
208    RightMouseUp = 4,
209    MouseMoved = 5,
210    LeftMouseDragged = 6,
211    RightMouseDragged = 7,
212
213    // Keyboard events.
214    KeyDown = 10,
215    KeyUp = 11,
216    FlagsChanged = 12,
217
218    // Specialized control devices.
219    ScrollWheel = 22,
220    TabletPointer = 23,
221    TabletProximity = 24,
222    OtherMouseDown = 25,
223    OtherMouseUp = 26,
224    OtherMouseDragged = 27,
225
226    // Out of band event types. These are delivered to the event tap callback
227    // to notify it of unusual conditions that disable the event tap.
228    TapDisabledByTimeout = 0xFFFFFFFE,
229    TapDisabledByUserInput = 0xFFFFFFFF,
230}
231
232/// Constants used as keys to access specialized fields in low-level events.
233///
234/// [Ref](https://developer.apple.com/documentation/coregraphics/cgeventfield)
235pub struct EventField;
236impl EventField {
237    /// Key to access an integer field that contains the mouse button event
238    /// number. Matching mouse-down and mouse-up events will have the same
239    /// event number.
240    pub const MOUSE_EVENT_NUMBER: CGEventField = 0;
241
242    /// Key to access an integer field that contains the mouse button click
243    /// state. A click state of 1 represents a single click. A click state of
244    /// 2 represents a double-click. A click state of 3 represents a
245    /// triple-click.
246    pub const MOUSE_EVENT_CLICK_STATE: CGEventField = 1;
247
248    /// Key to access a double field that contains the mouse button pressure.
249    /// The pressure value may range from 0 to 1, with 0 representing the
250    /// mouse being up. This value is commonly set by tablet pens mimicking a
251    /// mouse.
252    pub const MOUSE_EVENT_PRESSURE: CGEventField = 2;
253
254    /// Key to access an integer field that contains the mouse button number.
255    pub const MOUSE_EVENT_BUTTON_NUMBER: CGEventField = 3;
256
257    /// Key to access an integer field that contains the horizontal mouse
258    /// delta since the last mouse movement event.
259    pub const MOUSE_EVENT_DELTA_X: CGEventField = 4;
260
261    /// Key to access an integer field that contains the vertical mouse delta
262    /// since the last mouse movement event.
263    pub const MOUSE_EVENT_DELTA_Y: CGEventField = 5;
264
265    /// Key to access an integer field. The value is non-zero if the event
266    /// should be ignored by the Inkwell subsystem.
267    pub const MOUSE_EVENT_INSTANT_MOUSER: CGEventField = 6;
268
269    /// Key to access an integer field that encodes the mouse event subtype as
270    /// a `kCFNumberIntType`.
271    pub const MOUSE_EVENT_SUB_TYPE: CGEventField = 7;
272
273    /// Key to access an integer field, non-zero when this is an autorepeat of
274    /// a key-down, and zero otherwise.
275    pub const KEYBOARD_EVENT_AUTOREPEAT: CGEventField = 8;
276
277    /// Key to access an integer field that contains the virtual keycode of the
278    /// key-down or key-up event.
279    pub const KEYBOARD_EVENT_KEYCODE: CGEventField = 9;
280
281    /// Key to access an integer field that contains the keyboard type
282    /// identifier.
283    pub const KEYBOARD_EVENT_KEYBOARD_TYPE: CGEventField = 10;
284
285    /// Key to access an integer field that contains scrolling data. This field
286    /// typically contains the change in vertical position since the last
287    /// scrolling event from a Mighty Mouse scroller or a single-wheel mouse
288    /// scroller.
289    pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_1: CGEventField = 11;
290
291    /// Key to access an integer field that contains scrolling data. This field
292    /// typically contains the change in horizontal position since the last
293    /// scrolling event from a Mighty Mouse scroller.
294    pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_2: CGEventField = 12;
295
296    /// Key to access a field that contains scrolling data. The scrolling data
297    /// represents a line-based or pixel-based change in vertical position
298    /// since the last scrolling event from a Mighty Mouse scroller or a
299    /// single-wheel mouse scroller. The scrolling data uses a fixed-point
300    /// 16.16 signed integer format. If this key is passed to
301    /// `CGEventGetDoubleValueField`, the fixed-point value is converted to a
302    /// double value.
303    pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_1: CGEventField = 93;
304
305    /// Key to access a field that contains scrolling data. The scrolling data
306    /// represents a line-based or pixel-based change in horizontal position
307    /// since the last scrolling event from a Mighty Mouse scroller. The
308    /// scrolling data uses a fixed-point 16.16 signed integer format. If this
309    /// key is passed to `CGEventGetDoubleValueField`, the fixed-point value is
310    /// converted to a double value.
311    pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_2: CGEventField = 94;
312
313    /// Key to access an integer field that contains pixel-based scrolling
314    /// data. The scrolling data represents the change in vertical position
315    /// since the last scrolling event from a Mighty Mouse scroller or a
316    /// single-wheel mouse scroller.
317    pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_1: CGEventField = 96;
318
319    /// Key to access an integer field that contains pixel-based scrolling
320    /// data. The scrolling data represents the change in horizontal position
321    /// since the last scrolling event from a Mighty Mouse scroller.
322    pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_2: CGEventField = 97;
323
324    /// Key to access an integer field that indicates whether the event should
325    /// be ignored by the Inkwell subsystem. If the value is non-zero, the
326    /// event should be ignored.
327    pub const SCROLL_WHEEL_EVENT_INSTANT_MOUSER: CGEventField = 14;
328
329    /// Key to access an integer field that contains the absolute X coordinate
330    /// in tablet space at full tablet resolution.
331    pub const TABLET_EVENT_POINT_X: CGEventField = 15;
332
333    /// Key to access an integer field that contains the absolute Y coordinate
334    /// in tablet space at full tablet resolution.
335    pub const TABLET_EVENT_POINT_Y: CGEventField = 16;
336
337    /// Key to access an integer field that contains the absolute Z coordinate
338    /// in tablet space at full tablet resolution.
339    pub const TABLET_EVENT_POINT_Z: CGEventField = 17;
340
341    /// Key to access an integer field that contains the tablet button state.
342    /// Bit 0 is the first button, and a set bit represents a closed or pressed
343    /// button. Up to 16 buttons are supported.
344    pub const TABLET_EVENT_POINT_BUTTONS: CGEventField = 18;
345
346    /// Key to access a double field that contains the tablet pen pressure. A
347    /// value of 0.0 represents no pressure, and 1.0 represents maximum
348    /// pressure.
349    pub const TABLET_EVENT_POINT_PRESSURE: CGEventField = 19;
350
351    /// Key to access a double field that contains the horizontal tablet pen
352    /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt.
353    pub const TABLET_EVENT_TILT_X: CGEventField = 20;
354
355    /// Key to access a double field that contains the vertical tablet pen
356    /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt.
357    pub const TABLET_EVENT_TILT_Y: CGEventField = 21;
358
359    /// Key to access a double field that contains the tablet pen rotation.
360    pub const TABLET_EVENT_ROTATION: CGEventField = 22;
361
362    /// Key to access a double field that contains the tangential pressure on
363    /// the device. A value of 0.0 represents no pressure, and 1.0 represents
364    /// maximum pressure.
365    pub const TABLET_EVENT_TANGENTIAL_PRESSURE: CGEventField = 23;
366
367    /// Key to access an integer field that contains the system-assigned unique
368    /// device ID.
369    pub const TABLET_EVENT_DEVICE_ID: CGEventField = 24;
370
371    /// Key to access an integer field that contains a vendor-specified value.
372    pub const TABLET_EVENT_VENDOR_1: CGEventField = 25;
373
374    /// Key to access an integer field that contains a vendor-specified value.
375    pub const TABLET_EVENT_VENDOR_2: CGEventField = 26;
376
377    /// Key to access an integer field that contains a vendor-specified value.
378    pub const TABLET_EVENT_VENDOR_3: CGEventField = 27;
379
380    /// Key to access an integer field that contains the vendor-defined ID,
381    /// typically the USB vendor ID.
382    pub const TABLET_PROXIMITY_EVENT_VENDOR_ID: CGEventField = 28;
383
384    /// Key to access an integer field that contains the vendor-defined tablet
385    /// ID, typically the USB product ID.
386    pub const TABLET_PROXIMITY_EVENT_TABLET_ID: CGEventField = 29;
387
388    /// Key to access an integer field that contains the vendor-defined ID of
389    /// the pointing device.
390    pub const TABLET_PROXIMITY_EVENT_POINTER_ID: CGEventField = 30;
391
392    /// Key to access an integer field that contains the system-assigned
393    /// device ID.
394    pub const TABLET_PROXIMITY_EVENT_DEVICE_ID: CGEventField = 31;
395
396    /// Key to access an integer field that contains the system-assigned
397    /// unique tablet ID.
398    pub const TABLET_PROXIMITY_EVENT_SYSTEM_TABLET_ID: CGEventField = 32;
399
400    /// Key to access an integer field that contains the vendor-assigned
401    /// pointer type.
402    pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_TYPE: CGEventField = 33;
403
404    /// Key to access an integer field that contains the vendor-defined
405    /// pointer serial number.
406    pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_SERIAL_NUMBER: CGEventField = 34;
407
408    /// Key to access an integer field that contains the vendor-defined unique
409    /// ID.
410    pub const TABLET_PROXIMITY_EVENT_VENDOR_UNIQUE_ID: CGEventField = 35;
411
412    /// Key to access an integer field that contains the device capabilities
413    /// mask.
414    pub const TABLET_PROXIMITY_EVENT_CAPABILITY_MASK: CGEventField = 36;
415
416    /// Key to access an integer field that contains the pointer type.
417    pub const TABLET_PROXIMITY_EVENT_POINTER_TYPE: CGEventField = 37;
418
419    /// Key to access an integer field that indicates whether the pen is in
420    /// proximity to the tablet. The value is non-zero if the pen is in
421    /// proximity to the tablet and zero when leaving the tablet.
422    pub const TABLET_PROXIMITY_EVENT_ENTER_PROXIMITY: CGEventField = 38;
423
424    /// Key to access a field that contains the event target process serial
425    /// number. The value is a 64-bit value.
426    pub const EVENT_TARGET_PROCESS_SERIAL_NUMBER: CGEventField = 39;
427
428    /// Key to access a field that contains the event target Unix process ID.
429    pub const EVENT_TARGET_UNIX_PROCESS_ID: CGEventField = 40;
430
431    /// Key to access a field that contains the event source Unix process ID.
432    pub const EVENT_SOURCE_UNIX_PROCESS_ID: CGEventField = 41;
433
434    /// Key to access a field that contains the event source user-supplied
435    /// data, up to 64 bits.
436    pub const EVENT_SOURCE_USER_DATA: CGEventField = 42;
437
438    /// Key to access a field that contains the event source Unix effective UID.
439    pub const EVENT_SOURCE_USER_ID: CGEventField = 43;
440
441    /// Key to access a field that contains the event source Unix effective
442    /// GID.
443    pub const EVENT_SOURCE_GROUP_ID: CGEventField = 44;
444
445    /// Key to access a field that contains the event source state ID used to
446    /// create this event.
447    pub const EVENT_SOURCE_STATE_ID: CGEventField = 45;
448
449    /// Key to access an integer field that indicates whether a scrolling event
450    /// contains continuous, pixel-based scrolling data. The value is non-zero
451    /// when the scrolling data is pixel-based and zero when the scrolling data
452    /// is line-based.
453    pub const SCROLL_WHEEL_EVENT_IS_CONTINUOUS: CGEventField = 88;
454
455    /// Added in 10.5; made public in 10.7.
456    pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER: CGEventField = 91;
457    pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER_THAT_CAN_HANDLE_THIS_EVENT: CGEventField = 92;
458}
459
460// Constants that specify buttons on a one, two, or three-button mouse.
461#[repr(C)]
462#[derive(Clone, Copy, Debug)]
463pub enum CGMouseButton {
464    Left,
465    Right,
466    Center,
467}
468
469/// Possible tapping points for events.
470#[repr(C)]
471#[derive(Clone, Copy, Debug)]
472pub enum CGEventTapLocation {
473    HID,
474    Session,
475    AnnotatedSession,
476}
477
478// The next three enums are taken from:
479// [Ref](https://github.com/phracker/MacOSX-SDKs/blob/ef9fe35d5691b6dd383c8c46d867a499817a01b6/MacOSX10.15.sdk/System/Library/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGEventTypes.h)
480/* Constants that specify where a new event tap is inserted into the list of
481active event taps. */
482#[repr(u32)]
483#[derive(Clone, Copy, Debug)]
484pub enum CGEventTapPlacement {
485    HeadInsertEventTap = 0,
486    TailAppendEventTap,
487}
488
489/* Constants that specify whether a new event tap is an active filter or a
490passive listener. */
491#[repr(u32)]
492#[derive(Clone, Copy, Debug)]
493pub enum CGEventTapOptions {
494    Default = 0x00000000,
495    ListenOnly = 0x00000001,
496}
497
498pub type CGEventMask = u64;
499/* Generate an event mask for a single type of event. */
500macro_rules! CGEventMaskBit {
501    ($eventType:expr) => {
502        (1 << $eventType as CGEventMask)
503    };
504}
505
506pub type CGEventTapProxy = *const c_void;
507
508/// What the system should do with the event passed to the callback.
509///
510/// This value is ignored if [`CGEventTapOptions::ListenOnly`] is specified.
511pub enum CallbackResult {
512    /// Pass the event unchanged to other consumers.
513    Keep,
514    /// Drop the event so it is not passed to later consumers.
515    Drop,
516    /// Replace the event with a different one.
517    Replace(CGEvent),
518}
519
520type CGEventTapCallbackFn<'tap_life> =
521    Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> CallbackResult + 'tap_life>;
522type CGEventTapCallBackInternal = unsafe extern "C" fn(
523    proxy: CGEventTapProxy,
524    etype: CGEventType,
525    event: crate::sys::CGEventRef,
526    user_info: *const c_void,
527) -> crate::sys::CGEventRef;
528
529unsafe extern "C" fn cg_event_tap_callback_internal(
530    proxy: CGEventTapProxy,
531    etype: CGEventType,
532    event: crate::sys::CGEventRef,
533    user_info: *const c_void,
534) -> crate::sys::CGEventRef {
535    let callback = user_info as *mut CGEventTapCallbackFn;
536    let event = ManuallyDrop::new(CGEvent::from_ptr(event));
537    let response = (*callback)(proxy, etype, &event);
538    use CallbackResult::*;
539    match response {
540        Keep => event.as_ptr(),
541        Drop => ptr::null_mut(),
542        Replace(new_event) => ManuallyDrop::new(new_event).as_ptr(),
543    }
544}
545
546/// ```no_run
547/// use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
548/// use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType, CallbackResult};
549/// let current = CFRunLoop::get_current();
550///
551/// CGEventTap::with_enabled(
552///     CGEventTapLocation::HID,
553///     CGEventTapPlacement::HeadInsertEventTap,
554///     CGEventTapOptions::Default,
555///     vec![CGEventType::MouseMoved],
556///     |_proxy, _type, event| {
557///         println!("{:?}", event.location());
558///         CallbackResult::Keep
559///     },
560///     ||  CFRunLoop::run_current(),
561/// ).expect("Failed to install event tap");
562/// ```
563#[must_use = "CGEventTap is disabled when dropped"]
564pub struct CGEventTap<'tap_life> {
565    mach_port: CFMachPort,
566    _callback: Box<CGEventTapCallbackFn<'tap_life>>,
567}
568
569impl CGEventTap<'static> {
570    pub fn new<F: Fn(CGEventTapProxy, CGEventType, &CGEvent) -> CallbackResult + Send + 'static>(
571        tap: CGEventTapLocation,
572        place: CGEventTapPlacement,
573        options: CGEventTapOptions,
574        events_of_interest: std::vec::Vec<CGEventType>,
575        callback: F,
576    ) -> Result<Self, ()> {
577        // SAFETY: callback is 'static so even if this object is forgotten it
578        // will be valid to call. F is safe to send across threads.
579        unsafe { Self::new_unchecked(tap, place, options, events_of_interest, callback) }
580    }
581}
582
583impl<'tap_life> CGEventTap<'tap_life> {
584    /// Configures an event tap with the supplied options and callback, then
585    /// calls `with_fn`.
586    ///
587    /// Note that the current thread run loop must run within `with_fn` for the
588    /// tap to process events. The tap is destroyed when `with_fn` returns.
589    pub fn with_enabled<R>(
590        tap: CGEventTapLocation,
591        place: CGEventTapPlacement,
592        options: CGEventTapOptions,
593        events_of_interest: std::vec::Vec<CGEventType>,
594        callback: impl Fn(CGEventTapProxy, CGEventType, &CGEvent) -> CallbackResult + 'tap_life,
595        with_fn: impl FnOnce() -> R,
596    ) -> Result<R, ()> {
597        // SAFETY: We are okay to bypass the 'static restriction because the
598        // event tap is dropped before returning. The callback therefore cannot
599        // be called after its lifetime expires. Since we only enable the tap
600        // on the current thread run loop and don't hand it to user code, we
601        // know that the callback will only be called from the current thread.
602        let event_tap: Self =
603            unsafe { Self::new_unchecked(tap, place, options, events_of_interest, callback)? };
604        let loop_source = event_tap
605            .mach_port()
606            .create_runloop_source(0)
607            .expect("Runloop source creation failed");
608        CFRunLoop::get_current().add_source(&loop_source, unsafe { kCFRunLoopCommonModes });
609        event_tap.enable();
610        Ok(with_fn())
611    }
612
613    /// Caller is responsible for ensuring that this object is dropped before
614    /// `'tap_life` expires. Either state captured by `callback` must be safe to
615    /// send across threads, or the tap must only be installed on the current
616    /// thread's run loop.
617    pub unsafe fn new_unchecked(
618        tap: CGEventTapLocation,
619        place: CGEventTapPlacement,
620        options: CGEventTapOptions,
621        events_of_interest: std::vec::Vec<CGEventType>,
622        callback: impl Fn(CGEventTapProxy, CGEventType, &CGEvent) -> CallbackResult + 'tap_life,
623    ) -> Result<Self, ()> {
624        let event_mask: CGEventMask = events_of_interest
625            .iter()
626            .fold(CGEventType::Null as CGEventMask, |mask, &etype| {
627                mask | CGEventMaskBit!(etype)
628            });
629        let cb: Box<CGEventTapCallbackFn> = Box::new(Box::new(callback));
630        let cbr = Box::into_raw(cb);
631        unsafe {
632            let event_tap_ref = CGEventTapCreate(
633                tap,
634                place,
635                options,
636                event_mask,
637                cg_event_tap_callback_internal,
638                cbr as *const c_void,
639            );
640
641            if !event_tap_ref.is_null() {
642                Ok(Self {
643                    mach_port: (CFMachPort::wrap_under_create_rule(event_tap_ref)),
644                    _callback: Box::from_raw(cbr),
645                })
646            } else {
647                let _ = Box::from_raw(cbr);
648                Err(())
649            }
650        }
651    }
652
653    pub fn mach_port(&self) -> &CFMachPort {
654        &self.mach_port
655    }
656
657    pub fn enable(&self) {
658        unsafe { CGEventTapEnable(self.mach_port.as_concrete_TypeRef(), true) }
659    }
660}
661
662impl Drop for CGEventTap<'_> {
663    fn drop(&mut self) {
664        unsafe { CFMachPortInvalidate(self.mach_port.as_CFTypeRef() as *mut _) };
665    }
666}
667
668foreign_type! {
669    #[doc(hidden)]
670    pub unsafe type CGEvent {
671        type CType = crate::sys::CGEvent;
672        fn drop = |p| CFRelease(p as *mut _);
673        fn clone = |p| CFRetain(p as *const _) as *mut _;
674    }
675}
676
677impl CGEvent {
678    pub fn type_id() -> CFTypeID {
679        unsafe { CGEventGetTypeID() }
680    }
681
682    pub fn new(source: CGEventSource) -> Result<CGEvent, ()> {
683        unsafe {
684            let event_ref = CGEventCreate(source.as_ptr());
685            if !event_ref.is_null() {
686                Ok(Self::from_ptr(event_ref))
687            } else {
688                Err(())
689            }
690        }
691    }
692
693    pub fn new_keyboard_event(
694        source: CGEventSource,
695        keycode: CGKeyCode,
696        keydown: bool,
697    ) -> Result<CGEvent, ()> {
698        unsafe {
699            let event_ref = CGEventCreateKeyboardEvent(source.as_ptr(), keycode, keydown);
700            if !event_ref.is_null() {
701                Ok(Self::from_ptr(event_ref))
702            } else {
703                Err(())
704            }
705        }
706    }
707
708    pub fn new_mouse_event(
709        source: CGEventSource,
710        mouse_type: CGEventType,
711        mouse_cursor_position: CGPoint,
712        mouse_button: CGMouseButton,
713    ) -> Result<CGEvent, ()> {
714        unsafe {
715            let event_ref = CGEventCreateMouseEvent(
716                source.as_ptr(),
717                mouse_type,
718                mouse_cursor_position,
719                mouse_button,
720            );
721            if !event_ref.is_null() {
722                Ok(Self::from_ptr(event_ref))
723            } else {
724                Err(())
725            }
726        }
727    }
728
729    #[cfg(feature = "highsierra")]
730    pub fn new_scroll_event(
731        source: CGEventSource,
732        units: CGScrollEventUnit,
733        wheel_count: u32,
734        wheel1: i32,
735        wheel2: i32,
736        wheel3: i32,
737    ) -> Result<CGEvent, ()> {
738        unsafe {
739            let event_ref = CGEventCreateScrollWheelEvent2(
740                source.as_ptr(),
741                units,
742                wheel_count,
743                wheel1,
744                wheel2,
745                wheel3,
746            );
747            if !event_ref.is_null() {
748                Ok(Self::from_ptr(event_ref))
749            } else {
750                Err(())
751            }
752        }
753    }
754
755    pub fn post(&self, tap_location: CGEventTapLocation) {
756        unsafe {
757            CGEventPost(tap_location, self.as_ptr());
758        }
759    }
760
761    pub fn post_from_tap(&self, tap_proxy: CGEventTapProxy) {
762        unsafe {
763            CGEventTapPostEvent(tap_proxy, self.as_ptr());
764        }
765    }
766
767    pub fn location(&self) -> CGPoint {
768        unsafe { CGEventGetLocation(self.as_ptr()) }
769    }
770
771    pub fn set_location(&self, location: CGPoint) {
772        unsafe {
773            CGEventSetLocation(self.as_ptr(), location);
774        }
775    }
776
777    #[cfg(feature = "elcapitan")]
778    pub fn post_to_pid(&self, pid: libc::pid_t) {
779        unsafe {
780            CGEventPostToPid(pid, self.as_ptr());
781        }
782    }
783
784    pub fn set_flags(&self, flags: CGEventFlags) {
785        unsafe {
786            CGEventSetFlags(self.as_ptr(), flags);
787        }
788    }
789
790    pub fn get_flags(&self) -> CGEventFlags {
791        unsafe { CGEventGetFlags(self.as_ptr()) }
792    }
793
794    pub fn set_type(&self, event_type: CGEventType) {
795        unsafe {
796            CGEventSetType(self.as_ptr(), event_type);
797        }
798    }
799
800    pub fn get_type(&self) -> CGEventType {
801        unsafe { CGEventGetType(self.as_ptr()) }
802    }
803
804    pub fn set_string_from_utf16_unchecked(&self, buf: &[u16]) {
805        let buflen = buf.len() as c_ulong;
806        unsafe {
807            CGEventKeyboardSetUnicodeString(self.as_ptr(), buflen, buf.as_ptr());
808        }
809    }
810
811    pub fn set_string(&self, string: &str) {
812        let buf: Vec<u16> = string.encode_utf16().collect();
813        self.set_string_from_utf16_unchecked(&buf);
814    }
815
816    pub fn get_integer_value_field(&self, field: CGEventField) -> i64 {
817        unsafe { CGEventGetIntegerValueField(self.as_ptr(), field) }
818    }
819
820    pub fn set_integer_value_field(&self, field: CGEventField, value: i64) {
821        unsafe { CGEventSetIntegerValueField(self.as_ptr(), field, value) }
822    }
823
824    pub fn get_double_value_field(&self, field: CGEventField) -> f64 {
825        unsafe { CGEventGetDoubleValueField(self.as_ptr(), field) }
826    }
827
828    pub fn set_double_value_field(&self, field: CGEventField, value: f64) {
829        unsafe { CGEventSetDoubleValueField(self.as_ptr(), field, value) }
830    }
831}
832
833#[cfg_attr(feature = "link", link(name = "CoreGraphics", kind = "framework"))]
834extern "C" {
835    /// Return the type identifier for the opaque type [`CGEventRef`].
836    ///
837    /// [`CGEventRef`]: crate::sys::CGEventRef
838    fn CGEventGetTypeID() -> CFTypeID;
839
840    /// Return a new event using the event source `source`. If `source` is NULL,
841    /// the default source is used.
842    fn CGEventCreate(source: crate::sys::CGEventSourceRef) -> crate::sys::CGEventRef;
843
844    /// Return a new keyboard event.
845    ///
846    /// The event source may be taken from another event, or may be NULL. Based
847    /// on the virtual key code values entered, the appropriate key down, key up,
848    /// or flags changed events are generated.
849    ///
850    /// All keystrokes needed to generate a character must be entered, including
851    /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z',
852    /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT
853    /// and 'z' key must be released:
854    fn CGEventCreateKeyboardEvent(
855        source: crate::sys::CGEventSourceRef,
856        keycode: CGKeyCode,
857        keydown: bool,
858    ) -> crate::sys::CGEventRef;
859
860    /// Return a new mouse event.
861    ///
862    /// The event source may be taken from another event, or may be NULL.
863    /// `mouseType` should be one of the mouse event types. `mouseCursorPosition`
864    /// should be the position of the mouse cursor in global coordinates.
865    /// `mouseButton` should be the button that's changing state; `mouseButton`
866    /// is ignored unless `mouseType` is one of `kCGEventOtherMouseDown`,
867    /// `kCGEventOtherMouseDragged`, or `kCGEventOtherMouseUp`.
868    ///
869    /// The current implementation of the event system supports a maximum of
870    /// thirty-two buttons. Mouse button 0 is the primary button on the mouse.
871    /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is
872    /// the center button, and the remaining buttons are in USB device order.
873    fn CGEventCreateMouseEvent(
874        source: crate::sys::CGEventSourceRef,
875        mouseType: CGEventType,
876        mouseCursorPosition: CGPoint,
877        mouseButton: CGMouseButton,
878    ) -> crate::sys::CGEventRef;
879
880    /// A non-variadic variant version of [`CGEventCreateScrollWheelEvent`].
881    ///
882    /// Returns a new Quartz scrolling event.
883    ///
884    /// This function allows you to create a scrolling event and customize the
885    /// event before posting it to the event system.
886    #[cfg(feature = "highsierra")]
887    fn CGEventCreateScrollWheelEvent2(
888        source: crate::sys::CGEventSourceRef,
889        units: CGScrollEventUnit,
890        wheelCount: u32,
891        wheel1: i32,
892        wheel2: i32,
893        wheel3: i32,
894    ) -> crate::sys::CGEventRef;
895
896    /// Post an event into the event stream at a specified location.
897    ///
898    /// This function posts the specified event immediately before any event taps
899    /// instantiated for that location, and the event passes through any such
900    /// taps.
901    fn CGEventPost(tapLocation: CGEventTapLocation, event: crate::sys::CGEventRef);
902
903    fn CGEventTapPostEvent(tapProxy: CGEventTapProxy, event: crate::sys::CGEventRef);
904
905    #[cfg(feature = "elcapitan")]
906    /// Post an event to a specified process ID
907    fn CGEventPostToPid(pid: libc::pid_t, event: crate::sys::CGEventRef);
908
909    /// Set the event flags of an event.
910    fn CGEventSetFlags(event: crate::sys::CGEventRef, flags: CGEventFlags);
911
912    /// Return the event flags of an event.
913    fn CGEventGetFlags(event: crate::sys::CGEventRef) -> CGEventFlags;
914
915    /// Return the location of an event in global display coordinates.
916    /// `CGPointZero` is returned if event is not a valid [`CGEventRef`].
917    ///
918    /// [`CGEventRef`]: crate::sys::CGEventRef
919    fn CGEventGetLocation(event: crate::sys::CGEventRef) -> CGPoint;
920
921    /// Set the event type of an event.
922    fn CGEventSetType(event: crate::sys::CGEventRef, eventType: CGEventType);
923
924    /// Return the event type of an event (left mouse down, for example).
925    fn CGEventGetType(event: crate::sys::CGEventRef) -> CGEventType;
926
927    /// Set the Unicode string associated with a keyboard event.
928    ///
929    /// By default, the system translates the virtual key code in a keyboard
930    /// event into a Unicode string based on the keyboard ID in the event
931    /// source.  This function allows you to manually override this string.
932    /// Note that application frameworks may ignore the Unicode string in a
933    /// keyboard event and do their own translation based on the virtual
934    /// keycode and perceived event state.
935    fn CGEventKeyboardSetUnicodeString(
936        event: crate::sys::CGEventRef,
937        length: c_ulong,
938        string: *const u16,
939    );
940
941    /// Return the integer value of a field in an event.
942    fn CGEventGetIntegerValueField(event: crate::sys::CGEventRef, field: CGEventField) -> i64;
943
944    /// Set the integer value of a field in an event.
945    ///
946    /// Before calling this function, the event type must be set using a typed
947    /// event creation function such as [`CGEventCreateMouseEvent`], or by
948    /// calling [`CGEventSetType`].
949    ///
950    /// If you are creating a mouse event generated by a tablet, call this
951    /// function and specify the field `kCGMouseEventSubtype` with a value of
952    /// `kCGEventMouseSubtypeTabletPoint` or
953    /// `kCGEventMouseSubtypeTabletProximity` before setting other parameters.
954    fn CGEventSetIntegerValueField(event: crate::sys::CGEventRef, field: CGEventField, value: i64);
955
956    /// Return the floating-point value of a field in an event.
957    ///
958    /// In cases where the field value is represented within the event by a fixed
959    /// point number or an integer, the result is scaled to the appropriate range
960    /// as part of creating the floating-point representation.
961    fn CGEventGetDoubleValueField(event: crate::sys::CGEventRef, field: CGEventField) -> f64;
962
963    /// Set the floating-point value of a field in an event.
964    ///
965    /// Before calling this function, the event type must be set using a typed
966    /// event creation function such as [`CGEventCreateMouseEvent`], or by calling
967    /// [`CGEventSetType`].
968    ///
969    /// In cases where the field’s value is represented within the event by a
970    /// fixed point number or integer, the value parameter is scaled as needed
971    /// and converted to the appropriate type.
972    fn CGEventSetDoubleValueField(event: crate::sys::CGEventRef, field: CGEventField, value: f64);
973
974    // ::sys::CGEventTapRef is actually an CFMachPortRef
975    fn CGEventTapCreate(
976        tap: CGEventTapLocation,
977        place: CGEventTapPlacement,
978        options: CGEventTapOptions,
979        eventsOfInterest: CGEventMask,
980        callback: CGEventTapCallBackInternal,
981        userInfo: *const c_void,
982    ) -> CFMachPortRef;
983
984    /// Enable or disable an event tap.
985    ///
986    /// Event taps are normally enabled when created. If an event tap becomes
987    /// unresponsive, or if a user requests that event taps be disabled, then
988    /// a `kCGEventTapDisabled` event is passed to the event tap callback
989    /// function. Event taps may be re-enabled by calling this function.
990    fn CGEventTapEnable(tap: CFMachPortRef, enable: bool);
991
992    /// Set the location of a mouse event.
993    fn CGEventSetLocation(event: crate::sys::CGEventRef, location: CGPoint);
994}