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;
bitflags! {
pub flags CGEventFlags: u64 {
const CGEventFlagNull = 0,
const CGEventFlagAlphaShift = 0x00010000,
const CGEventFlagShift = 0x00020000,
const CGEventFlagControl = 0x00040000,
const CGEventFlagAlternate = 0x00080000,
const CGEventFlagCommand = 0x00100000,
const CGEventFlagHelp = 0x00400000,
const CGEventFlagSecondaryFn = 0x00800000,
const CGEventFlagNumericPad = 0x00200000,
const CGEventFlagNonCoalesced = 0x00000100,
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventType {
Null = 0,
LeftMouseDown = 1,
LeftMouseUp = 2,
RightMouseDown = 3,
RightMouseUp = 4,
MouseMoved = 5,
LeftMouseDragged = 6,
RightMouseDragged = 7,
KeyDown = 10,
KeyUp = 11,
FlagsChanged = 12,
ScrollWheel = 22,
TabletPointer = 23,
TabletProximity = 24,
OtherMouseDown = 25,
OtherMouseUp = 26,
OtherMouseDragged = 27,
TapDisabledByTimeout = 0xFFFFFFFE,
TapDisabledByUserInput = 0xFFFFFFFF,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGMouseButton {
Left,
Right,
Center,
}
#[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(source: CGEventSource) -> Result<CGEvent, ()> {
unsafe {
let event_ref = CGEventCreate(source.as_concrete_TypeRef());
if event_ref != ptr::null() {
Ok(TCFType::wrap_under_create_rule(event_ref))
} else {
Err(())
}
}
}
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 location(&self) -> CGPoint {
unsafe {
CGEventGetLocation(self.as_concrete_TypeRef())
}
}
#[cfg(feature = "elcapitan")]
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())
}
}
pub fn set_type(&self, event_type: CGEventType) {
unsafe {
CGEventSetType(self.as_concrete_TypeRef(), event_type);
}
}
pub fn get_type(&self) -> CGEventType {
unsafe {
CGEventGetType(self.as_concrete_TypeRef())
}
}
pub fn set_string_from_utf16_unchecked(&self, buf: &[u16]) {
let buflen = buf.len() as libc::c_ulong;
unsafe {
CGEventKeyboardSetUnicodeString(self.as_concrete_TypeRef(), buflen, buf.as_ptr());
}
}
pub fn set_string(&self, string: &str) {
let buf: Vec<u16> = string.encode_utf16().collect();
self.set_string_from_utf16_unchecked(&buf);
}
}
#[link(name = "ApplicationServices", kind = "framework")]
extern {
fn CGEventGetTypeID() -> CFTypeID;
fn CGEventCreate(source: CGEventSourceRef) -> CGEventRef;
fn CGEventCreateKeyboardEvent(source: CGEventSourceRef, keycode: CGKeyCode,
keydown: bool) -> CGEventRef;
fn CGEventCreateMouseEvent(source: CGEventSourceRef, mouseType: CGEventType,
mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> CGEventRef;
fn CGEventPost(tapLocation: CGEventTapLocation, event: CGEventRef);
#[cfg(feature = "elcapitan")]
fn CGEventPostToPid(pid: libc::pid_t, event: CGEventRef);
fn CGEventSetFlags(event: CGEventRef, flags: CGEventFlags);
fn CGEventGetFlags(event: CGEventRef) -> CGEventFlags;
fn CGEventGetLocation(event: CGEventRef) -> CGPoint;
fn CGEventSetType(event: CGEventRef, eventType: CGEventType);
fn CGEventGetType(event: CGEventRef) -> CGEventType;
fn CGEventKeyboardSetUnicodeString(event: CGEventRef,
length: libc::c_ulong,
string: *const u16);
}