4632N/A/*
4632N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
4632N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4632N/A *
4632N/A * This code is free software; you can redistribute it and/or modify it
4632N/A * under the terms of the GNU General Public License version 2 only, as
4632N/A * published by the Free Software Foundation. Oracle designates this
4632N/A * particular file as subject to the "Classpath" exception as provided
4632N/A * by Oracle in the LICENSE file that accompanied this code.
4632N/A *
4632N/A * This code is distributed in the hope that it will be useful, but WITHOUT
4632N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4632N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4632N/A * version 2 for more details (a copy is included in the LICENSE file that
4632N/A * accompanied this code).
4632N/A *
4632N/A * You should have received a copy of the GNU General Public License version
4632N/A * 2 along with this work; if not, write to the Free Software Foundation,
4632N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4632N/A *
4632N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4632N/A * or visit www.oracle.com if you need additional information or have any
4632N/A * questions.
4632N/A */
4632N/A
4632N/A#import <JavaNativeFoundation/JavaNativeFoundation.h>
4632N/A#import <ApplicationServices/ApplicationServices.h>
4639N/A
4632N/A#import "LWCToolkit.h"
4632N/A#import "sun_lwawt_macosx_CRobot.h"
4734N/A#import "java_awt_event_InputEvent.h"
6295N/A#import "sizecalc.h"
4734N/A
4632N/A
4647N/A// Starting number for event numbers generated by Robot.
4647N/A// Apple docs don't mention at all what are the requirements
4647N/A// for these numbers. It seems that they must be higher
4647N/A// than event numbers from real events, which start at some
4647N/A// value close to zero. There is no API for obtaining current
4647N/A// event number, so we have to start from some random number.
4647N/A// 32000 as starting value works for me, let's hope that it will
4647N/A// work for others as well.
4647N/A#define ROBOT_EVENT_NUMBER_START 32000
4647N/A
4632N/A#define k_JAVA_ROBOT_WHEEL_COUNT 1
4632N/A
4632N/A#if !defined(kCGBitmapByteOrder32Host)
4632N/A#define kCGBitmapByteOrder32Host 0
4632N/A#endif
4632N/A
4639N/A// In OS X, left and right mouse button share the same click count.
4639N/A// That is, if one starts clicking the left button rapidly and then
4639N/A// switches to the right button, then the click count will continue
4639N/A// increasing, without dropping to 1 in between. The middle button,
4639N/A// however, has its own click count.
4639N/A// For robot, we aren't going to emulate all that complexity. All our
4639N/A// synhtetic clicks share the same click count.
4639N/Astatic int gsClickCount;
4639N/Astatic NSTimeInterval gsLastClickTime;
4639N/A
4647N/A// Apparently, for mouse up/down events we have to set an event number
4647N/A// that is incremented on each button press. Otherwise, strange things
4647N/A// happen with z-order.
4647N/Astatic int gsEventNumber;
4734N/Astatic int* gsButtonEventNumber;
4647N/A
4632N/Astatic inline CGKeyCode GetCGKeyCode(jint javaKeyCode);
4632N/A
4647N/Astatic void PostMouseEvent(const CGPoint point, CGMouseButton button,
4647N/A CGEventType type, int clickCount, int eventNumber);
4632N/A
4639N/Astatic int GetClickCount(BOOL isDown);
4632N/A
4632N/Astatic void
4632N/ACreateJavaException(JNIEnv* env, CGError err)
4632N/A{
4632N/A // Throw a java exception indicating what is wrong.
4632N/A NSString* s = [NSString stringWithFormat:@"Robot: CGError: %d", err];
4632N/A (*env)->ThrowNew(env, (*env)->FindClass(env, "java/awt/AWTException"),
4632N/A [s UTF8String]);
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_lwawt_macosx_CRobot
4632N/A * Method: initRobot
4734N/A * Signature: (V)V
4632N/A */
4632N/AJNIEXPORT void JNICALL
4632N/AJava_sun_lwawt_macosx_CRobot_initRobot
4632N/A(JNIEnv *env, jobject peer)
4632N/A{
4632N/A // Set things up to let our app act like a synthetic keyboard and mouse.
4632N/A // Always set all states, in case Apple ever changes default behaviors.
4632N/A static int setupDone = 0;
4647N/A if (!setupDone) {
4734N/A int i;
4734N/A jint* tmp;
4734N/A jboolean copy = JNI_FALSE;
4734N/A
4632N/A setupDone = 1;
4632N/A // Don't block local events after posting ours
4632N/A CGSetLocalEventsSuppressionInterval(0.0);
4632N/A
4632N/A // Let our event's modifier key state blend with local hardware events
4632N/A CGEnableEventStateCombining(TRUE);
4632N/A
4632N/A // Don't let our events block local hardware events
4632N/A CGSetLocalEventsFilterDuringSupressionState(
4632N/A kCGEventFilterMaskPermitAllEvents,
4632N/A kCGEventSupressionStateSupressionInterval);
4632N/A CGSetLocalEventsFilterDuringSupressionState(
4632N/A kCGEventFilterMaskPermitAllEvents,
4632N/A kCGEventSupressionStateRemoteMouseDrag);
4647N/A
4639N/A gsClickCount = 0;
4639N/A gsLastClickTime = 0;
4734N/A gsEventNumber = ROBOT_EVENT_NUMBER_START;
4647N/A
6295N/A gsButtonEventNumber = (int*)SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(int), gNumberOfButtons);
4734N/A if (gsButtonEventNumber == NULL) {
4734N/A JNU_ThrowOutOfMemoryError(env, NULL);
4734N/A return;
4734N/A }
4734N/A
4734N/A for (i = 0; i < gNumberOfButtons; ++i) {
4734N/A gsButtonEventNumber[i] = ROBOT_EVENT_NUMBER_START;
4734N/A }
4632N/A }
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_lwawt_macosx_CRobot
4632N/A * Method: mouseEvent
4734N/A * Signature: (IIIIZZ)V
4632N/A */
4632N/AJNIEXPORT void JNICALL
4632N/AJava_sun_lwawt_macosx_CRobot_mouseEvent
4632N/A(JNIEnv *env, jobject peer,
6062N/A jint displayID, jint mouseLastX, jint mouseLastY, jint buttonsState,
4734N/A jboolean isButtonsDownState, jboolean isMouseMove)
4632N/A{
4632N/A JNF_COCOA_ENTER(env);
4632N/A
4632N/A // This is the native method called when Robot mouse events occur.
4632N/A // The CRobot tracks the mouse position, and which button was
4632N/A // pressed. If the mouse position is unknown it is obtained from
4632N/A // CGEvents. The peer also tracks the mouse button desired state,
4632N/A // the appropriate key modifier state, and whether the mouse action
4632N/A // is simply a mouse move with no mouse button state changes.
4632N/A
4632N/A CGError err = kCGErrorSuccess;
4632N/A
4632N/A CGRect globalDeviceBounds = CGDisplayBounds(displayID);
4632N/A
4632N/A // Set unknown mouse location, if needed.
4632N/A if ((mouseLastX == sun_lwawt_macosx_CRobot_MOUSE_LOCATION_UNKNOWN) ||
4632N/A (mouseLastY == sun_lwawt_macosx_CRobot_MOUSE_LOCATION_UNKNOWN))
4632N/A {
4632N/A CGEventRef event = CGEventCreate(NULL);
4632N/A if (event == NULL) {
4632N/A return;
4632N/A }
4632N/A
4632N/A CGPoint globalPos = CGEventGetLocation(event);
4632N/A CFRelease(event);
4632N/A
4632N/A // Normalize the coords within this display device, as
4632N/A // per Robot rules.
4632N/A if (globalPos.x < CGRectGetMinX(globalDeviceBounds)) {
4632N/A globalPos.x = CGRectGetMinX(globalDeviceBounds);
4632N/A }
4632N/A else if (globalPos.x > CGRectGetMaxX(globalDeviceBounds)) {
4632N/A globalPos.x = CGRectGetMaxX(globalDeviceBounds);
4632N/A }
4632N/A
4632N/A if (globalPos.y < CGRectGetMinY(globalDeviceBounds)) {
4632N/A globalPos.y = CGRectGetMinY(globalDeviceBounds);
4632N/A }
4632N/A else if (globalPos.y > CGRectGetMaxY(globalDeviceBounds)) {
4632N/A globalPos.y = CGRectGetMaxY(globalDeviceBounds);
4632N/A }
4632N/A
4632N/A mouseLastX = (jint)globalPos.x;
4632N/A mouseLastY = (jint)globalPos.y;
4632N/A }
4632N/A
4632N/A // volatile, otherwise it warns that it might be clobbered by 'longjmp'
4632N/A volatile CGPoint point;
4632N/A
4632N/A // Translate the device relative point into a valid global CGPoint.
4632N/A point.x = mouseLastX + globalDeviceBounds.origin.x;
4632N/A point.y = mouseLastY + globalDeviceBounds.origin.y;
4632N/A
4734N/A __block CGMouseButton button = kCGMouseButtonLeft;
4734N/A __block CGEventType type = kCGEventMouseMoved;
4734N/A
4734N/A void (^HandleRobotButton)(CGMouseButton, CGEventType, CGEventType, CGEventType) =
4734N/A ^(CGMouseButton cgButton, CGEventType cgButtonUp, CGEventType cgButtonDown,
4734N/A CGEventType cgButtonDragged) {
4734N/A
4734N/A button = cgButton;
4734N/A type = cgButtonUp;
4734N/A
4734N/A if (isButtonsDownState) {
4734N/A if (isMouseMove) {
4734N/A type = cgButtonDragged;
4734N/A } else {
4734N/A type = cgButtonDown;
4734N/A }
4734N/A }
4734N/A };
4734N/A
4734N/A // Left
4734N/A if (buttonsState & java_awt_event_InputEvent_BUTTON1_MASK ||
4734N/A buttonsState & java_awt_event_InputEvent_BUTTON1_DOWN_MASK ) {
4734N/A
4734N/A HandleRobotButton(kCGMouseButtonLeft, kCGEventLeftMouseUp,
4734N/A kCGEventLeftMouseDown, kCGEventLeftMouseDragged);
4734N/A }
4734N/A
4734N/A // Other
4734N/A if (buttonsState & java_awt_event_InputEvent_BUTTON2_MASK ||
4734N/A buttonsState & java_awt_event_InputEvent_BUTTON2_DOWN_MASK ) {
4734N/A
4734N/A HandleRobotButton(kCGMouseButtonCenter, kCGEventOtherMouseUp,
4734N/A kCGEventOtherMouseDown, kCGEventOtherMouseDragged);
4734N/A }
4734N/A
4734N/A // Right
4734N/A if (buttonsState & java_awt_event_InputEvent_BUTTON3_MASK ||
4734N/A buttonsState & java_awt_event_InputEvent_BUTTON3_DOWN_MASK ) {
4734N/A
4734N/A HandleRobotButton(kCGMouseButtonRight, kCGEventRightMouseUp,
4734N/A kCGEventRightMouseDown, kCGEventRightMouseDragged);
4734N/A }
4734N/A
4734N/A // Extra
4734N/A if (gNumberOfButtons > 3) {
4734N/A int extraButton;
4734N/A for (extraButton = 3; extraButton < gNumberOfButtons; ++extraButton) {
4734N/A if ((buttonsState & gButtonDownMasks[extraButton])) {
4734N/A HandleRobotButton(extraButton, kCGEventOtherMouseUp,
4734N/A kCGEventOtherMouseDown, kCGEventOtherMouseDragged);
4734N/A }
4734N/A }
4734N/A }
4734N/A
4639N/A int clickCount = 0;
4647N/A int eventNumber = gsEventNumber;
4632N/A
4734N/A if (isMouseMove) {
4647N/A // any mouse movement resets click count
4647N/A gsLastClickTime = 0;
4734N/A } else {
4734N/A clickCount = GetClickCount(isButtonsDownState);
4647N/A
4734N/A if (isButtonsDownState) {
4734N/A gsButtonEventNumber[button] = gsEventNumber++;
4632N/A }
4734N/A eventNumber = gsButtonEventNumber[button];
4632N/A }
4632N/A
4647N/A PostMouseEvent(point, button, type, clickCount, eventNumber);
4632N/A
4632N/A JNF_COCOA_EXIT(env);
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_lwawt_macosx_CRobot
4632N/A * Method: mouseWheel
4632N/A * Signature: (I)V
4632N/A */
4632N/AJNIEXPORT void JNICALL
4632N/AJava_sun_lwawt_macosx_CRobot_mouseWheel
4632N/A(JNIEnv *env, jobject peer, jint wheelAmt)
4632N/A{
4632N/A CGEventRef event = CGEventCreateScrollWheelEvent(NULL,
4632N/A kCGScrollEventUnitLine,
4632N/A k_JAVA_ROBOT_WHEEL_COUNT, wheelAmt);
4632N/A
4632N/A if (event != NULL) {
4632N/A CGEventPost(kCGSessionEventTap, event);
4632N/A CFRelease(event);
4632N/A }
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_lwawt_macosx_CRobot
4632N/A * Method: keyEvent
4632N/A * Signature: (IZ)V
4632N/A */
4632N/AJNIEXPORT void JNICALL
4632N/AJava_sun_lwawt_macosx_CRobot_keyEvent
4632N/A(JNIEnv *env, jobject peer, jint javaKeyCode, jboolean keyPressed)
4632N/A{
4639N/A /*
4647N/A * Well, using CGEventCreateKeyboardEvent/CGEventPost would have been
4639N/A * a better solution, however, it gives me all kinds of trouble and I have
4647N/A * no idea how to solve them without inserting delays between simulated
4647N/A * events. So, I've ended up disabling it and opted for another approach
4647N/A * that uses Accessibility API instead.
4639N/A */
4632N/A CGKeyCode keyCode = GetCGKeyCode(javaKeyCode);
4647N/A AXUIElementRef elem = AXUIElementCreateSystemWide();
4639N/A AXUIElementPostKeyboardEvent(elem, (CGCharCode)0, keyCode, keyPressed);
4639N/A CFRelease(elem);
4639N/A
4647N/A
4639N/A#if 0
4632N/A CGEventRef event = CGEventCreateKeyboardEvent(NULL, keyCode, keyPressed);
4632N/A if (event != NULL) {
4632N/A CGEventPost(kCGSessionEventTap, event);
4632N/A CFRelease(event);
4632N/A }
4639N/A#endif
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_lwawt_macosx_CRobot
4632N/A * Method: nativeGetScreenPixels
4632N/A * Signature: (IIIII[I)V
4632N/A */
4632N/AJNIEXPORT void JNICALL
4632N/AJava_sun_lwawt_macosx_CRobot_nativeGetScreenPixels
4632N/A(JNIEnv *env, jobject peer,
4632N/A jint x, jint y, jint width, jint height, jintArray pixels)
4632N/A{
4632N/A JNF_COCOA_ENTER(env);
4632N/A
4632N/A jint picX = x;
4632N/A jint picY = y;
4632N/A jint picWidth = width;
4632N/A jint picHeight = height;
4632N/A
4632N/A CGRect screenRect = CGRectMake(picX, picY, picWidth, picHeight);
4632N/A CGImageRef screenPixelsImage = CGWindowListCreateImage(screenRect,
4632N/A kCGWindowListOptionOnScreenOnly,
4632N/A kCGNullWindowID, kCGWindowImageDefault);
4632N/A
4632N/A if (screenPixelsImage == NULL) {
4632N/A return;
4632N/A }
4632N/A
4632N/A // get a pointer to the Java int array
4632N/A void *jPixelData = (*env)->GetPrimitiveArrayCritical(env, pixels, 0);
4632N/A
4632N/A // create a graphics context around the Java int array
4632N/A CGColorSpaceRef picColorSpace = CGColorSpaceCreateWithName(
4632N/A kCGColorSpaceGenericRGB);
4632N/A CGContextRef jPicContextRef = CGBitmapContextCreate(
4632N/A jPixelData,
4632N/A picWidth, picHeight,
4632N/A 8, picWidth * sizeof(jint),
4632N/A picColorSpace,
4632N/A kCGBitmapByteOrder32Host |
4632N/A kCGImageAlphaPremultipliedFirst);
4632N/A
4632N/A CGColorSpaceRelease(picColorSpace);
4632N/A
4632N/A // flip, scale, and color correct the screen image into the Java pixels
4632N/A CGRect bounds = { { 0, 0 }, { picWidth, picHeight } };
4632N/A CGContextDrawImage(jPicContextRef, bounds, screenPixelsImage);
4632N/A CGContextFlush(jPicContextRef);
4632N/A
4632N/A // cleanup
4632N/A CGContextRelease(jPicContextRef);
4632N/A CGImageRelease(screenPixelsImage);
4632N/A
4632N/A // release the Java int array back up to the JVM
4632N/A (*env)->ReleasePrimitiveArrayCritical(env, pixels, jPixelData, 0);
4632N/A
4632N/A JNF_COCOA_EXIT(env);
4632N/A}
4632N/A
4632N/A/****************************************************
4632N/A * Helper methods
4632N/A ****************************************************/
4632N/A
4647N/Astatic void PostMouseEvent(const CGPoint point, CGMouseButton button,
4647N/A CGEventType type, int clickCount, int eventNumber)
4647N/A{
4632N/A CGEventRef mouseEvent = CGEventCreateMouseEvent(NULL, type, point, button);
4632N/A if (mouseEvent != NULL) {
4647N/A CGEventSetIntegerValueField(mouseEvent, kCGMouseEventClickState, clickCount);
4647N/A CGEventSetIntegerValueField(mouseEvent, kCGMouseEventNumber, eventNumber);
4632N/A CGEventPost(kCGSessionEventTap, mouseEvent);
4632N/A CFRelease(mouseEvent);
4632N/A }
4632N/A}
4632N/A
4632N/A// NOTE: Don't modify this table directly. It is machine generated. See below.
4632N/Astatic const unsigned char javaToMacKeyCode[] = {
4632N/A 127, // 0 0 VK_UNDEFINED No_Equivalent
4632N/A 127, // 1 0x1 Not_Used
4632N/A 127, // 2 0x2 Not_Used
4632N/A 127, // 3 0x3 VK_CANCEL No_Equivalent
4632N/A 127, // 4 0x4 Not_Used
4632N/A 127, // 5 0x5 Not_Used
4632N/A 127, // 6 0x6 Not_Used
4632N/A 127, // 7 0x7 Not_Used
4632N/A 51, // 8 0x8 VK_BACK_SPACE
4632N/A 48, // 9 0x9 VK_TAB
4632N/A 36, // 10 0xa VK_ENTER
4632N/A 127, // 11 0xb Not_Used
4632N/A 71, // 12 0xc VK_CLEAR
4632N/A 127, // 13 0xd Not_Used
4632N/A 127, // 14 0xe Not_Used
4632N/A 127, // 15 0xf Not_Used
4632N/A 56, // 16 0x10 VK_SHIFT
4632N/A 59, // 17 0x11 VK_CONTROL
4632N/A 58, // 18 0x12 VK_ALT
4632N/A 113, // 19 0x13 VK_PAUSE
4632N/A 57, // 20 0x14 VK_CAPS_LOCK
4632N/A 127, // 21 0x15 VK_KANA No_Equivalent
4632N/A 127, // 22 0x16 Not_Used
4632N/A 127, // 23 0x17 Not_Used
4632N/A 127, // 24 0x18 VK_FINAL No_Equivalent
4632N/A 127, // 25 0x19 VK_KANJI No_Equivalent
4632N/A 127, // 26 0x1a Not_Used
4632N/A 53, // 27 0x1b VK_ESCAPE
4632N/A 127, // 28 0x1c VK_CONVERT No_Equivalent
4632N/A 127, // 29 0x1d VK_NONCONVERT No_Equivalent
4632N/A 127, // 30 0x1e VK_ACCEPT No_Equivalent
4632N/A 127, // 31 0x1f VK_MODECHANGE No_Equivalent
4632N/A 49, // 32 0x20 VK_SPACE
4632N/A 116, // 33 0x21 VK_PAGE_UP
4632N/A 121, // 34 0x22 VK_PAGE_DOWN
4632N/A 119, // 35 0x23 VK_END
4632N/A 115, // 36 0x24 VK_HOME
4632N/A 123, // 37 0x25 VK_LEFT
4632N/A 126, // 38 0x26 VK_UP
4632N/A 124, // 39 0x27 VK_RIGHT
4632N/A 125, // 40 0x28 VK_DOWN
4632N/A 127, // 41 0x29 Not_Used
4632N/A 127, // 42 0x2a Not_Used
4632N/A 127, // 43 0x2b Not_Used
4632N/A 43, // 44 0x2c VK_COMMA
4632N/A 27, // 45 0x2d VK_MINUS
4632N/A 47, // 46 0x2e VK_PERIOD
4632N/A 44, // 47 0x2f VK_SLASH
4632N/A 29, // 48 0x30 VK_0
4632N/A 18, // 49 0x31 VK_1
4632N/A 19, // 50 0x32 VK_2
4632N/A 20, // 51 0x33 VK_3
4632N/A 21, // 52 0x34 VK_4
4632N/A 23, // 53 0x35 VK_5
4632N/A 22, // 54 0x36 VK_6
4632N/A 26, // 55 0x37 VK_7
4632N/A 28, // 56 0x38 VK_8
4632N/A 25, // 57 0x39 VK_9
4632N/A 127, // 58 0x3a Not_Used
4632N/A 41, // 59 0x3b VK_SEMICOLON
4632N/A 127, // 60 0x3c Not_Used
4632N/A 24, // 61 0x3d VK_EQUALS
4632N/A 127, // 62 0x3e Not_Used
4632N/A 127, // 63 0x3f Not_Used
4632N/A 127, // 64 0x40 Not_Used
4632N/A 0, // 65 0x41 VK_A
4632N/A 11, // 66 0x42 VK_B
4632N/A 8, // 67 0x43 VK_C
4632N/A 2, // 68 0x44 VK_D
4632N/A 14, // 69 0x45 VK_E
4632N/A 3, // 70 0x46 VK_F
4632N/A 5, // 71 0x47 VK_G
4632N/A 4, // 72 0x48 VK_H
4632N/A 34, // 73 0x49 VK_I
4632N/A 38, // 74 0x4a VK_J
4632N/A 40, // 75 0x4b VK_K
4632N/A 37, // 76 0x4c VK_L
4632N/A 46, // 77 0x4d VK_M
4632N/A 45, // 78 0x4e VK_N
4632N/A 31, // 79 0x4f VK_O
4632N/A 35, // 80 0x50 VK_P
4632N/A 12, // 81 0x51 VK_Q
4632N/A 15, // 82 0x52 VK_R
4632N/A 1, // 83 0x53 VK_S
4632N/A 17, // 84 0x54 VK_T
4632N/A 32, // 85 0x55 VK_U
4632N/A 9, // 86 0x56 VK_V
4632N/A 13, // 87 0x57 VK_W
4632N/A 7, // 88 0x58 VK_X
4632N/A 16, // 89 0x59 VK_Y
4632N/A 6, // 90 0x5a VK_Z
4632N/A 33, // 91 0x5b VK_OPEN_BRACKET
4632N/A 42, // 92 0x5c VK_BACK_SLASH
4632N/A 30, // 93 0x5d VK_CLOSE_BRACKET
4632N/A 127, // 94 0x5e Not_Used
4632N/A 127, // 95 0x5f Not_Used
4632N/A 82, // 96 0x60 VK_NUMPAD0
4632N/A 83, // 97 0x61 VK_NUMPAD1
4632N/A 84, // 98 0x62 VK_NUMPAD2
4632N/A 85, // 99 0x63 VK_NUMPAD3
4632N/A 86, // 100 0x64 VK_NUMPAD4
4632N/A 87, // 101 0x65 VK_NUMPAD5
4632N/A 88, // 102 0x66 VK_NUMPAD6
4632N/A 89, // 103 0x67 VK_NUMPAD7
4632N/A 91, // 104 0x68 VK_NUMPAD8
4632N/A 92, // 105 0x69 VK_NUMPAD9
4632N/A 67, // 106 0x6a VK_MULTIPLY
4632N/A 69, // 107 0x6b VK_ADD
4632N/A 127, // 108 0x6c VK_SEPARATER No_Equivalent
4632N/A 78, // 109 0x6d VK_SUBTRACT
4632N/A 65, // 110 0x6e VK_DECIMAL
4632N/A 75, // 111 0x6f VK_DIVIDE
4632N/A 122, // 112 0x70 VK_F1
4632N/A 120, // 113 0x71 VK_F2
4632N/A 99, // 114 0x72 VK_F3
4632N/A 118, // 115 0x73 VK_F4
4632N/A 96, // 116 0x74 VK_F5
4632N/A 97, // 117 0x75 VK_F6
4632N/A 98, // 118 0x76 VK_F7
4632N/A 100, // 119 0x77 VK_F8
4632N/A 101, // 120 0x78 VK_F9
4632N/A 109, // 121 0x79 VK_F10
4632N/A 103, // 122 0x7a VK_F11
4632N/A 111, // 123 0x7b VK_F12
4632N/A 127, // 124 0x7c Not_Used
4632N/A 127, // 125 0x7d Not_Used
4632N/A 127, // 126 0x7e Not_Used
4632N/A 117, // 127 0x7f VK_DELETE
4632N/A 127, // 128 0x80 VK_DEAD_GRAVE No_Equivalent
4632N/A 127, // 129 0x81 VK_DEAD_ACUTE No_Equivalent
4632N/A 127, // 130 0x82 VK_DEAD_CIRCUMFLEX No_Equivalent
4632N/A 127, // 131 0x83 VK_DEAD_TILDE No_Equivalent
4632N/A 127, // 132 0x84 VK_DEAD_MACRON No_Equivalent
4632N/A 127, // 133 0x85 VK_DEAD_BREVE No_Equivalent
4632N/A 127, // 134 0x86 VK_DEAD_ABOVEDOT No_Equivalent
4632N/A 127, // 135 0x87 VK_DEAD_DIAERESIS No_Equivalent
4632N/A 127, // 136 0x88 VK_DEAD_ABOVERING No_Equivalent
4632N/A 127, // 137 0x89 VK_DEAD_DOUBLEACUTE No_Equivalent
4632N/A 127, // 138 0x8a VK_DEAD_CARON No_Equivalent
4632N/A 127, // 139 0x8b VK_DEAD_CEDILLA No_Equivalent
4632N/A 127, // 140 0x8c VK_DEAD_OGONEK No_Equivalent
4632N/A 127, // 141 0x8d VK_DEAD_IOTA No_Equivalent
4632N/A 127, // 142 0x8e VK_DEAD_VOICED_SOUND No_Equivalent
4632N/A 127, // 143 0x8f VK_DEAD_SEMIVOICED_SOUND No_Equivalent
4632N/A 127, // 144 0x90 VK_NUM_LOCK No_Equivalent
4632N/A 107, // 145 0x91 VK_SCROLL_LOCK
4632N/A 127, // 146 0x92 Not_Used
4632N/A 127, // 147 0x93 Not_Used
4632N/A 127, // 148 0x94 Not_Used
4632N/A 127, // 149 0x95 Not_Used
4632N/A 127, // 150 0x96 VK_AMPERSAND No_Equivalent
4632N/A 127, // 151 0x97 VK_ASTERISK No_Equivalent
4632N/A 127, // 152 0x98 VK_QUOTEDBL No_Equivalent
4632N/A 127, // 153 0x99 VK_LESS No_Equivalent
4632N/A 105, // 154 0x9a VK_PRINTSCREEN
4632N/A 127, // 155 0x9b VK_INSERT No_Equivalent
4632N/A 114, // 156 0x9c VK_HELP
4632N/A 55, // 157 0x9d VK_META
4632N/A 127, // 158 0x9e Not_Used
4632N/A 127, // 159 0x9f Not_Used
4632N/A 127, // 160 0xa0 VK_GREATER No_Equivalent
4632N/A 127, // 161 0xa1 VK_BRACELEFT No_Equivalent
4632N/A 127, // 162 0xa2 VK_BRACERIGHT No_Equivalent
4632N/A 127, // 163 0xa3 Not_Used
4632N/A 127, // 164 0xa4 Not_Used
4632N/A 127, // 165 0xa5 Not_Used
4632N/A 127, // 166 0xa6 Not_Used
4632N/A 127, // 167 0xa7 Not_Used
4632N/A 127, // 168 0xa8 Not_Used
4632N/A 127, // 169 0xa9 Not_Used
4632N/A 127, // 170 0xaa Not_Used
4632N/A 127, // 171 0xab Not_Used
4632N/A 127, // 172 0xac Not_Used
4632N/A 127, // 173 0xad Not_Used
4632N/A 127, // 174 0xae Not_Used
4632N/A 127, // 175 0xaf Not_Used
4632N/A 127, // 176 0xb0 Not_Used
4632N/A 127, // 177 0xb1 Not_Used
4632N/A 127, // 178 0xb2 Not_Used
4632N/A 127, // 179 0xb3 Not_Used
4632N/A 127, // 180 0xb4 Not_Used
4632N/A 127, // 181 0xb5 Not_Used
4632N/A 127, // 182 0xb6 Not_Used
4632N/A 127, // 183 0xb7 Not_Used
4632N/A 127, // 184 0xb8 Not_Used
4632N/A 127, // 185 0xb9 Not_Used
4632N/A 127, // 186 0xba Not_Used
4632N/A 127, // 187 0xbb Not_Used
4632N/A 127, // 188 0xbc Not_Used
4632N/A 127, // 189 0xbd Not_Used
4632N/A 127, // 190 0xbe Not_Used
4632N/A 127, // 191 0xbf Not_Used
4632N/A 50, // 192 0xc0 VK_BACK_QUOTE
4632N/A 127, // 193 0xc1 Not_Used
4632N/A 127, // 194 0xc2 Not_Used
4632N/A 127, // 195 0xc3 Not_Used
4632N/A 127, // 196 0xc4 Not_Used
4632N/A 127, // 197 0xc5 Not_Used
4632N/A 127, // 198 0xc6 Not_Used
4632N/A 127, // 199 0xc7 Not_Used
4632N/A 127, // 200 0xc8 Not_Used
4632N/A 127, // 201 0xc9 Not_Used
4632N/A 127, // 202 0xca Not_Used
4632N/A 127, // 203 0xcb Not_Used
4632N/A 127, // 204 0xcc Not_Used
4632N/A 127, // 205 0xcd Not_Used
4632N/A 127, // 206 0xce Not_Used
4632N/A 127, // 207 0xcf Not_Used
4632N/A 127, // 208 0xd0 Not_Used
4632N/A 127, // 209 0xd1 Not_Used
4632N/A 127, // 210 0xd2 Not_Used
4632N/A 127, // 211 0xd3 Not_Used
4632N/A 127, // 212 0xd4 Not_Used
4632N/A 127, // 213 0xd5 Not_Used
4632N/A 127, // 214 0xd6 Not_Used
4632N/A 127, // 215 0xd7 Not_Used
4632N/A 127, // 216 0xd8 Not_Used
4632N/A 127, // 217 0xd9 Not_Used
4632N/A 127, // 218 0xda Not_Used
4632N/A 127, // 219 0xdb Not_Used
4632N/A 127, // 220 0xdc Not_Used
4632N/A 127, // 221 0xdd Not_Used
4632N/A 39 // 222 0xde VK_QUOTE
4632N/A};
4632N/A
4632N/A// NOTE: All values above 222 don't have an equivalent on MacOSX.
4632N/Astatic inline CGKeyCode GetCGKeyCode(jint javaKeyCode)
4632N/A{
4632N/A if (javaKeyCode > 222) {
4632N/A return 127;
4632N/A } else {
4632N/A return javaToMacKeyCode[javaKeyCode];
4632N/A }
4632N/A}
4639N/A
4647N/Astatic int GetClickCount(BOOL isDown) {
4639N/A NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];
4639N/A NSTimeInterval clickInterval = now - gsLastClickTime;
4647N/A BOOL isWithinTreshold = clickInterval < [NSEvent doubleClickInterval];
4647N/A
4639N/A if (isDown) {
4639N/A if (isWithinTreshold) {
4639N/A gsClickCount++;
4639N/A } else {
4647N/A gsClickCount = 1;
4639N/A }
4647N/A
4639N/A gsLastClickTime = now;
4647N/A } else {
4647N/A // In OS X, a mouse up has the click count of the last mouse down
4639N/A // if an interval between up and down is within the double click
4639N/A // threshold, and 0 otherwise.
4639N/A if (!isWithinTreshold) {
4639N/A gsClickCount = 0;
4639N/A }
4639N/A }
4647N/A
4639N/A return gsClickCount;
4639N/A}