From fe2f06f36e45e2c35feff51f5efec1e347923563 Mon Sep 17 00:00:00 2001 From: kappaOne Date: Mon, 14 Jan 2013 23:35:46 +0000 Subject: [PATCH] Implement Keyboard and Mouse input when using CALayer mode --- build.xml | 1 + src/java/org/lwjgl/opengl/MacOSXDisplay.java | 130 ++++++++++++++---- .../lwjgl/opengl/MacOSXMouseEventQueue.java | 113 +++++++++++++++ src/native/macosx/org_lwjgl_opengl_Display.m | 13 +- .../macosx/org_lwjgl_opengl_MacOSXAWTMouse.m | 73 ++++++++++ .../org_lwjgl_opengl_MacOSXCanvasPeerInfo.m | 4 +- ...lwjgl_opengl_MacOSXContextImplementation.m | 7 + 7 files changed, 311 insertions(+), 30 deletions(-) create mode 100644 src/java/org/lwjgl/opengl/MacOSXMouseEventQueue.java create mode 100644 src/native/macosx/org_lwjgl_opengl_MacOSXAWTMouse.m diff --git a/build.xml b/build.xml index cd03ab97..bb544cfd 100644 --- a/build.xml +++ b/build.xml @@ -323,6 +323,7 @@ + diff --git a/src/java/org/lwjgl/opengl/MacOSXDisplay.java b/src/java/org/lwjgl/opengl/MacOSXDisplay.java index ea2d0168..e6b0bde4 100644 --- a/src/java/org/lwjgl/opengl/MacOSXDisplay.java +++ b/src/java/org/lwjgl/opengl/MacOSXDisplay.java @@ -70,7 +70,7 @@ final class MacOSXDisplay implements DisplayImplementation { private MacOSXCanvasListener canvas_listener; private Canvas canvas; private Robot robot; - //private MacOSXMouseEventQueue mouse_queue; + private MacOSXMouseEventQueue mouse_queue; private KeyboardEventQueue keyboard_queue; private java.awt.DisplayMode requested_mode; @@ -154,7 +154,13 @@ final class MacOSXDisplay implements DisplayImplementation { } private boolean isNativeMode() { - return true; + //return true; + + if (Display.isFullscreen() || Display.getParent() == null) { + return true; + } + + return false; } public void doHandleQuit() { @@ -163,10 +169,22 @@ final class MacOSXDisplay implements DisplayImplementation { } } + public native void nDestroyCALayer(ByteBuffer peer_info_handle); + public native void nDestroyWindow(ByteBuffer window_handle); public void destroyWindow() { - nDestroyWindow(window); + + if (!native_mode) { + DrawableGL gl_drawable = (DrawableGL)Display.getDrawable(); + PeerInfo peer_info = gl_drawable.peer_info; + if (peer_info != null) { + ByteBuffer peer_handle = peer_info.getHandle(); + nDestroyCALayer(peer_handle); + } + } + + nDestroyWindow(window); } public int getGammaRampLength() { @@ -262,8 +280,12 @@ final class MacOSXDisplay implements DisplayImplementation { } public boolean isActive() { - boolean ret = nIsFocused(window); - return ret; + if (native_mode) { + return nIsFocused(window); + } + else { + return Display.getParent().hasFocus(); + } } public Canvas getCanvas() { @@ -311,29 +333,57 @@ final class MacOSXDisplay implements DisplayImplementation { } public void createMouse() throws LWJGLException { - mouse = new MacOSXNativeMouse(this, window); - mouse.register(); + if (native_mode) { + mouse = new MacOSXNativeMouse(this, window); + mouse.register(); + } + else { + this.mouse_queue = new MacOSXMouseEventQueue(canvas); + mouse_queue.register(); + } } public void destroyMouse() { - //MacOSXMouseEventQueue.nGrabMouse(false); - - if (mouse != null) { - mouse.unregister(); - } - mouse = null; + if (native_mode) { + if (mouse != null) { + mouse.unregister(); + } + mouse = null; + } + else { + if (mouse_queue != null) { + MacOSXMouseEventQueue.nGrabMouse(false); + mouse_queue.unregister(); + } + this.mouse_queue = null; + } } public void pollMouse(IntBuffer coord_buffer, ByteBuffer buttons_buffer) { - mouse.poll(coord_buffer, buttons_buffer); + if (native_mode) { + mouse.poll(coord_buffer, buttons_buffer); + } + else { + mouse_queue.poll(coord_buffer, buttons_buffer); + } } public void readMouse(ByteBuffer buffer) { - mouse.copyEvents(buffer); + if (native_mode) { + mouse.copyEvents(buffer); + } + else { + mouse_queue.copyEvents(buffer); + } } public void grabMouse(boolean grab) { - mouse.setGrabbed(grab); + if (native_mode) { + mouse.setGrabbed(grab); + } + else { + mouse_queue.setGrabbed(grab); + } } public int getNativeCursorCapabilities() { @@ -341,10 +391,14 @@ final class MacOSXDisplay implements DisplayImplementation { } public void setCursorPosition(int x, int y) { - if (mouse != null) { - mouse.setCursorPosition(x, y); + if (native_mode) { + if (mouse != null) { + mouse.setCursorPosition(x, y); + } + } + else { + //MacOSXMouseEventQueue.nWarpCursor(x, y); } - //MacOSXMouseEventQueue.nWarpCursor(x, y); } public void setNativeCursor(Object handle) throws LWJGLException { @@ -360,23 +414,47 @@ final class MacOSXDisplay implements DisplayImplementation { /* Keyboard */ public void createKeyboard() throws LWJGLException { - this.keyboard = new MacOSXNativeKeyboard(window); - keyboard.register(); + if (native_mode) { + this.keyboard = new MacOSXNativeKeyboard(window); + keyboard.register(); + } + else { + this.keyboard_queue = new KeyboardEventQueue(canvas); + keyboard_queue.register(); + } } public void destroyKeyboard() { - if (keyboard != null) { - keyboard.unregister(); + if (native_mode) { + if (keyboard != null) { + keyboard.unregister(); + } + keyboard = null; + } + else { + if (keyboard_queue != null) { + keyboard_queue.unregister(); + } + this.keyboard_queue = null; } - keyboard = null; } public void pollKeyboard(ByteBuffer keyDownBuffer) { - keyboard.poll(keyDownBuffer); + if (native_mode) { + keyboard.poll(keyDownBuffer); + } + else { + keyboard_queue.poll(keyDownBuffer); + } } public void readKeyboard(ByteBuffer buffer) { - keyboard.copyEvents(buffer); + if (native_mode) { + keyboard.copyEvents(buffer); + } + else { + keyboard_queue.copyEvents(buffer); + } } /** Native cursor handles */ diff --git a/src/java/org/lwjgl/opengl/MacOSXMouseEventQueue.java b/src/java/org/lwjgl/opengl/MacOSXMouseEventQueue.java new file mode 100644 index 00000000..3104c18c --- /dev/null +++ b/src/java/org/lwjgl/opengl/MacOSXMouseEventQueue.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.lwjgl.opengl; + +/** + * An AWT implementation of a LWJGL compatible Mouse event queue. + * @author elias_naur + */ + +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; +import java.nio.IntBuffer; + +import org.lwjgl.BufferUtils; + +final class MacOSXMouseEventQueue extends MouseEventQueue { + private final IntBuffer delta_buffer = BufferUtils.createIntBuffer(2); + + private boolean skip_event; + private static boolean is_grabbed; + + MacOSXMouseEventQueue(Component component) { + super(component); + } + + public void setGrabbed(boolean grab) { + if (is_grabbed != grab) { + super.setGrabbed(grab); + warpCursor(); + grabMouse(grab); + } + } + + private static synchronized void grabMouse(boolean grab) { + is_grabbed = grab; + if (!grab) + nGrabMouse(grab); + } + + protected void resetCursorToCenter() { + super.resetCursorToCenter(); + /* Clear accumulated deltas */ + getMouseDeltas(delta_buffer); + } + + protected void updateDeltas(long nanos) { + super.updateDeltas(nanos); + synchronized ( this ) { + getMouseDeltas(delta_buffer); + int dx = delta_buffer.get(0); + int dy = -delta_buffer.get(1); + if (skip_event) { + skip_event = false; + nGrabMouse(isGrabbed()); + return; + } + if ( dx != 0 || dy != 0 ) { + putMouseEventWithCoords((byte)-1, (byte)0, dx, dy, 0, nanos); + addDelta(dx, dy); + } + } + } + + void warpCursor() { + synchronized (this) { + // If we're going to warp the cursor position, we'll skip the next event to avoid bogus delta values + skip_event = isGrabbed(); + } + if (isGrabbed()) { + Rectangle bounds = getComponent().getBounds(); + Point location_on_screen = getComponent().getLocationOnScreen(); + int x = location_on_screen.x + bounds.width/2; + int y = location_on_screen.y + bounds.height/2; + nWarpCursor(x, y); + } + } + + private static native void getMouseDeltas(IntBuffer delta_buffer); + + private static native void nWarpCursor(int x, int y); + + static native void nGrabMouse(boolean grab); +} \ No newline at end of file diff --git a/src/native/macosx/org_lwjgl_opengl_Display.m b/src/native/macosx/org_lwjgl_opengl_Display.m index 93eaadac..902ddbc9 100644 --- a/src/native/macosx/org_lwjgl_opengl_Display.m +++ b/src/native/macosx/org_lwjgl_opengl_Display.m @@ -495,7 +495,7 @@ JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_MacOSXDisplay_nCreateWindow(JNIE // Inform the view of its parent window info; [window_info->view setParent:window_info]; - if (peer_info->isCALayer) { + if (!fullscreen && peer_info->isCALayer) { // hidden window when using CALayer [window_info->window orderOut:nil]; } @@ -514,7 +514,7 @@ JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_MacOSXDisplay_nCreateWindow(JNIE JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXDisplay_nDestroyWindow(JNIEnv *env, jobject this, jobject window_handle) { MacOSXWindowInfo *window_info = (MacOSXWindowInfo *)(*env)->GetDirectBufferAddress(env, window_handle); - + if (window_info->fullscreen) { [window_info->view exitFullScreenModeWithOptions: nil]; } @@ -534,6 +534,15 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXDisplay_nDestroyWindow(JNIEnv [pool drain]; } +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXDisplay_nDestroyCALayer(JNIEnv *env, jobject this, jobject peer_info_handle) { + MacOSXPeerInfo *peer_info = (MacOSXPeerInfo *)(*env)->GetDirectBufferAddress(env, peer_info_handle); + if (peer_info->isCALayer) { + peer_info->isCALayer = false; + [peer_info->glLayer performSelectorOnMainThread:@selector(removeLayer) withObject:nil waitUntilDone:YES]; + [peer_info->glLayer release]; + } +} + JNIEXPORT jint JNICALL Java_org_lwjgl_DefaultSysImplementation_getJNIVersion(JNIEnv *env, jobject ignored) { return org_lwjgl_MacOSXSysImplementation_JNI_VERSION; } diff --git a/src/native/macosx/org_lwjgl_opengl_MacOSXAWTMouse.m b/src/native/macosx/org_lwjgl_opengl_MacOSXAWTMouse.m new file mode 100644 index 00000000..16122a82 --- /dev/null +++ b/src/native/macosx/org_lwjgl_opengl_MacOSXAWTMouse.m @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * $Id$ + * + * Mac OS X mouse handling. + * + * @author elias_naur + * @version $Revision$ + */ + +#include +#include +#include "org_lwjgl_opengl_MacOSXMouseEventQueue.h" +#include "common_tools.h" + +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXMouseEventQueue_nGrabMouse(JNIEnv *env, jclass unused, jboolean grab) { + CGAssociateMouseAndMouseCursorPosition(grab == JNI_TRUE ? FALSE : TRUE); + if (grab) + CGDisplayHideCursor(kCGDirectMainDisplay); + else + CGDisplayShowCursor(kCGDirectMainDisplay); +} + +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXMouseEventQueue_nWarpCursor(JNIEnv *env, jclass unused, jint x, jint y) { + CGPoint p; + p.x = x; + p.y = y; + CGWarpMouseCursorPosition(p); +} + +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXMouseEventQueue_getMouseDeltas(JNIEnv *env, jclass unused, jobject delta_buffer) { + CGMouseDelta dx, dy; + CGGetLastMouseDelta(&dx, &dy); + int buffer_length = (*env)->GetDirectBufferCapacity(env, delta_buffer); + if (buffer_length != 2) { + printfDebugJava(env, "Delta buffer not large enough!"); + return; + } + jint *buffer = (*env)->GetDirectBufferAddress(env, delta_buffer); + buffer[0] = dx; + buffer[1] = dy; +} \ No newline at end of file diff --git a/src/native/macosx/org_lwjgl_opengl_MacOSXCanvasPeerInfo.m b/src/native/macosx/org_lwjgl_opengl_MacOSXCanvasPeerInfo.m index b4ad9350..6a8e7249 100644 --- a/src/native/macosx/org_lwjgl_opengl_MacOSXCanvasPeerInfo.m +++ b/src/native/macosx/org_lwjgl_opengl_MacOSXCanvasPeerInfo.m @@ -195,7 +195,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nInitHandle GLint originalReadFBO; // get and save the current fbo values - glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &originalReadFBO); + //glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &originalReadFBO); // read the LWJGL FBO and blit it into this CALayers FBO glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fboID); @@ -205,7 +205,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nInitHandle GL_NEAREST); // restore original fbo read value - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, originalReadFBO); + //glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, originalReadFBO); // call super to finalize the drawing - by default all it does is call glFlush() [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; diff --git a/src/native/macosx/org_lwjgl_opengl_MacOSXContextImplementation.m b/src/native/macosx/org_lwjgl_opengl_MacOSXContextImplementation.m index ae6625d8..6fee4190 100644 --- a/src/native/macosx/org_lwjgl_opengl_MacOSXContextImplementation.m +++ b/src/native/macosx/org_lwjgl_opengl_MacOSXContextImplementation.m @@ -192,6 +192,13 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXContextImplementation_nDestro NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; MacOSXContext *context_info = (MacOSXContext *)(*env)->GetDirectBufferAddress(env, context_handle); + + if (context_info->peer_info->isCALayer) { + context_info->peer_info->isCALayer = false; + [context_info->peer_info->glLayer performSelectorOnMainThread:@selector(removeLayer) withObject:nil waitUntilDone:YES]; + [context_info->peer_info->glLayer release]; + } + // clearDrawable on main thread to ensure its not in use [context_info->context performSelectorOnMainThread:@selector(clearDrawable) withObject:nil waitUntilDone:YES]; [context_info->peer_info->window_info->view setOpenGLContext:nil];