author | prr |
Fri, 19 Sep 2014 09:41:05 -0700 | |
changeset 26751 | 70bac69b37c9 |
parent 25859 | jdk/src/java.desktop/macosx/native/libawt_lwawt/sun/awt/CRobot.m@3317bb8137f4 |
child 30924 | c8765f1fea21 |
permissions | -rw-r--r-- |
12047 | 1 |
/* |
23321
7f1737ac8b30
8034766: [parfait] JNI exception pending in jdk/src/macosx/native/sun/awt/CRobot.m
serb
parents:
23274
diff
changeset
|
2 |
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. |
12047 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
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 |
||
23321
7f1737ac8b30
8034766: [parfait] JNI exception pending in jdk/src/macosx/native/sun/awt/CRobot.m
serb
parents:
23274
diff
changeset
|
26 |
|
7f1737ac8b30
8034766: [parfait] JNI exception pending in jdk/src/macosx/native/sun/awt/CRobot.m
serb
parents:
23274
diff
changeset
|
27 |
#import "jni_util.h" |
7f1737ac8b30
8034766: [parfait] JNI exception pending in jdk/src/macosx/native/sun/awt/CRobot.m
serb
parents:
23274
diff
changeset
|
28 |
|
12047 | 29 |
#import <JavaNativeFoundation/JavaNativeFoundation.h> |
30 |
#import <ApplicationServices/ApplicationServices.h> |
|
31 |
||
32 |
#import "LWCToolkit.h" |
|
33 |
#import "sun_lwawt_macosx_CRobot.h" |
|
34 |
#import "java_awt_event_InputEvent.h" |
|
18232 | 35 |
#import "sizecalc.h" |
12047 | 36 |
|
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 |
|
56 |
// switches to the right button, then the click count will continue |
|
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. |
|
97 |
static int setupDone = 0; |
|
98 |
if (!setupDone) { |
|
99 |
int i; |
|
100 |
jint* tmp; |
|
101 |
jboolean copy = JNI_FALSE; |
|
102 |
||
103 |
setupDone = 1; |
|
104 |
// Don't block local events after posting ours |
|
105 |
CGSetLocalEventsSuppressionInterval(0.0); |
|
106 |
||
107 |
// Let our event's modifier key state blend with local hardware events |
|
108 |
CGEnableEventStateCombining(TRUE); |
|
109 |
||
110 |
// Don't let our events block local hardware events |
|
111 |
CGSetLocalEventsFilterDuringSupressionState( |
|
112 |
kCGEventFilterMaskPermitAllEvents, |
|
113 |
kCGEventSupressionStateSupressionInterval); |
|
114 |
CGSetLocalEventsFilterDuringSupressionState( |
|
115 |
kCGEventFilterMaskPermitAllEvents, |
|
116 |
kCGEventSupressionStateRemoteMouseDrag); |
|
117 |
||
118 |
gsClickCount = 0; |
|
119 |
gsLastClickTime = 0; |
|
120 |
gsEventNumber = ROBOT_EVENT_NUMBER_START; |
|
121 |
||
18232 | 122 |
gsButtonEventNumber = (int*)SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(int), gNumberOfButtons); |
12047 | 123 |
if (gsButtonEventNumber == NULL) { |
124 |
JNU_ThrowOutOfMemoryError(env, NULL); |
|
125 |
return; |
|
126 |
} |
|
127 |
||
128 |
for (i = 0; i < gNumberOfButtons; ++i) { |
|
129 |
gsButtonEventNumber[i] = ROBOT_EVENT_NUMBER_START; |
|
130 |
} |
|
131 |
} |
|
132 |
} |
|
133 |
||
134 |
/* |
|
135 |
* Class: sun_lwawt_macosx_CRobot |
|
136 |
* Method: mouseEvent |
|
137 |
* Signature: (IIIIZZ)V |
|
138 |
*/ |
|
139 |
JNIEXPORT void JNICALL |
|
140 |
Java_sun_lwawt_macosx_CRobot_mouseEvent |
|
141 |
(JNIEnv *env, jobject peer, |
|
15988 | 142 |
jint displayID, jint mouseLastX, jint mouseLastY, jint buttonsState, |
12047 | 143 |
jboolean isButtonsDownState, jboolean isMouseMove) |
144 |
{ |
|
145 |
JNF_COCOA_ENTER(env); |
|
146 |
||
147 |
// This is the native method called when Robot mouse events occur. |
|
148 |
// The CRobot tracks the mouse position, and which button was |
|
149 |
// pressed. If the mouse position is unknown it is obtained from |
|
150 |
// CGEvents. The peer also tracks the mouse button desired state, |
|
151 |
// the appropriate key modifier state, and whether the mouse action |
|
152 |
// is simply a mouse move with no mouse button state changes. |
|
153 |
||
154 |
CGError err = kCGErrorSuccess; |
|
155 |
||
156 |
CGRect globalDeviceBounds = CGDisplayBounds(displayID); |
|
157 |
||
158 |
// Set unknown mouse location, if needed. |
|
159 |
if ((mouseLastX == sun_lwawt_macosx_CRobot_MOUSE_LOCATION_UNKNOWN) || |
|
160 |
(mouseLastY == sun_lwawt_macosx_CRobot_MOUSE_LOCATION_UNKNOWN)) |
|
161 |
{ |
|
162 |
CGEventRef event = CGEventCreate(NULL); |
|
163 |
if (event == NULL) { |
|
164 |
return; |
|
165 |
} |
|
166 |
||
167 |
CGPoint globalPos = CGEventGetLocation(event); |
|
168 |
CFRelease(event); |
|
169 |
||
170 |
// Normalize the coords within this display device, as |
|
171 |
// per Robot rules. |
|
172 |
if (globalPos.x < CGRectGetMinX(globalDeviceBounds)) { |
|
173 |
globalPos.x = CGRectGetMinX(globalDeviceBounds); |
|
174 |
} |
|
175 |
else if (globalPos.x > CGRectGetMaxX(globalDeviceBounds)) { |
|
176 |
globalPos.x = CGRectGetMaxX(globalDeviceBounds); |
|
177 |
} |
|
178 |
||
179 |
if (globalPos.y < CGRectGetMinY(globalDeviceBounds)) { |
|
180 |
globalPos.y = CGRectGetMinY(globalDeviceBounds); |
|
181 |
} |
|
182 |
else if (globalPos.y > CGRectGetMaxY(globalDeviceBounds)) { |
|
183 |
globalPos.y = CGRectGetMaxY(globalDeviceBounds); |
|
184 |
} |
|
185 |
||
186 |
mouseLastX = (jint)globalPos.x; |
|
187 |
mouseLastY = (jint)globalPos.y; |
|
188 |
} |
|
189 |
||
190 |
// volatile, otherwise it warns that it might be clobbered by 'longjmp' |
|
191 |
volatile CGPoint point; |
|
192 |
||
23274
3b6993da89df
8013116: Robot moves mouse to point which differs from set in mouseMove on Unity shell
bagiras
parents:
18232
diff
changeset
|
193 |
point.x = mouseLastX; |
3b6993da89df
8013116: Robot moves mouse to point which differs from set in mouseMove on Unity shell
bagiras
parents:
18232
diff
changeset
|
194 |
point.y = mouseLastY; |
12047 | 195 |
|
196 |
__block CGMouseButton button = kCGMouseButtonLeft; |
|
197 |
__block CGEventType type = kCGEventMouseMoved; |
|
198 |
||
199 |
void (^HandleRobotButton)(CGMouseButton, CGEventType, CGEventType, CGEventType) = |
|
200 |
^(CGMouseButton cgButton, CGEventType cgButtonUp, CGEventType cgButtonDown, |
|
201 |
CGEventType cgButtonDragged) { |
|
202 |
||
203 |
button = cgButton; |
|
204 |
type = cgButtonUp; |
|
205 |
||
206 |
if (isButtonsDownState) { |
|
207 |
if (isMouseMove) { |
|
208 |
type = cgButtonDragged; |
|
209 |
} else { |
|
210 |
type = cgButtonDown; |
|
211 |
} |
|
212 |
} |
|
213 |
}; |
|
214 |
||
215 |
// Left |
|
216 |
if (buttonsState & java_awt_event_InputEvent_BUTTON1_MASK || |
|
217 |
buttonsState & java_awt_event_InputEvent_BUTTON1_DOWN_MASK ) { |
|
218 |
||
219 |
HandleRobotButton(kCGMouseButtonLeft, kCGEventLeftMouseUp, |
|
220 |
kCGEventLeftMouseDown, kCGEventLeftMouseDragged); |
|
221 |
} |
|
222 |
||
223 |
// Other |
|
224 |
if (buttonsState & java_awt_event_InputEvent_BUTTON2_MASK || |
|
225 |
buttonsState & java_awt_event_InputEvent_BUTTON2_DOWN_MASK ) { |
|
226 |
||
227 |
HandleRobotButton(kCGMouseButtonCenter, kCGEventOtherMouseUp, |
|
228 |
kCGEventOtherMouseDown, kCGEventOtherMouseDragged); |
|
229 |
} |
|
230 |
||
231 |
// Right |
|
232 |
if (buttonsState & java_awt_event_InputEvent_BUTTON3_MASK || |
|
233 |
buttonsState & java_awt_event_InputEvent_BUTTON3_DOWN_MASK ) { |
|
234 |
||
235 |
HandleRobotButton(kCGMouseButtonRight, kCGEventRightMouseUp, |
|
236 |
kCGEventRightMouseDown, kCGEventRightMouseDragged); |
|
237 |
} |
|
238 |
||
239 |
// Extra |
|
240 |
if (gNumberOfButtons > 3) { |
|
241 |
int extraButton; |
|
242 |
for (extraButton = 3; extraButton < gNumberOfButtons; ++extraButton) { |
|
243 |
if ((buttonsState & gButtonDownMasks[extraButton])) { |
|
244 |
HandleRobotButton(extraButton, kCGEventOtherMouseUp, |
|
245 |
kCGEventOtherMouseDown, kCGEventOtherMouseDragged); |
|
246 |
} |
|
247 |
} |
|
248 |
} |
|
249 |
||
250 |
int clickCount = 0; |
|
251 |
int eventNumber = gsEventNumber; |
|
252 |
||
253 |
if (isMouseMove) { |
|
254 |
// any mouse movement resets click count |
|
255 |
gsLastClickTime = 0; |
|
256 |
} else { |
|
257 |
clickCount = GetClickCount(isButtonsDownState); |
|
258 |
||
259 |
if (isButtonsDownState) { |
|
260 |
gsButtonEventNumber[button] = gsEventNumber++; |
|
261 |
} |
|
262 |
eventNumber = gsButtonEventNumber[button]; |
|
263 |
} |
|
264 |
||
265 |
PostMouseEvent(point, button, type, clickCount, eventNumber); |
|
266 |
||
267 |
JNF_COCOA_EXIT(env); |
|
268 |
} |
|
269 |
||
270 |
/* |
|
271 |
* Class: sun_lwawt_macosx_CRobot |
|
272 |
* Method: mouseWheel |
|
273 |
* Signature: (I)V |
|
274 |
*/ |
|
275 |
JNIEXPORT void JNICALL |
|
276 |
Java_sun_lwawt_macosx_CRobot_mouseWheel |
|
277 |
(JNIEnv *env, jobject peer, jint wheelAmt) |
|
278 |
{ |
|
279 |
CGEventRef event = CGEventCreateScrollWheelEvent(NULL, |
|
280 |
kCGScrollEventUnitLine, |
|
281 |
k_JAVA_ROBOT_WHEEL_COUNT, wheelAmt); |
|
282 |
||
283 |
if (event != NULL) { |
|
284 |
CGEventPost(kCGSessionEventTap, event); |
|
285 |
CFRelease(event); |
|
286 |
} |
|
287 |
} |
|
288 |
||
289 |
/* |
|
290 |
* Class: sun_lwawt_macosx_CRobot |
|
291 |
* Method: keyEvent |
|
292 |
* Signature: (IZ)V |
|
293 |
*/ |
|
294 |
JNIEXPORT void JNICALL |
|
295 |
Java_sun_lwawt_macosx_CRobot_keyEvent |
|
296 |
(JNIEnv *env, jobject peer, jint javaKeyCode, jboolean keyPressed) |
|
297 |
{ |
|
298 |
/* |
|
299 |
* Well, using CGEventCreateKeyboardEvent/CGEventPost would have been |
|
300 |
* a better solution, however, it gives me all kinds of trouble and I have |
|
301 |
* no idea how to solve them without inserting delays between simulated |
|
302 |
* events. So, I've ended up disabling it and opted for another approach |
|
303 |
* that uses Accessibility API instead. |
|
304 |
*/ |
|
305 |
CGKeyCode keyCode = GetCGKeyCode(javaKeyCode); |
|
306 |
AXUIElementRef elem = AXUIElementCreateSystemWide(); |
|
307 |
AXUIElementPostKeyboardEvent(elem, (CGCharCode)0, keyCode, keyPressed); |
|
308 |
CFRelease(elem); |
|
309 |
||
310 |
||
311 |
#if 0 |
|
312 |
CGEventRef event = CGEventCreateKeyboardEvent(NULL, keyCode, keyPressed); |
|
313 |
if (event != NULL) { |
|
314 |
CGEventPost(kCGSessionEventTap, event); |
|
315 |
CFRelease(event); |
|
316 |
} |
|
317 |
#endif |
|
318 |
} |
|
319 |
||
320 |
/* |
|
321 |
* Class: sun_lwawt_macosx_CRobot |
|
322 |
* Method: nativeGetScreenPixels |
|
323 |
* Signature: (IIIII[I)V |
|
324 |
*/ |
|
325 |
JNIEXPORT void JNICALL |
|
326 |
Java_sun_lwawt_macosx_CRobot_nativeGetScreenPixels |
|
327 |
(JNIEnv *env, jobject peer, |
|
328 |
jint x, jint y, jint width, jint height, jintArray pixels) |
|
329 |
{ |
|
330 |
JNF_COCOA_ENTER(env); |
|
331 |
||
332 |
jint picX = x; |
|
333 |
jint picY = y; |
|
334 |
jint picWidth = width; |
|
335 |
jint picHeight = height; |
|
336 |
||
337 |
CGRect screenRect = CGRectMake(picX, picY, picWidth, picHeight); |
|
338 |
CGImageRef screenPixelsImage = CGWindowListCreateImage(screenRect, |
|
339 |
kCGWindowListOptionOnScreenOnly, |
|
340 |
kCGNullWindowID, kCGWindowImageDefault); |
|
341 |
||
342 |
if (screenPixelsImage == NULL) { |
|
343 |
return; |
|
344 |
} |
|
345 |
||
346 |
// get a pointer to the Java int array |
|
347 |
void *jPixelData = (*env)->GetPrimitiveArrayCritical(env, pixels, 0); |
|
23321
7f1737ac8b30
8034766: [parfait] JNI exception pending in jdk/src/macosx/native/sun/awt/CRobot.m
serb
parents:
23274
diff
changeset
|
348 |
CHECK_NULL(jPixelData); |
12047 | 349 |
|
350 |
// create a graphics context around the Java int array |
|
351 |
CGColorSpaceRef picColorSpace = CGColorSpaceCreateWithName( |
|
352 |
kCGColorSpaceGenericRGB); |
|
353 |
CGContextRef jPicContextRef = CGBitmapContextCreate( |
|
354 |
jPixelData, |
|
355 |
picWidth, picHeight, |
|
356 |
8, picWidth * sizeof(jint), |
|
357 |
picColorSpace, |
|
358 |
kCGBitmapByteOrder32Host | |
|
359 |
kCGImageAlphaPremultipliedFirst); |
|
360 |
||
361 |
CGColorSpaceRelease(picColorSpace); |
|
362 |
||
363 |
// flip, scale, and color correct the screen image into the Java pixels |
|
364 |
CGRect bounds = { { 0, 0 }, { picWidth, picHeight } }; |
|
365 |
CGContextDrawImage(jPicContextRef, bounds, screenPixelsImage); |
|
366 |
CGContextFlush(jPicContextRef); |
|
367 |
||
368 |
// cleanup |
|
369 |
CGContextRelease(jPicContextRef); |
|
370 |
CGImageRelease(screenPixelsImage); |
|
371 |
||
372 |
// release the Java int array back up to the JVM |
|
373 |
(*env)->ReleasePrimitiveArrayCritical(env, pixels, jPixelData, 0); |
|
374 |
||
375 |
JNF_COCOA_EXIT(env); |
|
376 |
} |
|
377 |
||
378 |
/**************************************************** |
|
379 |
* Helper methods |
|
380 |
****************************************************/ |
|
381 |
||
382 |
static void PostMouseEvent(const CGPoint point, CGMouseButton button, |
|
383 |
CGEventType type, int clickCount, int eventNumber) |
|
384 |
{ |
|
385 |
CGEventRef mouseEvent = CGEventCreateMouseEvent(NULL, type, point, button); |
|
386 |
if (mouseEvent != NULL) { |
|
387 |
CGEventSetIntegerValueField(mouseEvent, kCGMouseEventClickState, clickCount); |
|
388 |
CGEventSetIntegerValueField(mouseEvent, kCGMouseEventNumber, eventNumber); |
|
389 |
CGEventPost(kCGSessionEventTap, mouseEvent); |
|
390 |
CFRelease(mouseEvent); |
|
391 |
} |
|
392 |
} |
|
393 |
||
394 |
// NOTE: Don't modify this table directly. It is machine generated. See below. |
|
395 |
static const unsigned char javaToMacKeyCode[] = { |
|
396 |
127, // 0 0 VK_UNDEFINED No_Equivalent |
|
397 |
127, // 1 0x1 Not_Used |
|
398 |
127, // 2 0x2 Not_Used |
|
399 |
127, // 3 0x3 VK_CANCEL No_Equivalent |
|
400 |
127, // 4 0x4 Not_Used |
|
401 |
127, // 5 0x5 Not_Used |
|
402 |
127, // 6 0x6 Not_Used |
|
403 |
127, // 7 0x7 Not_Used |
|
404 |
51, // 8 0x8 VK_BACK_SPACE |
|
405 |
48, // 9 0x9 VK_TAB |
|
406 |
36, // 10 0xa VK_ENTER |
|
407 |
127, // 11 0xb Not_Used |
|
408 |
71, // 12 0xc VK_CLEAR |
|
409 |
127, // 13 0xd Not_Used |
|
410 |
127, // 14 0xe Not_Used |
|
411 |
127, // 15 0xf Not_Used |
|
412 |
56, // 16 0x10 VK_SHIFT |
|
413 |
59, // 17 0x11 VK_CONTROL |
|
414 |
58, // 18 0x12 VK_ALT |
|
415 |
113, // 19 0x13 VK_PAUSE |
|
416 |
57, // 20 0x14 VK_CAPS_LOCK |
|
417 |
127, // 21 0x15 VK_KANA No_Equivalent |
|
418 |
127, // 22 0x16 Not_Used |
|
419 |
127, // 23 0x17 Not_Used |
|
420 |
127, // 24 0x18 VK_FINAL No_Equivalent |
|
421 |
127, // 25 0x19 VK_KANJI No_Equivalent |
|
422 |
127, // 26 0x1a Not_Used |
|
423 |
53, // 27 0x1b VK_ESCAPE |
|
424 |
127, // 28 0x1c VK_CONVERT No_Equivalent |
|
425 |
127, // 29 0x1d VK_NONCONVERT No_Equivalent |
|
426 |
127, // 30 0x1e VK_ACCEPT No_Equivalent |
|
427 |
127, // 31 0x1f VK_MODECHANGE No_Equivalent |
|
428 |
49, // 32 0x20 VK_SPACE |
|
429 |
116, // 33 0x21 VK_PAGE_UP |
|
430 |
121, // 34 0x22 VK_PAGE_DOWN |
|
431 |
119, // 35 0x23 VK_END |
|
432 |
115, // 36 0x24 VK_HOME |
|
433 |
123, // 37 0x25 VK_LEFT |
|
434 |
126, // 38 0x26 VK_UP |
|
435 |
124, // 39 0x27 VK_RIGHT |
|
436 |
125, // 40 0x28 VK_DOWN |
|
437 |
127, // 41 0x29 Not_Used |
|
438 |
127, // 42 0x2a Not_Used |
|
439 |
127, // 43 0x2b Not_Used |
|
440 |
43, // 44 0x2c VK_COMMA |
|
441 |
27, // 45 0x2d VK_MINUS |
|
442 |
47, // 46 0x2e VK_PERIOD |
|
443 |
44, // 47 0x2f VK_SLASH |
|
444 |
29, // 48 0x30 VK_0 |
|
445 |
18, // 49 0x31 VK_1 |
|
446 |
19, // 50 0x32 VK_2 |
|
447 |
20, // 51 0x33 VK_3 |
|
448 |
21, // 52 0x34 VK_4 |
|
449 |
23, // 53 0x35 VK_5 |
|
450 |
22, // 54 0x36 VK_6 |
|
451 |
26, // 55 0x37 VK_7 |
|
452 |
28, // 56 0x38 VK_8 |
|
453 |
25, // 57 0x39 VK_9 |
|
454 |
127, // 58 0x3a Not_Used |
|
455 |
41, // 59 0x3b VK_SEMICOLON |
|
456 |
127, // 60 0x3c Not_Used |
|
457 |
24, // 61 0x3d VK_EQUALS |
|
458 |
127, // 62 0x3e Not_Used |
|
459 |
127, // 63 0x3f Not_Used |
|
460 |
127, // 64 0x40 Not_Used |
|
461 |
0, // 65 0x41 VK_A |
|
462 |
11, // 66 0x42 VK_B |
|
463 |
8, // 67 0x43 VK_C |
|
464 |
2, // 68 0x44 VK_D |
|
465 |
14, // 69 0x45 VK_E |
|
466 |
3, // 70 0x46 VK_F |
|
467 |
5, // 71 0x47 VK_G |
|
468 |
4, // 72 0x48 VK_H |
|
469 |
34, // 73 0x49 VK_I |
|
470 |
38, // 74 0x4a VK_J |
|
471 |
40, // 75 0x4b VK_K |
|
472 |
37, // 76 0x4c VK_L |
|
473 |
46, // 77 0x4d VK_M |
|
474 |
45, // 78 0x4e VK_N |
|
475 |
31, // 79 0x4f VK_O |
|
476 |
35, // 80 0x50 VK_P |
|
477 |
12, // 81 0x51 VK_Q |
|
478 |
15, // 82 0x52 VK_R |
|
479 |
1, // 83 0x53 VK_S |
|
480 |
17, // 84 0x54 VK_T |
|
481 |
32, // 85 0x55 VK_U |
|
482 |
9, // 86 0x56 VK_V |
|
483 |
13, // 87 0x57 VK_W |
|
484 |
7, // 88 0x58 VK_X |
|
485 |
16, // 89 0x59 VK_Y |
|
486 |
6, // 90 0x5a VK_Z |
|
487 |
33, // 91 0x5b VK_OPEN_BRACKET |
|
488 |
42, // 92 0x5c VK_BACK_SLASH |
|
489 |
30, // 93 0x5d VK_CLOSE_BRACKET |
|
490 |
127, // 94 0x5e Not_Used |
|
491 |
127, // 95 0x5f Not_Used |
|
492 |
82, // 96 0x60 VK_NUMPAD0 |
|
493 |
83, // 97 0x61 VK_NUMPAD1 |
|
494 |
84, // 98 0x62 VK_NUMPAD2 |
|
495 |
85, // 99 0x63 VK_NUMPAD3 |
|
496 |
86, // 100 0x64 VK_NUMPAD4 |
|
497 |
87, // 101 0x65 VK_NUMPAD5 |
|
498 |
88, // 102 0x66 VK_NUMPAD6 |
|
499 |
89, // 103 0x67 VK_NUMPAD7 |
|
500 |
91, // 104 0x68 VK_NUMPAD8 |
|
501 |
92, // 105 0x69 VK_NUMPAD9 |
|
502 |
67, // 106 0x6a VK_MULTIPLY |
|
503 |
69, // 107 0x6b VK_ADD |
|
504 |
127, // 108 0x6c VK_SEPARATER No_Equivalent |
|
505 |
78, // 109 0x6d VK_SUBTRACT |
|
506 |
65, // 110 0x6e VK_DECIMAL |
|
507 |
75, // 111 0x6f VK_DIVIDE |
|
508 |
122, // 112 0x70 VK_F1 |
|
509 |
120, // 113 0x71 VK_F2 |
|
510 |
99, // 114 0x72 VK_F3 |
|
511 |
118, // 115 0x73 VK_F4 |
|
512 |
96, // 116 0x74 VK_F5 |
|
513 |
97, // 117 0x75 VK_F6 |
|
514 |
98, // 118 0x76 VK_F7 |
|
515 |
100, // 119 0x77 VK_F8 |
|
516 |
101, // 120 0x78 VK_F9 |
|
517 |
109, // 121 0x79 VK_F10 |
|
518 |
103, // 122 0x7a VK_F11 |
|
519 |
111, // 123 0x7b VK_F12 |
|
520 |
127, // 124 0x7c Not_Used |
|
521 |
127, // 125 0x7d Not_Used |
|
522 |
127, // 126 0x7e Not_Used |
|
523 |
117, // 127 0x7f VK_DELETE |
|
524 |
127, // 128 0x80 VK_DEAD_GRAVE No_Equivalent |
|
525 |
127, // 129 0x81 VK_DEAD_ACUTE No_Equivalent |
|
526 |
127, // 130 0x82 VK_DEAD_CIRCUMFLEX No_Equivalent |
|
527 |
127, // 131 0x83 VK_DEAD_TILDE No_Equivalent |
|
528 |
127, // 132 0x84 VK_DEAD_MACRON No_Equivalent |
|
529 |
127, // 133 0x85 VK_DEAD_BREVE No_Equivalent |
|
530 |
127, // 134 0x86 VK_DEAD_ABOVEDOT No_Equivalent |
|
531 |
127, // 135 0x87 VK_DEAD_DIAERESIS No_Equivalent |
|
532 |
127, // 136 0x88 VK_DEAD_ABOVERING No_Equivalent |
|
533 |
127, // 137 0x89 VK_DEAD_DOUBLEACUTE No_Equivalent |
|
534 |
127, // 138 0x8a VK_DEAD_CARON No_Equivalent |
|
535 |
127, // 139 0x8b VK_DEAD_CEDILLA No_Equivalent |
|
536 |
127, // 140 0x8c VK_DEAD_OGONEK No_Equivalent |
|
537 |
127, // 141 0x8d VK_DEAD_IOTA No_Equivalent |
|
538 |
127, // 142 0x8e VK_DEAD_VOICED_SOUND No_Equivalent |
|
539 |
127, // 143 0x8f VK_DEAD_SEMIVOICED_SOUND No_Equivalent |
|
540 |
127, // 144 0x90 VK_NUM_LOCK No_Equivalent |
|
541 |
107, // 145 0x91 VK_SCROLL_LOCK |
|
542 |
127, // 146 0x92 Not_Used |
|
543 |
127, // 147 0x93 Not_Used |
|
544 |
127, // 148 0x94 Not_Used |
|
545 |
127, // 149 0x95 Not_Used |
|
546 |
127, // 150 0x96 VK_AMPERSAND No_Equivalent |
|
547 |
127, // 151 0x97 VK_ASTERISK No_Equivalent |
|
548 |
127, // 152 0x98 VK_QUOTEDBL No_Equivalent |
|
549 |
127, // 153 0x99 VK_LESS No_Equivalent |
|
550 |
105, // 154 0x9a VK_PRINTSCREEN |
|
551 |
127, // 155 0x9b VK_INSERT No_Equivalent |
|
552 |
114, // 156 0x9c VK_HELP |
|
553 |
55, // 157 0x9d VK_META |
|
554 |
127, // 158 0x9e Not_Used |
|
555 |
127, // 159 0x9f Not_Used |
|
556 |
127, // 160 0xa0 VK_GREATER No_Equivalent |
|
557 |
127, // 161 0xa1 VK_BRACELEFT No_Equivalent |
|
558 |
127, // 162 0xa2 VK_BRACERIGHT No_Equivalent |
|
559 |
127, // 163 0xa3 Not_Used |
|
560 |
127, // 164 0xa4 Not_Used |
|
561 |
127, // 165 0xa5 Not_Used |
|
562 |
127, // 166 0xa6 Not_Used |
|
563 |
127, // 167 0xa7 Not_Used |
|
564 |
127, // 168 0xa8 Not_Used |
|
565 |
127, // 169 0xa9 Not_Used |
|
566 |
127, // 170 0xaa Not_Used |
|
567 |
127, // 171 0xab Not_Used |
|
568 |
127, // 172 0xac Not_Used |
|
569 |
127, // 173 0xad Not_Used |
|
570 |
127, // 174 0xae Not_Used |
|
571 |
127, // 175 0xaf Not_Used |
|
572 |
127, // 176 0xb0 Not_Used |
|
573 |
127, // 177 0xb1 Not_Used |
|
574 |
127, // 178 0xb2 Not_Used |
|
575 |
127, // 179 0xb3 Not_Used |
|
576 |
127, // 180 0xb4 Not_Used |
|
577 |
127, // 181 0xb5 Not_Used |
|
578 |
127, // 182 0xb6 Not_Used |
|
579 |
127, // 183 0xb7 Not_Used |
|
580 |
127, // 184 0xb8 Not_Used |
|
581 |
127, // 185 0xb9 Not_Used |
|
582 |
127, // 186 0xba Not_Used |
|
583 |
127, // 187 0xbb Not_Used |
|
584 |
127, // 188 0xbc Not_Used |
|
585 |
127, // 189 0xbd Not_Used |
|
586 |
127, // 190 0xbe Not_Used |
|
587 |
127, // 191 0xbf Not_Used |
|
588 |
50, // 192 0xc0 VK_BACK_QUOTE |
|
589 |
127, // 193 0xc1 Not_Used |
|
590 |
127, // 194 0xc2 Not_Used |
|
591 |
127, // 195 0xc3 Not_Used |
|
592 |
127, // 196 0xc4 Not_Used |
|
593 |
127, // 197 0xc5 Not_Used |
|
594 |
127, // 198 0xc6 Not_Used |
|
595 |
127, // 199 0xc7 Not_Used |
|
596 |
127, // 200 0xc8 Not_Used |
|
597 |
127, // 201 0xc9 Not_Used |
|
598 |
127, // 202 0xca Not_Used |
|
599 |
127, // 203 0xcb Not_Used |
|
600 |
127, // 204 0xcc Not_Used |
|
601 |
127, // 205 0xcd Not_Used |
|
602 |
127, // 206 0xce Not_Used |
|
603 |
127, // 207 0xcf Not_Used |
|
604 |
127, // 208 0xd0 Not_Used |
|
605 |
127, // 209 0xd1 Not_Used |
|
606 |
127, // 210 0xd2 Not_Used |
|
607 |
127, // 211 0xd3 Not_Used |
|
608 |
127, // 212 0xd4 Not_Used |
|
609 |
127, // 213 0xd5 Not_Used |
|
610 |
127, // 214 0xd6 Not_Used |
|
611 |
127, // 215 0xd7 Not_Used |
|
612 |
127, // 216 0xd8 Not_Used |
|
613 |
127, // 217 0xd9 Not_Used |
|
614 |
127, // 218 0xda Not_Used |
|
615 |
127, // 219 0xdb Not_Used |
|
616 |
127, // 220 0xdc Not_Used |
|
617 |
127, // 221 0xdd Not_Used |
|
618 |
39 // 222 0xde VK_QUOTE |
|
619 |
}; |
|
620 |
||
621 |
// NOTE: All values above 222 don't have an equivalent on MacOSX. |
|
622 |
static inline CGKeyCode GetCGKeyCode(jint javaKeyCode) |
|
623 |
{ |
|
624 |
if (javaKeyCode > 222) { |
|
625 |
return 127; |
|
626 |
} else { |
|
627 |
return javaToMacKeyCode[javaKeyCode]; |
|
628 |
} |
|
629 |
} |
|
630 |
||
631 |
static int GetClickCount(BOOL isDown) { |
|
632 |
NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate]; |
|
633 |
NSTimeInterval clickInterval = now - gsLastClickTime; |
|
634 |
BOOL isWithinTreshold = clickInterval < [NSEvent doubleClickInterval]; |
|
635 |
||
636 |
if (isDown) { |
|
637 |
if (isWithinTreshold) { |
|
638 |
gsClickCount++; |
|
639 |
} else { |
|
640 |
gsClickCount = 1; |
|
641 |
} |
|
642 |
||
643 |
gsLastClickTime = now; |
|
644 |
} else { |
|
645 |
// In OS X, a mouse up has the click count of the last mouse down |
|
646 |
// if an interval between up and down is within the double click |
|
647 |
// threshold, and 0 otherwise. |
|
648 |
if (!isWithinTreshold) { |
|
649 |
gsClickCount = 0; |
|
650 |
} |
|
651 |
} |
|
652 |
||
653 |
return gsClickCount; |
|
654 |
} |