diff options
author | Sven Gothel <[email protected]> | 2013-11-17 01:54:32 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-11-17 01:54:32 +0100 |
commit | 88f6e0012b36ca69dedaadb4e403e2a424b20cbf (patch) | |
tree | ee43887c90dda1e02b5bb488a04b5287dfcd4048 /src | |
parent | ebed9f0322e2a2279a525e04ee3875c9034a7f45 (diff) |
Bug 903 - NEWT: Support 'Continue Drag on Exit'; Consistent Mouse ENTER/EXIT
- Support 'Continue Drag on Exit'
- Track dragging operation, allow exterior dragging
- Hence track EXIT (see below)
- Windows:
- Capture mouse for exterior dragging
- Only 'NewtWindows_trackPointerLeave' if 'entering'
- Simplify touch: No 'inside' check - Not required.
- Consistent Mouse ENTER/EXIT
- Track ENTER/EXIT and synthesize if required, drop duplicate
- OSX benefits, since it never produced ENTER/EXIT events
- AWT (or other TK) translated events beahve equal now.
- Required for EXIT event after ending exterior dragging and final RELEASE
Tests: Passed unit tests 'junit.run.newt.event' on
- GNU/Linux
- Windows7
- OSX 10.7
Tested exterior tracking manually w/ NEWT TestGearsES2NEWT and TestGearsES2NewtCanvasAWT:
- GNU/Linux
- Windows7 (mouse)
- Windows8.1 (touch)
- OSX 10.7
Diffstat (limited to 'src')
-rw-r--r-- | src/newt/classes/com/jogamp/newt/event/MouseEvent.java | 2 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/event/MouseListener.java | 2 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/WindowImpl.java | 236 | ||||
-rw-r--r-- | src/newt/native/InputEvent.h | 6 | ||||
-rw-r--r-- | src/newt/native/WindowsWindow.c | 132 |
5 files changed, 257 insertions, 121 deletions
diff --git a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java index 635bdba52..272e4beb0 100644 --- a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java @@ -589,7 +589,9 @@ public class MouseEvent extends InputEvent private static final PointerType[] constMousePointerTypes = new PointerType[] { PointerType.Mouse }; public static final short EVENT_MOUSE_CLICKED = 200; + /** Only generated for {@link PointerType#Mouse} */ public static final short EVENT_MOUSE_ENTERED = 201; + /** Only generated for {@link PointerType#Mouse} */ public static final short EVENT_MOUSE_EXITED = 202; public static final short EVENT_MOUSE_PRESSED = 203; public static final short EVENT_MOUSE_RELEASED = 204; diff --git a/src/newt/classes/com/jogamp/newt/event/MouseListener.java b/src/newt/classes/com/jogamp/newt/event/MouseListener.java index 5378080b9..6e5142044 100644 --- a/src/newt/classes/com/jogamp/newt/event/MouseListener.java +++ b/src/newt/classes/com/jogamp/newt/event/MouseListener.java @@ -44,7 +44,9 @@ import com.jogamp.newt.event.MouseEvent.PointerType; public interface MouseListener extends NEWTEventListener { public void mouseClicked(MouseEvent e); + /** Only generated for {@link PointerType#Mouse} */ public void mouseEntered(MouseEvent e); + /** Only generated for {@link PointerType#Mouse} */ public void mouseExited(MouseEvent e); public void mousePressed(MouseEvent e); public void mouseReleased(MouseEvent e); diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 246c288d0..99e863a0e 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -186,37 +186,45 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer /** from event passing: {@link WindowImpl#consumePointerEvent(MouseEvent)}. */ private static class PointerState0 { - /** mouse entered window - is inside the window (may be synthetic) */ + /** Pointer entered window - is inside the window (may be synthetic) */ boolean insideWindow = false; + /** Mouse EXIT has been sent (only for MOUSE type enter/exit)*/ + boolean exitSent = false; - /** last time when a mouse button was pressed */ + /** last time when a pointer button was pressed */ long lastButtonPressTime = 0; + /** Pointer in dragging mode */ + boolean dragging = false; + void clearButton() { lastButtonPressTime = 0; } + public String toString() { return "PState0[inside "+insideWindow+", exitSent "+exitSent+", lastPress "+lastButtonPressTime+", dragging "+dragging+"]"; } } private final PointerState0 pState0 = new PointerState0(); /** from direct input: {@link WindowImpl#doPointerEvent(boolean, boolean, int[], short, int, int, boolean, short[], int[], int[], float[], float, float[], float)}. */ private static class PointerState1 extends PointerState0 { - /** current pressed mouse button number */ + /** Current pressed mouse button number */ short buttonPressed = (short)0; - /** current pressed mouse button modifier mask */ + /** Current pressed mouse button modifier mask */ int buttonPressedMask = 0; - /** last mouse button click count */ + /** Last mouse button click count */ short lastButtonClickCount = (short)0; @Override final void clearButton() { super.clearButton(); - lastButtonPressTime = 0; lastButtonClickCount = (short)0; - buttonPressed = 0; - buttonPressedMask = 0; + if( !dragging || 0 == buttonPressedMask ) { + buttonPressed = 0; + buttonPressedMask = 0; + dragging = false; + } } - /** last pointer-move position for 8 touch-down pointers */ + /** Last pointer-move position for 8 touch-down pointers */ final Point[] movePositions = new Point[] { new Point(), new Point(), new Point(), new Point(), new Point(), new Point(), new Point(), new Point() }; @@ -226,10 +234,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } return null; } + public final String toString() { return "PState1[inside "+insideWindow+", exitSent "+exitSent+", lastPress "+lastButtonPressTime+ + ", pressed [button "+buttonPressed+", mask "+buttonPressedMask+", dragging "+dragging+", clickCount "+lastButtonClickCount+"]"; } } private final PointerState1 pState1 = new PointerState1(); - /** pointer names -> pointer ID (consecutive index, starting w/ 0) */ + /** Pointer names -> pointer ID (consecutive index, starting w/ 0) */ private final ArrayHashSet<Integer> pName2pID = new ArrayHashSet<Integer>(); private boolean defaultGestureHandlerEnabled = true; @@ -2365,25 +2375,25 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // Native MouseEvents pre-processed to be enqueued or consumed directly // - public final void sendMouseEvent(short eventType, int modifiers, - int x, int y, short button, float rotation) { + public final void sendMouseEvent(final short eventType, final int modifiers, + final int x, final int y, final short button, final float rotation) { doMouseEvent(false, false, eventType, modifiers, x, y, button, MouseEvent.getRotationXYZ(rotation, modifiers), 1f); } - public final void enqueueMouseEvent(boolean wait, short eventType, int modifiers, - int x, int y, short button, float rotation) { + public final void enqueueMouseEvent(final boolean wait, final short eventType, final int modifiers, + final int x, final int y, final short button, final float rotation) { doMouseEvent(true, wait, eventType, modifiers, x, y, button, MouseEvent.getRotationXYZ(rotation, modifiers), 1f); } - protected final void doMouseEvent(boolean enqueue, boolean wait, short eventType, int modifiers, - int x, int y, short button, float rotation) { + protected final void doMouseEvent(final boolean enqueue, final boolean wait, final short eventType, final int modifiers, + final int x, final int y, final short button, final float rotation) { doMouseEvent(enqueue, wait, eventType, modifiers, x, y, button, MouseEvent.getRotationXYZ(rotation, modifiers), 1f); } /** - public final void sendMouseEvent(short eventType, int modifiers, - int x, int y, short button, float[] rotationXYZ, float rotationScale) { + public final void sendMouseEvent(final short eventType, final int modifiers, + final int x, final int y, final short button, final float[] rotationXYZ, final float rotationScale) { doMouseEvent(false, false, eventType, modifiers, x, y, button, rotationXYZ, rotationScale); } - public final void enqueueMouseEvent(boolean wait, short eventType, int modifiers, - int x, int y, short button, float[] rotationXYZ, float rotationScale) { + public final void enqueueMouseEvent(final boolean wait, final short eventType, final int modifiers, + final int x, final int y, final short button, final float[] rotationXYZ, final float rotationScale) { doMouseEvent(true, wait, eventType, modifiers, x, y, button, rotationXYZ, rotationScale); } */ @@ -2394,8 +2404,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer * otherwise {@link #consumeEvent(NEWTEvent) consumed} directly. * @param wait if true wait until {@link #consumeEvent(NEWTEvent) consumed}. */ - protected void doMouseEvent(boolean enqueue, boolean wait, short eventType, int modifiers, - int x, int y, short button, final float[] rotationXYZ, float rotationScale) { + protected void doMouseEvent(final boolean enqueue, final boolean wait, final short eventType, final int modifiers, + final int x, final int y, final short button, final float[] rotationXYZ, final float rotationScale) { if( 0 > button || button > MouseEvent.BUTTON_COUNT ) { throw new NativeWindowException("Invalid mouse button number" + button); } @@ -2437,10 +2447,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer * @param pPressure Pressure for each pointer (multiple pointer) * @param maxPressure Maximum pointer pressure for all pointer */ - public final void doPointerEvent(boolean enqueue, boolean wait, - final PointerType[] pTypes, short eventType, int modifiers, - int actionIdx, boolean normalPNames, final int[] pNames, - final int[] pX, final int[] pY, float[] pPressure, + public final void doPointerEvent(final boolean enqueue, final boolean wait, + final PointerType[] pTypes, final short eventType, final int modifiers, + final int actionIdx, final boolean normalPNames, final int[] pNames, + final int[] pX, final int[] pY, final float[] pPressure, float maxPressure, final float[] rotationXYZ, final float rotationScale) { final int pCount = pNames.length; final short[] pIDs = new short[pCount]; @@ -2511,10 +2521,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer * @param pPressure Pressure for each pointer (multiple pointer) * @param maxPressure Maximum pointer pressure for all pointer */ - public final void doPointerEvent(boolean enqueue, boolean wait, - final PointerType[] pTypes, short eventType, int modifiers, - int pActionIdx, final short[] pID, final int[] pX, final int[] pY, final float[] pPressure, - float maxPressure, final float[] rotationXYZ, float rotationScale) { + public final void doPointerEvent(final boolean enqueue, final boolean wait, + final PointerType[] pTypes, final short eventType, int modifiers, + final int pActionIdx, final short[] pID, final int[] pX, final int[] pY, final float[] pPressure, + final float maxPressure, final float[] rotationXYZ, final float rotationScale) { final long when = System.currentTimeMillis(); final int pCount = pTypes.length; @@ -2565,9 +2575,19 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // int x = pX[0]; int y = pY[0]; + final boolean insideWindow = x >= 0 && y >= 0 && x < getWidth() && y < getHeight(); final Point movePositionP0 = pState1.getMovePosition(id); switch( eventType ) { case MouseEvent.EVENT_MOUSE_EXITED: + if( pState1.dragging ) { + // Drop mouse EXIT if dragging, i.e. due to exterior dragging outside of window. + // NOTE-1: X11 produces the 'premature' EXIT, however it also produces 'EXIT' after exterior dragging! + // NOTE-2: consumePointerEvent(MouseEvent) will synthesize a missing EXIT event! + if(DEBUG_MOUSE_EVENT) { + System.err.println("doPointerEvent: drop "+MouseEvent.getEventTypeString(eventType)+" due to dragging: "+pState1); + } + return; + } if( null != movePositionP0 ) { if( x==-1 && y==-1 ) { x = movePositionP0.getX(); @@ -2578,21 +2598,35 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // Fall through intended! case MouseEvent.EVENT_MOUSE_ENTERED: + if( eventType == MouseEvent.EVENT_MOUSE_ENTERED ) { + pState1.insideWindow = true; + pState1.exitSent = false; + } else { + pState1.insideWindow = false; + pState1.exitSent = true; + } + pState1.clearButton(); + if( pTypes[0] != PointerType.Mouse ) { + // Drop !MOUSE ENTER/EXIT Events - Safeguard for non compliant implementations only. + if(DEBUG_MOUSE_EVENT) { + System.err.println("doPointerEvent: drop "+MouseEvent.getEventTypeString(eventType)+" due to !Mouse but "+pTypes[0]+": "+pState1); + } + return; + } // clip coordinates to window dimension x = Math.min(Math.max(x, 0), getWidth()-1); y = Math.min(Math.max(y, 0), getHeight()-1); - pState1.insideWindow = eventType == MouseEvent.EVENT_MOUSE_ENTERED; - pState1.clearButton(); break; case MouseEvent.EVENT_MOUSE_MOVED: case MouseEvent.EVENT_MOUSE_DRAGGED: if( null != movePositionP0 ) { - if( pState1.insideWindow && movePositionP0.getX() == x && movePositionP0.getY() == y ) { + if( movePositionP0.getX() == x && movePositionP0.getY() == y ) { + // Drop same position if(DEBUG_MOUSE_EVENT) { - System.err.println("doPointerEvent: skip "+MouseEvent.getEventTypeString(eventType)+" w/ same position: "+movePositionP0); + System.err.println("doPointerEvent: drop "+MouseEvent.getEventTypeString(eventType)+" w/ same position: "+movePositionP0+", "+pState1); } - return; // skip same position + return; } movePositionP0.set(x, y); } @@ -2600,25 +2634,30 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // Fall through intended ! default: - if(!pState1.insideWindow) { - pState1.insideWindow = true; + if( pState1.insideWindow != insideWindow ) { + // ENTER/EXIT! + pState1.insideWindow = insideWindow; + if( insideWindow ) { + pState1.exitSent = false; + } pState1.clearButton(); } } // - // Drop exterior events + // Drop exterior events if not dragging pointer and not EXIT event + // Safeguard for non compliant implementations! // - if( x < 0 || y < 0 || x >= getWidth() || y >= getHeight() ) { + if( !pState1.dragging && !insideWindow && MouseEvent.EVENT_MOUSE_EXITED != eventType ) { if(DEBUG_MOUSE_EVENT) { System.err.println("doPointerEvent: drop: "+MouseEvent.getEventTypeString(eventType)+ - ", mod "+modifiers+", pos "+x+"/"+y+", button "+button+", lastMousePosition: "+movePositionP0); + ", mod "+modifiers+", pos "+x+"/"+y+", button "+button+", lastMousePosition: "+movePositionP0+", insideWindow "+insideWindow+", "+pState1); } return; // .. invalid .. } if(DEBUG_MOUSE_EVENT) { System.err.println("doPointerEvent: enqueue "+enqueue+", wait "+wait+", "+MouseEvent.getEventTypeString(eventType)+ - ", mod "+modifiers+", pos "+x+"/"+y+", button "+button+", lastMousePosition: "+movePositionP0); + ", mod "+modifiers+", pos "+x+"/"+y+", button "+button+", lastMousePosition: "+movePositionP0+", "+pState1); } final int buttonMask = InputEvent.getButtonMask(button); @@ -2668,6 +2707,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } break; case MouseEvent.EVENT_MOUSE_RELEASED: + pState1.buttonPressedMask &= ~buttonMask; if( 1 == pCount ) { e = new MouseEvent(eventType, this, when, modifiers, pTypes, pID, pX, pY, pPressure, maxPressure, button, pState1.lastButtonClickCount, rotationXYZ, rotationScale); @@ -2676,11 +2716,14 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer pState1.lastButtonPressTime = 0; } pState1.buttonPressed = 0; + pState1.dragging = false; } else { e = new MouseEvent(eventType, this, when, modifiers, pTypes, pID, pX, pY, pPressure, maxPressure, button, (short)1, rotationXYZ, rotationScale); + if( 0 == pState1.buttonPressedMask ) { + pState1.clearButton(); + } } - pState1.buttonPressedMask &= ~buttonMask; if( null != movePositionP0 ) { movePositionP0.set(0, 0); } @@ -2689,6 +2732,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if ( 0 != pState1.buttonPressedMask ) { // any button or pointer move -> drag e = new MouseEvent(MouseEvent.EVENT_MOUSE_DRAGGED, this, when, modifiers, pTypes, pID, pX, pY, pPressure, maxPressure, pState1.buttonPressed, (short)1, rotationXYZ, rotationScale); + pState1.dragging = true; } else { e = new MouseEvent(eventType, this, when, modifiers, pTypes, pID, pX, pY, pPressure, maxPressure, button, (short)0, rotationXYZ, rotationScale); @@ -2698,6 +2742,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( 0 >= pPressure[0] ) { pPressure[0] = maxPressure; } + pState1.dragging = true; // Fall through intended! default: e = new MouseEvent(eventType, this, when, modifiers, pTypes, pID, @@ -2831,7 +2876,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer * <ul> * <li>Validate</li> * <li>Handle gestures</li> - * <li>Synthesize events ENTERED, CLICK and gestures.</li> + * <li>Synthesize events [ENTERED, EXIT, CLICK] and gestures.</li> * <li>Drop exterior events</li> * <li>Dispatch event to listener</li> * </ul> @@ -2842,50 +2887,84 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer int y = pe.getY(); if(DEBUG_MOUSE_EVENT) { - System.err.println("consumePointerEvent.in: "+pe); + System.err.println("consumePointerEvent.in: "+pe+", "+pState0+", pos "+x+"/"+y+" clientSize["+getWidth()+"x"+getHeight()+"]"); } // // - Determine ENTERED/EXITED state - // - Synthesize ENTERED event + // - Synthesize ENTERED and EXIT event // - Reset states if applicable // final long when = pe.getWhen(); - int eventType = pe.getEventType(); - final MouseEvent eEntered; + final int eventType = pe.getEventType(); + final boolean insideWindow; + boolean eExitAllowed = false; + MouseEvent eEntered = null, eExited = null; switch( eventType ) { case MouseEvent.EVENT_MOUSE_EXITED: + if( pState0.exitSent || pState0.dragging ) { + if(DEBUG_MOUSE_EVENT) { + System.err.println("consumePointerEvent: drop "+(pState0.exitSent?"already sent":"due to dragging")+": "+pe+", "+pState0); + } + return; + } + // Fall through intended ! case MouseEvent.EVENT_MOUSE_ENTERED: // clip coordinates to window dimension x = Math.min(Math.max(x, 0), getWidth()-1); y = Math.min(Math.max(y, 0), getHeight()-1); - pState0.insideWindow = eventType == MouseEvent.EVENT_MOUSE_ENTERED; pState0.clearButton(); - eEntered = null; + if( eventType == MouseEvent.EVENT_MOUSE_ENTERED ) { + insideWindow = true; + pState0.insideWindow = true; + pState0.exitSent = false; + pState0.dragging = false; + } else { + insideWindow = false; + pState0.insideWindow = false; + pState0.exitSent = true; + } break; + case MouseEvent.EVENT_MOUSE_MOVED: + case MouseEvent.EVENT_MOUSE_RELEASED: + if( 1 >= pe.getButtonDownCount() ) { // MOVE or RELEASE last button + eExitAllowed = !pState0.exitSent; + pState0.dragging = false; + } + // Fall through intended ! + default: - if(!pState0.insideWindow) { - pState0.insideWindow = true; + insideWindow = x >= 0 && y >= 0 && x < getWidth() && y < getHeight(); + if( pe.getPointerType(0) == PointerType.Mouse ) { + if( !pState0.insideWindow && insideWindow ) { + // ENTER .. use clipped coordinates + eEntered = new MouseEvent(MouseEvent.EVENT_MOUSE_ENTERED, pe.getSource(), pe.getWhen(), pe.getModifiers(), + Math.min(Math.max(x, 0), getWidth()-1), + Math.min(Math.max(y, 0), getHeight()-1), + (short)0, (short)0, pe.getRotation(), pe.getRotationScale()); + pState0.exitSent = false; + } else if( !insideWindow && eExitAllowed ) { + // EXIT .. use clipped coordinates + eExited = new MouseEvent(MouseEvent.EVENT_MOUSE_EXITED, pe.getSource(), pe.getWhen(), pe.getModifiers(), + Math.min(Math.max(x, 0), getWidth()-1), + Math.min(Math.max(y, 0), getHeight()-1), + (short)0, (short)0, pe.getRotation(), pe.getRotationScale()); + pState0.exitSent = true; + } + } + if( pState0.insideWindow != insideWindow || null != eEntered || null != eExited) { pState0.clearButton(); - eEntered = pe.createVariant(MouseEvent.EVENT_MOUSE_ENTERED); - } else { - eEntered = null; } + pState0.insideWindow = insideWindow; } if( null != eEntered ) { if(DEBUG_MOUSE_EVENT) { - System.err.println("consumePointerEvent.send.0: "+eEntered); + System.err.println("consumePointerEvent.send.0: "+eEntered+", "+pState0); } dispatchMouseEvent(eEntered); - } else if( x < 0 || y < 0 || x >= getWidth() || y >= getHeight() ) { - // - // Drop exterior events - // - if(DEBUG_MOUSE_EVENT) { - System.err.println("consumePointerEvent.drop: "+pe); - } - return; // .. invalid .. + } else if( DEBUG_MOUSE_EVENT && !insideWindow ) { + System.err.println("INFO consumePointerEvent.exterior: "+pState0+", "+pe); } // @@ -2906,7 +2985,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer scaledScrollSlop = Math.round(DoubleTapScrollGesture.SCROLL_SLOP_MM * pixPerMM); scaledDoubleTapSlop = Math.round(DoubleTapScrollGesture.DOUBLE_TAP_SLOP_MM * pixPerMM); if(DEBUG_MOUSE_EVENT) { - System.err.println("consumePointerEvent.gscroll: scrollSlop "+scaledScrollSlop+", doubleTapSlop "+scaledDoubleTapSlop+", pixPerMM "+pixPerMM+", "+monitor); + System.err.println("consumePointerEvent.gscroll: scrollSlop "+scaledScrollSlop+", doubleTapSlop "+scaledDoubleTapSlop+", pixPerMM "+pixPerMM+", "+monitor+", "+pState0); } } else { scaledScrollSlop = DoubleTapScrollGesture.SCROLL_SLOP_PIXEL; @@ -2919,7 +2998,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer pe = (MouseEvent) gesture2PtrTouchScroll.getGestureEvent(); gesture2PtrTouchScroll.clear(false); if(DEBUG_MOUSE_EVENT) { - System.err.println("consumePointerEvent.gscroll: "+pe); + System.err.println("consumePointerEvent.gscroll: "+pe+", "+pState0); } dispatchMouseEvent(pe); return; @@ -2962,46 +3041,51 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // - Synthesize mouse CLICKED // - Ignore sent CLICKED // - final MouseEvent eClicked; + MouseEvent eClicked = null; switch( eventType ) { case MouseEvent.EVENT_MOUSE_PRESSED: if( 1 == pe.getPointerCount() ) { pState0.lastButtonPressTime = when; } - eClicked = null; break; case MouseEvent.EVENT_MOUSE_RELEASED: if( 1 == pe.getPointerCount() && when - pState0.lastButtonPressTime < MouseEvent.getClickTimeout() ) { eClicked = pe.createVariant(MouseEvent.EVENT_MOUSE_CLICKED); } else { - eClicked = null; pState0.lastButtonPressTime = 0; } break; case MouseEvent.EVENT_MOUSE_CLICKED: // ignore - synthesized here .. if(DEBUG_MOUSE_EVENT) { - System.err.println("consumePointerEvent: drop recv'ed (synth here) "+pe); + System.err.println("consumePointerEvent: drop recv'ed (synth here) "+pe+", "+pState0); } pe = null; - eClicked = null; break; - default: - eClicked = null; + + case MouseEvent.EVENT_MOUSE_DRAGGED: + pState0.dragging = true; + break; } if( null != pe ) { if(DEBUG_MOUSE_EVENT) { - System.err.println("consumePointerEvent.send.1: "+pe); + System.err.println("consumePointerEvent.send.1: "+pe+", "+pState0); } dispatchMouseEvent(pe); // actual mouse event } if( null != eClicked ) { if(DEBUG_MOUSE_EVENT) { - System.err.println("consumePointerEvent.send.2: "+eClicked); + System.err.println("consumePointerEvent.send.2: "+eClicked+", "+pState0); } dispatchMouseEvent(eClicked); } + if( null != eExited ) { + if(DEBUG_MOUSE_EVENT) { + System.err.println("consumePointerEvent.send.3: "+eExited+", "+pState0); + } + dispatchMouseEvent(eExited); + } } private final void dispatchMouseEvent(MouseEvent e) { @@ -3205,11 +3289,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // @Override public void sendWindowEvent(int eventType) { - consumeWindowEvent( new WindowEvent((short)eventType, this, System.currentTimeMillis()) ); // FIXME + consumeWindowEvent( new WindowEvent((short)eventType, this, System.currentTimeMillis()) ); } public void enqueueWindowEvent(boolean wait, int eventType) { - enqueueEvent( wait, new WindowEvent((short)eventType, this, System.currentTimeMillis()) ); // FIXME + enqueueEvent( wait, new WindowEvent((short)eventType, this, System.currentTimeMillis()) ); } @Override diff --git a/src/newt/native/InputEvent.h b/src/newt/native/InputEvent.h index 3fa7dbefe..2de46f82e 100644 --- a/src/newt/native/InputEvent.h +++ b/src/newt/native/InputEvent.h @@ -50,6 +50,12 @@ #define EVENT_BUTTON8_MASK (1 << 12) #define EVENT_BUTTON9_MASK (1 << 13) +/** 16 buttons */ +#define EVENT_BUTTONLAST_MASK (1 << 20) + +/** 16 buttons */ +#define EVENT_BUTTONALL_MASK ( 0xffff << 5 ) + #define EVENT_AUTOREPEAT_MASK (1 << 29) #define EVENT_CONFINED_MASK (1 << 30) #define EVENT_INVISIBLE_MASK (1 << 31) diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index 884e538d3..692bb9d4f 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -186,7 +186,8 @@ typedef struct { int height; /** Tristate: -1 HIDE, 0 NOP, 1 SHOW */ int setPointerVisible; - int mouseInside; + int pointerCaptured; + int pointerInside; int touchDownCount; int touchDownLastUp; // mitigate LBUTTONUP after last TOUCH lift int supportsMTouch; @@ -985,11 +986,14 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP case WM_LBUTTONDOWN: { - DBG_PRINT("*** WindowsWindow: WM_LBUTTONDOWN %d/%d [%dx%d] inside %d, tDown [c %d, lastUp %d]\n", + DBG_PRINT("*** WindowsWindow: WM_LBUTTONDOWN %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - wud->width, wud->height, wud->mouseInside, wud->touchDownCount, wud->touchDownLastUp); + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); if( 0 == wud->touchDownLastUp && 0 == wud->touchDownCount ) { - wud->mouseInside = 1; + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jshort) EVENT_MOUSE_PRESSED, @@ -1002,14 +1006,22 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP break; case WM_LBUTTONUP: { - DBG_PRINT("*** WindowsWindow: WM_LBUTTONUP %d/%d [%dx%d] inside %d, tDown [c %d, lastUp %d]\n", + DBG_PRINT("*** WindowsWindow: WM_LBUTTONUP %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - wud->width, wud->height, wud->mouseInside, wud->touchDownCount, wud->touchDownLastUp); + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); if( 0 < wud->touchDownLastUp ) { // mitigate LBUTTONUP after last TOUCH lift wud->touchDownLastUp = 0; } else if( 0 == wud->touchDownCount ) { - wud->mouseInside = 1; + jint modifiers = GetModifiers(0); + if( wud->pointerCaptured && 0 == ( modifiers & EVENT_BUTTONALL_MASK ) ) { + wud->pointerCaptured = 0; + ReleaseCapture(); + } + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } (*env)->CallVoidMethod(env, window, sendMouseEventID, (jshort) EVENT_MOUSE_RELEASED, GetModifiers( 0 ), @@ -1021,11 +1033,14 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP break; case WM_MBUTTONDOWN: { - DBG_PRINT("*** WindowsWindow: WM_MBUTTONDOWN %d/%d [%dx%d] inside %d, tDown [c %d, lastUp %d]\n", + DBG_PRINT("*** WindowsWindow: WM_MBUTTONDOWN %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - wud->width, wud->height, wud->mouseInside, wud->touchDownCount, wud->touchDownLastUp); + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); if( 0 == wud->touchDownCount ) { - wud->mouseInside = 1; + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jshort) EVENT_MOUSE_PRESSED, @@ -1038,11 +1053,19 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP break; case WM_MBUTTONUP: { - DBG_PRINT("*** WindowsWindow: WM_MBUTTONUP %d/%d [%dx%d] inside %d, tDown [c %d, lastUp %d]\n", + DBG_PRINT("*** WindowsWindow: WM_MBUTTONUP %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - wud->width, wud->height, wud->mouseInside, wud->touchDownCount, wud->touchDownLastUp); + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); if( 0 == wud->touchDownCount ) { - wud->mouseInside = 1; + jint modifiers = GetModifiers(0); + if( wud->pointerCaptured && 0 == ( modifiers & EVENT_BUTTONALL_MASK ) ) { + wud->pointerCaptured = 0; + ReleaseCapture(); + } + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } (*env)->CallVoidMethod(env, window, sendMouseEventID, (jshort) EVENT_MOUSE_RELEASED, GetModifiers( 0 ), @@ -1054,11 +1077,14 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP break; case WM_RBUTTONDOWN: { - DBG_PRINT("*** WindowsWindow: WM_RBUTTONDOWN %d/%d [%dx%d] inside %d, tDown [c %d, lastUp %d]\n", + DBG_PRINT("*** WindowsWindow: WM_RBUTTONDOWN %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - wud->width, wud->height, wud->mouseInside, wud->touchDownCount, wud->touchDownLastUp); + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); if( 0 == wud->touchDownCount ) { - wud->mouseInside = 1; + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jshort) EVENT_MOUSE_PRESSED, @@ -1071,11 +1097,19 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP break; case WM_RBUTTONUP: { - DBG_PRINT("*** WindowsWindow: WM_RBUTTONUP %d/%d [%dx%d] inside %d, tDown [c %d, lastUp %d]\n", + DBG_PRINT("*** WindowsWindow: WM_RBUTTONUP %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - wud->width, wud->height, wud->mouseInside, wud->touchDownCount, wud->touchDownLastUp); + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); if( 0 == wud->touchDownCount ) { - wud->mouseInside = 1; + jint modifiers = GetModifiers(0); + if( wud->pointerCaptured && 0 == ( modifiers & EVENT_BUTTONALL_MASK ) ) { + wud->pointerCaptured = 0; + ReleaseCapture(); + } + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } (*env)->CallVoidMethod(env, window, sendMouseEventID, (jshort) EVENT_MOUSE_RELEASED, GetModifiers( 0 ), @@ -1087,15 +1121,22 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP break; case WM_MOUSEMOVE: { - DBG_PRINT("*** WindowsWindow: WM_MOUSEMOVE %d/%d [%dx%d] inside %d, tDown [c %d, lastUp %d]\n", + DBG_PRINT("*** WindowsWindow: WM_MOUSEMOVE %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - wud->width, wud->height, wud->mouseInside, wud->touchDownCount, wud->touchDownLastUp); + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); if( 0 == wud->touchDownLastUp && 0 == wud->touchDownCount ) { - wud->mouseInside = 1; - NewtWindows_trackPointerLeave(wnd); + jint modifiers = GetModifiers(0); + if( 0 == wud->pointerCaptured && 0 != ( modifiers & EVENT_BUTTONALL_MASK ) ) { + wud->pointerCaptured = 1; + SetCapture(wnd); + } + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } (*env)->CallVoidMethod(env, window, sendMouseEventID, (jshort) EVENT_MOUSE_MOVED, - GetModifiers( 0 ), + modifiers, (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), (jshort) 0, (jfloat) 0.0f); } @@ -1103,11 +1144,11 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP } break; case WM_MOUSELEAVE: { - DBG_PRINT("*** WindowsWindow: WM_MOUSELEAVE %d/%d [%dx%d] inside %d, tDown [c %d, lastUp %d]\n", + DBG_PRINT("*** WindowsWindow: WM_MOUSELEAVE %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - wud->width, wud->height, wud->mouseInside, wud->touchDownCount, wud->touchDownLastUp); + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); if( 0 == wud->touchDownCount ) { - wud->mouseInside = 0; + wud->pointerInside = 0; (*env)->CallVoidMethod(env, window, sendMouseEventID, (jshort) EVENT_MOUSE_EXITED, 0, @@ -1203,7 +1244,6 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP int isPrim = pTi->dwFlags & TOUCHEVENTF_PRIMARY; int isNoCoalesc = pTi->dwFlags & TOUCHEVENTF_NOCOALESCE; - int isPInside; #ifdef VERBOSE_ON const char * touchAction; @@ -1223,8 +1263,8 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP eventPt.y = TOUCH_COORD_TO_PIXEL(pTi->y); ScreenToClient(wnd, &eventPt); - isPInside = 0 <= eventPt.x && 0 <= eventPt.y && eventPt.x < wud->width && eventPt.y < wud->height; - allPInside &= isPInside; + int pInside = 0 <= eventPt.x && 0 <= eventPt.y && eventPt.x < wud->width && eventPt.y < wud->height; + allPInside &= pInside; x[i] = (jint)eventPt.x; y[i] = (jint)eventPt.y; @@ -1252,16 +1292,16 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP #ifdef VERBOSE_ON DBG_PRINT("*** WindowsWindow: WM_TOUCH[%d/%d].%s name 0x%x, prim %d, nocoalsc %d, %d/%d [%dx%d] inside [%d/%d], tDown [c %d, lastUp %d]\n", (i+1), cInputs, touchAction, (int)(pTi->dwID), isPrim, isNoCoalesc, x[i], y[i], wud->width, wud->height, - isPInside, allPInside, wud->touchDownCount, wud->touchDownLastUp); + pInside, allPInside, wud->touchDownCount, wud->touchDownLastUp); #endif } - wud->mouseInside = allPInside; - if( sendFocus && allPInside ) { + wud->pointerInside = allPInside; + if( sendFocus ) { (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); } int sentCount = 0, updownCount=0, moveCount=0; // Primary first, if available! - if( 0 <= actionIdx && allPInside ) { + if( 0 <= actionIdx ) { sendTouchScreenEvent(env, window, eventType[actionIdx], modifiers, actionIdx, cInputs, pointerNames, x, y, pressure, maxPressure); sentCount++; @@ -1270,7 +1310,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP for (i=0; i < cInputs; i++) { short et = eventType[i]; if( (jshort) EVENT_MOUSE_MOVED == et ) { - if( i != actionIdx && 0 == moveCount && allPInside ) { + if( i != actionIdx && 0 == moveCount ) { sendTouchScreenEvent(env, window, et, modifiers, i, cInputs, pointerNames, x, y, pressure, maxPressure); sentCount++; @@ -1282,7 +1322,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP for (i=0; i < cInputs; i++) { short et = eventType[i]; if( (jshort) EVENT_MOUSE_MOVED != et ) { - if( i != actionIdx && allPInside ) { + if( i != actionIdx ) { sendTouchScreenEvent(env, window, et, modifiers, i, cInputs, pointerNames, x, y, pressure, maxPressure); sentCount++; @@ -1290,8 +1330,8 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP updownCount++; } } - DBG_PRINT("*** WindowsWindow: WM_TOUCH.summary pCount %d, prim %d, updown %d, move %d, sent %d, inside %d, tDown [c %d, lastUp %d]\n", - cInputs, actionIdx, updownCount, moveCount, sentCount, wud->mouseInside, wud->touchDownCount, wud->touchDownLastUp); + DBG_PRINT("*** WindowsWindow: WM_TOUCH.summary pCount %d, prim %d, updown %d, move %d, sent %d, inside %d, captured %d, tDown [c %d, lastUp %d]\n", + cInputs, actionIdx, updownCount, moveCount, sentCount, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); // Message processed - close it WinTouch_CloseTouchInputHandle(hTouch); @@ -1310,10 +1350,14 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP break; case WM_KILLFOCUS: - DBG_PRINT("*** WindowsWindow: WM_KILLFOCUS window %p, received %p, inside %d, tDown %d\n", - wnd, (HWND)wParam, wud->mouseInside, wud->touchDownCount); + DBG_PRINT("*** WindowsWindow: WM_KILLFOCUS window %p, received %p, inside %d, captured %d, tDown %d\n", + wnd, (HWND)wParam, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount); if( wud->touchDownCount == 0 ) { - wud->mouseInside=0; + wud->pointerInside = 0; + if( wud->pointerCaptured ) { + wud->pointerCaptured = 0; + ReleaseCapture(); + } (*env)->CallVoidMethod(env, window, focusChangedID, JNI_FALSE, JNI_FALSE); useDefWindowProc = 1; } else { @@ -1963,7 +2007,8 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindo wud->width = width; wud->height = height; wud->setPointerVisible = 0; - wud->mouseInside = 0; + wud->pointerCaptured = 0; + wud->pointerInside = 0; wud->touchDownCount = 0; wud->touchDownLastUp = 0; wud->supportsMTouch = 0; @@ -2214,12 +2259,9 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowDriver_confineP jboolean res; if(JNI_TRUE == confine) { - // SetCapture(hwnd); - // res = ( GetCapture() == hwnd ) ? JNI_TRUE : JNI_FALSE; RECT rect = { l, t, r, b }; res = ClipCursor(&rect) ? JNI_TRUE : JNI_FALSE; } else { - // res = ReleaseCapture() ? JNI_TRUE : JNI_FALSE; res = ClipCursor(NULL) ? JNI_TRUE : JNI_FALSE; } DBG_PRINT( "*** WindowsWindow: confinePointer0: %d, [ l %d t %d r %d b %d ], res %d\n", |