16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27 #import "jni_util.h"
28
29 #import <JavaNativeFoundation/JavaNativeFoundation.h>
30 #import <ApplicationServices/ApplicationServices.h>
31
32 #import "CRobotKeyCode.h"
33 #import "LWCToolkit.h"
34 #import "sun_lwawt_macosx_CRobot.h"
35 #import "java_awt_event_InputEvent.h"
36 #import "sizecalc.h"
37
38 // Starting number for event numbers generated by Robot.
39 // Apple docs don't mention at all what are the requirements
40 // for these numbers. It seems that they must be higher
41 // than event numbers from real events, which start at some
42 // value close to zero. There is no API for obtaining current
43 // event number, so we have to start from some random number.
44 // 32000 as starting value works for me, let's hope that it will
45 // work for others as well.
46 #define ROBOT_EVENT_NUMBER_START 32000
47
48 #define k_JAVA_ROBOT_WHEEL_COUNT 1
49
50 #if !defined(kCGBitmapByteOrder32Host)
51 #define kCGBitmapByteOrder32Host 0
52 #endif
53
54 // In OS X, left and right mouse button share the same click count.
55 // That is, if one starts clicking the left button rapidly and then
57 // increasing, without dropping to 1 in between. The middle button,
58 // however, has its own click count.
59 // For robot, we aren't going to emulate all that complexity. All our
60 // synhtetic clicks share the same click count.
61 static int gsClickCount;
62 static NSTimeInterval gsLastClickTime;
63
64 // Apparently, for mouse up/down events we have to set an event number
65 // that is incremented on each button press. Otherwise, strange things
66 // happen with z-order.
67 static int gsEventNumber;
68 static int* gsButtonEventNumber;
69
70 static inline CGKeyCode GetCGKeyCode(jint javaKeyCode);
71
72 static void PostMouseEvent(const CGPoint point, CGMouseButton button,
73 CGEventType type, int clickCount, int eventNumber);
74
75 static int GetClickCount(BOOL isDown);
76
77 static void
78 CreateJavaException(JNIEnv* env, CGError err)
79 {
80 // Throw a java exception indicating what is wrong.
81 NSString* s = [NSString stringWithFormat:@"Robot: CGError: %d", err];
82 (*env)->ThrowNew(env, (*env)->FindClass(env, "java/awt/AWTException"),
83 [s UTF8String]);
84 }
85
86 /*
87 * Class: sun_lwawt_macosx_CRobot
88 * Method: initRobot
89 * Signature: (V)V
90 */
91 JNIEXPORT void JNICALL
92 Java_sun_lwawt_macosx_CRobot_initRobot
93 (JNIEnv *env, jobject peer)
94 {
95 // Set things up to let our app act like a synthetic keyboard and mouse.
96 // Always set all states, in case Apple ever changes default behaviors.
248 CFRelease(event);
249 }
250 }
251
252 /*
253 * Class: sun_lwawt_macosx_CRobot
254 * Method: keyEvent
255 * Signature: (IZ)V
256 */
257 JNIEXPORT void JNICALL
258 Java_sun_lwawt_macosx_CRobot_keyEvent
259 (JNIEnv *env, jobject peer, jint javaKeyCode, jboolean keyPressed)
260 {
261 /*
262 * Well, using CGEventCreateKeyboardEvent/CGEventPost would have been
263 * a better solution, however, it gives me all kinds of trouble and I have
264 * no idea how to solve them without inserting delays between simulated
265 * events. So, I've ended up disabling it and opted for another approach
266 * that uses Accessibility API instead.
267 */
268 CGKeyCode keyCode = GetCGKeyCode(javaKeyCode);
269 AXUIElementRef elem = AXUIElementCreateSystemWide();
270 AXUIElementPostKeyboardEvent(elem, (CGCharCode)0, keyCode, keyPressed);
271 CFRelease(elem);
272
273
274 #if 0
275 CGEventRef event = CGEventCreateKeyboardEvent(NULL, keyCode, keyPressed);
276 if (event != NULL) {
277 CGEventPost(kCGSessionEventTap, event);
278 CFRelease(event);
279 }
280 #endif
281 }
282
283 /*
284 * Class: sun_lwawt_macosx_CRobot
285 * Method: nativeGetScreenPixels
286 * Signature: (IIIII[I)V
287 */
288 JNIEXPORT void JNICALL
289 Java_sun_lwawt_macosx_CRobot_nativeGetScreenPixels
290 (JNIEnv *env, jobject peer,
291 jint x, jint y, jint width, jint height, jintArray pixels)
292 {
293 JNF_COCOA_ENTER(env);
294
295 jint picX = x;
296 jint picY = y;
297 jint picWidth = width;
298 jint picHeight = height;
299
300 CGRect screenRect = CGRectMake(picX, picY, picWidth, picHeight);
367
368 if (isDown) {
369 if (isWithinTreshold) {
370 gsClickCount++;
371 } else {
372 gsClickCount = 1;
373 }
374
375 gsLastClickTime = now;
376 } else {
377 // In OS X, a mouse up has the click count of the last mouse down
378 // if an interval between up and down is within the double click
379 // threshold, and 0 otherwise.
380 if (!isWithinTreshold) {
381 gsClickCount = 0;
382 }
383 }
384
385 return gsClickCount;
386 }
|
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27 #import "jni_util.h"
28
29 #import <JavaNativeFoundation/JavaNativeFoundation.h>
30 #import <ApplicationServices/ApplicationServices.h>
31
32 #import "CRobotKeyCode.h"
33 #import "LWCToolkit.h"
34 #import "sun_lwawt_macosx_CRobot.h"
35 #import "java_awt_event_InputEvent.h"
36 #import "java_awt_event_KeyEvent.h"
37 #import "sizecalc.h"
38
39 // Starting number for event numbers generated by Robot.
40 // Apple docs don't mention at all what are the requirements
41 // for these numbers. It seems that they must be higher
42 // than event numbers from real events, which start at some
43 // value close to zero. There is no API for obtaining current
44 // event number, so we have to start from some random number.
45 // 32000 as starting value works for me, let's hope that it will
46 // work for others as well.
47 #define ROBOT_EVENT_NUMBER_START 32000
48
49 #define k_JAVA_ROBOT_WHEEL_COUNT 1
50
51 #if !defined(kCGBitmapByteOrder32Host)
52 #define kCGBitmapByteOrder32Host 0
53 #endif
54
55 // In OS X, left and right mouse button share the same click count.
56 // That is, if one starts clicking the left button rapidly and then
58 // increasing, without dropping to 1 in between. The middle button,
59 // however, has its own click count.
60 // For robot, we aren't going to emulate all that complexity. All our
61 // synhtetic clicks share the same click count.
62 static int gsClickCount;
63 static NSTimeInterval gsLastClickTime;
64
65 // Apparently, for mouse up/down events we have to set an event number
66 // that is incremented on each button press. Otherwise, strange things
67 // happen with z-order.
68 static int gsEventNumber;
69 static int* gsButtonEventNumber;
70
71 static inline CGKeyCode GetCGKeyCode(jint javaKeyCode);
72
73 static void PostMouseEvent(const CGPoint point, CGMouseButton button,
74 CGEventType type, int clickCount, int eventNumber);
75
76 static int GetClickCount(BOOL isDown);
77
78 static BOOL IsModifierKey(jint javaKeyCode);
79
80 static void
81 CreateJavaException(JNIEnv* env, CGError err)
82 {
83 // Throw a java exception indicating what is wrong.
84 NSString* s = [NSString stringWithFormat:@"Robot: CGError: %d", err];
85 (*env)->ThrowNew(env, (*env)->FindClass(env, "java/awt/AWTException"),
86 [s UTF8String]);
87 }
88
89 /*
90 * Class: sun_lwawt_macosx_CRobot
91 * Method: initRobot
92 * Signature: (V)V
93 */
94 JNIEXPORT void JNICALL
95 Java_sun_lwawt_macosx_CRobot_initRobot
96 (JNIEnv *env, jobject peer)
97 {
98 // Set things up to let our app act like a synthetic keyboard and mouse.
99 // Always set all states, in case Apple ever changes default behaviors.
251 CFRelease(event);
252 }
253 }
254
255 /*
256 * Class: sun_lwawt_macosx_CRobot
257 * Method: keyEvent
258 * Signature: (IZ)V
259 */
260 JNIEXPORT void JNICALL
261 Java_sun_lwawt_macosx_CRobot_keyEvent
262 (JNIEnv *env, jobject peer, jint javaKeyCode, jboolean keyPressed)
263 {
264 /*
265 * Well, using CGEventCreateKeyboardEvent/CGEventPost would have been
266 * a better solution, however, it gives me all kinds of trouble and I have
267 * no idea how to solve them without inserting delays between simulated
268 * events. So, I've ended up disabling it and opted for another approach
269 * that uses Accessibility API instead.
270 */
271
272 CGKeyCode keyCode = GetCGKeyCode(javaKeyCode);
273
274 /*
275 * JDK-8155740: AXUIElementPostKeyboardEvent posts 0 key code for all
276 * the modifier keys with key codes (16, 17,18, 20, 157) and also for
277 * newly added modifier key VK_ALT_GRAPH. But it posts correct key code
278 * for all the other keys. On the other hand CGEventCreateKeyboardEvent
279 * posts correct key code for all the modifier keys and hence it is used
280 * to post modifier key events and AXUIElementPostKeyboardEvent is used to
281 * post all the remaining key events.
282 */
283 if (IsModifierKey(javaKeyCode)) {
284 CGEventRef event = CGEventCreateKeyboardEvent(NULL, keyCode, keyPressed);
285 if (event != NULL) {
286 CGEventPost(kCGSessionEventTap, event);
287 CFRelease(event);
288 }
289 } else {
290 AXUIElementRef elem = AXUIElementCreateSystemWide();
291 AXUIElementPostKeyboardEvent(elem, (CGCharCode)0, keyCode, keyPressed);
292 CFRelease(elem);
293 }
294 }
295
296 /*
297 * Class: sun_lwawt_macosx_CRobot
298 * Method: nativeGetScreenPixels
299 * Signature: (IIIII[I)V
300 */
301 JNIEXPORT void JNICALL
302 Java_sun_lwawt_macosx_CRobot_nativeGetScreenPixels
303 (JNIEnv *env, jobject peer,
304 jint x, jint y, jint width, jint height, jintArray pixels)
305 {
306 JNF_COCOA_ENTER(env);
307
308 jint picX = x;
309 jint picY = y;
310 jint picWidth = width;
311 jint picHeight = height;
312
313 CGRect screenRect = CGRectMake(picX, picY, picWidth, picHeight);
380
381 if (isDown) {
382 if (isWithinTreshold) {
383 gsClickCount++;
384 } else {
385 gsClickCount = 1;
386 }
387
388 gsLastClickTime = now;
389 } else {
390 // In OS X, a mouse up has the click count of the last mouse down
391 // if an interval between up and down is within the double click
392 // threshold, and 0 otherwise.
393 if (!isWithinTreshold) {
394 gsClickCount = 0;
395 }
396 }
397
398 return gsClickCount;
399 }
400
401 static BOOL IsModifierKey(jint javaKeyCode) {
402
403 switch (javaKeyCode) {
404 case java_awt_event_KeyEvent_VK_SHIFT:
405 case java_awt_event_KeyEvent_VK_CONTROL:
406 case java_awt_event_KeyEvent_VK_ALT:
407 case java_awt_event_KeyEvent_VK_CAPS_LOCK:
408 case java_awt_event_KeyEvent_VK_META:
409 case java_awt_event_KeyEvent_VK_ALT_GRAPH:
410 return YES;
411 }
412
413 return NO;
414 }
|