Auto merge of #59 - WilsonGiese:master, r=jdm
Add CGEvent and CGEventSource Added CGEvent and CGEventSource to simulate keyboard events. FFI corresponds mostly to their respective headers in CoreGraphics except for some data types which are defined in CGEventTypes.h. Uses: CoreGraphics.framework/Headers/CGEvent.h CoreGraphics.framework/Headers/CGEventSource.h CoreGraphics.framework/Headers/CGEventTypes.h <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/core-graphics-rs/59) <!-- Reviewable:end -->
This commit is contained in:
+258
@@ -0,0 +1,258 @@
|
||||
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
|
||||
use geometry::CGPoint;
|
||||
use event_source::{CGEventSource,CGEventSourceRef};
|
||||
|
||||
use libc;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
pub type CGKeyCode = libc::uint16_t;
|
||||
|
||||
/// Flags for events
|
||||
///
|
||||
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CGEventFlags {
|
||||
// Device-independent modifier key bits.
|
||||
AlphaShift = 0x00010000,
|
||||
Shift = 0x00020000,
|
||||
Control = 0x00040000,
|
||||
Alternate = 0x00080000,
|
||||
Command = 0x00100000,
|
||||
|
||||
// Special key identifiers.
|
||||
Help = 0x00400000,
|
||||
SecondaryFn = 0x00800000,
|
||||
|
||||
// Identifies key events from numeric keypad area on extended keyboards.
|
||||
NumericPad = 0x00200000,
|
||||
|
||||
// Indicates if mouse/pen movement events are not being coalesced
|
||||
NonCoalesced = 0x00000100,
|
||||
}
|
||||
|
||||
/// Constants that specify the different types of input events.
|
||||
///
|
||||
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CGEventType {
|
||||
Null = 1 << 0,
|
||||
|
||||
// Mouse events.
|
||||
LeftMouseDown = 1 << 1,
|
||||
LeftMouseUp = 1 << 2,
|
||||
RightMouseDown = 1 << 3,
|
||||
RightMouseUp = 1 << 4,
|
||||
MouseMoved = 1 << 5,
|
||||
LeftMouseDragged = 1 << 6,
|
||||
RightMouseDragged = 1 << 7,
|
||||
|
||||
// Keyboard events.
|
||||
KeyDown = 1 << 10,
|
||||
KeyUp = 1 << 11,
|
||||
FlagsChanged = 1 << 12,
|
||||
|
||||
// Specialized control devices.
|
||||
ScrollWheel = 1 << 22,
|
||||
TabletPointer = 1 << 23,
|
||||
TabletProximity = 1 << 24,
|
||||
OtherMouseDown = 1 << 25,
|
||||
OtherMouseUp = 1 << 26,
|
||||
OtherMouseDragged = 1 << 27,
|
||||
|
||||
// Out of band event types. These are delivered to the event tap callback
|
||||
// to notify it of unusual conditions that disable the event tap.
|
||||
TapDisabledByTimeout = 0xFFFFFFFE,
|
||||
TapDisabledByUserInput = 0xFFFFFFFF,
|
||||
}
|
||||
|
||||
// Constants that specify buttons on a one, two, or three-button mouse.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CGMouseButton {
|
||||
Left,
|
||||
Right,
|
||||
Center,
|
||||
}
|
||||
|
||||
/// Possible tapping points for events.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CGEventTapLocation {
|
||||
HID,
|
||||
Session,
|
||||
AnnotatedSession,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct __CGEvent;
|
||||
|
||||
pub type CGEventRef = *const __CGEvent;
|
||||
|
||||
pub struct CGEvent {
|
||||
obj: CGEventRef,
|
||||
}
|
||||
|
||||
impl Clone for CGEvent {
|
||||
#[inline]
|
||||
fn clone(&self) -> CGEvent {
|
||||
unsafe {
|
||||
TCFType::wrap_under_get_rule(self.obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CGEvent {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let ptr = self.as_CFTypeRef();
|
||||
assert!(ptr != ptr::null());
|
||||
CFRelease(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TCFType<CGEventRef> for CGEvent {
|
||||
#[inline]
|
||||
fn as_concrete_TypeRef(&self) -> CGEventRef {
|
||||
self.obj
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn wrap_under_get_rule(reference: CGEventRef) -> CGEvent {
|
||||
let reference: CGEventRef = mem::transmute(CFRetain(mem::transmute(reference)));
|
||||
TCFType::wrap_under_create_rule(reference)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_CFTypeRef(&self) -> CFTypeRef {
|
||||
unsafe {
|
||||
mem::transmute(self.as_concrete_TypeRef())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn wrap_under_create_rule(obj: CGEventRef) -> CGEvent {
|
||||
CGEvent {
|
||||
obj: obj,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_id() -> CFTypeID {
|
||||
unsafe {
|
||||
CGEventGetTypeID()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CGEvent {
|
||||
pub fn new_keyboard_event(
|
||||
source: CGEventSource,
|
||||
keycode: CGKeyCode,
|
||||
keydown: bool
|
||||
) -> Result<CGEvent, ()> {
|
||||
unsafe {
|
||||
let event_ref = CGEventCreateKeyboardEvent(source.as_concrete_TypeRef(), keycode, keydown);
|
||||
if event_ref != ptr::null() {
|
||||
Ok(TCFType::wrap_under_create_rule(event_ref))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_mouse_event(
|
||||
source: CGEventSource,
|
||||
mouse_type: CGEventType,
|
||||
mouse_cursor_position: CGPoint,
|
||||
mouse_button: CGMouseButton
|
||||
) -> Result<CGEvent, ()> {
|
||||
unsafe {
|
||||
let event_ref = CGEventCreateMouseEvent(source.as_concrete_TypeRef(), mouse_type,
|
||||
mouse_cursor_position, mouse_button);
|
||||
if event_ref != ptr::null() {
|
||||
Ok(TCFType::wrap_under_create_rule(event_ref))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn post(&self, tap_location: CGEventTapLocation) {
|
||||
unsafe {
|
||||
CGEventPost(tap_location, self.as_concrete_TypeRef());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn post_to_pid(&self, pid: libc::pid_t) {
|
||||
unsafe {
|
||||
CGEventPostToPid(pid, self.as_concrete_TypeRef());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_flags(&self, flags: CGEventFlags) {
|
||||
unsafe {
|
||||
CGEventSetFlags(self.as_concrete_TypeRef(), flags);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> CGEventFlags {
|
||||
unsafe {
|
||||
CGEventGetFlags(self.as_concrete_TypeRef())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[link(name = "ApplicationServices", kind = "framework")]
|
||||
extern {
|
||||
/// Return the type identifier for the opaque type `CGEventRef'.
|
||||
fn CGEventGetTypeID() -> CFTypeID;
|
||||
|
||||
/// Return a new keyboard event.
|
||||
///
|
||||
/// The event source may be taken from another event, or may be NULL. Based
|
||||
/// on the virtual key code values entered, the appropriate key down, key up,
|
||||
/// or flags changed events are generated.
|
||||
///
|
||||
/// All keystrokes needed to generate a character must be entered, including
|
||||
/// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z',
|
||||
/// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT
|
||||
/// and 'z' key must be released:
|
||||
fn CGEventCreateKeyboardEvent(source: CGEventSourceRef, keycode: CGKeyCode,
|
||||
keydown: bool) -> CGEventRef;
|
||||
|
||||
/// Return a new mouse event.
|
||||
///
|
||||
/// The event source may be taken from another event, or may be NULL.
|
||||
/// `mouseType' should be one of the mouse event types. `mouseCursorPosition'
|
||||
/// should be the position of the mouse cursor in global coordinates.
|
||||
/// `mouseButton' should be the button that's changing state; `mouseButton'
|
||||
/// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown',
|
||||
/// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'.
|
||||
///
|
||||
/// The current implemementation of the event system supports a maximum of
|
||||
/// thirty-two buttons. Mouse button 0 is the primary button on the mouse.
|
||||
/// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is
|
||||
/// the center button, and the remaining buttons are in USB device order.
|
||||
fn CGEventCreateMouseEvent(source: CGEventSourceRef, mouseType: CGEventType,
|
||||
mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> CGEventRef;
|
||||
|
||||
/// Post an event into the event stream at a specified location.
|
||||
///
|
||||
/// This function posts the specified event immediately before any event taps
|
||||
/// instantiated for that location, and the event passes through any such
|
||||
/// taps.
|
||||
fn CGEventPost(tapLocation: CGEventTapLocation, event: CGEventRef);
|
||||
|
||||
/// Post an event to a specified process ID
|
||||
fn CGEventPostToPid(pid: libc::pid_t, event: CGEventRef);
|
||||
|
||||
/// Set the event flags of an event.
|
||||
fn CGEventSetFlags(event: CGEventRef, flags: CGEventFlags);
|
||||
|
||||
/// Return the event flags of an event.
|
||||
fn CGEventGetFlags(event: CGEventRef) -> CGEventFlags;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
|
||||
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
/// Possible source states of an event source.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CGEventSourceStateID {
|
||||
Private = -1,
|
||||
CombinedSessionState = 0,
|
||||
HIDSystemState = 1,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct __CGEventSource;
|
||||
|
||||
pub type CGEventSourceRef = *const __CGEventSource;
|
||||
|
||||
pub struct CGEventSource {
|
||||
obj: CGEventSourceRef,
|
||||
}
|
||||
|
||||
impl Clone for CGEventSource {
|
||||
#[inline]
|
||||
fn clone(&self) -> CGEventSource {
|
||||
unsafe {
|
||||
TCFType::wrap_under_get_rule(self.obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CGEventSource {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let ptr = self.as_CFTypeRef();
|
||||
assert!(ptr != ptr::null());
|
||||
CFRelease(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TCFType<CGEventSourceRef> for CGEventSource {
|
||||
#[inline]
|
||||
fn as_concrete_TypeRef(&self) -> CGEventSourceRef {
|
||||
self.obj
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn wrap_under_get_rule(reference: CGEventSourceRef) -> CGEventSource {
|
||||
let reference: CGEventSourceRef = mem::transmute(CFRetain(mem::transmute(reference)));
|
||||
TCFType::wrap_under_create_rule(reference)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_CFTypeRef(&self) -> CFTypeRef {
|
||||
unsafe {
|
||||
mem::transmute(self.as_concrete_TypeRef())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn wrap_under_create_rule(obj: CGEventSourceRef) -> CGEventSource {
|
||||
CGEventSource {
|
||||
obj: obj,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_id() -> CFTypeID {
|
||||
unsafe {
|
||||
CGEventSourceGetTypeID()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CGEventSource {
|
||||
pub fn new(state_id: CGEventSourceStateID) -> Result<CGEventSource, ()> {
|
||||
unsafe {
|
||||
let event_source_ref = CGEventSourceCreate(state_id);
|
||||
if event_source_ref != ptr::null() {
|
||||
Ok(TCFType::wrap_under_create_rule(event_source_ref))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[link(name = "ApplicationServices", kind = "framework")]
|
||||
extern {
|
||||
/// Return the type identifier for the opaque type `CGEventSourceRef'.
|
||||
fn CGEventSourceGetTypeID() -> CFTypeID;
|
||||
|
||||
/// Return a Quartz event source created with a specified source state.
|
||||
fn CGEventSourceCreate(stateID: CGEventSourceStateID) -> CGEventSourceRef;
|
||||
}
|
||||
+2
-1
@@ -16,7 +16,8 @@ pub mod color_space;
|
||||
pub mod context;
|
||||
pub mod data_provider;
|
||||
pub mod display;
|
||||
pub mod event;
|
||||
pub mod event_source;
|
||||
pub mod font;
|
||||
pub mod geometry;
|
||||
pub mod private;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user