Native cursors implemented

This commit is contained in:
Elias Naur 2003-05-16 18:39:46 +00:00
parent fd75f7a959
commit e886d95122
20 changed files with 1351 additions and 238 deletions

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2002 Lightweight Java Game Library 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 'Light Weight Java Game Library' 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.input;
/**
* $Id$
*
* A class representing a native cursor. Instances of this
* class can be used with Mouse.setCursor(), if available.
*
* @author elias_naur <elias_naur@users.sourceforge.net>
* @version $Revision$
*/
public class Cursor {
/**
* The native handle to the cursor
*/
private final int nativeHandle;
/**
* Constructs a new Cursor, with the given parameters. Mouse must have been created before you can create
* Cursor objects. Cursor images are in ARGB format, but only one bit transparancy is guaranteed to be supported.
* So to maximize portability, lwjgl applications should only create cursor images with 0x00 or 0xff as alpha values.
*
* @param width cursor image width
* @param height cursor image height
* @param xHotspot the x coordinate of the cursor hotspot
* @param yHotspot the y coordinate of the cursor hotspot
* @param cursorAddress the address of an int array containing the cursor image
* @throws Exception if the cursor could not be created for any reason
*/
public Cursor(int width, int height, int xHotspot, int yHotspot, int imageAddress) throws Exception {
assert Mouse.isCreated();
nativeHandle = nCreateCursor(width, height, xHotspot, yHotspot, imageAddress);
}
/**
* Destroy the native cursor. Cursor must not be current.
*/
public void destroy() {
nDestroyCursor(nativeHandle);
}
/**
* Gets the native handle associated with the cursor object.
*/
public int getHandle() {
return nativeHandle;
}
/**
* Native method to create a native cursor
*/
private static native int nCreateCursor(int width, int height, int xHotspot, int yHotspot, int imageAddresses);
/**
* Native method to destroy a native cursor
*/
private static native void nDestroyCursor(int handle);
}

View file

@ -70,6 +70,9 @@ public class Mouse {
/** Does this mouse support a scroll wheel */
public static boolean hasWheel = false;
/** The current native cursor, if any */
private static Cursor currentCursor;
static {
initialize();
}
@ -80,6 +83,83 @@ public class Mouse {
private Mouse() {
}
/**
* Gets the currently bound native cursor, if any.
*
* @return the currently bound native cursor, if any.
public Cursor getNativeCursor() {
return currentCursor;
}
/**
* Check native cursor support
* @return true if native cursors are supported
*/
public static boolean isNativeCursorSupported() {
return nIsNativeCursorSupported();
}
/**
* Native function to determine native cursor support
*/
private static native boolean nIsNativeCursorSupported();
/**
* Binds a native cursor. If the cursor argument is null, the
* native cursor is disabled, as if native cursors were not supported.
* The Mouse must be created before a native cursor can be bound.
*
* NOTE: The native cursor is not constrained to the window, but
* relative events will not be generated if the cursor is outside.
* The initial position of the cursor is in the upper left corner of
* the window, and the cursor will be moved to this origin when a
* native cursor is set and the previous cursor is null.
*
* @param cursor the native cursor object to bind. May be null.
* @return The previous Cursor object set, or null.
* @throws Exception if the cursor could not be set for any reason
*/
public static Cursor setNativeCursor(Cursor cursor) throws Exception {
assert created && isNativeCursorSupported();
Cursor oldCursor = currentCursor;
currentCursor = cursor;
if (currentCursor != null) {
nSetNativeCursor(currentCursor.getHandle());
} else {
nSetNativeCursor(Sys.NULL);
}
return oldCursor;
}
/** Native method to set the native cursor */
private static native void nSetNativeCursor(int handle);
/**
* Gets the minimum size of a native cursor. Can only be called if
* The Mouse is created and isNativeCursorSupported() returns true
*
* @return the maximum size of a native cursor
*/
public static int getMinCursorSize() {
return nGetMinCursorSize();
}
/** Native method returning the minimum cursor size */
private static native int nGetMinCursorSize();
/**
* Gets the maximum size of a native cursor. Can only be called if
* The Mouse is created and isNativeCursorSupported() returns true
*
* @return the maximum size of a native cursor
*/
public static int getMaxCursorSize() {
return nGetMaxCursorSize();
}
/** Native method returning the maximum cursor size */
private static native int nGetMaxCursorSize();
/**
* Static initialization
*/
@ -104,13 +184,14 @@ public class Mouse {
if (!nCreate())
throw new Exception("The mouse could not be created.");
created = true;
currentCursor = null;
//set mouse buttons
buttons = new boolean[buttonCount];
}
/**
* Native method to create the mouse
* Native method to create the mouse.
*
* @return true if the mouse was created
*/
@ -124,13 +205,16 @@ public class Mouse {
}
/**
* "Destroy" the mouse
* "Destroy" the mouse. Remember to reset the native cursor if
* setNativeCursor() has been called with anything else than null.
*/
public static void destroy() {
assert currentCursor == null;
if (!created)
return;
created = false;
buttons = null;
currentCursor = null;
nDestroy();
}
@ -163,4 +247,4 @@ public class Mouse {
assert created : "The mouse has not been created.";
return buttons[button];
}
}
}

View file

@ -0,0 +1,361 @@
/*
* Copyright (c) 2003 Lightweight Java Game Library 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 'Lightweight Java Game Library' 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.test.input;
import org.lwjgl.*;
import org.lwjgl.input.*;
import org.lwjgl.opengl.*;
import org.lwjgl.vector.Vector2f;
import java.nio.*;
/**
* $Id$
*
* Tests switching between windowed and fullscreen - including hardware cursor test
*
* @author Brian Matzon <brian@matzon.dk>
* @version $Revision$
*/
public class HWCursorTest {
/** Intended deiplay mode */
private DisplayMode mode;
/** GL instance */
private GL gl;
/** GLU instance */
private GLU glu;
/** The native cursor */
private static Cursor cursor = null;
/** The mouse cursor position */
private static int mouse_x;
private static int mouse_y;
/**
* Executes the test
*/
public void execute() {
initialize();
mainLoop();
cleanup();
}
/**
* Initializes the test
*/
private void initialize() {
try {
//find displaymode
mode = findDisplayMode(800, 600, 16);
// start of in windowed mode
gl = new GL("Test", 50, 50, mode.width, mode.height, mode.bpp, 0, 0, 0);
gl.create();
glu = new GLU(gl);
glInit();
Keyboard.create();
initNativeCursor();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void initNativeCursor() {
try {
Mouse.create();
} catch (Exception e) {
e.printStackTrace();
}
if (!Mouse.isNativeCursorSupported()) {
System.out.println("No HW cursor support!");
System.exit(0);
}
System.out.println("Maximum native cursor size: " + Mouse.getMaxCursorSize() + ", min size: " + Mouse.getMinCursorSize());
mouse_x = mouse_y = 0;
// int num_images = 3;
int image_size = Mouse.getMaxCursorSize()*Mouse.getMaxCursorSize();
IntBuffer cursor_images = ByteBuffer.allocateDirect(/*num_images**/image_size*4).order(ByteOrder.nativeOrder()).asIntBuffer();
/* IntBuffer delays = ByteBuffer.allocateDirect(num_images*4).order(ByteOrder.nativeOrder()).asIntBuffer();
delays.put(0, 500);
delays.put(1, 500);
delays.put(2, 500);*/
int color_scale = 255/Mouse.getMaxCursorSize();
int bit_mask = 0x81000000;
for (int j = 0; j < image_size; j++) {
if (j % 4 == 0)
bit_mask = (~bit_mask) & 0x81000000;
int color = (j*color_scale/Mouse.getMaxCursorSize()) << 16;
cursor_images.put(0*image_size + j, 0x00000020 | color | bit_mask);
}
/* for (int j = 0; j < image_size; j++) {
int color = (j*color_scale/Mouse.getMaxCursorSize()) << 8;
cursor_images.put(1*image_size + j, 0x80000000 | color);
}
for (int j = 0; j < image_size; j++) {
int color = j*color_scale/Mouse.getMaxCursorSize();
cursor_images.put(2*image_size + j, 0x80000000 | color);
}*/
try {
cursor = new Cursor(Mouse.getMaxCursorSize(), Mouse.getMaxCursorSize(), Mouse.getMaxCursorSize()/2, Mouse.getMaxCursorSize()/2/*, num_images*/, Sys.getDirectBufferAddress(cursor_images)/*, Sys.getDirectBufferAddress(delays)*/);
Mouse.setNativeCursor(cursor);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
/**
* Runs the main loop of the "test"
*/
private void mainLoop() {
while (!Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)
&& !gl.isCloseRequested()) {
// allow subsystem to get a chance to run too
gl.tick();
if (!gl.isMinimized()) {
// check keyboard input
processKeyboard();
render();
// paint window
gl.paint();
} else {
// no need to render/paint if nothing has changed (ie. window dragged over)
if (gl.isDirty()) {
render();
gl.paint();
}
// don't waste cpu time, sleep more
try {
Thread.sleep(100);
} catch (InterruptedException inte) {
}
}
}
}
/**
* Performs the logic
*/
private void render() {
//clear background
gl.clear(GL.COLOR_BUFFER_BIT);
// draw white quad
gl.pushMatrix();
{
gl.translatef(mouse_x, 600 - mouse_y, 0);
gl.color3f(1.0f, 1.0f, 1.0f);
gl.begin(GL.QUADS);
{
gl.vertex2i(-50, -50);
gl.vertex2i(50, -50);
gl.vertex2i(50, 50);
gl.vertex2i(-50, 50);
}
gl.end();
}
gl.popMatrix();
}
/**
* Processes keyboard input
*/
private void processKeyboard() {
Keyboard.poll();
Mouse.poll();
if (Mouse.dx != 0 || Mouse.dy != 0) {
mouse_x += Mouse.dx;
mouse_y += Mouse.dy;
System.out.println("mouse_x " + mouse_x + " mouse_y " + mouse_y);
}
//check for fullscreen key
if (Keyboard.isKeyDown(Keyboard.KEY_F)) {
try {
Keyboard.destroy();
try {
Mouse.setNativeCursor(null);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
cursor.destroy();
Mouse.destroy();
gl.destroy();
Display.setDisplayMode(mode);
gl = new GL("Test", mode.bpp, 0, 0, 0);
gl.create();
glu = new GLU(gl);
glInit();
Keyboard.create();
initNativeCursor();
} catch (Exception e) {
e.printStackTrace();
}
}
//check for window key
if (Keyboard.isKeyDown(Keyboard.KEY_W)) {
try {
Keyboard.destroy();
try {
Mouse.setNativeCursor(null);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
cursor.destroy();
Mouse.destroy();
gl.destroy();
Display.resetDisplayMode();
gl = new GL("Test", 50, 50, mode.width, mode.height, mode.bpp, 0, 0, 0);
gl.create();
glu = new GLU(gl);
glInit();
Keyboard.create();
initNativeCursor();
} catch (Exception e) {
e.printStackTrace();
}
}
if (Keyboard.isKeyDown(Keyboard.KEY_M)) {
try {
Mouse.setNativeCursor(null);
} catch (Exception e) {
e.printStackTrace();
}
}
if (Keyboard.isKeyDown(Keyboard.KEY_N)) {
try {
Mouse.setNativeCursor(cursor);
mouse_x = mouse_y = 0;
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Cleans up the test
*/
private void cleanup() {
Keyboard.destroy();
try {
Mouse.setNativeCursor(null);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
cursor.destroy();
Mouse.destroy();
Display.resetDisplayMode();
gl.destroy();
}
/**
* Retrieves a displaymode, if one such is available
*
* @param width Required width
* @param height Required height
* @param bpp Minimum required bits per pixel
* @return
*/
private DisplayMode findDisplayMode(int width, int height, int bpp) {
DisplayMode[] modes = Display.getAvailableDisplayModes();
for (int i = 0; i < modes.length; i++) {
if (modes[i].width == width
&& modes[i].height == height
&& modes[i].bpp >= bpp) {
return modes[i];
}
}
return null;
}
/**
* Initializes OGL
*/
private void glInit() {
// Go into orthographic projection mode.
gl.determineAvailableExtensions();
gl.matrixMode(GL.PROJECTION);
gl.loadIdentity();
glu.ortho2D(0, mode.width, 0, mode.height);
gl.matrixMode(GL.MODELVIEW);
gl.loadIdentity();
gl.viewport(0, 0, mode.width, mode.height);
//set clear color to black
gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
//sync frame (only works on windows)
if (GL.WGL_EXT_swap_control) {
GL.wglSwapIntervalEXT(1);
}
}
/**
* Test entry point
*/
public static void main(String[] args) {
System.out.println(
"Change between fullscreen and windowed mode, by pressing F and W respectively. Enable hw cursor with N and disable it with M.");
System.out.println(
"Move quad using arrowkeys, and change rotation using +/-");
HWCursorTest cursorTest = new HWCursorTest();
cursorTest.execute();
}
}

View file

@ -3331,7 +3331,6 @@ int extgl_Open(void)
void extgl_Close(void)
{
#ifdef _X11
printf("closing handles\n");
dlclose(lib_glu_handle);
dlclose(lib_gl_handle);
#endif

View file

@ -0,0 +1,31 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_lwjgl_input_Cursor */
#ifndef _Included_org_lwjgl_input_Cursor
#define _Included_org_lwjgl_input_Cursor
#ifdef __cplusplus
extern "C" {
#endif
/* Inaccessible static: _00024assertionsDisabled */
/* Inaccessible static: class_00024org_00024lwjgl_00024input_00024Cursor */
/*
* Class: org_lwjgl_input_Cursor
* Method: nCreateCursor
* Signature: (IIIII)I
*/
JNIEXPORT jint JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor
(JNIEnv *, jclass, jint, jint, jint, jint, jint);
/*
* Class: org_lwjgl_input_Cursor
* Method: nDestroyCursor
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Cursor_nDestroyCursor
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -15,7 +15,40 @@ extern "C" {
/* Inaccessible static: dwheel */
/* Inaccessible static: buttonCount */
/* Inaccessible static: hasWheel */
/* Inaccessible static: class_000240 */
/* Inaccessible static: currentCursor */
/* Inaccessible static: class_00024org_00024lwjgl_00024input_00024Mouse */
/*
* Class: org_lwjgl_input_Mouse
* Method: nIsNativeCursorSupported
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nIsNativeCursorSupported
(JNIEnv *, jclass);
/*
* Class: org_lwjgl_input_Mouse
* Method: nSetNativeCursor
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nSetNativeCursor
(JNIEnv *, jclass, jint);
/*
* Class: org_lwjgl_input_Mouse
* Method: nGetMinCursorSize
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetMinCursorSize
(JNIEnv *, jclass);
/*
* Class: org_lwjgl_input_Mouse
* Method: nGetMaxCursorSize
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetMaxCursorSize
(JNIEnv *, jclass);
/*
* Class: org_lwjgl_input_Mouse
* Method: initIDs

View file

@ -9,7 +9,8 @@ NATIVE = \
org_lwjgl_input_Controller.cpp \
org_lwjgl_input_Keyboard.cpp \
org_lwjgl_input_Mouse.cpp \
org_lwjgl_input_Cursor.cpp \
org_lwjgl_opengl_BaseGL.cpp \
org_lwjgl_Window.cpp
org_lwjgl_Window.cpp \
extxcursor.cpp

View file

@ -47,6 +47,11 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
/*
* update input grabbing(keyboard, mouse)
*/
extern void updateInput(void);
/*
* release input (keyboard, mouse)
*/
@ -99,6 +104,16 @@
*/
extern Window getCurrentWindow(void);
/*
* Return true if a native cursor is active
*/
extern bool isNativeCursor(void);
/*
* Return true if we are in fullscreen mode
*/
extern bool isFullscreen(void);
/*
* Utility function to throw an Exception
*/

View file

@ -0,0 +1,63 @@
#include <stdio.h>
#include <dlfcn.h>
#include "extxcursor.h"
static void * xcursor_handle = NULL;
static const char *xcursor_lib_name = "libXcursor.so.1";
static bool load_success;
XcursorSupportsARGBPROC XcursorSupportsARGB = NULL;
XcursorSupportsAnimPROC XcursorSupportsAnim = NULL;
XcursorImageCreatePROC XcursorImageCreate = NULL;
XcursorImageDestroyPROC XcursorImageDestroy = NULL;
XcursorImagesCreatePROC XcursorImagesCreate = NULL;
XcursorImagesDestroyPROC XcursorImagesDestroy = NULL;
XcursorImagesLoadCursorPROC XcursorImagesLoadCursor = NULL;
static void * loadHandle(const char * func_name) {
void * func_pointer = dlsym(xcursor_handle, func_name);
if (func_pointer == NULL) {
load_success = false;
return NULL;
}
return func_pointer;
}
static bool loadFunctionPointers(void) {
XcursorSupportsARGB = (XcursorSupportsARGBPROC)loadHandle("XcursorSupportsARGB");
XcursorSupportsAnim = (XcursorSupportsAnimPROC)loadHandle("XcursorSupportsAnim");
XcursorImageCreate = (XcursorImageCreatePROC)loadHandle("XcursorImageCreate");
XcursorImageDestroy = (XcursorImageDestroyPROC)loadHandle("XcursorImageDestroy");
XcursorImagesCreate = (XcursorImagesCreatePROC)loadHandle("XcursorImagesCreate");
XcursorImagesDestroy = (XcursorImagesDestroyPROC)loadHandle("XcursorImagesDestroy");
XcursorImagesLoadCursor = (XcursorImagesLoadCursorPROC)loadHandle("XcursorImagesLoadCursor");
return load_success;
}
bool loadXcursor(void) {
load_success = true;
xcursor_handle = dlopen(xcursor_lib_name, RTLD_GLOBAL | RTLD_LAZY);
if (xcursor_handle == NULL) {
printf("Could not load %s: %s\n", xcursor_lib_name, dlerror());
return false;
}
loadFunctionPointers();
return load_success;
}
bool isXcursorLoaded(void) {
return load_success;
}
void closeXcursor(void) {
load_success = false;
dlclose(xcursor_handle);
xcursor_handle = NULL;
XcursorSupportsARGB = NULL;
XcursorSupportsAnim = NULL;
XcursorImageCreate = NULL;
XcursorImageDestroy = NULL;
XcursorImagesCreate = NULL;
XcursorImagesDestroy = NULL;
XcursorImagesLoadCursor = NULL;
}

View file

@ -0,0 +1,51 @@
#include <X11/Xlib.h>
#define XcursorTrue 1
#define XcursorFalse 0
typedef int XcursorBool;
typedef int XcursorBool;
typedef unsigned int XcursorUInt;
typedef XcursorUInt XcursorDim;
typedef XcursorUInt XcursorPixel;
typedef struct _XcursorImage {
XcursorUInt version; /* version of the image data */
XcursorDim size; /* nominal size for matching */
XcursorDim width; /* actual width */
XcursorDim height; /* actual height */
XcursorDim xhot; /* hot spot x (must be inside image) */
XcursorDim yhot; /* hot spot y (must be inside image) */
XcursorUInt delay; /* animation delay to next frame (ms) */
XcursorPixel *pixels; /* pointer to pixels */
} XcursorImage;
/*
* Other data structures exposed by the library API
*/
typedef struct _XcursorImages {
int nimage; /* number of images */
XcursorImage **images; /* array of XcursorImage pointers */
} XcursorImages;
typedef XcursorBool (* XcursorSupportsARGBPROC ) (Display *dpy);
typedef XcursorBool (* XcursorSupportsAnimPROC ) (Display *dpy);
typedef XcursorImage * (* XcursorImageCreatePROC) (int width, int height);
typedef void (* XcursorImageDestroyPROC) (XcursorImage *image);
typedef XcursorImages * (* XcursorImagesCreatePROC) (int size);
typedef void (* XcursorImagesDestroyPROC) (XcursorImages *images);
typedef Cursor (* XcursorImagesLoadCursorPROC) (Display *dpy, const XcursorImages *images);
extern XcursorSupportsARGBPROC XcursorSupportsARGB;
extern XcursorSupportsAnimPROC XcursorSupportsAnim;
extern XcursorImageCreatePROC XcursorImageCreate;
extern XcursorImageDestroyPROC XcursorImageDestroy;
extern XcursorImagesCreatePROC XcursorImagesCreate;
extern XcursorImagesDestroyPROC XcursorImagesDestroy;
extern XcursorImagesLoadCursorPROC XcursorImagesLoadCursor;
bool loadXcursor(void);
bool isXcursorLoaded(void);
void closeXcursor(void);

View file

@ -68,15 +68,6 @@ static void waitMapped(Display *disp, Window win) {
} while ((event.type != MapNotify) || (event.xmap.event != win));
}
bool releaseInput(void) {
if (current_fullscreen || input_released)
return false;
releaseKeyboard();
releasePointer();
input_released = true;
return true;
}
static void acquireInput(void) {
if (input_released) {
acquireKeyboard();
@ -85,6 +76,30 @@ static void acquireInput(void) {
}
}
static void doReleaseInput(void) {
releaseKeyboard();
releasePointer();
input_released = true;
}
void updateInput(void) {
if (!input_released) {
doReleaseInput();
acquireInput();
}
}
bool releaseInput(void) {
if (current_fullscreen || input_released)
return false;
doReleaseInput();
return true;
}
bool isFullscreen(void) {
return current_fullscreen;
}
static void handleMessages(JNIEnv *env, jobject window_obj) {
XEvent event;
while (XPending(current_disp) > 0) {
@ -108,6 +123,7 @@ static void handleMessages(JNIEnv *env, jobject window_obj) {
env->SetBooleanField(window_obj, env->GetFieldID(env->GetObjectClass(window_obj), "minimized", "Z"), JNI_TRUE);
break;
case Expose:
// XSetInputFocus(current_disp, current_win, RevertToParent, CurrentTime);
env->SetBooleanField(window_obj, env->GetFieldID(env->GetObjectClass(window_obj), "dirty", "Z"), JNI_TRUE);
break;
case ButtonPress:
@ -183,6 +199,7 @@ void createWindow(JNIEnv* env, Display *disp, int screen, XVisualInfo *vis_info,
XMapRaised(disp, win);
waitMapped(disp, win);
XClearWindow(disp, win);
XSetInputFocus(current_disp, current_win, RevertToParent, CurrentTime);
XSync(disp, True);
}

View file

@ -0,0 +1,45 @@
#include "org_lwjgl_input_Cursor.h"
#include "extxcursor.h"
#include "Window.h"
/*
* Class: org_lwjgl_input_Cursor
* Method: nCreateCursor
* Signature: (IIIIIII)I
*/
JNIEXPORT jint JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor
(JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, /*jint num_cursors,*/ jint image_address/*, jint delay_addresses*/)
{
XcursorPixel *pixels = (XcursorPixel *)image_address;
/* int *delays = (int *)delay_addresses;
int stride = width*height;*/
int num_cursors = 1;
XcursorImages *cursor_images = XcursorImagesCreate(num_cursors);
if (cursor_images == NULL)
throwException(env, "Could not allocate cursor.");
cursor_images->nimage = num_cursors;
// for (int i = 0; i < num_cursors; i++) {
XcursorImage *cursor_image = XcursorImageCreate(width, height);
cursor_image->xhot = x_hotspot;
cursor_image->yhot = y_hotspot;
cursor_image->pixels = pixels;
// cursor_image->pixels = &(pixels[stride*i]);
cursor_image->delay = 0/*delays[i]*/;
cursor_images->images[0] = cursor_image;
// }
Cursor cursor = XcursorImagesLoadCursor(getCurrentDisplay(), cursor_images);
XcursorImagesDestroy(cursor_images);
return (jint)cursor;
}
/*
* Class: org_lwjgl_input_Cursor
* Method: nDestroyCursor
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Cursor_nDestroyCursor
(JNIEnv *env, jclass clazz, jint cursor_handle)
{
Cursor cursor = (Cursor)cursor_handle;
XFreeCursor(getCurrentDisplay(), cursor);
}

View file

@ -83,28 +83,34 @@ static void setRepeatMode(int mode) {
XChangeKeyboardControl(getCurrentDisplay(), KBAutoRepeatMode, &repeat_mode);
}
static int grabKeyboard(void) {
int result = XGrabKeyboard(getCurrentDisplay(), getCurrentWindow(), False, GrabModeAsync, GrabModeAsync, CurrentTime);
if (result == GrabSuccess) {
keyboard_grabbed = true;
static void grabKeyboard(void) {
if (isFullscreen() || !isNativeCursor()) {
if (!keyboard_grabbed) {
int result = XGrabKeyboard(getCurrentDisplay(), getCurrentWindow(), False, GrabModeAsync, GrabModeAsync, CurrentTime);
if (result == GrabSuccess) {
keyboard_grabbed = true;
setRepeatMode(AutoRepeatModeOff);
}
}
} else
setRepeatMode(AutoRepeatModeOff);
}
return result;
}
static void ungrabKeyboard(void) {
keyboard_grabbed = false;
XUngrabKeyboard(getCurrentDisplay(), CurrentTime);
if (keyboard_grabbed) {
keyboard_grabbed = false;
XUngrabKeyboard(getCurrentDisplay(), CurrentTime);
}
setRepeatMode(AutoRepeatModeDefault);
}
static void updateGrab(void) {
if (!created)
return;
if (should_grab) {
if (!keyboard_grabbed)
grabKeyboard();
grabKeyboard();
} else {
if (keyboard_grabbed)
ungrabKeyboard();
ungrabKeyboard();
}
}
@ -165,8 +171,7 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Keyboard_nCreate
JNIEXPORT void JNICALL Java_org_lwjgl_input_Keyboard_nDestroy
(JNIEnv * env, jclass clazz)
{
if (keyboard_grabbed)
ungrabKeyboard();
ungrabKeyboard();
created = false;
}
@ -259,7 +264,6 @@ void handleKeyEvent(XKeyEvent *event) {
JNIEXPORT void JNICALL Java_org_lwjgl_input_Keyboard_nPoll
(JNIEnv * env, jclass clazz, jint buf)
{
updateGrab();
memcpy((unsigned char*)buf, key_buf, KEYBOARD_SIZE*sizeof(unsigned char));
}
@ -275,7 +279,6 @@ JNIEXPORT int JNICALL Java_org_lwjgl_input_Keyboard_nRead
int buf_count = 0;
int num_events = 0;
updateGrab();
while (buf_count < KEYBOARD_BUFFER_SIZE * 2 && (key_event = nextEventElement()) != NULL) {
num_events++;
unsigned char keycode = getKeycode(key_event);
@ -286,7 +289,6 @@ JNIEXPORT int JNICALL Java_org_lwjgl_input_Keyboard_nRead
if (translation_enabled)
num_events += translateEvent(&buf_count, key_event);
}
return num_events;
}

View file

@ -47,6 +47,7 @@
#include <string.h>
#include <Window.h>
#include "org_lwjgl_input_Mouse.h"
#include "extxcursor.h"
#define NUM_BUTTONS 3
@ -55,9 +56,10 @@
// scale the mouse wheel according to win32
#define WHEEL_SCALE 120
static bool pointer_grabbed;
static bool pointer_grabbed = false;
static bool created = false;
static bool should_grab = false;
static bool native_cursor = false;
static jfieldID fid_has_wheel = NULL;
static jfieldID fid_button_count = NULL;
@ -75,6 +77,9 @@ static int current_z;
static unsigned char buttons[NUM_BUTTONS];
static Cursor blank_cursor;
static Cursor current_cursor;
static int grab_mask = FocusChangeMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
/*
* Class: org_lwjgl_input_Mouse
@ -118,30 +123,39 @@ static int blankCursor(void) {
return 1;
}
static int grabPointer(void) {
int result;
int mask = FocusChangeMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
result = XGrabPointer(getCurrentDisplay(), getCurrentWindow(), False, mask, GrabModeAsync, GrabModeAsync, getCurrentWindow(), blank_cursor, CurrentTime);
if (result == GrabSuccess) {
pointer_grabbed = true;
XWarpPointer(getCurrentDisplay(), None, getCurrentWindow(), 0, 0, 0, 0, current_x, current_y);
XF86VidModeSetViewPort(getCurrentDisplay(), getCurrentScreen(), 0, 0); // make sure we have a centered window
bool isNativeCursor(void) {
return native_cursor;
}
static void grabPointer(void) {
if (isFullscreen() || !native_cursor) {
if (!pointer_grabbed) {
int result;
result = XGrabPointer(getCurrentDisplay(), getCurrentWindow(), False, grab_mask, GrabModeAsync,
GrabModeAsync, getCurrentWindow(), current_cursor, CurrentTime);
if (result == GrabSuccess) {
pointer_grabbed = true;
// make sure we have a centered window
XF86VidModeSetViewPort(getCurrentDisplay(), getCurrentScreen(), 0, 0);
}
}
}
return result;
}
static void ungrabPointer(void) {
pointer_grabbed = false;
XUngrabPointer(getCurrentDisplay(), CurrentTime);
if (pointer_grabbed) {
pointer_grabbed = false;
XUngrabPointer(getCurrentDisplay(), CurrentTime);
}
}
static void updateGrab(void) {
if (!created)
return;
if (should_grab) {
if (!pointer_grabbed)
grabPointer();
grabPointer();
} else {
if (pointer_grabbed)
ungrabPointer();
ungrabPointer();
}
}
@ -155,6 +169,73 @@ void releasePointer(void) {
updateGrab();
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nIsNativeCursorSupported
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nIsNativeCursorSupported
(JNIEnv *env, jclass clazz) {
if (!isXcursorLoaded())
return false;
XcursorBool argb_supported = XcursorSupportsARGB(getCurrentDisplay());
XcursorBool anim_supported = XcursorSupportsAnim(getCurrentDisplay());
return argb_supported && anim_supported ? JNI_TRUE : JNI_FALSE;
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nSetNativeCursor
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nSetNativeCursor
(JNIEnv *env, jclass clazz, jint cursor_handle)
{
Cursor cursor = (Cursor)cursor_handle;
if (cursor != None) {
if (!native_cursor) {
current_x = current_y = 0;
XWarpPointer(getCurrentDisplay(), None, getCurrentWindow(), 0, 0, 0, 0, current_x, current_y);
native_cursor = true;
}
XDefineCursor(getCurrentDisplay(), getCurrentWindow(), cursor);
current_cursor = cursor;
updateInput();
} else {
if (native_cursor) {
current_cursor = blank_cursor;
XUndefineCursor(getCurrentDisplay(), getCurrentWindow());
native_cursor = false;
updateInput();
}
}
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nGetMaxCursorSize
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetMinCursorSize
(JNIEnv *env, jclass clazz)
{
return 0;
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nGetMaxCursorSize
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetMaxCursorSize
(JNIEnv *env, jclass clazz)
{
unsigned int width_return = 0;
unsigned int height_return = 0;
XQueryBestCursor(getCurrentDisplay(), getCurrentWindow(), 0xffffffff, 0xffffffff, &width_return, &height_return);
return width_return > height_return ? height_return : width_return;
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nCreate
@ -164,21 +245,24 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nCreate
(JNIEnv * env, jclass clazz)
{
int i;
env->SetStaticIntField(clazz, fid_button_count, NUM_BUTTONS);
env->SetStaticBooleanField(clazz, fid_has_wheel, JNI_TRUE);
current_x = current_y = current_z = last_x = last_y = last_z = pointer_grabbed = 0;
current_x = current_y = current_z = last_x = last_y = last_z;
for (i = 0; i < NUM_BUTTONS; i++)
buttons[i] = JNI_FALSE;
if (!blankCursor()) {
#ifdef _DEBUG
printf("Could create blank cursor\n");
printf("Could not create blank cursor\n");
#endif
return JNI_FALSE;
}
current_cursor = blank_cursor;
native_cursor = false;
created = true;
should_grab = true;
pointer_grabbed = false;
updateGrab();
loadXcursor();
return JNI_TRUE;
}
@ -190,60 +274,66 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nCreate
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nDestroy
(JNIEnv * env, jclass clazz)
{
if (pointer_grabbed)
ungrabPointer();
closeXcursor();
ungrabPointer();
XFreeCursor(getCurrentDisplay(), blank_cursor);
created = false;
should_grab = false;
}
void handleButtonPress(XButtonEvent *event) {
switch (event->button) {
case Button1:
buttons[0] = JNI_TRUE;
break;
case Button2:
buttons[2] = JNI_TRUE;
break;
case Button3:
buttons[1] = JNI_TRUE;
break;
case Button4:
current_z += WHEEL_SCALE;
break;
case Button5:
current_z -= WHEEL_SCALE;
break;
default: assert(0);
if (pointer_grabbed || native_cursor) {
switch (event->button) {
case Button1:
buttons[0] = JNI_TRUE;
break;
case Button2:
buttons[2] = JNI_TRUE;
break;
case Button3:
buttons[1] = JNI_TRUE;
break;
case Button4:
current_z += WHEEL_SCALE;
break;
case Button5:
current_z -= WHEEL_SCALE;
break;
default: assert(0);
}
}
}
void handleButtonRelease(XButtonEvent *event) {
switch (event->button) {
case Button1:
buttons[0] = JNI_FALSE;
break;
case Button2:
buttons[2] = JNI_FALSE;
break;
case Button3:
buttons[1] = JNI_FALSE;
break;
case Button4: /* Fall through */
case Button5:
break;
default: assert(0);
if (pointer_grabbed || native_cursor) {
switch (event->button) {
case Button1:
buttons[0] = JNI_FALSE;
break;
case Button2:
buttons[2] = JNI_FALSE;
break;
case Button3:
buttons[1] = JNI_FALSE;
break;
case Button4: /* Fall through */
case Button5:
break;
default: assert(0);
}
}
}
void handlePointerMotion(XMotionEvent *event) {
current_x = event->x;
current_y = event->y;
if (pointer_grabbed || native_cursor) {
current_x = event->x;
current_y = event->y;
}
}
static void warpPointer(void) {
int i;
if (!pointer_grabbed)
if (!pointer_grabbed || native_cursor)
return;
// Reset pointer to middle of screen if inside a certain inner border
if (current_x < POINTER_WARP_BORDER || current_y < POINTER_WARP_BORDER ||
@ -279,7 +369,6 @@ static void warpPointer(void) {
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nPoll
(JNIEnv * env, jclass clazz)
{
updateGrab();
int moved_x = current_x - last_x;
int moved_y = current_y - last_y;
int moved_z = current_z - last_z;

View file

@ -59,6 +59,7 @@
extern LPDIRECTINPUT lpdi; // DirectInput
extern bool isFullScreen; // Whether we're fullscreen or not
extern bool isMinimized; // Whether we're minimized or not
extern RECT clientSize;
#endif /* _PRIVATE_WINDOW_H_ */
/*
@ -82,7 +83,6 @@
*/
WINDOW_H_API void closeWindow();
/*
* Utility function to throw an Exception
*/
@ -93,4 +93,4 @@
*/
WINDOW_H_API void throwRuntimeException(JNIEnv * env, const char * err);
#endif /* _LWJGL_WINDOW_H_INCLUDED_ */
#endif /* _LWJGL_WINDOW_H_INCLUDED_ */

View file

@ -52,6 +52,7 @@ bool isMinimized = false; // Whether we're minimized or not
JNIEnv * environment = NULL; // Cached environment
jobject window; // Cached Java Window instance handle
extern HINSTANCE dll_handle; // Handle to the LWJGL dll
RECT clientSize;
#define WINDOWCLASSNAME "LWJGL"
@ -140,9 +141,7 @@ void closeWindow()
}
// Show the mouse
if (isFullScreen) {
ShowCursor(TRUE);
}
ShowCursor(TRUE);
}
/*
@ -153,8 +152,9 @@ void appActivate(bool active)
if (active) {
SetForegroundWindow(hwnd);
ShowWindow(hwnd, SW_RESTORE);
} else if (isFullScreen)
} else if (isFullScreen) {
ShowWindow(hwnd, SW_MINIMIZE);
}
}
/*
@ -239,7 +239,7 @@ bool registerWindow()
windowClass.cbWndExtra = 0;
windowClass.hInstance = dll_handle;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hCursor = NULL/*LoadCursor(NULL, IDC_ARROW)*/;
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = WINDOWCLASSNAME;
@ -283,7 +283,6 @@ bool createWindow(const char * title, int x, int y, int width, int height, bool
// If we're not a fullscreen window, adjust the height to account for the
// height of the title bar:
RECT clientSize;
clientSize.bottom = height;
clientSize.left = 0;
clientSize.right = width;
@ -296,16 +295,13 @@ bool createWindow(const char * title, int x, int y, int width, int height, bool
exstyle // extended window style
);
clientSize.bottom -= clientSize.top;
clientSize.right -= clientSize.left;
// Create the window now, using that class:
hwnd = CreateWindowEx (
exstyle,
WINDOWCLASSNAME,
title,
windowflags,
x, y, clientSize.right, clientSize.bottom,
x, y, clientSize.right - clientSize.left, clientSize.bottom - clientSize.top,
NULL,
NULL,
dll_handle,
@ -332,9 +328,7 @@ bool createWindow(const char * title, int x, int y, int width, int height, bool
// 3. Hide the mouse if necessary
isFullScreen = fullscreen == JNI_TRUE;
if (isFullScreen) {
ShowCursor(FALSE);
}
ShowCursor(FALSE);
// 4. Create DirectInput
if (!createDirectInput()) {

View file

@ -51,45 +51,45 @@
extern HINSTANCE dll_handle;
extern HWND hwnd;
IDirectInput* cDI; // DI instance
IDirectInputDevice2* cDIDevice; // DI Device instance
DIJOYSTATE2 cJS; // State of Controller
static IDirectInput* cDI; // DI instance
static IDirectInputDevice2* cDIDevice; // DI Device instance
static DIJOYSTATE2 cJS; // State of Controller
int cButtoncount = 0; // Temporary buttoncount
bool cHasx; // Temporary xaxis check
bool cHasrx; // Temporary rotational xaxis check
bool cHasy; // Temporary yaxis check
bool cHasry; // Temporary rotational yaxis check
bool cHasz; // Temporary zaxis check
bool cHasrz; // Temporary rotational zaxis check
bool cHaspov; // Temporary pov check
bool cHasslider; // Temporary slider check
static int cButtoncount = 0; // Temporary buttoncount
static bool cHasx; // Temporary xaxis check
static bool cHasrx; // Temporary rotational xaxis check
static bool cHasy; // Temporary yaxis check
static bool cHasry; // Temporary rotational yaxis check
static bool cHasz; // Temporary zaxis check
static bool cHasrz; // Temporary rotational zaxis check
static bool cHaspov; // Temporary pov check
static bool cHasslider; // Temporary slider check
JNIEnv* cEnvironment; // JNIEnvironment copy
static JNIEnv* cEnvironment; // JNIEnvironment copy
bool cCreate_success; // bool used to determine successfull creation
bool cFirstTimeInitialization = true; // boolean to determine first time initialization
static bool cCreate_success; // bool used to determine successfull creation
static bool cFirstTimeInitialization = true; // boolean to determine first time initialization
// Cached fields of Controller.java
jclass clsController;
jfieldID fidCButtonCount;
jfieldID fidCHasXAxis;
jfieldID fidCHasRXAxis;
jfieldID fidCHasYAxis;
jfieldID fidCHasRYAxis;
jfieldID fidCHasZAxis;
jfieldID fidCHasRZAxis;
jfieldID fidCHasPOV;
jfieldID fidCHasSlider;
jfieldID fidCButtons;
jfieldID fidCX;
jfieldID fidCRX;
jfieldID fidCY;
jfieldID fidCRY;
jfieldID fidCZ;
jfieldID fidCRZ;
jfieldID fidCPOV;
jfieldID fidCSlider;
static jclass clsController;
static jfieldID fidCButtonCount;
static jfieldID fidCHasXAxis;
static jfieldID fidCHasRXAxis;
static jfieldID fidCHasYAxis;
static jfieldID fidCHasRYAxis;
static jfieldID fidCHasZAxis;
static jfieldID fidCHasRZAxis;
static jfieldID fidCHasPOV;
static jfieldID fidCHasSlider;
static jfieldID fidCButtons;
static jfieldID fidCX;
static jfieldID fidCRX;
static jfieldID fidCY;
static jfieldID fidCRY;
static jfieldID fidCZ;
static jfieldID fidCRZ;
static jfieldID fidCPOV;
static jfieldID fidCSlider;
// Function prototypes (defined in the cpp file, since header file is generic across platforms
void EnumerateControllerCapabilities();

View file

@ -0,0 +1,111 @@
#include <windows.h>
#include "org_lwjgl_input_Cursor.h"
#include "Window.h"
/*
* Class: org_lwjgl_input_Cursor
* Method: nCreateCursor
* Signature: (IIIIIII)I
*/
JNIEXPORT jint JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor
(JNIEnv *env, jclass clazz, jint width, jint height, jint x_hotspot, jint y_hotspot, jint image_address)
{
int *pixels = (int *)image_address;
BITMAPINFO bitmapInfo;
char *ptrCursorImage;
HBITMAP colorDIB;
HBITMAP colorBitmap;
int x, y;
memset(&bitmapInfo, 0, sizeof(BITMAPINFO));
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = width;
bitmapInfo.bmiHeader.biHeight = -height;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 24;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
colorDIB = CreateDIBSection(hdc, (BITMAPINFO*)&(bitmapInfo),
DIB_RGB_COLORS,
(void**)&(ptrCursorImage),
NULL, 0);
int *srcPtr = pixels;
char *dstPtr = ptrCursorImage;
if (!dstPtr) {
throwException(env, "Could not allocate DIB section.");
return 0;
}
for (y = 0; y < height; y++ ) {
for (x = 0; x < width; x++ ) {
dstPtr[2] = (*srcPtr >> 0x10) & 0xFF;
dstPtr[1] = (*srcPtr >> 0x08) & 0xFF;
dstPtr[0] = *srcPtr & 0xFF;
srcPtr++;
dstPtr += 3;
}
}
colorBitmap = CreateDIBitmap(hdc,
(BITMAPINFOHEADER*)&bitmapInfo.bmiHeader,
CBM_INIT,
(void *)ptrCursorImage,
(BITMAPINFO*)&bitmapInfo,
DIB_RGB_COLORS);
DeleteObject(colorDIB);
// Convert alpha map to pixel packed mask
int bitWidth = width >> 3;
int scanlinePad = bitWidth & (sizeof(WORD) - 1);
int imageSize = (bitWidth + scanlinePad)*height; // Size in bits
unsigned char *maskPixels = new unsigned char[imageSize];
memset(maskPixels, 0, imageSize);
int pixelCount = 0;
int maskCount = 0;
for (y = 0; y < height; y++)
for (x = 0; x < bitWidth; x++) {
unsigned char col0 = (pixels[pixelCount++] & 0x01000000) >> 17;
unsigned char col1 = (pixels[pixelCount++] & 0x01000000) >> 18;
unsigned char col2 = (pixels[pixelCount++] & 0x01000000) >> 19;
unsigned char col3 = (pixels[pixelCount++] & 0x01000000) >> 20;
unsigned char col4 = (pixels[pixelCount++] & 0x01000000) >> 21;
unsigned char col5 = (pixels[pixelCount++] & 0x01000000) >> 22;
unsigned char col6 = (pixels[pixelCount++] & 0x01000000) >> 23;
unsigned char col7 = (pixels[pixelCount++] & 0x01000000) >> 24;
unsigned char mask = col0 | col1 | col2 | col3 | col4 | col5 | col6 | col7;
maskPixels[maskCount++] = ~mask; // 1 is tranparant, 0 opaque
}
HBITMAP cursorMask = CreateBitmap(width, height, 1, 1, maskPixels);
HCURSOR cursor = NULL;
ICONINFO iconInfo;
memset(&iconInfo, 0, sizeof(ICONINFO));
iconInfo.hbmMask = cursorMask;
iconInfo.hbmColor = colorBitmap;
iconInfo.fIcon = FALSE;
iconInfo.xHotspot = x_hotspot;
iconInfo.yHotspot = y_hotspot;
cursor = CreateIconIndirect(&iconInfo);
DeleteObject(colorBitmap);
DeleteObject(cursorMask);
delete[] maskPixels;
return (jint)cursor;
}
/*
* Class: org_lwjgl_input_Cursor
* Method: nDestroyCursor
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Cursor_nDestroyCursor
(JNIEnv *env, jclass clazz, jint cursor_handle)
{
HCURSOR cursor = (HCURSOR)cursor_handle;
DestroyCursor(cursor);
}

View file

@ -48,10 +48,11 @@
#include "Window.h"
#define KEYBOARD_BUFFER_SIZE 50
BYTE readBuffer[KEYBOARD_BUFFER_SIZE*4];
LPDIRECTINPUTDEVICE lpdiKeyboard = NULL;
jfieldID fid_readBuffer;
bool translationEnabled;
static BYTE readBuffer[KEYBOARD_BUFFER_SIZE*4];
static LPDIRECTINPUTDEVICE lpdiKeyboard = NULL;
static jfieldID fid_readBuffer;
static bool translationEnabled;
/*

View file

@ -46,25 +46,26 @@
#include "Window.h"
#include <dinput.h>
extern HINSTANCE dll_handle;
LPDIRECTINPUTDEVICE mDIDevice; // DI Device instance
DIMOUSESTATE diMouseState; // State of Mouse
static LPDIRECTINPUTDEVICE mDIDevice; // DI Device instance
static int mButtoncount = 0; // Temporary buttoncount
static bool mHaswheel; // Temporary wheel check
static JNIEnv* mEnvironment; // JNIEnvironment copy
int mButtoncount = 0; // Temporary buttoncount
bool mHaswheel; // Temporary wheel check
JNIEnv* mEnvironment; // JNIEnvironment copy
bool mCreate_success; // bool used to determine successfull creation
bool mFirstTimeInitialization = true; // boolean to determine first time initialization
static bool mCreate_success; // bool used to determine successfull creation
static bool mFirstTimeInitialization = true; // boolean to determine first time initialization
// Cached fields of Mouse.java
jclass clsMouse;
jfieldID fidMButtonCount;
jfieldID fidMButtons;
jfieldID fidMDX;
jfieldID fidMDY;
jfieldID fidMDWheel;
jfieldID fidMHasWheel;
static jclass clsMouse;
static jfieldID fidMButtonCount;
static jfieldID fidMButtons;
static jfieldID fidMDX;
static jfieldID fidMDY;
static jfieldID fidMDWheel;
static jfieldID fidMHasWheel;
static POINT cursorPos;
static RECT windowRect;
static bool usingNativeCursor;
// Function prototypes (defined in the cpp file, since header file is generic across platforms
void EnumerateMouseCapabilities();
@ -77,6 +78,16 @@ void CacheMouseFields();
void UpdateMouseFields();
void SetMouseCapabilities();
static void getScreenClientRect(RECT* clientRect, RECT* windowRect)
{
GetClientRect(hwnd, clientRect);
// transform clientRect to screen coordinates
clientRect->top = -clientSize.top + windowRect->top;
clientRect->left = -clientSize.left + windowRect->left;
clientRect->bottom += clientRect->top;
clientRect->right += clientRect->left;
}
/**
* Initializes any field ids
*/
@ -92,51 +103,131 @@ JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_initIDs(JNIEnv * env, jclass c
* Called when the Mouse instance is to be created
*/
JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nCreate(JNIEnv *env, jclass clazz) {
HRESULT hr;
HRESULT hr;
mEnvironment = env;
clsMouse = clazz;
mEnvironment = env;
clsMouse = clazz;
CacheMouseFields();
CacheMouseFields();
/* skip enumeration, since we only want system mouse */
CreateMouse();
/* skip enumeration, since we only want system mouse */
CreateMouse();
//check for first time initialization - need to detect capabilities
if (mFirstTimeInitialization) {
mFirstTimeInitialization = false;
/* Enumerate capabilities of Mouse */
EnumerateMouseCapabilities();
if (!mCreate_success) {
#if _DEBUG
printf("EnumerateMouseCapabilities failed\n");
#endif
ShutdownMouse();
return JNI_FALSE;
}
/* Do setup of Mouse */
SetupMouse();
/* Set capabilities */
SetMouseCapabilities();
} else {
if(mCreate_success) {
/* Do setup of Mouse */
SetupMouse();
}
}
/* Aquire the Mouse */
hr = mDIDevice->Acquire();
if(FAILED(hr)) {
//check for first time initialization - need to detect capabilities
if (mFirstTimeInitialization) {
mFirstTimeInitialization = false;
/* Enumerate capabilities of Mouse */
EnumerateMouseCapabilities();
if (!mCreate_success) {
#if _DEBUG
printf("Failed to acquire mouse\n");
printf("EnumerateMouseCapabilities failed\n");
#endif
}
ShutdownMouse();
return JNI_FALSE;
}
/* Do setup of Mouse */
SetupMouse();
return mCreate_success ? JNI_TRUE : JNI_FALSE;
/* Set capabilities */
SetMouseCapabilities();
} else {
if(mCreate_success) {
/* Do setup of Mouse */
SetupMouse();
}
}
/* Aquire the Mouse */
hr = mDIDevice->Acquire();
if(FAILED(hr)) {
#if _DEBUG
printf("Failed to acquire mouse\n");
#endif
}
return mCreate_success ? JNI_TRUE : JNI_FALSE;
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nIsNativeCursorSupported
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Mouse_nIsNativeCursorSupported
(JNIEnv *env, jclass clazz)
{
return JNI_TRUE;
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nSetNativeCursor
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nSetNativeCursor
(JNIEnv *env, jclass clazz, jint cursor_handle)
{
if (cursor_handle != NULL) {
if (mDIDevice == NULL)
throwException(env, "null device!");
mDIDevice->Unacquire();
if(mDIDevice->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND) != DI_OK) {
#if _DEBUG
printf("SetCooperativeLevel failed\n");
#endif
throwException(env, "Could not set the CooperativeLevel.");
return;
}
HCURSOR cursor = (HCURSOR)cursor_handle;
SetClassLong(hwnd, GCL_HCURSOR, (LONG)cursor);
SetCursor(cursor);
if (!usingNativeCursor) {
/* Reset cursor position to 0, 0 */
RECT clientRect;
GetWindowRect(hwnd, &windowRect);
getScreenClientRect(&clientRect, &windowRect);
SetCursorPos(clientRect.left, clientRect.top);
cursorPos.x = clientRect.left;
cursorPos.y = clientRect.top;
while (ShowCursor(TRUE) < 0)
;
usingNativeCursor = true;
}
} else {
while (ShowCursor(FALSE) >= 0)
;
SetClassLong(hwnd, GCL_HCURSOR, (LONG)NULL);
SetCursor(NULL);
mDIDevice->Unacquire();
if(mDIDevice->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND) != DI_OK) {
#if _DEBUG
printf("SetCooperativeLevel failed\n");
#endif
throwException(env, "Could not set the CooperativeLevel.");
return;
}
usingNativeCursor = false;
}
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nGetMaxCursorSize
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetMaxCursorSize
(JNIEnv *env, jclass clazz)
{
return GetSystemMetrics(SM_CXCURSOR);
}
/*
* Class: org_lwjgl_input_Mouse
* Method: nGetMaxCursorSize
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetMinCursorSize
(JNIEnv *env, jclass clazz)
{
return GetSystemMetrics(SM_CXCURSOR);
}
/*
@ -177,25 +268,25 @@ void ShutdownMouse() {
* Enumerates the capabilities of the Mouse attached to the system
*/
void EnumerateMouseCapabilities() {
HRESULT hr;
hr = mDIDevice->EnumObjects(EnumMouseObjectsCallback, NULL, DIDFT_ALL);
if FAILED(hr) {
HRESULT hr;
hr = mDIDevice->EnumObjects(EnumMouseObjectsCallback, NULL, DIDFT_ALL);
if FAILED(hr) {
#if _DEBUG
printf("EnumObjects failed\n");
printf("EnumObjects failed\n");
#endif
mCreate_success = false;
return;
}
mCreate_success = false;
return;
}
//check for > 4 buttons - need to clamp since we're using dx 5
if(mButtoncount > 4) {
mButtoncount = 4;
//check for > 4 buttons - need to clamp since we're using dx 5
if(mButtoncount > 4) {
mButtoncount = 4;
#ifdef _DEBUG
printf("WARNING: Clamping to 4 mouse buttons");
printf("WARNING: Clamping to 4 mouse buttons\n");
#endif
}
}
mCreate_success = true;
mCreate_success = true;
}
/**
@ -259,46 +350,80 @@ void SetupMouse() {
mCreate_success = true;
}
static void getGDICursorDelta(int* return_dx, int* return_dy) {
int dx = 0;
int dy = 0;
POINT newCursorPos;
GetCursorPos(&newCursorPos);
RECT clientRect;
RECT newWindowRect;
GetWindowRect(hwnd, &newWindowRect);
cursorPos.x += newWindowRect.left - windowRect.left;
cursorPos.y += newWindowRect.top - windowRect.top;
windowRect = newWindowRect;
getScreenClientRect(&clientRect, &windowRect);
// Clip the position to the client rect
if (newCursorPos.x < clientRect.right && newCursorPos.x >= clientRect.left &&
newCursorPos.y < clientRect.bottom && newCursorPos.y >= clientRect.top) {
dx = newCursorPos.x - cursorPos.x;
dy = newCursorPos.y - cursorPos.y;
cursorPos.x += dx;
cursorPos.y += dy;
}
*return_dx = dx;
*return_dy = dy;
}
/**
* Updates the fields on the Mouse
*/
void UpdateMouseFields() {
HRESULT hRes;
HRESULT hRes;
DIMOUSESTATE diMouseState; // State of Mouse
int dx, dy;
// get data from the Mouse
hRes = mDIDevice->GetDeviceState(sizeof(DIMOUSESTATE), &diMouseState);
if (hRes != DI_OK) {
// Don't allow the mouse to drift when failed
diMouseState.lX = 0;
diMouseState.lY = 0;
diMouseState.lZ = 0;
// did the read fail because we lost input for some reason?
// if so, then attempt to reacquire.
if(hRes == DIERR_INPUTLOST || hRes == DIERR_NOTACQUIRED) {
mDIDevice->Acquire();
// get data from the Mouse
hRes = mDIDevice->GetDeviceState(sizeof(DIMOUSESTATE), &diMouseState);
if (hRes != DI_OK) {
// Don't allow the mouse to drift when failed
diMouseState.lX = 0;
diMouseState.lY = 0;
diMouseState.lZ = 0;
// did the read fail because we lost input for some reason?
// if so, then attempt to reacquire.
if(hRes == DIERR_INPUTLOST || hRes == DIERR_NOTACQUIRED) {
mDIDevice->Acquire();
#if _DEBUG
printf("DIERR_INPUTLOST, reaquiring input : mCreate_success=%d\n", mCreate_success);
printf("DIERR_INPUTLOST, reaquiring input : mCreate_success=%d\n", mCreate_success);
#endif
} else {
} else {
#if _DEBUG
printf("Error getting mouse state: %d\n", hRes);
printf("Error getting mouse state: %d\n", hRes);
#endif
}
}
}
}
mEnvironment->SetStaticIntField(clsMouse, fidMDX, (jint) diMouseState.lX);
mEnvironment->SetStaticIntField(clsMouse, fidMDY, (jint) diMouseState.lY);
mEnvironment->SetStaticIntField(clsMouse, fidMDWheel, (jint) diMouseState.lZ);
if (usingNativeCursor) {
getGDICursorDelta(&dx, &dy);
} else {
dx = diMouseState.lX;
dy = diMouseState.lY;
}
mEnvironment->SetStaticIntField(clsMouse, fidMDX, (jint)dx);
mEnvironment->SetStaticIntField(clsMouse, fidMDY, (jint)dy);
mEnvironment->SetStaticIntField(clsMouse, fidMDWheel, (jint)diMouseState.lZ);
for (int i = 0; i < mButtoncount; i++) {
if (diMouseState.rgbButtons[i] != 0) {
diMouseState.rgbButtons[i] = JNI_TRUE;
} else {
diMouseState.rgbButtons[i] = JNI_FALSE;
}
}
jbooleanArray mButtonsArray = (jbooleanArray) mEnvironment->GetStaticObjectField(clsMouse, fidMButtons);
mEnvironment->SetBooleanArrayRegion(mButtonsArray, 0, mButtoncount, diMouseState.rgbButtons);
for (int i = 0; i < mButtoncount; i++) {
if (diMouseState.rgbButtons[i] != 0) {
diMouseState.rgbButtons[i] = JNI_TRUE;
} else {
diMouseState.rgbButtons[i] = JNI_FALSE;
}
}
jbooleanArray mButtonsArray = (jbooleanArray) mEnvironment->GetStaticObjectField(clsMouse, fidMButtons);
mEnvironment->SetBooleanArrayRegion(mButtonsArray, 0, mButtoncount, diMouseState.rgbButtons);
}
/**