alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (CRobot.m)

This example Java source code file (CRobot.m) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

cfrelease, cgeventref, cgeventtype, cgkeycode, cgmousebutton, cgpoint, cgrect, handlerobotbutton, jnicall, jnienv, jniexport, no_equivalent, not_used, null

The CRobot.m Java example source code

/*
 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#import <JavaNativeFoundation/JavaNativeFoundation.h>
#import <ApplicationServices/ApplicationServices.h>

#import "LWCToolkit.h"
#import "sun_lwawt_macosx_CRobot.h"
#import "java_awt_event_InputEvent.h"
#import "sizecalc.h"


// Starting number for event numbers generated by Robot.
// Apple docs don't mention at all what are the requirements
// for these numbers. It seems that they must be higher
// than event numbers from real events, which start at some
// value close to zero. There is no API for obtaining current
// event number, so we have to start from some random number.
// 32000 as starting value works for me, let's hope that it will
// work for others as well.
#define ROBOT_EVENT_NUMBER_START 32000

#define k_JAVA_ROBOT_WHEEL_COUNT 1

#if !defined(kCGBitmapByteOrder32Host)
#define kCGBitmapByteOrder32Host 0
#endif

// In OS X, left and right mouse button share the same click count.
// That is, if one starts clicking the left button rapidly and then
// switches to the right button, then the click count will continue
// increasing, without dropping to 1 in between. The middle button,
// however, has its own click count.
// For robot, we aren't going to emulate all that complexity. All our
// synhtetic clicks share the same click count.
static int gsClickCount;
static NSTimeInterval gsLastClickTime;

// Apparently, for mouse up/down events we have to set an event number
// that is incremented on each button press. Otherwise, strange things
// happen with z-order.
static int gsEventNumber;
static int* gsButtonEventNumber;

static inline CGKeyCode GetCGKeyCode(jint javaKeyCode);

static void PostMouseEvent(const CGPoint point, CGMouseButton button,
                           CGEventType type, int clickCount, int eventNumber);

static int GetClickCount(BOOL isDown);

static void
CreateJavaException(JNIEnv* env, CGError err)
{
    // Throw a java exception indicating what is wrong.
    NSString* s = [NSString stringWithFormat:@"Robot: CGError: %d", err];
    (*env)->ThrowNew(env, (*env)->FindClass(env, "java/awt/AWTException"),
                     [s UTF8String]);
}

/*
 * Class:     sun_lwawt_macosx_CRobot
 * Method:    initRobot
 * Signature: (V)V
 */
JNIEXPORT void JNICALL
Java_sun_lwawt_macosx_CRobot_initRobot
(JNIEnv *env, jobject peer)
{
    // Set things up to let our app act like a synthetic keyboard and mouse.
    // Always set all states, in case Apple ever changes default behaviors.
    static int setupDone = 0;
    if (!setupDone) {
        int i;
        jint* tmp;
        jboolean copy = JNI_FALSE;

        setupDone = 1;
        // Don't block local events after posting ours
        CGSetLocalEventsSuppressionInterval(0.0);

        // Let our event's modifier key state blend with local hardware events
        CGEnableEventStateCombining(TRUE);

        // Don't let our events block local hardware events
        CGSetLocalEventsFilterDuringSupressionState(
                                    kCGEventFilterMaskPermitAllEvents,
                                    kCGEventSupressionStateSupressionInterval);
        CGSetLocalEventsFilterDuringSupressionState(
                                    kCGEventFilterMaskPermitAllEvents,
                                    kCGEventSupressionStateRemoteMouseDrag);

        gsClickCount = 0;
        gsLastClickTime = 0;
        gsEventNumber = ROBOT_EVENT_NUMBER_START;

        gsButtonEventNumber = (int*)SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(int), gNumberOfButtons);
        if (gsButtonEventNumber == NULL) {
            JNU_ThrowOutOfMemoryError(env, NULL);
            return;
        }

        for (i = 0; i < gNumberOfButtons; ++i) {
            gsButtonEventNumber[i] = ROBOT_EVENT_NUMBER_START;
        }
    }
}

/*
 * Class:     sun_lwawt_macosx_CRobot
 * Method:    mouseEvent
 * Signature: (IIIIZZ)V
 */
JNIEXPORT void JNICALL
Java_sun_lwawt_macosx_CRobot_mouseEvent
(JNIEnv *env, jobject peer,
 jint displayID, jint mouseLastX, jint mouseLastY, jint buttonsState,
 jboolean isButtonsDownState, jboolean isMouseMove)
{
    JNF_COCOA_ENTER(env);

    // This is the native method called when Robot mouse events occur.
    // The CRobot tracks the mouse position, and which button was
    // pressed. If the mouse position is unknown it is obtained from
    // CGEvents. The peer also tracks the mouse button desired state,
    // the appropriate key modifier state, and whether the mouse action
    // is simply a mouse move with no mouse button state changes.

    CGError err = kCGErrorSuccess;

    CGRect globalDeviceBounds = CGDisplayBounds(displayID);

    // Set unknown mouse location, if needed.
    if ((mouseLastX == sun_lwawt_macosx_CRobot_MOUSE_LOCATION_UNKNOWN) ||
        (mouseLastY == sun_lwawt_macosx_CRobot_MOUSE_LOCATION_UNKNOWN))
    {
        CGEventRef event = CGEventCreate(NULL);
        if (event == NULL) {
            return;
        }

        CGPoint globalPos = CGEventGetLocation(event);
        CFRelease(event);

        // Normalize the coords within this display device, as
        // per Robot rules.
        if (globalPos.x < CGRectGetMinX(globalDeviceBounds)) {
            globalPos.x = CGRectGetMinX(globalDeviceBounds);
        }
        else if (globalPos.x > CGRectGetMaxX(globalDeviceBounds)) {
            globalPos.x = CGRectGetMaxX(globalDeviceBounds);
        }

        if (globalPos.y < CGRectGetMinY(globalDeviceBounds)) {
            globalPos.y = CGRectGetMinY(globalDeviceBounds);
        }
        else if (globalPos.y > CGRectGetMaxY(globalDeviceBounds)) {
            globalPos.y = CGRectGetMaxY(globalDeviceBounds);
        }

        mouseLastX = (jint)globalPos.x;
        mouseLastY = (jint)globalPos.y;
    }

    // volatile, otherwise it warns that it might be clobbered by 'longjmp'
    volatile CGPoint point;

    // Translate the device relative point into a valid global CGPoint.
    point.x = mouseLastX + globalDeviceBounds.origin.x;
    point.y = mouseLastY + globalDeviceBounds.origin.y;

    __block CGMouseButton button = kCGMouseButtonLeft;
    __block CGEventType type = kCGEventMouseMoved;

    void (^HandleRobotButton)(CGMouseButton, CGEventType, CGEventType, CGEventType) =
        ^(CGMouseButton cgButton, CGEventType cgButtonUp, CGEventType cgButtonDown,
          CGEventType cgButtonDragged) {

            button = cgButton;
            type = cgButtonUp;

            if (isButtonsDownState) {
                if (isMouseMove) {
                    type = cgButtonDragged;
                } else {
                    type = cgButtonDown;
                }
            }
        };

    // Left
    if (buttonsState & java_awt_event_InputEvent_BUTTON1_MASK ||
        buttonsState & java_awt_event_InputEvent_BUTTON1_DOWN_MASK ) {

        HandleRobotButton(kCGMouseButtonLeft, kCGEventLeftMouseUp,
                          kCGEventLeftMouseDown, kCGEventLeftMouseDragged);
    }

    // Other
    if (buttonsState & java_awt_event_InputEvent_BUTTON2_MASK ||
        buttonsState & java_awt_event_InputEvent_BUTTON2_DOWN_MASK ) {

        HandleRobotButton(kCGMouseButtonCenter, kCGEventOtherMouseUp,
                          kCGEventOtherMouseDown, kCGEventOtherMouseDragged);
    }

    // Right
    if (buttonsState & java_awt_event_InputEvent_BUTTON3_MASK ||
        buttonsState & java_awt_event_InputEvent_BUTTON3_DOWN_MASK ) {

        HandleRobotButton(kCGMouseButtonRight, kCGEventRightMouseUp,
                          kCGEventRightMouseDown, kCGEventRightMouseDragged);
    }

    // Extra
    if (gNumberOfButtons > 3) {
        int extraButton;
        for (extraButton = 3; extraButton < gNumberOfButtons; ++extraButton) {
            if ((buttonsState & gButtonDownMasks[extraButton])) {
                HandleRobotButton(extraButton, kCGEventOtherMouseUp,
                            kCGEventOtherMouseDown, kCGEventOtherMouseDragged);
            }
        }
    }

    int clickCount = 0;
    int eventNumber = gsEventNumber;

    if (isMouseMove) {
        // any mouse movement resets click count
        gsLastClickTime = 0;
    } else {
        clickCount = GetClickCount(isButtonsDownState);

        if (isButtonsDownState) {
            gsButtonEventNumber[button] = gsEventNumber++;
        }
        eventNumber = gsButtonEventNumber[button];
    }

    PostMouseEvent(point, button, type, clickCount, eventNumber);

    JNF_COCOA_EXIT(env);
}

/*
 * Class:     sun_lwawt_macosx_CRobot
 * Method:    mouseWheel
 * Signature: (I)V
 */
JNIEXPORT void JNICALL
Java_sun_lwawt_macosx_CRobot_mouseWheel
(JNIEnv *env, jobject peer, jint wheelAmt)
{
    CGEventRef event = CGEventCreateScrollWheelEvent(NULL,
                                            kCGScrollEventUnitLine,
                                            k_JAVA_ROBOT_WHEEL_COUNT, wheelAmt);

    if (event != NULL) {
        CGEventPost(kCGSessionEventTap, event);
        CFRelease(event);
    }
}

/*
 * Class:     sun_lwawt_macosx_CRobot
 * Method:    keyEvent
 * Signature: (IZ)V
 */
JNIEXPORT void JNICALL
Java_sun_lwawt_macosx_CRobot_keyEvent
(JNIEnv *env, jobject peer, jint javaKeyCode, jboolean keyPressed)
{
    /*
     * Well, using CGEventCreateKeyboardEvent/CGEventPost would have been
     * a better solution, however, it gives me all kinds of trouble and I have
     * no idea how to solve them without inserting delays between simulated
     * events. So, I've ended up disabling it and opted for another approach
     * that uses Accessibility API instead.
     */
    CGKeyCode keyCode = GetCGKeyCode(javaKeyCode);
    AXUIElementRef elem = AXUIElementCreateSystemWide();
    AXUIElementPostKeyboardEvent(elem, (CGCharCode)0, keyCode, keyPressed);
    CFRelease(elem);


#if 0
    CGEventRef event = CGEventCreateKeyboardEvent(NULL, keyCode, keyPressed);
    if (event != NULL) {
        CGEventPost(kCGSessionEventTap, event);
        CFRelease(event);
    }
#endif
}

/*
 * Class:     sun_lwawt_macosx_CRobot
 * Method:    nativeGetScreenPixels
 * Signature: (IIIII[I)V
 */
JNIEXPORT void JNICALL
Java_sun_lwawt_macosx_CRobot_nativeGetScreenPixels
(JNIEnv *env, jobject peer,
 jint x, jint y, jint width, jint height, jintArray pixels)
{
    JNF_COCOA_ENTER(env);

    jint picX = x;
    jint picY = y;
    jint picWidth = width;
    jint picHeight = height;

    CGRect screenRect = CGRectMake(picX, picY, picWidth, picHeight);
    CGImageRef screenPixelsImage = CGWindowListCreateImage(screenRect,
                                        kCGWindowListOptionOnScreenOnly,
                                        kCGNullWindowID, kCGWindowImageDefault);

    if (screenPixelsImage == NULL) {
        return;
    }

    // get a pointer to the Java int array
    void *jPixelData = (*env)->GetPrimitiveArrayCritical(env, pixels, 0);

    // create a graphics context around the Java int array
    CGColorSpaceRef picColorSpace = CGColorSpaceCreateWithName(
                                            kCGColorSpaceGenericRGB);
    CGContextRef jPicContextRef = CGBitmapContextCreate(
                                            jPixelData,
                                            picWidth, picHeight,
                                            8, picWidth * sizeof(jint),
                                            picColorSpace,
                                            kCGBitmapByteOrder32Host |
                                            kCGImageAlphaPremultipliedFirst);

    CGColorSpaceRelease(picColorSpace);

    // flip, scale, and color correct the screen image into the Java pixels
    CGRect bounds = { { 0, 0 }, { picWidth, picHeight } };
    CGContextDrawImage(jPicContextRef, bounds, screenPixelsImage);
    CGContextFlush(jPicContextRef);

    // cleanup
    CGContextRelease(jPicContextRef);
    CGImageRelease(screenPixelsImage);

    // release the Java int array back up to the JVM
    (*env)->ReleasePrimitiveArrayCritical(env, pixels, jPixelData, 0);

    JNF_COCOA_EXIT(env);
}

/****************************************************
 * Helper methods
 ****************************************************/

static void PostMouseEvent(const CGPoint point, CGMouseButton button,
                           CGEventType type, int clickCount, int eventNumber)
{
    CGEventRef mouseEvent = CGEventCreateMouseEvent(NULL, type, point, button);
    if (mouseEvent != NULL) {
        CGEventSetIntegerValueField(mouseEvent, kCGMouseEventClickState, clickCount);
        CGEventSetIntegerValueField(mouseEvent, kCGMouseEventNumber, eventNumber);
        CGEventPost(kCGSessionEventTap, mouseEvent);
        CFRelease(mouseEvent);
    }
}

// NOTE: Don't modify this table directly. It is machine generated. See below.
static const unsigned char javaToMacKeyCode[] = {
    127,    //     0     0 VK_UNDEFINED                      No_Equivalent
    127,    //     1   0x1 Not_Used
    127,    //     2   0x2 Not_Used
    127,    //     3   0x3 VK_CANCEL                         No_Equivalent
    127,    //     4   0x4 Not_Used
    127,    //     5   0x5 Not_Used
    127,    //     6   0x6 Not_Used
    127,    //     7   0x7 Not_Used
     51,    //     8   0x8 VK_BACK_SPACE
     48,    //     9   0x9 VK_TAB
     36,    //    10   0xa VK_ENTER
    127,    //    11   0xb Not_Used
     71,    //    12   0xc VK_CLEAR
    127,    //    13   0xd Not_Used
    127,    //    14   0xe Not_Used
    127,    //    15   0xf Not_Used
     56,    //    16  0x10 VK_SHIFT
     59,    //    17  0x11 VK_CONTROL
     58,    //    18  0x12 VK_ALT
    113,    //    19  0x13 VK_PAUSE
     57,    //    20  0x14 VK_CAPS_LOCK
    127,    //    21  0x15 VK_KANA                           No_Equivalent
    127,    //    22  0x16 Not_Used
    127,    //    23  0x17 Not_Used
    127,    //    24  0x18 VK_FINAL                          No_Equivalent
    127,    //    25  0x19 VK_KANJI                          No_Equivalent
    127,    //    26  0x1a Not_Used
     53,    //    27  0x1b VK_ESCAPE
    127,    //    28  0x1c VK_CONVERT                        No_Equivalent
    127,    //    29  0x1d VK_NONCONVERT                     No_Equivalent
    127,    //    30  0x1e VK_ACCEPT                         No_Equivalent
    127,    //    31  0x1f VK_MODECHANGE                     No_Equivalent
     49,    //    32  0x20 VK_SPACE
    116,    //    33  0x21 VK_PAGE_UP
    121,    //    34  0x22 VK_PAGE_DOWN
    119,    //    35  0x23 VK_END
    115,    //    36  0x24 VK_HOME
    123,    //    37  0x25 VK_LEFT
    126,    //    38  0x26 VK_UP
    124,    //    39  0x27 VK_RIGHT
    125,    //    40  0x28 VK_DOWN
    127,    //    41  0x29 Not_Used
    127,    //    42  0x2a Not_Used
    127,    //    43  0x2b Not_Used
     43,    //    44  0x2c VK_COMMA
     27,    //    45  0x2d VK_MINUS
     47,    //    46  0x2e VK_PERIOD
     44,    //    47  0x2f VK_SLASH
     29,    //    48  0x30 VK_0
     18,    //    49  0x31 VK_1
     19,    //    50  0x32 VK_2
     20,    //    51  0x33 VK_3
     21,    //    52  0x34 VK_4
     23,    //    53  0x35 VK_5
     22,    //    54  0x36 VK_6
     26,    //    55  0x37 VK_7
     28,    //    56  0x38 VK_8
     25,    //    57  0x39 VK_9
    127,    //    58  0x3a Not_Used
     41,    //    59  0x3b VK_SEMICOLON
    127,    //    60  0x3c Not_Used
     24,    //    61  0x3d VK_EQUALS
    127,    //    62  0x3e Not_Used
    127,    //    63  0x3f Not_Used
    127,    //    64  0x40 Not_Used
      0,    //    65  0x41 VK_A
     11,    //    66  0x42 VK_B
      8,    //    67  0x43 VK_C
      2,    //    68  0x44 VK_D
     14,    //    69  0x45 VK_E
      3,    //    70  0x46 VK_F
      5,    //    71  0x47 VK_G
      4,    //    72  0x48 VK_H
     34,    //    73  0x49 VK_I
     38,    //    74  0x4a VK_J
     40,    //    75  0x4b VK_K
     37,    //    76  0x4c VK_L
     46,    //    77  0x4d VK_M
     45,    //    78  0x4e VK_N
     31,    //    79  0x4f VK_O
     35,    //    80  0x50 VK_P
     12,    //    81  0x51 VK_Q
     15,    //    82  0x52 VK_R
      1,    //    83  0x53 VK_S
     17,    //    84  0x54 VK_T
     32,    //    85  0x55 VK_U
      9,    //    86  0x56 VK_V
     13,    //    87  0x57 VK_W
      7,    //    88  0x58 VK_X
     16,    //    89  0x59 VK_Y
      6,    //    90  0x5a VK_Z
     33,    //    91  0x5b VK_OPEN_BRACKET
     42,    //    92  0x5c VK_BACK_SLASH
     30,    //    93  0x5d VK_CLOSE_BRACKET
    127,    //    94  0x5e Not_Used
    127,    //    95  0x5f Not_Used
     82,    //    96  0x60 VK_NUMPAD0
     83,    //    97  0x61 VK_NUMPAD1
     84,    //    98  0x62 VK_NUMPAD2
     85,    //    99  0x63 VK_NUMPAD3
     86,    //   100  0x64 VK_NUMPAD4
     87,    //   101  0x65 VK_NUMPAD5
     88,    //   102  0x66 VK_NUMPAD6
     89,    //   103  0x67 VK_NUMPAD7
     91,    //   104  0x68 VK_NUMPAD8
     92,    //   105  0x69 VK_NUMPAD9
     67,    //   106  0x6a VK_MULTIPLY
     69,    //   107  0x6b VK_ADD
    127,    //   108  0x6c VK_SEPARATER                      No_Equivalent
     78,    //   109  0x6d VK_SUBTRACT
     65,    //   110  0x6e VK_DECIMAL
     75,    //   111  0x6f VK_DIVIDE
    122,    //   112  0x70 VK_F1
    120,    //   113  0x71 VK_F2
     99,    //   114  0x72 VK_F3
    118,    //   115  0x73 VK_F4
     96,    //   116  0x74 VK_F5
     97,    //   117  0x75 VK_F6
     98,    //   118  0x76 VK_F7
    100,    //   119  0x77 VK_F8
    101,    //   120  0x78 VK_F9
    109,    //   121  0x79 VK_F10
    103,    //   122  0x7a VK_F11
    111,    //   123  0x7b VK_F12
    127,    //   124  0x7c Not_Used
    127,    //   125  0x7d Not_Used
    127,    //   126  0x7e Not_Used
    117,    //   127  0x7f VK_DELETE
    127,    //   128  0x80 VK_DEAD_GRAVE                     No_Equivalent
    127,    //   129  0x81 VK_DEAD_ACUTE                     No_Equivalent
    127,    //   130  0x82 VK_DEAD_CIRCUMFLEX                No_Equivalent
    127,    //   131  0x83 VK_DEAD_TILDE                     No_Equivalent
    127,    //   132  0x84 VK_DEAD_MACRON                    No_Equivalent
    127,    //   133  0x85 VK_DEAD_BREVE                     No_Equivalent
    127,    //   134  0x86 VK_DEAD_ABOVEDOT                  No_Equivalent
    127,    //   135  0x87 VK_DEAD_DIAERESIS                 No_Equivalent
    127,    //   136  0x88 VK_DEAD_ABOVERING                 No_Equivalent
    127,    //   137  0x89 VK_DEAD_DOUBLEACUTE               No_Equivalent
    127,    //   138  0x8a VK_DEAD_CARON                     No_Equivalent
    127,    //   139  0x8b VK_DEAD_CEDILLA                   No_Equivalent
    127,    //   140  0x8c VK_DEAD_OGONEK                    No_Equivalent
    127,    //   141  0x8d VK_DEAD_IOTA                      No_Equivalent
    127,    //   142  0x8e VK_DEAD_VOICED_SOUND              No_Equivalent
    127,    //   143  0x8f VK_DEAD_SEMIVOICED_SOUND          No_Equivalent
    127,    //   144  0x90 VK_NUM_LOCK                       No_Equivalent
    107,    //   145  0x91 VK_SCROLL_LOCK
    127,    //   146  0x92 Not_Used
    127,    //   147  0x93 Not_Used
    127,    //   148  0x94 Not_Used
    127,    //   149  0x95 Not_Used
    127,    //   150  0x96 VK_AMPERSAND                      No_Equivalent
    127,    //   151  0x97 VK_ASTERISK                       No_Equivalent
    127,    //   152  0x98 VK_QUOTEDBL                       No_Equivalent
    127,    //   153  0x99 VK_LESS                           No_Equivalent
    105,    //   154  0x9a VK_PRINTSCREEN
    127,    //   155  0x9b VK_INSERT                         No_Equivalent
    114,    //   156  0x9c VK_HELP
     55,    //   157  0x9d VK_META
    127,    //   158  0x9e Not_Used
    127,    //   159  0x9f Not_Used
    127,    //   160  0xa0 VK_GREATER                        No_Equivalent
    127,    //   161  0xa1 VK_BRACELEFT                      No_Equivalent
    127,    //   162  0xa2 VK_BRACERIGHT                     No_Equivalent
    127,    //   163  0xa3 Not_Used
    127,    //   164  0xa4 Not_Used
    127,    //   165  0xa5 Not_Used
    127,    //   166  0xa6 Not_Used
    127,    //   167  0xa7 Not_Used
    127,    //   168  0xa8 Not_Used
    127,    //   169  0xa9 Not_Used
    127,    //   170  0xaa Not_Used
    127,    //   171  0xab Not_Used
    127,    //   172  0xac Not_Used
    127,    //   173  0xad Not_Used
    127,    //   174  0xae Not_Used
    127,    //   175  0xaf Not_Used
    127,    //   176  0xb0 Not_Used
    127,    //   177  0xb1 Not_Used
    127,    //   178  0xb2 Not_Used
    127,    //   179  0xb3 Not_Used
    127,    //   180  0xb4 Not_Used
    127,    //   181  0xb5 Not_Used
    127,    //   182  0xb6 Not_Used
    127,    //   183  0xb7 Not_Used
    127,    //   184  0xb8 Not_Used
    127,    //   185  0xb9 Not_Used
    127,    //   186  0xba Not_Used
    127,    //   187  0xbb Not_Used
    127,    //   188  0xbc Not_Used
    127,    //   189  0xbd Not_Used
    127,    //   190  0xbe Not_Used
    127,    //   191  0xbf Not_Used
     50,    //   192  0xc0 VK_BACK_QUOTE
    127,    //   193  0xc1 Not_Used
    127,    //   194  0xc2 Not_Used
    127,    //   195  0xc3 Not_Used
    127,    //   196  0xc4 Not_Used
    127,    //   197  0xc5 Not_Used
    127,    //   198  0xc6 Not_Used
    127,    //   199  0xc7 Not_Used
    127,    //   200  0xc8 Not_Used
    127,    //   201  0xc9 Not_Used
    127,    //   202  0xca Not_Used
    127,    //   203  0xcb Not_Used
    127,    //   204  0xcc Not_Used
    127,    //   205  0xcd Not_Used
    127,    //   206  0xce Not_Used
    127,    //   207  0xcf Not_Used
    127,    //   208  0xd0 Not_Used
    127,    //   209  0xd1 Not_Used
    127,    //   210  0xd2 Not_Used
    127,    //   211  0xd3 Not_Used
    127,    //   212  0xd4 Not_Used
    127,    //   213  0xd5 Not_Used
    127,    //   214  0xd6 Not_Used
    127,    //   215  0xd7 Not_Used
    127,    //   216  0xd8 Not_Used
    127,    //   217  0xd9 Not_Used
    127,    //   218  0xda Not_Used
    127,    //   219  0xdb Not_Used
    127,    //   220  0xdc Not_Used
    127,    //   221  0xdd Not_Used
     39     //   222  0xde VK_QUOTE
};

// NOTE: All values above 222 don't have an equivalent on MacOSX.
static inline CGKeyCode GetCGKeyCode(jint javaKeyCode)
{
    if (javaKeyCode > 222) {
        return 127;
    } else {
        return javaToMacKeyCode[javaKeyCode];
    }
}

static int GetClickCount(BOOL isDown) {
    NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];
    NSTimeInterval clickInterval = now - gsLastClickTime;
    BOOL isWithinTreshold = clickInterval < [NSEvent doubleClickInterval];

    if (isDown) {
        if (isWithinTreshold) {
            gsClickCount++;
        } else {
            gsClickCount = 1;
        }

        gsLastClickTime = now;
    } else {
        // In OS X, a mouse up has the click count of the last mouse down
        // if an interval between up and down is within the double click
        // threshold, and 0 otherwise.
        if (!isWithinTreshold) {
            gsClickCount = 0;
        }
    }

    return gsClickCount;
}

Other Java examples (source code examples)

Here is a short list of links related to this Java CRobot.m source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.