Linux: improve cursor position handling (warp behaviour)
This commit is contained in:
parent
caf9b62ce9
commit
aa60495bb5
|
@ -55,15 +55,12 @@
|
|||
*/
|
||||
extern bool releaseInput(void);
|
||||
|
||||
extern void resetCursor(int x, int y);
|
||||
|
||||
extern bool checkXError(JNIEnv *env);
|
||||
|
||||
extern Atom getWarpAtom(void);
|
||||
|
||||
/*
|
||||
* Various functions to release/acquire keyboard and mouse
|
||||
*/
|
||||
extern void handleWarpEvent(XClientMessageEvent *);
|
||||
extern void handlePointerMotion(XMotionEvent *);
|
||||
extern void handleButtonPress(XButtonEvent *);
|
||||
extern void handleButtonRelease(XButtonEvent *);
|
||||
|
|
|
@ -73,6 +73,14 @@ static unsigned short *g_ramp;
|
|||
static unsigned short *b_ramp;
|
||||
static extension current_extension = NONE;
|
||||
|
||||
int getScreenModeWidth(void) {
|
||||
return current_width;
|
||||
}
|
||||
|
||||
int getScreenModeHeight(void) {
|
||||
return current_height;
|
||||
}
|
||||
|
||||
extension getCurrentDisplayModeExtension(void) {
|
||||
return current_extension;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
|
||||
typedef enum {XRANDR, XF86VIDMODE, NONE} extension;
|
||||
|
||||
extern int getScreenModeWidth(void);
|
||||
extern int getScreenModeHeight(void);
|
||||
extern jobject initDisplay(JNIEnv *env, int screen);
|
||||
extern void switchDisplayMode(JNIEnv * env, jobject mode, int screen);
|
||||
extern void resetDisplayMode(JNIEnv * env, int screen);
|
||||
|
|
|
@ -72,8 +72,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_input_Cursor_nCreateCursor
|
|||
for (int i = 0; i < num_images; i++) {
|
||||
XcursorImage *cursor_image = XcursorImageCreate(width, height);
|
||||
cursor_image->xhot = x_hotspot;
|
||||
// Of some reason, the y hotspot coordinate is offset by 1
|
||||
cursor_image->yhot = y_hotspot + 1;
|
||||
cursor_image->yhot = y_hotspot;
|
||||
cursor_image->pixels = &(pixels[stride*i]);
|
||||
if (num_images > 1)
|
||||
cursor_image->delay = delays[i];
|
||||
|
|
|
@ -39,17 +39,16 @@
|
|||
* @version $Revision$
|
||||
*/
|
||||
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/xf86vmode.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "Window.h"
|
||||
#include "common_tools.h"
|
||||
#include "display.h"
|
||||
#include "org_lwjgl_input_Mouse.h"
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
//#include "extxcursor.h"
|
||||
|
||||
#define NUM_BUTTONS 3
|
||||
|
||||
|
@ -61,12 +60,12 @@
|
|||
static bool pointer_grabbed;
|
||||
static bool created;
|
||||
|
||||
static int dx;
|
||||
static int dy;
|
||||
static int dz;
|
||||
static int last_x;
|
||||
static int last_y;
|
||||
static int last_z;
|
||||
static int current_x;
|
||||
static int current_y;
|
||||
static int current_z;
|
||||
static jbyte buttons[NUM_BUTTONS];
|
||||
static event_queue_t event_queue;
|
||||
static bool buffer_enabled;
|
||||
|
@ -84,24 +83,21 @@ static int cap(int val, int min, int max) {
|
|||
}
|
||||
|
||||
static void setCursorPos(int x, int y) {
|
||||
current_x = cap(x, 0, getWindowWidth() - 1);
|
||||
current_y = cap(y, 0, getWindowHeight() - 1);
|
||||
int current_x = x;
|
||||
int current_y = y;
|
||||
dx += current_x - last_x;
|
||||
dy += current_y - last_y;
|
||||
last_x = current_x;
|
||||
last_y = current_y;
|
||||
}
|
||||
|
||||
static int transformY(int y) {
|
||||
return getWindowHeight() - 1 - y;
|
||||
}
|
||||
|
||||
static void transformCursorPos(int x, int y) {
|
||||
// transform to OpenGL coordinate system center
|
||||
y = transformY(y);
|
||||
setCursorPos(x, y);
|
||||
}
|
||||
|
||||
void resetCursor(int x, int y) {
|
||||
transformCursorPos(x, y);
|
||||
last_x = current_x;
|
||||
last_y = current_y;
|
||||
static void resetCursor(int x, int y) {
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
}
|
||||
|
||||
static bool blankCursor(void) {
|
||||
|
@ -170,27 +166,21 @@ void updatePointerGrab(void) {
|
|||
updateCursor();
|
||||
}
|
||||
|
||||
static void doWarpPointer(void ) {
|
||||
XEvent ignore_warp_guard;
|
||||
ignore_warp_guard.type = ClientMessage;
|
||||
ignore_warp_guard.xclient.message_type = getWarpAtom();
|
||||
ignore_warp_guard.xclient.format = 8;
|
||||
// Tell event loop to start ignoring motion events
|
||||
ignore_warp_guard.xclient.data.b[0] = 1;
|
||||
XSendEvent(getDisplay(), getCurrentWindow(), False, 0, &ignore_warp_guard);
|
||||
XWarpPointer(getDisplay(), None, getCurrentWindow(), 0, 0, 0, 0, getWindowWidth()/2, transformY(getWindowHeight()/2));
|
||||
// Tell event loop to stop ignoring motion events
|
||||
ignore_warp_guard.xclient.data.b[0] = 0;
|
||||
XSendEvent(getDisplay(), getCurrentWindow(), False, 0, &ignore_warp_guard);
|
||||
void handleWarpEvent(XClientMessageEvent *event) {
|
||||
int center_x = event->data.l[0];
|
||||
int center_y = event->data.l[1];
|
||||
resetCursor(center_x, center_y);
|
||||
}
|
||||
|
||||
static void warpPointer(void) {
|
||||
if (!pointer_grabbed || !shouldGrab())
|
||||
return;
|
||||
// Reset pointer to middle of screen if outside a certain inner border
|
||||
if (current_x < POINTER_WARP_BORDER || current_y < POINTER_WARP_BORDER ||
|
||||
current_x > getWindowWidth() - POINTER_WARP_BORDER || current_y > getWindowHeight() - POINTER_WARP_BORDER)
|
||||
doWarpPointer();
|
||||
static void doWarpPointer(int center_x, int center_y) {
|
||||
XEvent warp_event;
|
||||
warp_event.type = ClientMessage;
|
||||
warp_event.xclient.message_type = getWarpAtom();
|
||||
warp_event.xclient.format = 32;
|
||||
warp_event.xclient.data.l[0] = center_x;
|
||||
warp_event.xclient.data.l[1] = center_y;
|
||||
XSendEvent(getDisplay(), getCurrentWindow(), False, 0, &warp_event);
|
||||
XWarpPointer(getDisplay(), None, getCurrentWindow(), 0, 0, 0, 0, center_x, center_y);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_lwjgl_input_Mouse_nGetNativeCursorCaps
|
||||
|
@ -247,7 +237,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nCreate
|
|||
if (disp == NULL)
|
||||
return;
|
||||
int i;
|
||||
current_z = last_z = 0;
|
||||
last_z = last_y = last_x = dx = dy = dz = 0;
|
||||
for (i = 0; i < NUM_BUTTONS; i++)
|
||||
buttons[i] = 0;
|
||||
if (!blankCursor()) {
|
||||
|
@ -261,7 +251,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nCreate
|
|||
buffer_enabled = false;
|
||||
updatePointerGrab();
|
||||
initEventQueue(&event_queue);
|
||||
doWarpPointer();
|
||||
doWarpPointer(getWindowWidth()/2, getWindowHeight()/2);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nDestroy
|
||||
|
@ -299,10 +289,10 @@ static void handleButton(XButtonEvent *event, unsigned char state) {
|
|||
void handleButtonPress(XButtonEvent *event) {
|
||||
switch (event->button) {
|
||||
case Button4:
|
||||
current_z += WHEEL_SCALE;
|
||||
dz += WHEEL_SCALE;
|
||||
break;
|
||||
case Button5:
|
||||
current_z -= WHEEL_SCALE;
|
||||
dz -= WHEEL_SCALE;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
@ -313,14 +303,44 @@ void handleButtonRelease(XButtonEvent *event) {
|
|||
handleButton(event, 0);
|
||||
}
|
||||
|
||||
static int max(int v1, int v2) {
|
||||
return v1 > v2 ? v1 : v2;
|
||||
}
|
||||
|
||||
static int min(int v1, int v2) {
|
||||
return v1 < v2 ? v1 : v2;
|
||||
}
|
||||
|
||||
void handlePointerMotion(XMotionEvent *event) {
|
||||
setCursorPos(event->x, event->y);
|
||||
int x = event->x;
|
||||
int y = event->y;
|
||||
setCursorPos(x, y);
|
||||
if (!pointer_grabbed || !shouldGrab())
|
||||
return;
|
||||
int x_root = event->x_root;
|
||||
int y_root = event->y_root;
|
||||
// find the window position in root coordinates
|
||||
int win_left = x_root - x;
|
||||
int win_top = y_root - y;
|
||||
int win_right = win_left + getWindowWidth();
|
||||
int win_bottom = win_top + getWindowHeight();
|
||||
// cap the window position to the screen dimensions
|
||||
int border_left = max(0, win_left);
|
||||
int border_top = max(0, win_top);
|
||||
int border_right = min(getScreenModeWidth(), win_right);
|
||||
int border_bottom = min(getScreenModeHeight(), win_bottom);
|
||||
// determine whether the cursor is outside the bounds
|
||||
bool outside_limits = x_root < border_left + POINTER_WARP_BORDER || y_root < border_top + POINTER_WARP_BORDER ||
|
||||
x_root > border_right - POINTER_WARP_BORDER || y_root > border_bottom - POINTER_WARP_BORDER;
|
||||
if (outside_limits) {
|
||||
// Find the center of the limits in window coordinates
|
||||
int center_x = (border_right - border_left)/2;
|
||||
int center_y = (border_bottom - border_top)/2;
|
||||
doWarpPointer(center_x, center_y);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nPoll(JNIEnv * env, jclass clazz, jobject coord_buffer_obj, jobject button_buffer_obj) {
|
||||
int moved_x = current_x - last_x;
|
||||
int moved_y = -(current_y - last_y);
|
||||
int moved_z = current_z - last_z;
|
||||
int *coords = (int *)env->GetDirectBufferAddress(coord_buffer_obj);
|
||||
int coords_length = env->GetDirectBufferCapacity(coord_buffer_obj);
|
||||
unsigned char *buttons_buffer = (unsigned char *)env->GetDirectBufferAddress(button_buffer_obj);
|
||||
|
@ -329,18 +349,17 @@ JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nPoll(JNIEnv * env, jclass cla
|
|||
printfDebug("ERROR: Not enough space in coords array: %d < 3\n", coords_length);
|
||||
return;
|
||||
}
|
||||
coords[0] = moved_x;
|
||||
coords[1] = moved_y;
|
||||
coords[2] = moved_z;
|
||||
last_x = current_x;
|
||||
last_y = current_y;
|
||||
last_z = current_z;
|
||||
coords[0] = dx;
|
||||
coords[1] = -dy;
|
||||
coords[2] = dz;
|
||||
dx = 0;
|
||||
dy = 0;
|
||||
dz = 0;
|
||||
int num_buttons = NUM_BUTTONS;
|
||||
if (num_buttons > buttons_length)
|
||||
num_buttons = buttons_length;
|
||||
for (int i = 0; i < num_buttons; i++)
|
||||
buttons_buffer[i] = buttons[i];
|
||||
warpPointer();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_lwjgl_input_Mouse_nEnableBuffer(JNIEnv *env, jclass clazz) {
|
||||
|
|
|
@ -88,7 +88,6 @@ static bool minimized;
|
|||
static bool focused;
|
||||
static bool closerequested;
|
||||
static bool grab;
|
||||
static bool ignore_motion_events;
|
||||
|
||||
static int current_screen;
|
||||
static Display *display_connection = NULL;
|
||||
|
@ -105,10 +104,6 @@ GLXContext getCurrentGLXContext(void) {
|
|||
return context;
|
||||
}
|
||||
|
||||
Atom getWarpAtom(void) {
|
||||
return warp_atom;
|
||||
}
|
||||
|
||||
int getCurrentScreen(void) {
|
||||
return current_screen;
|
||||
}
|
||||
|
@ -153,13 +148,17 @@ Display *incDisplay(JNIEnv *env) {
|
|||
printfDebug("Could not open X display connection\n");
|
||||
return NULL;
|
||||
}
|
||||
warp_atom = XInternAtom(getDisplay(), "ignore_warp_atom", False);
|
||||
warp_atom = XInternAtom(display_connection, "_LWJGL_WARP", False);
|
||||
}
|
||||
async_x_error = false;
|
||||
display_connection_usage++;
|
||||
return display_connection;
|
||||
}
|
||||
|
||||
Atom getWarpAtom(void) {
|
||||
return warp_atom;
|
||||
}
|
||||
|
||||
void decDisplay(void) {
|
||||
display_connection_usage--;
|
||||
if (display_connection_usage == 0) {
|
||||
|
@ -231,14 +230,6 @@ void setGrab(bool new_grab) {
|
|||
}
|
||||
}
|
||||
|
||||
static void handleMotion(XMotionEvent *event) {
|
||||
if (ignore_motion_events) {
|
||||
resetCursor(event->x, event->y);
|
||||
} else {
|
||||
handlePointerMotion(event);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkInput(void) {
|
||||
Window win;
|
||||
int revert_mode;
|
||||
|
@ -256,8 +247,8 @@ static void handleMessages() {
|
|||
XNextEvent(getDisplay(), &event);
|
||||
switch (event.type) {
|
||||
case ClientMessage:
|
||||
if (event.xclient.message_type == getWarpAtom()) {
|
||||
ignore_motion_events = event.xclient.data.b[0] == 1 ? true : false;
|
||||
if (event.xclient.message_type == warp_atom) {
|
||||
handleWarpEvent(&(event.xclient));
|
||||
} else if ((event.xclient.format == 32) && ((Atom)event.xclient.data.l[0] == delete_atom))
|
||||
closerequested = true;
|
||||
break;
|
||||
|
@ -289,7 +280,7 @@ static void handleMessages() {
|
|||
handleButtonRelease(&(event.xbutton));
|
||||
break;
|
||||
case MotionNotify:
|
||||
handleMotion(&(event.xmotion));
|
||||
handlePointerMotion(&(event.xmotion));
|
||||
break;
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
|
@ -351,7 +342,6 @@ static bool createWindow(JNIEnv* env, int width, int height) {
|
|||
closerequested = false;
|
||||
vsync_enabled = false;
|
||||
grab = false;
|
||||
ignore_motion_events = false;
|
||||
Window root_win;
|
||||
Window win;
|
||||
XSetWindowAttributes attribs;
|
||||
|
@ -367,7 +357,7 @@ static bool createWindow(JNIEnv* env, int width, int height) {
|
|||
attribs.background_pixel = 0xFF000000;
|
||||
attribs.win_gravity = NorthWestGravity;
|
||||
attribmask = CWColormap | CWBackPixel | CWEventMask | CWWinGravity;
|
||||
if (isLegacyFullscreen()/* || undecorated*/) {
|
||||
if (isLegacyFullscreen()) {
|
||||
attribmask |= CWOverrideRedirect;
|
||||
attribs.override_redirect = True;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue