1
+ #include "../mouse.h"
2
+ #include "../microsleep.h"
3
+
4
+ #include <math.h> /* For floor() */
5
+ #include <ApplicationServices/ApplicationServices.h>
6
+
7
+ #if !defined(M_SQRT2 )
8
+ #define M_SQRT2 1.4142135623730950488016887 /* Fix for MSVC. */
9
+ #endif
10
+
11
+ #define MMMouseToCGEventType (down , button ) \
12
+ (down ? MMMouseDownToCGEventType(button) : MMMouseUpToCGEventType(button))
13
+
14
+ #define MMMouseDownToCGEventType (button ) \
15
+ ((button) == (LEFT_BUTTON) ? kCGEventLeftMouseDown \
16
+ : ((button) == RIGHT_BUTTON ? kCGEventRightMouseDown \
17
+ : kCGEventOtherMouseDown))
18
+
19
+ #define MMMouseUpToCGEventType (button ) \
20
+ ((button) == LEFT_BUTTON ? kCGEventLeftMouseUp \
21
+ : ((button) == RIGHT_BUTTON ? kCGEventRightMouseUp \
22
+ : kCGEventOtherMouseUp))
23
+
24
+ #define MMMouseDragToCGEventType (button ) \
25
+ ((button) == LEFT_BUTTON ? kCGEventLeftMouseDragged \
26
+ : ((button) == RIGHT_BUTTON ? kCGEventRightMouseDragged \
27
+ : kCGEventOtherMouseDragged))
28
+
29
+ /**
30
+ * Calculate the delta for a mouse move and add them to the event.
31
+ * @param event The mouse move event (by ref).
32
+ * @param point The new mouse x and y.
33
+ */
34
+ void calculateDeltas (CGEventRef * event , MMPoint point )
35
+ {
36
+ /**
37
+ * The next few lines are a workaround for games not detecting mouse moves.
38
+ * See this issue for more information:
39
+ * https://github.com/octalmage/robotjs/issues/159
40
+ */
41
+ CGEventRef get = CGEventCreate (NULL );
42
+ CGPoint mouse = CGEventGetLocation (get );
43
+
44
+ // Calculate the deltas.
45
+ int64_t deltaX = point .x - mouse .x ;
46
+ int64_t deltaY = point .y - mouse .y ;
47
+
48
+ CGEventSetIntegerValueField (* event , kCGMouseEventDeltaX , deltaX );
49
+ CGEventSetIntegerValueField (* event , kCGMouseEventDeltaY , deltaY );
50
+
51
+ CFRelease (get );
52
+ }
53
+
54
+ /**
55
+ * Move the mouse to a specific point.
56
+ * @param point The coordinates to move the mouse to (x, y).
57
+ */
58
+ void moveMouse (MMPoint point )
59
+ {
60
+ CGPoint position = CGPointMake (point .x , point .y );
61
+ // Create an HID hardware event source
62
+ CGEventSourceRef src = CGEventSourceCreate (kCGEventSourceStateHIDSystemState );
63
+
64
+ CGEventRef evt = NULL ;
65
+ if (CGEventSourceButtonState (kCGEventSourceStateHIDSystemState , kCGMouseButtonLeft ))
66
+ {
67
+ // Create a left button drag
68
+ evt = CGEventCreateMouseEvent (src , kCGEventLeftMouseDragged , position , kCGMouseButtonLeft );
69
+ }
70
+ else
71
+ {
72
+ if (CGEventSourceButtonState (kCGEventSourceStateHIDSystemState , kCGMouseButtonRight ))
73
+ {
74
+ // Create a right button drag
75
+ evt = CGEventCreateMouseEvent (src , kCGEventRightMouseDragged , position , kCGMouseButtonLeft );
76
+ }
77
+ else
78
+ {
79
+ // Create a mouse move event
80
+ evt = CGEventCreateMouseEvent (src , kCGEventMouseMoved , position , kCGMouseButtonLeft );
81
+ }
82
+ }
83
+
84
+ // Post mouse event and release
85
+ CGEventPost (kCGHIDEventTap , evt );
86
+ if (evt != NULL )
87
+ {
88
+ CFRelease (evt );
89
+ }
90
+ CFRelease (src );
91
+ }
92
+
93
+ void dragMouse (MMPoint point , const MMMouseButton button )
94
+ {
95
+ CGEventSourceRef src = CGEventSourceCreate (kCGEventSourceStateHIDSystemState );
96
+ const CGEventType dragType = MMMouseDragToCGEventType (button );
97
+ CGEventRef drag = CGEventCreateMouseEvent (src , dragType , CGPointFromMMPoint (point ), (CGMouseButton )button );
98
+ calculateDeltas (& drag , point );
99
+
100
+ CGEventPost (kCGHIDEventTap , drag );
101
+ CFRelease (drag );
102
+ CFRelease (src );
103
+ }
104
+
105
+ MMPoint getMousePos ()
106
+ {
107
+ CGEventSourceRef src = CGEventSourceCreate (kCGEventSourceStateHIDSystemState );
108
+ CGEventRef event = CGEventCreate (src );
109
+ CGPoint point = CGEventGetLocation (event );
110
+ CFRelease (event );
111
+ CFRelease (src );
112
+
113
+ return MMPointFromCGPoint (point );
114
+ }
115
+
116
+ /**
117
+ * Press down a button, or release it.
118
+ * @param down True for down, false for up.
119
+ * @param button The button to press down or release.
120
+ */
121
+ void toggleMouse (bool down , MMMouseButton button )
122
+ {
123
+ const CGPoint currentPos = CGPointFromMMPoint (getMousePos ());
124
+ const CGEventType mouseType = MMMouseToCGEventType (down , button );
125
+ CGEventSourceRef src = CGEventSourceCreate (kCGEventSourceStateHIDSystemState );
126
+ CGEventRef event = CGEventCreateMouseEvent (src , mouseType , currentPos , (CGMouseButton )button );
127
+ CGEventPost (kCGHIDEventTap , event );
128
+ CFRelease (event );
129
+ CFRelease (src );
130
+ }
131
+
132
+ void clickMouse (MMMouseButton button )
133
+ {
134
+ toggleMouse (true, button );
135
+ toggleMouse (false, button );
136
+ }
137
+
138
+ /**
139
+ * Special function for sending double clicks, needed for Mac OS X.
140
+ * @param button Button to click.
141
+ */
142
+ void doubleClick (MMMouseButton button )
143
+ {
144
+ /* Double click for Mac. */
145
+ const CGPoint currentPos = CGPointFromMMPoint (getMousePos ());
146
+ const CGEventType mouseTypeDown = MMMouseToCGEventType (true, button );
147
+ const CGEventType mouseTypeUP = MMMouseToCGEventType (false, button );
148
+
149
+ CGEventSourceRef src = CGEventSourceCreate (kCGEventSourceStateHIDSystemState );
150
+ CGEventRef event = CGEventCreateMouseEvent (src , mouseTypeDown , currentPos , kCGMouseButtonLeft );
151
+
152
+ /* Set event to double click. */
153
+ CGEventSetIntegerValueField (event , kCGMouseEventClickState , 2 );
154
+
155
+ CGEventPost (kCGHIDEventTap , event );
156
+
157
+ CGEventSetType (event , mouseTypeUP );
158
+ CGEventPost (kCGHIDEventTap , event );
159
+
160
+ CFRelease (event );
161
+ CFRelease (src );
162
+ }
163
+
164
+ void scrollMouse (int x , int y )
165
+ {
166
+ /*
167
+ * Direction should only be considered based on the scrollDirection.
168
+ * This should not interfere.
169
+ * Set up the OS specific solution
170
+ */
171
+
172
+ CGEventRef event ;
173
+
174
+ event = CGEventCreateScrollWheelEvent (NULL , kCGScrollEventUnitPixel , 2 , y , x );
175
+ CGEventPost (kCGHIDEventTap , event );
176
+
177
+ CFRelease (event );
178
+ }
0 commit comments