reworked animated native cursors, to use X animation when required

added initial setGrabbed(boolean) feature - Work in progress
both needs verification on linux
This commit is contained in:
Brian Matzon 2004-04-12 00:33:01 +00:00
parent 438e790987
commit 86eb042b81
12 changed files with 197 additions and 102 deletions

View File

@ -36,6 +36,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import org.lwjgl.Display;
import org.lwjgl.Sys;
import org.lwjgl.LWJGLException;
@ -100,22 +101,39 @@ public class Cursor {
IntBuffer images_copy = ByteBuffer.allocateDirect(images.remaining()*4).order(ByteOrder.nativeOrder()).asIntBuffer();
flipImages(width, height, numImages, images, images_copy);
// create our cursor elements
cursors = new CursorElement[numImages];
for(int i=0; i<numImages; i++) {
cursors[i] = new CursorElement();
cursors[i].cursorHandle = nCreateCursor(width, height, xHotspot, yHotspot, 1, images_copy, images_copy.position());
cursors[i].delay = (delays != null) ? delays.get(i) : 0;
cursors[i].timeout = System.currentTimeMillis();
// offset to next image
images_copy.position(width*height*(i+1));
}
// set index
index = 0;
}
// Win32 doesn't (afaik) allow for animation based cursors, except when they're
// in the .ani format, which we don't support.
// The cursor animation was therefor developed using java side time tracking.
// unfortunately X flickers when changing cursor. We therefor check for either
// Win32 or X and do accordingly. This hasn't been implemented on Mac, but we
// might want to split it into a X/Win/Mac cursor if it gets too cluttered
switch(Display.getPlatform()) {
case Display.PLATFORM_GLX:
// create our cursor elements
cursors = new CursorElement[1];
cursors[0] = new CursorElement();
cursors[0].cursorHandle = nCreateCursor(width, height, xHotspot, yHotspot, numImages, images_copy, images_copy.position(), delays, delays.position());
break;
case Display.PLATFORM_WGL:
// create our cursor elements
cursors = new CursorElement[numImages];
for(int i=0; i<numImages; i++) {
cursors[i] = new CursorElement();
cursors[i].cursorHandle = nCreateCursor(width, height, xHotspot, yHotspot, 1, images_copy, images_copy.position(), null, 0);
cursors[i].delay = (delays != null) ? delays.get(i) : 0;
cursors[i].timeout = System.currentTimeMillis();
// offset to next image
images_copy.position(width*height*(i+1));
}
// set index
index = 0;
break;
case Display.PLATFORM_AGL:
break;
}
}
/**
* Flips the images so they're oriented according to opengl
@ -202,7 +220,7 @@ public class Cursor {
/**
* Native method to create a native cursor
*/
private static native long nCreateCursor(int width, int height, int xHotspot, int yHotspot, int numImages, IntBuffer images, int images_offset);
private static native long nCreateCursor(int width, int height, int xHotspot, int yHotspot, int numImages, IntBuffer images, int images_offset, IntBuffer delays, int delays_offset);
/**
* Native method to destroy a native cursor

View File

@ -38,6 +38,7 @@ import java.util.HashMap;
import java.util.Map;
import org.lwjgl.BufferUtils;
import org.lwjgl.Display;
import org.lwjgl.Sys;
import org.lwjgl.opengl.Window;
import org.lwjgl.LWJGLException;
@ -59,69 +60,71 @@ import org.lwjgl.LWJGLException;
* @version $Revision$
*/
public class Mouse {
/** 1 bit transparency for native cursor */
public final static int CURSOR_ONE_BIT_TRANSPARENCY = 1;
public final static int CURSOR_ONE_BIT_TRANSPARENCY = 1;
/** 8 bit alhpa native cursor */
public final static int CURSOR_8_BIT_ALPHA = 2;
public final static int CURSOR_8_BIT_ALPHA = 2;
/** animation native cursor */
public final static int CURSOR_ANIMATION = 4;
public final static int CURSOR_ANIMATION = 4;
/** Has the mouse been created? */
private static boolean created;
private static boolean created;
/** The mouse buttons status from the last poll */
private static ByteBuffer buttons;
private static ByteBuffer buttons;
/** X */
private static int x;
private static int x;
/** Y */
private static int y;
private static int y;
/** Buffer to hold the deltas dx, dy and dwheel */
private static IntBuffer coord_buffer;
private static IntBuffer coord_buffer;
/** Delta X */
private static int dx;
private static int dx;
/** Delta Y */
private static int dy;
private static int dy;
/** Delta Z */
private static int dwheel;
private static int dwheel;
/** Number of buttons supported by the mouse */
private static int buttonCount = -1;
private static int buttonCount = -1;
/** Does this mouse support a scroll wheel */
private static boolean hasWheel = false;
private static boolean hasWheel = false;
/** The current native cursor, if any */
private static Cursor currentCursor;
private static Cursor currentCursor;
/** Button names. These are set upon create(), to names like BUTTON0, BUTTON1, etc. */
private static String[] buttonName;
private static String[] buttonName;
/** hashmap of button names, for fast lookup */
private static final Map buttonMap = new HashMap(16);
private static final Map buttonMap = new HashMap(16);
/** Lazy initialization */
private static boolean initialized;
private static boolean initialized;
/** The mouse button events from the last read */
private static ByteBuffer readBuffer = null;
private static ByteBuffer readBuffer = null;
/** The current mouse event button being examined */
private static int eventButton;
private static int eventButton;
/** The current state of the button being examined in the event queue */
private static boolean eventState;
private static boolean eventState;
/** Buffer size in events */
private final static int BUFFER_SIZE = 50;
private final static int BUFFER_SIZE = 50;
private static boolean isGrabbed;
/**
* Mouse cannot be constructed.
@ -172,17 +175,17 @@ public class Mouse {
* @throws LWJGLException if the cursor could not be set for any reason
*/
public static Cursor setNativeCursor(Cursor cursor) throws LWJGLException {
if (!created)
throw new IllegalStateException("Create the Mouse before setting the native cursor");
if (!created) throw new IllegalStateException("Create the Mouse before setting the native cursor");
if ((getNativeCursorCaps() & CURSOR_ONE_BIT_TRANSPARENCY) == 0)
throw new IllegalStateException("Mouse doesn't support native cursors");
throw new IllegalStateException("Mouse doesn't support native cursors");
Cursor oldCursor = currentCursor;
currentCursor = cursor;
if (currentCursor != null) {
nSetNativeCursor(currentCursor.getHandle());
currentCursor.setTimeout();
x = Window.getWidth() / 2;
y = Window.getHeight() / 2;
currentCursor.setTimeout();
x = Window.getWidth() / 2;
y = Window.getHeight() / 2;
isGrabbed = false;
} else {
nSetNativeCursor(0);
}
@ -225,14 +228,14 @@ public class Mouse {
*/
private static void initialize() {
Sys.initialize();
// Assign names to all the buttons
buttonName = new String[16];
for (int i = 0; i < 16; i ++) {
for (int i = 0; i < 16; i++) {
buttonName[i] = "BUTTON" + i;
buttonMap.put(buttonName[i], new Integer(i));
}
initialized = true;
}
@ -242,14 +245,11 @@ public class Mouse {
* @throws LWJGLException if the mouse could not be created for any reason
*/
public static void create() throws LWJGLException {
if (!Window.isCreated())
throw new IllegalStateException("Window must be created prior to creating mouse");
if (!Window.isCreated()) throw new IllegalStateException("Window must be created prior to creating mouse");
initialize();
if (created) {
return;
}
if (created) { return; }
nCreate();
hasWheel = nHasWheel();
created = true;
@ -281,7 +281,7 @@ public class Mouse {
public static boolean isCreated() {
return created;
}
/**
* @return true if buffering is enabled
*/
@ -297,12 +297,10 @@ public class Mouse {
try {
setNativeCursor(null);
} catch (LWJGLException e) {
if (Sys.DEBUG)
e.printStackTrace();
if (Sys.DEBUG) e.printStackTrace();
}
}
if (!created)
return;
if (!created) return;
created = false;
buttons = null;
coord_buffer = null;
@ -341,10 +339,9 @@ public class Mouse {
* @see org.lwjgl.input.Mouse#enableBuffer()
*/
public static void poll() {
if (!created)
throw new IllegalStateException("Mouse must be created before you can poll it");
if (!created) throw new IllegalStateException("Mouse must be created before you can poll it");
nPoll(coord_buffer, buttons);
int poll_dx = coord_buffer.get(0);
int poll_dy = coord_buffer.get(1);
int poll_dwheel = coord_buffer.get(2);
@ -356,28 +353,27 @@ public class Mouse {
dwheel = poll_dwheel;
// if window has been created, clamp to edges
if(Window.isCreated()) {
if (Window.isCreated()) {
// clamp x, y
if (x < 0) {
x = 0;
} else if (x > Window.getWidth()) {
x = Window.getWidth();
}
if (y < 0) {
y = 0;
} else if (y > Window.getHeight()) {
y = Window.getHeight();
}
}
if (readBuffer != null)
read();
if (readBuffer != null) read();
}
private static void read() {
readBuffer.compact();
int numEvents = nRead(readBuffer, readBuffer.position());
readBuffer.position(readBuffer.position() + numEvents*2);
readBuffer.position(readBuffer.position() + numEvents * 2);
readBuffer.flip();
}
@ -393,14 +389,13 @@ public class Mouse {
* @return true if the specified button is down
*/
public static boolean isButtonDown(int button) {
if (!created)
throw new IllegalStateException("Mouse must be created before you can poll the button state");
if (!created) throw new IllegalStateException("Mouse must be created before you can poll the button state");
if (button >= buttonCount || button < 0)
return false;
else
return buttons.get(button) == 1;
}
/**
* Gets a button's name
* @param button The button
@ -412,7 +407,7 @@ public class Mouse {
else
return buttonName[button];
}
/**
* Get's a button's index. If the button is unrecognised then -1 is returned.
* @param buttonName The button name
@ -429,9 +424,8 @@ public class Mouse {
* Enable mouse button buffering. Must be called after the mouse is created.
*/
public static void enableBuffer() throws LWJGLException {
if (!created)
throw new IllegalStateException("Mouse must be created before you can enable buffering");
readBuffer = BufferUtils.createByteBuffer(2*BUFFER_SIZE);
if (!created) throw new IllegalStateException("Mouse must be created before you can enable buffering");
readBuffer = BufferUtils.createByteBuffer(2 * BUFFER_SIZE);
readBuffer.limit(0);
nEnableBuffer();
}
@ -458,10 +452,9 @@ public class Mouse {
* @return true if a mouse event was read, false otherwise
*/
public static boolean next() {
if (!created)
throw new IllegalStateException("Mouse must be created before you can read events");
if (!created) throw new IllegalStateException("Mouse must be created before you can read events");
if (readBuffer == null)
throw new IllegalStateException("Event buffering must be enabled before you can read events");
throw new IllegalStateException("Event buffering must be enabled before you can read events");
if (readBuffer.hasRemaining()) {
eventButton = readBuffer.get() & 0xFF;
@ -470,14 +463,14 @@ public class Mouse {
} else
return false;
}
/**
* @return Current events button
*/
public static int getEventButton() {
return eventButton;
}
/**
* @return Current events button state
*/
@ -503,8 +496,8 @@ public class Mouse {
*/
public static int getY() {
return y;
}
}
/**
* @return Movement on the x axis since last time getDX() was called
*/
@ -540,19 +533,35 @@ public class Mouse {
return hasWheel;
}
/**
* @return whether or not the mouse has grabbed the cursor
*/
public static boolean isGrabbed() {
return isGrabbed;
}
/**
* Sets whether or not the mouse has grabbed the cursor
* (and thus hidden).
*/
public static void setGrabbed(boolean grab) {
isGrabbed = grab;
nGrabMouse(isGrabbed);
}
private static native void nGrabMouse(boolean grab);
/**
* Updates the cursor, so that animation can be changed if needed.
* This method is called automatically by the window on its update.
*/
public static void updateCursor() {
if(currentCursor != null && currentCursor.hasTimedOut()) {
if (Display.getPlatform() == Display.PLATFORM_WGL && currentCursor != null && currentCursor.hasTimedOut()) {
currentCursor.nextCursor();
try {
setNativeCursor(currentCursor);
} catch (LWJGLException e) {
if (Sys.DEBUG)
e.printStackTrace();
if (Sys.DEBUG) e.printStackTrace();
}
}
}
}
}

View File

@ -346,6 +346,11 @@ public class HWCursorTest {
e.printStackTrace();
}
}
if(Keyboard.isKeyDown(Keyboard.KEY_SPACE)) {
Mouse.setGrabbed(!Mouse.isGrabbed());
System.out.println("Grabbed: " + Mouse.isGrabbed());
}
}
/**

View File

@ -242,6 +242,7 @@ public class MouseTest {
if (Mouse.getDX() == Mouse.getDY() && Mouse.getDX() == 0 && Mouse.getDWheel() == 0) {
return;
}
// determine direction moved
// ============================
if(Mouse.getDX() > 0) {
@ -259,8 +260,8 @@ public class MouseTest {
if(Mouse.getDY() < 0) {
direction = 2;
}
// ----------------------------
// ----------------------------
if(direction > -1) {
// based on which button was last pushed, update model
@ -316,6 +317,10 @@ public class MouseTest {
if(Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
closing = true;
}
if(Keyboard.isKeyDown(Keyboard.KEY_SPACE)) {
Mouse.setGrabbed(!Mouse.isGrabbed());
}
}
/**

View File

@ -16,7 +16,7 @@ extern "C" {
* Signature: (IIIIILjava/nio/IntBuffer;I)J
*/
JNIEXPORT jlong JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor
(JNIEnv *, jclass, jint, jint, jint, jint, jint, jobject, jint);
(JNIEnv *, jclass, jint, jint, jint, jint, jint, jobject, jint, jobject, jint);
/*
* Class: org_lwjgl_input_Cursor

View File

@ -103,6 +103,14 @@ JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nDestroy
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nPoll
(JNIEnv *, jclass, jobject, jobject);
/*
* Class: org_lwjgl_input_Mouse
* Method: nGrabMouse
* Signature: (Z)Z
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nGrabMouse
(JNIEnv * env, jclass clazz, jboolean grab);
/*
* Class: org_lwjgl_input_Mouse

View File

@ -50,11 +50,14 @@
* Signature: (IIIIIII)I
*/
JNIEXPORT jlong JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor
(JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, jint num_images, jobject image_buffer, jint images_offset)
(JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, jint num_images, jobject image_buffer, jint images_offset, jobject delay_buffer, jint delays_offset)
{
Display *disp = incDisplay(env);
if (disp == NULL)
return 0;
const int *delays = NULL;
if (delay_buffer != NULL)
delays = (const int *)env->GetDirectBufferAddress(delay_buffer) + delays_offset;
XcursorPixel *pixels = (XcursorPixel *)env->GetDirectBufferAddress(image_buffer) + images_offset;
int stride = width*height;
XcursorImages *cursor_images = XcursorImagesCreate(num_images);
@ -66,6 +69,8 @@ JNIEXPORT jlong JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor
cursor_image->xhot = x_hotspot;
cursor_image->yhot = y_hotspot;
cursor_image->pixels = &(pixels[stride*i]);
if (num_images > 1)
cursor_image->delay = delays[i];
cursor_images->images[i] = cursor_image;
}
Cursor cursor = XcursorImagesLoadCursor(disp, cursor_images);

View File

@ -399,3 +399,17 @@ JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nRead(JNIEnv *env, jclass claz
int buffer_size = env->GetDirectBufferCapacity(buffer) - buffer_position;
return copyEvents(&event_queue, buffer_ptr + buffer_position, buffer_size, 2);
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nGrabMouse
* Signature: (Z)Z
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nGrabMouse
(JNIEnv * env, jclass clazz, jboolean grab) {
if(native_cursor) {
return;
}
// do it?
}

View File

@ -41,7 +41,7 @@
#include "org_lwjgl_input_Cursor.h"
JNIEXPORT jlong JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor(JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, jint num_images, jobject image_buffer, jint images_offset) {
JNIEXPORT jlong JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor(JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, jint num_images, jobject image_buffer, jint images_offset, jobject delay_buffer, jint delays_offset) {
}
JNIEXPORT void JNICALL Java_org_lwjgl_input_Cursor_nDestroyCursor(JNIEnv *env, jclass clazz, jlong cursor_handle) {

View File

@ -257,3 +257,13 @@ JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nRead(JNIEnv *env, jclass claz
int buffer_size = env->GetDirectBufferCapacity(buffer) - buffer_position;
return copyEvents(&event_queue, buffer_ptr + buffer_position, buffer_size, 2);
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nGrabMouse
* Signature: (Z)Z
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nGrabMouse
(JNIEnv * env, jclass clazz, jboolean grab) {
// do it?
}

View File

@ -50,7 +50,7 @@
* Signature: (IIIIIIIII)I
*/
JNIEXPORT jlong JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor
(JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, jint num_images, jobject image_buffer, jint images_offset)
(JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, jint num_images, jobject image_buffer, jint images_offset, jobject delay_buffer, jint delays_offset)
{
int *pixels = (int *)env->GetDirectBufferAddress(image_buffer) + images_offset;

View File

@ -57,6 +57,7 @@ static bool mFirstTimeInitialization = true; // boolean to determine first time
static POINT cursorPos;
static RECT windowRect;
static bool usingNativeCursor;
static int mouseMask = DISCL_NONEXCLUSIVE | DISCL_FOREGROUND;
// Function prototypes (defined in the cpp file, since header file is generic across platforms
void EnumerateMouseCapabilities();
@ -97,8 +98,6 @@ JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nCreate(JNIEnv *env, jclass cl
return;
}
ShowCursor(FALSE);
/* skip enumeration, since we only want system mouse */
CreateMouse();
@ -240,19 +239,18 @@ JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nSetNativeCursor
cursorPos.x = (clientRect.left + clientRect.right)/2;
cursorPos.y = clientRect.bottom - 1 - (clientRect.bottom - clientRect.top)/2;
SetCursorPos(cursorPos.x, cursorPos.y);
ShowCursor(TRUE);
usingNativeCursor = true;
}
} else {
if (usingNativeCursor) {
SetClassLong(hwnd, GCL_HCURSOR, (LONG)NULL);
SetCursor(NULL);
ShowCursor(TRUE);
mDIDevice->Unacquire();
if(mDIDevice->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND) != DI_OK) {
if(mDIDevice->SetCooperativeLevel(hwnd, mouseMask) != DI_OK) {
throwException(env, "Could not set the CooperativeLevel.");
return;
}
ShowCursor(FALSE);
usingNativeCursor = false;
mDIDevice->Acquire();
}
@ -287,12 +285,11 @@ JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetMinCursorSize
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nDestroy(JNIEnv *env, jclass clazz) {
ShowCursor(TRUE);
ShutdownMouse();
}
/*
* Class: org_lwjgl_input_Controller
* Class: org_lwjgl_input_Mouse
* Method: nPoll
* Signature: ()V
*/
@ -301,6 +298,30 @@ JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nPoll(JNIEnv * env, jclass cla
UpdateMouseFields(env, clazz, coord_buffer_obj, button_buffer_obj);
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nGrabMouse
* Signature: (Z)Z
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nGrabMouse
(JNIEnv * env, jclass clazz, jboolean grab) {
if(usingNativeCursor) {
return;
}
if(grab) {
mouseMask = DISCL_EXCLUSIVE | DISCL_FOREGROUND;
} else {
mouseMask = DISCL_NONEXCLUSIVE | DISCL_FOREGROUND;
}
mDIDevice->Unacquire();
if(mDIDevice->SetCooperativeLevel(hwnd, mouseMask) != DI_OK) {
throwException(env, "Could not set the CooperativeLevel.");
return;
}
mDIDevice->Acquire();
}
/**
* Shutdown DI
*/
@ -384,7 +405,7 @@ void SetupMouse() {
mDIDevice->SetProperty(DIPROP_BUFFERSIZE, &dipropdw.diph);
// set the cooperative level
if(mDIDevice->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND) != DI_OK) {
if(mDIDevice->SetCooperativeLevel(hwnd, mouseMask) != DI_OK) {
printfDebug("SetCooperativeLevel failed\n");
mCreate_success = false;
return;