changeset 4643:f9fd4c285876

7124289: [macosx] Modal behavior difference with and without Robot interaction Reviewed-by: anthony
author leonidr
date Fri, 30 Dec 2011 17:32:06 +0300
parents 9dfe50f456be
children ab26116ef4fc
files src/macosx/native/sun/awt/CRobot.m
diffstat 1 files changed, 62 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/macosx/native/sun/awt/CRobot.m	Fri Dec 30 17:37:53 2011 +0300
+++ b/src/macosx/native/sun/awt/CRobot.m	Fri Dec 30 17:32:06 2011 +0300
@@ -30,6 +30,16 @@
 #import "LWCToolkit.h"
 #import "sun_lwawt_macosx_CRobot.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
+
 // Theoretically, Quarts works with up to 32 buttons.
 #define k_JAVA_ROBOT_NUMBER_KNOWN_BUTTONS    3
 #define k_JAVA_ROBOT_WHEEL_COUNT 1
@@ -48,10 +58,15 @@
 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 inline CGKeyCode GetCGKeyCode(jint javaKeyCode);
 
-static void postMouseEvent(const CGPoint point, CGMouseButton button, 
-                           CGEventType type, int clickCount);
+static void PostMouseEvent(const CGPoint point, CGMouseButton button,
+                           CGEventType type, int clickCount, int eventNumber);
 
 static int GetClickCount(BOOL isDown);
 
@@ -76,7 +91,7 @@
     // 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) {        
+    if (!setupDone) {
         setupDone = 1;
         // Don't block local events after posting ours
         CGSetLocalEventsSuppressionInterval(0.0);
@@ -91,9 +106,11 @@
         CGSetLocalEventsFilterDuringSupressionState(
                                     kCGEventFilterMaskPermitAllEvents,
                                     kCGEventSupressionStateRemoteMouseDrag);
-        
+
         gsClickCount = 0;
         gsLastClickTime = 0;
+
+        gsEventNumber = ROBOT_EVENT_NUMBER_START;
     }
 }
 
@@ -167,6 +184,7 @@
     CGMouseButton button = kCGMouseButtonLeft;
     CGEventType type = kCGEventMouseMoved;
     int clickCount = 0;
+    int eventNumber = gsEventNumber;
 
     // When moving, the buttons aren't changed from their current state.
     if (mouseMoveAction == JNI_FALSE) {
@@ -174,39 +192,57 @@
 
         // Left
         if (mouse1State != sun_lwawt_macosx_CRobot_BUTTON_STATE_UNKNOWN) {
+            static int sEventNumber = ROBOT_EVENT_NUMBER_START;
+
             button = kCGMouseButtonLeft;
             if (mouse1State == sun_lwawt_macosx_CRobot_BUTTON_STATE_DOWN) {
+                sEventNumber = gsEventNumber++;
                 type = kCGEventLeftMouseDown;
                 isDown = YES;
             } else {
                 type = kCGEventLeftMouseUp;
             }
+
+            eventNumber = sEventNumber;
         }
 
         // Other
         if (mouse2State != sun_lwawt_macosx_CRobot_BUTTON_STATE_UNKNOWN) {
+            static int sEventNumber = ROBOT_EVENT_NUMBER_START;
+
             button = kCGMouseButtonCenter;
             if (mouse2State == sun_lwawt_macosx_CRobot_BUTTON_STATE_DOWN) {
+                sEventNumber = gsEventNumber++;
                 type = kCGEventOtherMouseDown;
                 isDown = YES;
             } else {
                 type = kCGEventOtherMouseUp;
             }
+
+            eventNumber = sEventNumber;
         }
 
         // Right
         if (mouse3State != sun_lwawt_macosx_CRobot_BUTTON_STATE_UNKNOWN) {
+            static int sEventNumber = ROBOT_EVENT_NUMBER_START;
+
             button = kCGMouseButtonRight;
             if (mouse3State == sun_lwawt_macosx_CRobot_BUTTON_STATE_DOWN) {
+                sEventNumber = gsEventNumber++;
                 type = kCGEventRightMouseDown;
                 isDown = YES;
             } else {
                 type = kCGEventRightMouseUp;
             }
+
+            eventNumber = sEventNumber;
         }
-        
-        clickCount = GetClickCount(isDown);        
+
+        clickCount = GetClickCount(isDown);
     } else {
+        // any mouse movement resets click count
+        gsLastClickTime = 0;
+
         // could be mouse moved or mouse dragged
         if (mouse1State == sun_lwawt_macosx_CRobot_BUTTON_STATE_DOWN) {
             type = kCGEventLeftMouseDragged;
@@ -219,7 +255,7 @@
         }
     }
 
-    postMouseEvent(point, button, type, clickCount);    
+    PostMouseEvent(point, button, type, clickCount, eventNumber);
 
     JNF_COCOA_EXIT(env);
 }
@@ -253,18 +289,18 @@
 (JNIEnv *env, jobject peer, jint javaKeyCode, jboolean keyPressed)
 {
     /*
-     * Well, using CGEventCreateKeyboardEvent/CGEventPost would have been 
+     * 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. 
+     * 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();    
+    AXUIElementRef elem = AXUIElementCreateSystemWide();
     AXUIElementPostKeyboardEvent(elem, (CGCharCode)0, keyCode, keyPressed);
     CFRelease(elem);
 
-    
+
 #if 0
     CGEventRef event = CGEventCreateKeyboardEvent(NULL, keyCode, keyPressed);
     if (event != NULL) {
@@ -335,12 +371,13 @@
  * Helper methods
  ****************************************************/
 
-static void postMouseEvent(const CGPoint point, CGMouseButton button,
-                           CGEventType type, int clickCount)
-{ 
+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, kCGMouseEventClickState, clickCount);
+        CGEventSetIntegerValueField(mouseEvent, kCGMouseEventNumber, eventNumber);
         CGEventPost(kCGSessionEventTap, mouseEvent);
         CFRelease(mouseEvent);
     }
@@ -583,27 +620,27 @@
     }
 }
 
-static int GetClickCount(BOOL isDown) {    
+static int GetClickCount(BOOL isDown) {
     NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];
     NSTimeInterval clickInterval = now - gsLastClickTime;
-    BOOL isWithinTreshold = clickInterval < [NSEvent doubleClickInterval]; 
-    
+    BOOL isWithinTreshold = clickInterval < [NSEvent doubleClickInterval];
+
     if (isDown) {
         if (isWithinTreshold) {
             gsClickCount++;
         } else {
-            gsClickCount = 1;        
+            gsClickCount = 1;
         }
-        
+
         gsLastClickTime = now;
-    } else { 
-        // In OS X, a mouse up has the click count of the last mouse down 
+    } 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;
 }