Skip to content

Commit 3d50c8e

Browse files
author
bors-servo
authored
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 -->
2 parents 224361a + b88ff77 commit 3d50c8e

File tree

3 files changed

+357
-1
lines changed

3 files changed

+357
-1
lines changed

src/event.rs

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
2+
use geometry::CGPoint;
3+
use event_source::{CGEventSource,CGEventSourceRef};
4+
5+
use libc;
6+
use std::mem;
7+
use std::ptr;
8+
9+
pub type CGKeyCode = libc::uint16_t;
10+
11+
/// Flags for events
12+
///
13+
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
14+
#[repr(C)]
15+
#[derive(Clone, Copy, Debug)]
16+
pub enum CGEventFlags {
17+
// Device-independent modifier key bits.
18+
AlphaShift = 0x00010000,
19+
Shift = 0x00020000,
20+
Control = 0x00040000,
21+
Alternate = 0x00080000,
22+
Command = 0x00100000,
23+
24+
// Special key identifiers.
25+
Help = 0x00400000,
26+
SecondaryFn = 0x00800000,
27+
28+
// Identifies key events from numeric keypad area on extended keyboards.
29+
NumericPad = 0x00200000,
30+
31+
// Indicates if mouse/pen movement events are not being coalesced
32+
NonCoalesced = 0x00000100,
33+
}
34+
35+
/// Constants that specify the different types of input events.
36+
///
37+
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
38+
#[repr(C)]
39+
#[derive(Clone, Copy, Debug)]
40+
pub enum CGEventType {
41+
Null = 1 << 0,
42+
43+
// Mouse events.
44+
LeftMouseDown = 1 << 1,
45+
LeftMouseUp = 1 << 2,
46+
RightMouseDown = 1 << 3,
47+
RightMouseUp = 1 << 4,
48+
MouseMoved = 1 << 5,
49+
LeftMouseDragged = 1 << 6,
50+
RightMouseDragged = 1 << 7,
51+
52+
// Keyboard events.
53+
KeyDown = 1 << 10,
54+
KeyUp = 1 << 11,
55+
FlagsChanged = 1 << 12,
56+
57+
// Specialized control devices.
58+
ScrollWheel = 1 << 22,
59+
TabletPointer = 1 << 23,
60+
TabletProximity = 1 << 24,
61+
OtherMouseDown = 1 << 25,
62+
OtherMouseUp = 1 << 26,
63+
OtherMouseDragged = 1 << 27,
64+
65+
// Out of band event types. These are delivered to the event tap callback
66+
// to notify it of unusual conditions that disable the event tap.
67+
TapDisabledByTimeout = 0xFFFFFFFE,
68+
TapDisabledByUserInput = 0xFFFFFFFF,
69+
}
70+
71+
// Constants that specify buttons on a one, two, or three-button mouse.
72+
#[repr(C)]
73+
#[derive(Clone, Copy, Debug)]
74+
pub enum CGMouseButton {
75+
Left,
76+
Right,
77+
Center,
78+
}
79+
80+
/// Possible tapping points for events.
81+
#[repr(C)]
82+
#[derive(Clone, Copy, Debug)]
83+
pub enum CGEventTapLocation {
84+
HID,
85+
Session,
86+
AnnotatedSession,
87+
}
88+
89+
#[repr(C)]
90+
pub struct __CGEvent;
91+
92+
pub type CGEventRef = *const __CGEvent;
93+
94+
pub struct CGEvent {
95+
obj: CGEventRef,
96+
}
97+
98+
impl Clone for CGEvent {
99+
#[inline]
100+
fn clone(&self) -> CGEvent {
101+
unsafe {
102+
TCFType::wrap_under_get_rule(self.obj)
103+
}
104+
}
105+
}
106+
107+
impl Drop for CGEvent {
108+
fn drop(&mut self) {
109+
unsafe {
110+
let ptr = self.as_CFTypeRef();
111+
assert!(ptr != ptr::null());
112+
CFRelease(ptr);
113+
}
114+
}
115+
}
116+
117+
impl TCFType<CGEventRef> for CGEvent {
118+
#[inline]
119+
fn as_concrete_TypeRef(&self) -> CGEventRef {
120+
self.obj
121+
}
122+
123+
#[inline]
124+
unsafe fn wrap_under_get_rule(reference: CGEventRef) -> CGEvent {
125+
let reference: CGEventRef = mem::transmute(CFRetain(mem::transmute(reference)));
126+
TCFType::wrap_under_create_rule(reference)
127+
}
128+
129+
#[inline]
130+
fn as_CFTypeRef(&self) -> CFTypeRef {
131+
unsafe {
132+
mem::transmute(self.as_concrete_TypeRef())
133+
}
134+
}
135+
136+
#[inline]
137+
unsafe fn wrap_under_create_rule(obj: CGEventRef) -> CGEvent {
138+
CGEvent {
139+
obj: obj,
140+
}
141+
}
142+
143+
#[inline]
144+
fn type_id() -> CFTypeID {
145+
unsafe {
146+
CGEventGetTypeID()
147+
}
148+
}
149+
}
150+
151+
impl CGEvent {
152+
pub fn new_keyboard_event(
153+
source: CGEventSource,
154+
keycode: CGKeyCode,
155+
keydown: bool
156+
) -> Result<CGEvent, ()> {
157+
unsafe {
158+
let event_ref = CGEventCreateKeyboardEvent(source.as_concrete_TypeRef(), keycode, keydown);
159+
if event_ref != ptr::null() {
160+
Ok(TCFType::wrap_under_create_rule(event_ref))
161+
} else {
162+
Err(())
163+
}
164+
}
165+
}
166+
167+
pub fn new_mouse_event(
168+
source: CGEventSource,
169+
mouse_type: CGEventType,
170+
mouse_cursor_position: CGPoint,
171+
mouse_button: CGMouseButton
172+
) -> Result<CGEvent, ()> {
173+
unsafe {
174+
let event_ref = CGEventCreateMouseEvent(source.as_concrete_TypeRef(), mouse_type,
175+
mouse_cursor_position, mouse_button);
176+
if event_ref != ptr::null() {
177+
Ok(TCFType::wrap_under_create_rule(event_ref))
178+
} else {
179+
Err(())
180+
}
181+
}
182+
}
183+
184+
pub fn post(&self, tap_location: CGEventTapLocation) {
185+
unsafe {
186+
CGEventPost(tap_location, self.as_concrete_TypeRef());
187+
}
188+
}
189+
190+
pub fn post_to_pid(&self, pid: libc::pid_t) {
191+
unsafe {
192+
CGEventPostToPid(pid, self.as_concrete_TypeRef());
193+
}
194+
}
195+
196+
pub fn set_flags(&self, flags: CGEventFlags) {
197+
unsafe {
198+
CGEventSetFlags(self.as_concrete_TypeRef(), flags);
199+
}
200+
}
201+
202+
pub fn get_flags(&self) -> CGEventFlags {
203+
unsafe {
204+
CGEventGetFlags(self.as_concrete_TypeRef())
205+
}
206+
}
207+
}
208+
209+
#[link(name = "ApplicationServices", kind = "framework")]
210+
extern {
211+
/// Return the type identifier for the opaque type `CGEventRef'.
212+
fn CGEventGetTypeID() -> CFTypeID;
213+
214+
/// Return a new keyboard event.
215+
///
216+
/// The event source may be taken from another event, or may be NULL. Based
217+
/// on the virtual key code values entered, the appropriate key down, key up,
218+
/// or flags changed events are generated.
219+
///
220+
/// All keystrokes needed to generate a character must be entered, including
221+
/// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z',
222+
/// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT
223+
/// and 'z' key must be released:
224+
fn CGEventCreateKeyboardEvent(source: CGEventSourceRef, keycode: CGKeyCode,
225+
keydown: bool) -> CGEventRef;
226+
227+
/// Return a new mouse event.
228+
///
229+
/// The event source may be taken from another event, or may be NULL.
230+
/// `mouseType' should be one of the mouse event types. `mouseCursorPosition'
231+
/// should be the position of the mouse cursor in global coordinates.
232+
/// `mouseButton' should be the button that's changing state; `mouseButton'
233+
/// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown',
234+
/// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'.
235+
///
236+
/// The current implemementation of the event system supports a maximum of
237+
/// thirty-two buttons. Mouse button 0 is the primary button on the mouse.
238+
/// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is
239+
/// the center button, and the remaining buttons are in USB device order.
240+
fn CGEventCreateMouseEvent(source: CGEventSourceRef, mouseType: CGEventType,
241+
mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> CGEventRef;
242+
243+
/// Post an event into the event stream at a specified location.
244+
///
245+
/// This function posts the specified event immediately before any event taps
246+
/// instantiated for that location, and the event passes through any such
247+
/// taps.
248+
fn CGEventPost(tapLocation: CGEventTapLocation, event: CGEventRef);
249+
250+
/// Post an event to a specified process ID
251+
fn CGEventPostToPid(pid: libc::pid_t, event: CGEventRef);
252+
253+
/// Set the event flags of an event.
254+
fn CGEventSetFlags(event: CGEventRef, flags: CGEventFlags);
255+
256+
/// Return the event flags of an event.
257+
fn CGEventGetFlags(event: CGEventRef) -> CGEventFlags;
258+
}

src/event_source.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
2+
3+
use std::mem;
4+
use std::ptr;
5+
6+
/// Possible source states of an event source.
7+
#[repr(C)]
8+
#[derive(Clone, Copy, Debug)]
9+
pub enum CGEventSourceStateID {
10+
Private = -1,
11+
CombinedSessionState = 0,
12+
HIDSystemState = 1,
13+
}
14+
15+
#[repr(C)]
16+
pub struct __CGEventSource;
17+
18+
pub type CGEventSourceRef = *const __CGEventSource;
19+
20+
pub struct CGEventSource {
21+
obj: CGEventSourceRef,
22+
}
23+
24+
impl Clone for CGEventSource {
25+
#[inline]
26+
fn clone(&self) -> CGEventSource {
27+
unsafe {
28+
TCFType::wrap_under_get_rule(self.obj)
29+
}
30+
}
31+
}
32+
33+
impl Drop for CGEventSource {
34+
fn drop(&mut self) {
35+
unsafe {
36+
let ptr = self.as_CFTypeRef();
37+
assert!(ptr != ptr::null());
38+
CFRelease(ptr);
39+
}
40+
}
41+
}
42+
43+
impl TCFType<CGEventSourceRef> for CGEventSource {
44+
#[inline]
45+
fn as_concrete_TypeRef(&self) -> CGEventSourceRef {
46+
self.obj
47+
}
48+
49+
#[inline]
50+
unsafe fn wrap_under_get_rule(reference: CGEventSourceRef) -> CGEventSource {
51+
let reference: CGEventSourceRef = mem::transmute(CFRetain(mem::transmute(reference)));
52+
TCFType::wrap_under_create_rule(reference)
53+
}
54+
55+
#[inline]
56+
fn as_CFTypeRef(&self) -> CFTypeRef {
57+
unsafe {
58+
mem::transmute(self.as_concrete_TypeRef())
59+
}
60+
}
61+
62+
#[inline]
63+
unsafe fn wrap_under_create_rule(obj: CGEventSourceRef) -> CGEventSource {
64+
CGEventSource {
65+
obj: obj,
66+
}
67+
}
68+
69+
#[inline]
70+
fn type_id() -> CFTypeID {
71+
unsafe {
72+
CGEventSourceGetTypeID()
73+
}
74+
}
75+
}
76+
77+
impl CGEventSource {
78+
pub fn new(state_id: CGEventSourceStateID) -> Result<CGEventSource, ()> {
79+
unsafe {
80+
let event_source_ref = CGEventSourceCreate(state_id);
81+
if event_source_ref != ptr::null() {
82+
Ok(TCFType::wrap_under_create_rule(event_source_ref))
83+
} else {
84+
Err(())
85+
}
86+
}
87+
}
88+
}
89+
90+
#[link(name = "ApplicationServices", kind = "framework")]
91+
extern {
92+
/// Return the type identifier for the opaque type `CGEventSourceRef'.
93+
fn CGEventSourceGetTypeID() -> CFTypeID;
94+
95+
/// Return a Quartz event source created with a specified source state.
96+
fn CGEventSourceCreate(stateID: CGEventSourceStateID) -> CGEventSourceRef;
97+
}

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ pub mod color_space;
1616
pub mod context;
1717
pub mod data_provider;
1818
pub mod display;
19+
pub mod event;
20+
pub mod event_source;
1921
pub mod font;
2022
pub mod geometry;
2123
pub mod private;
22-

0 commit comments

Comments
 (0)