core_graphics_helmer_fork/
event.rs

1#![allow(non_upper_case_globals)]
2use crate::event_source::CGEventSource;
3use crate::geometry::CGPoint;
4use core_foundation::{
5    base::{CFRelease, CFRetain, CFTypeID, TCFType},
6    mach_port::{CFMachPort, CFMachPortRef},
7};
8use foreign_types::ForeignType;
9use libc::c_void;
10use std::mem::ManuallyDrop;
11
12pub type CGEventField = u32;
13pub type CGKeyCode = u16;
14pub type CGScrollEventUnit = u32;
15
16bitflags! {
17    /// Flags for events
18    ///
19    /// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
20    #[repr(C)]
21    #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
22    pub struct CGEventFlags: u64 {
23        const CGEventFlagNull = 0;
24
25        // Device-independent modifier key bits.
26        const CGEventFlagAlphaShift = 0x00010000;
27        const CGEventFlagShift = 0x00020000;
28        const CGEventFlagControl = 0x00040000;
29        const CGEventFlagAlternate = 0x00080000;
30        const CGEventFlagCommand = 0x00100000;
31
32        // Special key identifiers.
33        const CGEventFlagHelp = 0x00400000;
34        const CGEventFlagSecondaryFn = 0x00800000;
35
36        // Identifies key events from numeric keypad area on extended keyboards.
37        const CGEventFlagNumericPad = 0x00200000;
38
39        // Indicates if mouse/pen movement events are not being coalesced
40        const CGEventFlagNonCoalesced = 0x00000100;
41    }
42}
43
44/// Key codes for keys that are independent of keyboard layout.
45///
46/// [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)
47#[repr(C)]
48pub struct KeyCode;
49impl KeyCode {
50    pub const RETURN: CGKeyCode = 0x24;
51    pub const TAB: CGKeyCode = 0x30;
52    pub const SPACE: CGKeyCode = 0x31;
53    pub const DELETE: CGKeyCode = 0x33;
54    pub const ESCAPE: CGKeyCode = 0x35;
55    pub const COMMAND: CGKeyCode = 0x37;
56    pub const SHIFT: CGKeyCode = 0x38;
57    pub const CAPS_LOCK: CGKeyCode = 0x39;
58    pub const OPTION: CGKeyCode = 0x3A;
59    pub const CONTROL: CGKeyCode = 0x3B;
60    pub const RIGHT_COMMAND: CGKeyCode = 0x36;
61    pub const RIGHT_SHIFT: CGKeyCode = 0x3C;
62    pub const RIGHT_OPTION: CGKeyCode = 0x3D;
63    pub const RIGHT_CONTROL: CGKeyCode = 0x3E;
64    pub const FUNCTION: CGKeyCode = 0x3F;
65    pub const VOLUME_UP: CGKeyCode = 0x48;
66    pub const VOLUME_DOWN: CGKeyCode = 0x49;
67    pub const MUTE: CGKeyCode = 0x4A;
68    pub const F1: CGKeyCode = 0x7A;
69    pub const F2: CGKeyCode = 0x78;
70    pub const F3: CGKeyCode = 0x63;
71    pub const F4: CGKeyCode = 0x76;
72    pub const F5: CGKeyCode = 0x60;
73    pub const F6: CGKeyCode = 0x61;
74    pub const F7: CGKeyCode = 0x62;
75    pub const F8: CGKeyCode = 0x64;
76    pub const F9: CGKeyCode = 0x65;
77    pub const F10: CGKeyCode = 0x6D;
78    pub const F11: CGKeyCode = 0x67;
79    pub const F12: CGKeyCode = 0x6F;
80    pub const F13: CGKeyCode = 0x69;
81    pub const F14: CGKeyCode = 0x6B;
82    pub const F15: CGKeyCode = 0x71;
83    pub const F16: CGKeyCode = 0x6A;
84    pub const F17: CGKeyCode = 0x40;
85    pub const F18: CGKeyCode = 0x4F;
86    pub const F19: CGKeyCode = 0x50;
87    pub const F20: CGKeyCode = 0x5A;
88    pub const HELP: CGKeyCode = 0x72;
89    pub const HOME: CGKeyCode = 0x73;
90    pub const PAGE_UP: CGKeyCode = 0x74;
91    pub const FORWARD_DELETE: CGKeyCode = 0x75;
92    pub const END: CGKeyCode = 0x77;
93    pub const PAGE_DOWN: CGKeyCode = 0x79;
94    pub const LEFT_ARROW: CGKeyCode = 0x7B;
95    pub const RIGHT_ARROW: CGKeyCode = 0x7C;
96    pub const DOWN_ARROW: CGKeyCode = 0x7D;
97    pub const UP_ARROW: CGKeyCode = 0x7E;
98}
99
100#[repr(C)]
101pub struct ScrollEventUnit {}
102impl ScrollEventUnit {
103    pub const PIXEL: CGScrollEventUnit = 0;
104    pub const LINE: CGScrollEventUnit = 1;
105}
106
107/// Constants that specify the different types of input events.
108///
109/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
110#[repr(u32)]
111#[derive(Clone, Copy, Debug)]
112pub enum CGEventType {
113    Null = 0,
114
115    // Mouse events.
116    LeftMouseDown = 1,
117    LeftMouseUp = 2,
118    RightMouseDown = 3,
119    RightMouseUp = 4,
120    MouseMoved = 5,
121    LeftMouseDragged = 6,
122    RightMouseDragged = 7,
123
124    // Keyboard events.
125    KeyDown = 10,
126    KeyUp = 11,
127    FlagsChanged = 12,
128
129    // Specialized control devices.
130    ScrollWheel = 22,
131    TabletPointer = 23,
132    TabletProximity = 24,
133    OtherMouseDown = 25,
134    OtherMouseUp = 26,
135    OtherMouseDragged = 27,
136
137    // Out of band event types. These are delivered to the event tap callback
138    // to notify it of unusual conditions that disable the event tap.
139    TapDisabledByTimeout = 0xFFFFFFFE,
140    TapDisabledByUserInput = 0xFFFFFFFF,
141}
142
143/// Constants used as keys to access specialized fields in low-level events.
144///
145/// [Ref](https://developer.apple.com/documentation/coregraphics/cgeventfield)
146pub struct EventField;
147impl EventField {
148    /// Key to access an integer field that contains the mouse button event
149    /// number. Matching mouse-down and mouse-up events will have the same
150    /// event number.
151    pub const MOUSE_EVENT_NUMBER: CGEventField = 0;
152
153    /// Key to access an integer field that contains the mouse button click
154    /// state. A click state of 1 represents a single click. A click state of
155    /// 2 represents a double-click. A click state of 3 represents a
156    /// triple-click.
157    pub const MOUSE_EVENT_CLICK_STATE: CGEventField = 1;
158
159    /// Key to access a double field that contains the mouse button pressure.
160    /// The pressure value may range from 0 to 1, with 0 representing the
161    /// mouse being up. This value is commonly set by tablet pens mimicking a
162    /// mouse.
163    pub const MOUSE_EVENT_PRESSURE: CGEventField = 2;
164
165    /// Key to access an integer field that contains the mouse button number.
166    pub const MOUSE_EVENT_BUTTON_NUMBER: CGEventField = 3;
167
168    /// Key to access an integer field that contains the horizontal mouse
169    /// delta since the last mouse movement event.
170    pub const MOUSE_EVENT_DELTA_X: CGEventField = 4;
171
172    /// Key to access an integer field that contains the vertical mouse delta
173    /// since the last mouse movement event.
174    pub const MOUSE_EVENT_DELTA_Y: CGEventField = 5;
175
176    /// Key to access an integer field. The value is non-zero if the event
177    /// should be ignored by the Inkwell subsystem.
178    pub const MOUSE_EVENT_INSTANT_MOUSER: CGEventField = 6;
179
180    /// Key to access an integer field that encodes the mouse event subtype as
181    /// a `kCFNumberIntType`.
182    pub const MOUSE_EVENT_SUB_TYPE: CGEventField = 7;
183
184    /// Key to access an integer field, non-zero when this is an autorepeat of
185    /// a key-down, and zero otherwise.
186    pub const KEYBOARD_EVENT_AUTOREPEAT: CGEventField = 8;
187
188    /// Key to access an integer field that contains the virtual keycode of the
189    /// key-down or key-up event.
190    pub const KEYBOARD_EVENT_KEYCODE: CGEventField = 9;
191
192    /// Key to access an integer field that contains the keyboard type
193    /// identifier.
194    pub const KEYBOARD_EVENT_KEYBOARD_TYPE: CGEventField = 10;
195
196    /// Key to access an integer field that contains scrolling data. This field
197    /// typically contains the change in vertical position since the last
198    /// scrolling event from a Mighty Mouse scroller or a single-wheel mouse
199    /// scroller.
200    pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_1: CGEventField = 11;
201
202    /// Key to access an integer field that contains scrolling data. This field
203    /// typically contains the change in horizontal position since the last
204    /// scrolling event from a Mighty Mouse scroller.
205    pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_2: CGEventField = 12;
206
207    /// Key to access a field that contains scrolling data. The scrolling data
208    /// represents a line-based or pixel-based change in vertical position
209    /// since the last scrolling event from a Mighty Mouse scroller or a
210    /// single-wheel mouse scroller. The scrolling data uses a fixed-point
211    /// 16.16 signed integer format. If this key is passed to
212    /// `CGEventGetDoubleValueField`, the fixed-point value is converted to a
213    /// double value.
214    pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_1: CGEventField = 93;
215
216    /// Key to access a field that contains scrolling data. The scrolling data
217    /// represents a line-based or pixel-based change in horizontal position
218    /// since the last scrolling event from a Mighty Mouse scroller. The
219    /// scrolling data uses a fixed-point 16.16 signed integer format. If this
220    /// key is passed to `CGEventGetDoubleValueField`, the fixed-point value is
221    /// converted to a double value.
222    pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_2: CGEventField = 94;
223
224    /// Key to access an integer field that contains pixel-based scrolling
225    /// data. The scrolling data represents the change in vertical position
226    /// since the last scrolling event from a Mighty Mouse scroller or a
227    /// single-wheel mouse scroller.
228    pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_1: CGEventField = 96;
229
230    /// Key to access an integer field that contains pixel-based scrolling
231    /// data. The scrolling data represents the change in horizontal position
232    /// since the last scrolling event from a Mighty Mouse scroller.
233    pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_2: CGEventField = 97;
234
235    /// Key to access an integer field that indicates whether the event should
236    /// be ignored by the Inkwell subsystem. If the value is non-zero, the
237    /// event should be ignored.
238    pub const SCROLL_WHEEL_EVENT_INSTANT_MOUSER: CGEventField = 14;
239
240    /// Key to access an integer field that contains the absolute X coordinate
241    /// in tablet space at full tablet resolution.
242    pub const TABLET_EVENT_POINT_X: CGEventField = 15;
243
244    /// Key to access an integer field that contains the absolute Y coordinate
245    /// in tablet space at full tablet resolution.
246    pub const TABLET_EVENT_POINT_Y: CGEventField = 16;
247
248    /// Key to access an integer field that contains the absolute Z coordinate
249    /// in tablet space at full tablet resolution.
250    pub const TABLET_EVENT_POINT_Z: CGEventField = 17;
251
252    /// Key to access an integer field that contains the tablet button state.
253    /// Bit 0 is the first button, and a set bit represents a closed or pressed
254    /// button. Up to 16 buttons are supported.
255    pub const TABLET_EVENT_POINT_BUTTONS: CGEventField = 18;
256
257    /// Key to access a double field that contains the tablet pen pressure. A
258    /// value of 0.0 represents no pressure, and 1.0 represents maximum
259    /// pressure.
260    pub const TABLET_EVENT_POINT_PRESSURE: CGEventField = 19;
261
262    /// Key to access a double field that contains the horizontal tablet pen
263    /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt.
264    pub const TABLET_EVENT_TILT_X: CGEventField = 20;
265
266    /// Key to access a double field that contains the vertical tablet pen
267    /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt.
268    pub const TABLET_EVENT_TILT_Y: CGEventField = 21;
269
270    /// Key to access a double field that contains the tablet pen rotation.
271    pub const TABLET_EVENT_ROTATION: CGEventField = 22;
272
273    /// Key to access a double field that contains the tangential pressure on
274    /// the device. A value of 0.0 represents no pressure, and 1.0 represents
275    /// maximum pressure.
276    pub const TABLET_EVENT_TANGENTIAL_PRESSURE: CGEventField = 23;
277
278    /// Key to access an integer field that contains the system-assigned unique
279    /// device ID.
280    pub const TABLET_EVENT_DEVICE_ID: CGEventField = 24;
281
282    /// Key to access an integer field that contains a vendor-specified value.
283    pub const TABLET_EVENT_VENDOR_1: CGEventField = 25;
284
285    /// Key to access an integer field that contains a vendor-specified value.
286    pub const TABLET_EVENT_VENDOR_2: CGEventField = 26;
287
288    /// Key to access an integer field that contains a vendor-specified value.
289    pub const TABLET_EVENT_VENDOR_3: CGEventField = 27;
290
291    /// Key to access an integer field that contains the vendor-defined ID,
292    /// typically the USB vendor ID.
293    pub const TABLET_PROXIMITY_EVENT_VENDOR_ID: CGEventField = 28;
294
295    /// Key to access an integer field that contains the vendor-defined tablet
296    /// ID, typically the USB product ID.
297    pub const TABLET_PROXIMITY_EVENT_TABLET_ID: CGEventField = 29;
298
299    /// Key to access an integer field that contains the vendor-defined ID of
300    /// the pointing device.
301    pub const TABLET_PROXIMITY_EVENT_POINTER_ID: CGEventField = 30;
302
303    /// Key to access an integer field that contains the system-assigned
304    /// device ID.
305    pub const TABLET_PROXIMITY_EVENT_DEVICE_ID: CGEventField = 31;
306
307    /// Key to access an integer field that contains the system-assigned
308    /// unique tablet ID.
309    pub const TABLET_PROXIMITY_EVENT_SYSTEM_TABLET_ID: CGEventField = 32;
310
311    /// Key to access an integer field that contains the vendor-assigned
312    /// pointer type.
313    pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_TYPE: CGEventField = 33;
314
315    /// Key to access an integer field that contains the vendor-defined
316    /// pointer serial number.
317    pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_SERIAL_NUMBER: CGEventField = 34;
318
319    /// Key to access an integer field that contains the vendor-defined unique
320    /// ID.
321    pub const TABLET_PROXIMITY_EVENT_VENDOR_UNIQUE_ID: CGEventField = 35;
322
323    /// Key to access an integer field that contains the device capabilities
324    /// mask.
325    pub const TABLET_PROXIMITY_EVENT_CAPABILITY_MASK: CGEventField = 36;
326
327    /// Key to access an integer field that contains the pointer type.
328    pub const TABLET_PROXIMITY_EVENT_POINTER_TYPE: CGEventField = 37;
329
330    /// Key to access an integer field that indicates whether the pen is in
331    /// proximity to the tablet. The value is non-zero if the pen is in
332    /// proximity to the tablet and zero when leaving the tablet.
333    pub const TABLET_PROXIMITY_EVENT_ENTER_PROXIMITY: CGEventField = 38;
334
335    /// Key to access a field that contains the event target process serial
336    /// number. The value is a 64-bit value.
337    pub const EVENT_TARGET_PROCESS_SERIAL_NUMBER: CGEventField = 39;
338
339    /// Key to access a field that contains the event target Unix process ID.
340    pub const EVENT_TARGET_UNIX_PROCESS_ID: CGEventField = 40;
341
342    /// Key to access a field that contains the event source Unix process ID.
343    pub const EVENT_SOURCE_UNIX_PROCESS_ID: CGEventField = 41;
344
345    /// Key to access a field that contains the event source user-supplied
346    /// data, up to 64 bits.
347    pub const EVENT_SOURCE_USER_DATA: CGEventField = 42;
348
349    /// Key to access a field that contains the event source Unix effective UID.
350    pub const EVENT_SOURCE_USER_ID: CGEventField = 43;
351
352    /// Key to access a field that contains the event source Unix effective
353    /// GID.
354    pub const EVENT_SOURCE_GROUP_ID: CGEventField = 44;
355
356    /// Key to access a field that contains the event source state ID used to
357    /// create this event.
358    pub const EVENT_SOURCE_STATE_ID: CGEventField = 45;
359
360    /// Key to access an integer field that indicates whether a scrolling event
361    /// contains continuous, pixel-based scrolling data. The value is non-zero
362    /// when the scrolling data is pixel-based and zero when the scrolling data
363    /// is line-based.
364    pub const SCROLL_WHEEL_EVENT_IS_CONTINUOUS: CGEventField = 88;
365
366    /// Added in 10.5; made public in 10.7.
367    pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER: CGEventField = 91;
368    pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER_THAT_CAN_HANDLE_THIS_EVENT: CGEventField = 92;
369}
370
371// Constants that specify buttons on a one, two, or three-button mouse.
372#[repr(C)]
373#[derive(Clone, Copy, Debug)]
374pub enum CGMouseButton {
375    Left,
376    Right,
377    Center,
378}
379
380/// Possible tapping points for events.
381#[repr(C)]
382#[derive(Clone, Copy, Debug)]
383pub enum CGEventTapLocation {
384    HID,
385    Session,
386    AnnotatedSession,
387}
388
389// The next three enums are taken from:
390// [Ref](https://github.com/phracker/MacOSX-SDKs/blob/ef9fe35d5691b6dd383c8c46d867a499817a01b6/MacOSX10.15.sdk/System/Library/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGEventTypes.h)
391/* Constants that specify where a new event tap is inserted into the list of
392active event taps. */
393#[repr(u32)]
394#[derive(Clone, Copy, Debug)]
395pub enum CGEventTapPlacement {
396    HeadInsertEventTap = 0,
397    TailAppendEventTap,
398}
399
400/* Constants that specify whether a new event tap is an active filter or a
401passive listener. */
402#[repr(u32)]
403#[derive(Clone, Copy, Debug)]
404pub enum CGEventTapOptions {
405    Default = 0x00000000,
406    ListenOnly = 0x00000001,
407}
408
409pub type CGEventMask = u64;
410/* Generate an event mask for a single type of event. */
411macro_rules! CGEventMaskBit {
412    ($eventType:expr) => {
413        1 << $eventType as CGEventMask
414    };
415}
416
417pub type CGEventTapProxy = *const c_void;
418pub type CGEventTapCallBackFn<'tap_life> =
419    Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>;
420type CGEventTapCallBackInternal = unsafe extern "C" fn(
421    proxy: CGEventTapProxy,
422    etype: CGEventType,
423    event: crate::sys::CGEventRef,
424    user_info: *const c_void,
425) -> crate::sys::CGEventRef;
426
427unsafe extern "C" fn cg_event_tap_callback_internal(
428    _proxy: CGEventTapProxy,
429    _etype: CGEventType,
430    _event: crate::sys::CGEventRef,
431    _user_info: *const c_void,
432) -> crate::sys::CGEventRef {
433    let callback = _user_info as *mut CGEventTapCallBackFn;
434    let event = CGEvent::from_ptr(_event);
435    let new_event = (*callback)(_proxy, _etype, &event);
436    let event = match new_event {
437        Some(new_event) => new_event,
438        None => event,
439    };
440    ManuallyDrop::new(event).as_ptr()
441}
442
443/// ```no_run
444///extern crate core_foundation;
445///use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
446///use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType};
447///let current = CFRunLoop::get_current();
448///match CGEventTap::new(
449///     CGEventTapLocation::HID,
450///     CGEventTapPlacement::HeadInsertEventTap,
451///     CGEventTapOptions::Default,
452///     vec![CGEventType::MouseMoved],
453///     |_a, _b, d| {
454///         println!("{:?}", d.location());
455///         None
456///     },
457/// ) {
458///     Ok(tap) => unsafe {
459///         let loop_source = tap
460///             .mach_port
461///             .create_runloop_source(0)
462///             .expect("Somethings is bad ");
463///         current.add_source(&loop_source, kCFRunLoopCommonModes);
464///         tap.enable();
465///         CFRunLoop::run_current();
466///     },
467///     Err(_) => (assert!(false)),
468/// }
469/// ```
470pub struct CGEventTap<'tap_life> {
471    pub mach_port: CFMachPort,
472    pub callback_ref:
473        Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>,
474}
475
476impl<'tap_life> CGEventTap<'tap_life> {
477    pub fn new<F: Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>(
478        tap: CGEventTapLocation,
479        place: CGEventTapPlacement,
480        options: CGEventTapOptions,
481        events_of_interest: std::vec::Vec<CGEventType>,
482        callback: F,
483    ) -> Result<CGEventTap<'tap_life>, ()> {
484        let event_mask: CGEventMask = events_of_interest
485            .iter()
486            .fold(CGEventType::Null as CGEventMask, |mask, &etype| {
487                mask | CGEventMaskBit!(etype)
488            });
489        let cb = Box::new(Box::new(callback) as CGEventTapCallBackFn);
490        let cbr = Box::into_raw(cb);
491        unsafe {
492            let event_tap_ref = CGEventTapCreate(
493                tap,
494                place,
495                options,
496                event_mask,
497                cg_event_tap_callback_internal,
498                cbr as *const c_void,
499            );
500
501            if !event_tap_ref.is_null() {
502                Ok(Self {
503                    mach_port: (CFMachPort::wrap_under_create_rule(event_tap_ref)),
504                    callback_ref: Box::from_raw(cbr),
505                })
506            } else {
507                let _ = Box::from_raw(cbr);
508                Err(())
509            }
510        }
511    }
512
513    pub fn enable(&self) {
514        unsafe { CGEventTapEnable(self.mach_port.as_concrete_TypeRef(), true) }
515    }
516}
517
518foreign_type! {
519    #[doc(hidden)]
520    pub unsafe type CGEvent {
521        type CType = crate::sys::CGEvent;
522        fn drop = |p| CFRelease(p as *mut _);
523        fn clone = |p| CFRetain(p as *const _) as *mut _;
524    }
525}
526
527impl CGEvent {
528    pub fn type_id() -> CFTypeID {
529        unsafe { CGEventGetTypeID() }
530    }
531
532    pub fn new(source: CGEventSource) -> Result<CGEvent, ()> {
533        unsafe {
534            let event_ref = CGEventCreate(source.as_ptr());
535            if !event_ref.is_null() {
536                Ok(Self::from_ptr(event_ref))
537            } else {
538                Err(())
539            }
540        }
541    }
542
543    pub fn new_keyboard_event(
544        source: CGEventSource,
545        keycode: CGKeyCode,
546        keydown: bool,
547    ) -> Result<CGEvent, ()> {
548        unsafe {
549            let event_ref = CGEventCreateKeyboardEvent(source.as_ptr(), keycode, keydown);
550            if !event_ref.is_null() {
551                Ok(Self::from_ptr(event_ref))
552            } else {
553                Err(())
554            }
555        }
556    }
557
558    pub fn new_mouse_event(
559        source: CGEventSource,
560        mouse_type: CGEventType,
561        mouse_cursor_position: CGPoint,
562        mouse_button: CGMouseButton,
563    ) -> Result<CGEvent, ()> {
564        unsafe {
565            let event_ref = CGEventCreateMouseEvent(
566                source.as_ptr(),
567                mouse_type,
568                mouse_cursor_position,
569                mouse_button,
570            );
571            if !event_ref.is_null() {
572                Ok(Self::from_ptr(event_ref))
573            } else {
574                Err(())
575            }
576        }
577    }
578
579    #[cfg(feature = "highsierra")]
580    pub fn new_scroll_event(
581        source: CGEventSource,
582        units: CGScrollEventUnit,
583        wheel_count: u32,
584        wheel1: i32,
585        wheel2: i32,
586        wheel3: i32,
587    ) -> Result<CGEvent, ()> {
588        unsafe {
589            let event_ref = CGEventCreateScrollWheelEvent2(
590                source.as_ptr(),
591                units,
592                wheel_count,
593                wheel1,
594                wheel2,
595                wheel3,
596            );
597            if !event_ref.is_null() {
598                Ok(Self::from_ptr(event_ref))
599            } else {
600                Err(())
601            }
602        }
603    }
604
605    pub fn post(&self, tap_location: CGEventTapLocation) {
606        unsafe {
607            CGEventPost(tap_location, self.as_ptr());
608        }
609    }
610
611    pub fn post_from_tap(&self, tap_proxy: CGEventTapProxy) {
612        unsafe {
613            CGEventTapPostEvent(tap_proxy, self.as_ptr());
614        }
615    }
616
617    pub fn location(&self) -> CGPoint {
618        unsafe { CGEventGetLocation(self.as_ptr()) }
619    }
620
621    #[cfg(feature = "elcapitan")]
622    pub fn post_to_pid(&self, pid: libc::pid_t) {
623        unsafe {
624            CGEventPostToPid(pid, self.as_ptr());
625        }
626    }
627
628    pub fn set_flags(&self, flags: CGEventFlags) {
629        unsafe {
630            CGEventSetFlags(self.as_ptr(), flags);
631        }
632    }
633
634    pub fn get_flags(&self) -> CGEventFlags {
635        unsafe { CGEventGetFlags(self.as_ptr()) }
636    }
637
638    pub fn set_type(&self, event_type: CGEventType) {
639        unsafe {
640            CGEventSetType(self.as_ptr(), event_type);
641        }
642    }
643
644    pub fn get_type(&self) -> CGEventType {
645        unsafe { CGEventGetType(self.as_ptr()) }
646    }
647
648    pub fn set_string_from_utf16_unchecked(&self, buf: &[u16]) {
649        let buflen = buf.len() as libc::c_ulong;
650        unsafe {
651            CGEventKeyboardSetUnicodeString(self.as_ptr(), buflen, buf.as_ptr());
652        }
653    }
654
655    pub fn set_string(&self, string: &str) {
656        let buf: Vec<u16> = string.encode_utf16().collect();
657        self.set_string_from_utf16_unchecked(&buf);
658    }
659
660    pub fn get_integer_value_field(&self, field: CGEventField) -> i64 {
661        unsafe { CGEventGetIntegerValueField(self.as_ptr(), field) }
662    }
663
664    pub fn set_integer_value_field(&self, field: CGEventField, value: i64) {
665        unsafe { CGEventSetIntegerValueField(self.as_ptr(), field, value) }
666    }
667
668    pub fn get_double_value_field(&self, field: CGEventField) -> f64 {
669        unsafe { CGEventGetDoubleValueField(self.as_ptr(), field) }
670    }
671
672    pub fn set_double_value_field(&self, field: CGEventField, value: f64) {
673        unsafe { CGEventSetDoubleValueField(self.as_ptr(), field, value) }
674    }
675}
676
677#[cfg_attr(feature = "link", link(name = "CoreGraphics", kind = "framework"))]
678extern "C" {
679    /// Return the type identifier for the opaque type `CGEventRef'.
680    fn CGEventGetTypeID() -> CFTypeID;
681
682    /// Return a new event using the event source `source'. If `source' is NULL,
683    /// the default source is used.
684    fn CGEventCreate(source: crate::sys::CGEventSourceRef) -> crate::sys::CGEventRef;
685
686    /// Return a new keyboard event.
687    ///
688    /// The event source may be taken from another event, or may be NULL. Based
689    /// on the virtual key code values entered, the appropriate key down, key up,
690    /// or flags changed events are generated.
691    ///
692    /// All keystrokes needed to generate a character must be entered, including
693    /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z',
694    /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT
695    /// and 'z' key must be released:
696    fn CGEventCreateKeyboardEvent(
697        source: crate::sys::CGEventSourceRef,
698        keycode: CGKeyCode,
699        keydown: bool,
700    ) -> crate::sys::CGEventRef;
701
702    /// Return a new mouse event.
703    ///
704    /// The event source may be taken from another event, or may be NULL.
705    /// `mouseType' should be one of the mouse event types. `mouseCursorPosition'
706    /// should be the position of the mouse cursor in global coordinates.
707    /// `mouseButton' should be the button that's changing state; `mouseButton'
708    /// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown',
709    /// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'.
710    ///
711    /// The current implementation of the event system supports a maximum of
712    /// thirty-two buttons. Mouse button 0 is the primary button on the mouse.
713    /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is
714    /// the center button, and the remaining buttons are in USB device order.
715    fn CGEventCreateMouseEvent(
716        source: crate::sys::CGEventSourceRef,
717        mouseType: CGEventType,
718        mouseCursorPosition: CGPoint,
719        mouseButton: CGMouseButton,
720    ) -> crate::sys::CGEventRef;
721
722    /// A non-variadic variant version of CGEventCreateScrollWheelEvent.
723    ///
724    /// Returns a new Quartz scrolling event.
725    ///
726    /// This function allows you to create a scrolling event and customize the
727    /// event before posting it to the event system.
728    #[cfg(feature = "highsierra")]
729    fn CGEventCreateScrollWheelEvent2(
730        source: crate::sys::CGEventSourceRef,
731        units: CGScrollEventUnit,
732        wheelCount: u32,
733        wheel1: i32,
734        wheel2: i32,
735        wheel3: i32,
736    ) -> crate::sys::CGEventRef;
737
738    /// Post an event into the event stream at a specified location.
739    ///
740    /// This function posts the specified event immediately before any event taps
741    /// instantiated for that location, and the event passes through any such
742    /// taps.
743    fn CGEventPost(tapLocation: CGEventTapLocation, event: crate::sys::CGEventRef);
744
745    fn CGEventTapPostEvent(tapProxy: CGEventTapProxy, event: crate::sys::CGEventRef);
746
747    #[cfg(feature = "elcapitan")]
748    /// Post an event to a specified process ID
749    fn CGEventPostToPid(pid: libc::pid_t, event: crate::sys::CGEventRef);
750
751    /// Set the event flags of an event.
752    fn CGEventSetFlags(event: crate::sys::CGEventRef, flags: CGEventFlags);
753
754    /// Return the event flags of an event.
755    fn CGEventGetFlags(event: crate::sys::CGEventRef) -> CGEventFlags;
756
757    /// Return the location of an event in global display coordinates.
758    /// CGPointZero is returned if event is not a valid crate::sys::CGEventRef.
759    fn CGEventGetLocation(event: crate::sys::CGEventRef) -> CGPoint;
760
761    /// Set the event type of an event.
762    fn CGEventSetType(event: crate::sys::CGEventRef, eventType: CGEventType);
763
764    /// Return the event type of an event (left mouse down, for example).
765    fn CGEventGetType(event: crate::sys::CGEventRef) -> CGEventType;
766
767    /// Set the Unicode string associated with a keyboard event.
768    ///
769    /// By default, the system translates the virtual key code in a keyboard
770    /// event into a Unicode string based on the keyboard ID in the event
771    /// source.  This function allows you to manually override this string.
772    /// Note that application frameworks may ignore the Unicode string in a
773    /// keyboard event and do their own translation based on the virtual
774    /// keycode and perceived event state.
775    fn CGEventKeyboardSetUnicodeString(
776        event: crate::sys::CGEventRef,
777        length: libc::c_ulong,
778        string: *const u16,
779    );
780
781    /// Return the integer value of a field in an event.
782    fn CGEventGetIntegerValueField(event: crate::sys::CGEventRef, field: CGEventField) -> i64;
783
784    /// Set the integer value of a field in an event.
785    ///
786    /// Before calling this function, the event type must be set using a typed
787    /// event creation function such as `CGEventCreateMouseEvent', or by
788    /// calling `CGEventSetType'.
789    ///
790    /// If you are creating a mouse event generated by a tablet, call this
791    /// function and specify the field `kCGMouseEventSubtype' with a value of
792    /// `kCGEventMouseSubtypeTabletPoint' or
793    /// `kCGEventMouseSubtypeTabletProximity' before setting other parameters.
794    fn CGEventSetIntegerValueField(event: crate::sys::CGEventRef, field: CGEventField, value: i64);
795
796    /// Return the floating-point value of a field in an event.
797    ///
798    /// In cases where the field value is represented within the event by a fixed
799    /// point number or an integer, the result is scaled to the appropriate range
800    /// as part of creating the floating-point representation.
801    fn CGEventGetDoubleValueField(event: crate::sys::CGEventRef, field: CGEventField) -> f64;
802
803    /// Set the floating-point value of a field in an event.
804    ///
805    /// Before calling this function, the event type must be set using a typed
806    /// event creation function such as `CGEventCreateMouseEvent', or by calling
807    /// `CGEventSetType'.
808    ///
809    /// In cases where the field’s value is represented within the event by a
810    /// fixed point number or integer, the value parameter is scaled as needed
811    /// and converted to the appropriate type.
812    fn CGEventSetDoubleValueField(event: crate::sys::CGEventRef, field: CGEventField, value: f64);
813
814    // ::sys::CGEventTapRef is actually an CFMachPortRef
815    fn CGEventTapCreate(
816        tap: CGEventTapLocation,
817        place: CGEventTapPlacement,
818        options: CGEventTapOptions,
819        eventsOfInterest: CGEventMask,
820        callback: CGEventTapCallBackInternal,
821        userInfo: *const c_void,
822    ) -> CFMachPortRef;
823
824    fn CGEventTapEnable(tap: CFMachPortRef, enable: bool);
825
826}