Made glfwGetCursorPos query system directly.

Fixes #103.
Fixes #153.
Fixes #193.
Fixes #355.
Fixes #381.
This commit is contained in:
Camilla Berglund 2014-02-11 18:24:01 +01:00
parent 641761ddb0
commit d459145d28
11 changed files with 177 additions and 131 deletions

View File

@ -92,6 +92,8 @@ GLFW bundles a number of dependencies in the `deps/` directory.
the default behavior the default behavior
- Changed static library to build as position independent code for easier use - Changed static library to build as position independent code for easier use
from the Rust language from the Rust language
- Changed `glfwGetCursorPos` to query the system directly for all cursor modes
except captured mode
- Bugfix: The debug context attribute was set from `GL_ARB_debug_output` even - Bugfix: The debug context attribute was set from `GL_ARB_debug_output` even
when a debug context had not been requested when a debug context had not been requested
- Bugfix: The particles example was not linked against the threading library - Bugfix: The particles example was not linked against the threading library

View File

@ -228,10 +228,6 @@ double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos); glfwGetCursorPos(window, &xpos, &ypos);
@endcode @endcode
This function only returns cached cursor positions. It does not poll the
system for the current position. Whenever you poll state, you risk missing the
state change you are looking for.
@subsection input_cursor_mode Cursor modes @subsection input_cursor_mode Cursor modes

View File

@ -81,6 +81,13 @@ The support for EGL is now stable, successfully running on PandaBoards, Mesa,
ANGLE, Wayland, AMD EGL and others. ANGLE, Wayland, AMD EGL and others.
@subsection news_31_getcursorpos Direct query for cursor position
GLFW now queries the system cursor position directly when you call @ref
glfwGetCursorPos instead of returning cached data, except for when the window is
in captured cursor mode.
@section news_30 New features in version 3.0 @section news_30 New features in version 3.0
@subsection news_30_cmake CMake build system @subsection news_30_cmake CMake build system

View File

@ -2573,12 +2573,12 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key);
*/ */
GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button);
/*! @brief Retrieves the last reported cursor position, relative to the client /*! @brief Retrieves the position of the cursor relative to the client area of
* area of the window. * the window.
* *
* This function returns the last reported position of the cursor, in screen * This function returns the position of the cursor, in screen coordinates,
* coordinates, relative to the upper-left corner of the client area of the * relative to the upper-left corner of the client area of the specified
* specified window. * window.
* *
* If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor
* position is unbounded and limited only by the minimum and maximum values of * position is unbounded and limited only by the minimum and maximum values of

View File

@ -63,6 +63,11 @@ typedef struct _GLFWwindowNS
id view; id view;
unsigned int modifierFlags; unsigned int modifierFlags;
// The total sum of the distances the cursor has been warped
// since the last cursor motion event was processed
// This is kept to counteract Cocoa doing the same internally
double warpDeltaX, warpDeltaY;
} _GLFWwindowNS; } _GLFWwindowNS;

View File

@ -156,25 +156,31 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect)
- (void)windowDidResize:(NSNotification *)notification - (void)windowDidResize:(NSNotification *)notification
{ {
if (_glfw.focusedWindow == window &&
window->cursorMode == GLFW_CURSOR_DISABLED)
{
centerCursor(window);
}
const NSRect contentRect = [window->ns.view frame]; const NSRect contentRect = [window->ns.view frame];
const NSRect fbRect = convertRectToBacking(window, contentRect); const NSRect fbRect = convertRectToBacking(window, contentRect);
_glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
_glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height);
_glfwInputWindowDamage(window); _glfwInputWindowDamage(window);
if (window->cursorMode == GLFW_CURSOR_DISABLED)
centerCursor(window);
} }
- (void)windowDidMove:(NSNotification *)notification - (void)windowDidMove:(NSNotification *)notification
{ {
if (_glfw.focusedWindow == window &&
window->cursorMode == GLFW_CURSOR_DISABLED)
{
centerCursor(window);
}
int x, y; int x, y;
_glfwPlatformGetWindowPos(window, &x, &y); _glfwPlatformGetWindowPos(window, &x, &y);
_glfwInputWindowPos(window, x, y); _glfwInputWindowPos(window, x, y);
if (window->cursorMode == GLFW_CURSOR_DISABLED)
centerCursor(window);
} }
- (void)windowDidMiniaturize:(NSNotification *)notification - (void)windowDidMiniaturize:(NSNotification *)notification
@ -192,6 +198,12 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect)
if (window->monitor) if (window->monitor)
enterFullscreenMode(window); enterFullscreenMode(window);
if (_glfw.focusedWindow == window &&
window->cursorMode == GLFW_CURSOR_DISABLED)
{
centerCursor(window);
}
_glfwInputWindowFocus(window, GL_TRUE); _glfwInputWindowFocus(window, GL_TRUE);
_glfwPlatformApplyCursorMode(window); _glfwPlatformApplyCursorMode(window);
} }
@ -366,14 +378,21 @@ static int translateKey(unsigned int key)
- (void)mouseMoved:(NSEvent *)event - (void)mouseMoved:(NSEvent *)event
{ {
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
_glfwInputCursorMotion(window, [event deltaX], [event deltaY]); {
_glfwInputCursorMotion(window,
[event deltaX] - window->ns.warpDeltaX,
[event deltaY] - window->ns.warpDeltaY);
}
else else
{ {
const NSRect contentRect = [window->ns.view frame]; const NSRect contentRect = [window->ns.view frame];
const NSPoint p = [event locationInWindow]; const NSPoint pos = [event locationInWindow];
_glfwInputCursorMotion(window, p.x, contentRect.size.height - p.y); _glfwInputCursorMotion(window, pos.x, contentRect.size.height - pos.y);
} }
window->ns.warpDeltaX = 0;
window->ns.warpDeltaY = 0;
} }
- (void)rightMouseDown:(NSEvent *)event - (void)rightMouseDown:(NSEvent *)event
@ -563,11 +582,10 @@ static int translateKey(unsigned int key)
NSPasteboard* pasteboard = [sender draggingPasteboard]; NSPasteboard* pasteboard = [sender draggingPasteboard];
NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType]; NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType];
int height; const NSRect contentRect = [window->ns.view frame];
_glfwPlatformGetWindowSize(window, NULL, &height);
_glfwInputCursorMotion(window, _glfwInputCursorMotion(window,
[sender draggingLocation].x, [sender draggingLocation].x,
height - [sender draggingLocation].y); contentRect.size.height - [sender draggingLocation].y);
const int count = [files count]; const int count = [files count];
if (count) if (count)
@ -1098,10 +1116,27 @@ void _glfwPlatformPostEmptyEvent(void)
[pool drain]; [pool drain];
} }
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
{
const NSRect contentRect = [window->ns.view frame];
const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
if (xpos)
*xpos = pos.x;
if (ypos)
*ypos = contentRect.size.height - pos.y - 1;
}
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
{ {
updateModeCursor(window); updateModeCursor(window);
const NSRect contentRect = [window->ns.view frame];
const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
window->ns.warpDeltaX += x - pos.x;
window->ns.warpDeltaY += y - contentRect.size.height + pos.y;
if (window->monitor) if (window->monitor)
{ {
CGDisplayMoveCursorToPoint(window->monitor->ns.displayID, CGDisplayMoveCursorToPoint(window->monitor->ns.displayID,
@ -1109,7 +1144,6 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
} }
else else
{ {
const NSRect contentRect = [window->ns.view frame];
const NSPoint localPoint = NSMakePoint(x, contentRect.size.height - y - 1); const NSPoint localPoint = NSMakePoint(x, contentRect.size.height - y - 1);
const NSPoint globalPoint = [window->ns.object convertBaseToScreen:localPoint]; const NSPoint globalPoint = [window->ns.object convertBaseToScreen:localPoint];
@ -1123,10 +1157,7 @@ void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
updateModeCursor(window); updateModeCursor(window);
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
CGAssociateMouseAndMouseCursorPosition(false); CGAssociateMouseAndMouseCursorPosition(false);
centerCursor(window);
}
else else
CGAssociateMouseAndMouseCursorPosition(true); CGAssociateMouseAndMouseCursorPosition(true);
} }
@ -1192,10 +1223,10 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
{ {
const NSPoint p = [window->ns.object mouseLocationOutsideOfEventStream]; const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
if (window->cursorMode == GLFW_CURSOR_NORMAL && if (window->cursorMode == GLFW_CURSOR_NORMAL &&
[window->ns.view mouse:p inRect:[window->ns.view frame]]) [window->ns.view mouse:pos inRect:[window->ns.view frame]])
{ {
if (cursor) if (cursor)
[(NSCursor*) cursor->ns.object set]; [(NSCursor*) cursor->ns.object set];

View File

@ -59,20 +59,23 @@ static void setCursorMode(_GLFWwindow* window, int newMode)
{ {
if (oldMode == GLFW_CURSOR_DISABLED) if (oldMode == GLFW_CURSOR_DISABLED)
{ {
window->cursorPosX = _glfw.cursorPosX; _glfwPlatformSetCursorPos(window,
window->cursorPosY = _glfw.cursorPosY; _glfw.cursorPosX,
_glfw.cursorPosY);
_glfwPlatformSetCursorPos(window, _glfw.cursorPosX, _glfw.cursorPosY);
} }
else if (newMode == GLFW_CURSOR_DISABLED) else if (newMode == GLFW_CURSOR_DISABLED)
{ {
int width, height; int width, height;
_glfw.cursorPosX = window->cursorPosX; _glfwPlatformGetCursorPos(window,
_glfw.cursorPosY = window->cursorPosY; &_glfw.cursorPosX,
&_glfw.cursorPosY);
window->cursorPosX = _glfw.cursorPosX;
window->cursorPosY = _glfw.cursorPosY;
_glfwPlatformGetWindowSize(window, &width, &height); _glfwPlatformGetWindowSize(window, &width, &height);
_glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); _glfwPlatformSetCursorPos(window, width / 2, height / 2);
} }
_glfwPlatformApplyCursorMode(window); _glfwPlatformApplyCursorMode(window);
@ -198,22 +201,13 @@ void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y)
window->cursorPosX += x; window->cursorPosX += x;
window->cursorPosY += y; window->cursorPosY += y;
}
else
{
if (window->cursorPosX == x && window->cursorPosY == y)
return;
window->cursorPosX = x; x = window->cursorPosX;
window->cursorPosY = y; y = window->cursorPosY;
} }
if (window->callbacks.cursorPos) if (window->callbacks.cursorPos)
{ window->callbacks.cursorPos((GLFWwindow*) window, x, y);
window->callbacks.cursorPos((GLFWwindow*) window,
window->cursorPosX,
window->cursorPosY);
}
} }
void _glfwInputCursorEnter(_GLFWwindow* window, int entered) void _glfwInputCursorEnter(_GLFWwindow* window, int entered)
@ -332,11 +326,16 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos)
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
if (xpos) if (xpos)
*xpos = window->cursorPosX; *xpos = window->cursorPosX;
if (ypos) if (ypos)
*ypos = window->cursorPosY; *ypos = window->cursorPosY;
} }
else
_glfwPlatformGetCursorPos(window, xpos, ypos);
}
GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
{ {
@ -347,21 +346,18 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
if (_glfw.focusedWindow != window) if (_glfw.focusedWindow != window)
return; return;
// Don't do anything if the cursor position did not change if (window->cursorMode == GLFW_CURSOR_DISABLED)
if (xpos == window->cursorPosX && ypos == window->cursorPosY) {
return; // Only update the accumulated position if the cursor is disabled
// Set GLFW cursor position
window->cursorPosX = xpos; window->cursorPosX = xpos;
window->cursorPosY = ypos; window->cursorPosY = ypos;
}
// Do not move physical cursor if it is disabled else
if (window->cursorMode == GLFW_CURSOR_DISABLED) {
return; // Update system cursor position
// Update physical cursor position
_glfwPlatformSetCursorPos(window, xpos, ypos); _glfwPlatformSetCursorPos(window, xpos, ypos);
} }
}
GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
{ {

View File

@ -410,6 +410,11 @@ void _glfwPlatformTerminate(void);
*/ */
const char* _glfwPlatformGetVersionString(void); const char* _glfwPlatformGetVersionString(void);
/*! @copydoc glfwGetCursorPos
* @ingroup platform
*/
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos);
/*! @copydoc glfwSetCursorPos /*! @copydoc glfwSetCursorPos
* @ingroup platform * @ingroup platform
*/ */

View File

@ -158,10 +158,10 @@ typedef struct _GLFWwindowWin32
DWORD dwStyle; DWORD dwStyle;
DWORD dwExStyle; DWORD dwExStyle;
GLboolean cursorCentered;
GLboolean cursorInside; GLboolean cursorInside;
GLboolean cursorHidden;
int oldCursorX, oldCursorY; // The last received cursor position, regardless of source
int cursorPosX, cursorPosY;
} _GLFWwindowWin32; } _GLFWwindowWin32;

View File

@ -55,15 +55,8 @@ static void hideCursor(_GLFWwindow* window)
{ {
POINT pos; POINT pos;
ReleaseCapture();
ClipCursor(NULL); ClipCursor(NULL);
if (window->win32.cursorHidden)
{
ShowCursor(TRUE);
window->win32.cursorHidden = GL_FALSE;
}
if (GetCursorPos(&pos)) if (GetCursorPos(&pos))
{ {
if (WindowFromPoint(pos) == window->win32.handle) if (WindowFromPoint(pos) == window->win32.handle)
@ -75,14 +68,15 @@ static void hideCursor(_GLFWwindow* window)
// //
static void disableCursor(_GLFWwindow* window) static void disableCursor(_GLFWwindow* window)
{ {
if (!window->win32.cursorHidden) POINT pos;
{
ShowCursor(FALSE);
window->win32.cursorHidden = GL_TRUE;
}
updateClipRect(window); updateClipRect(window);
SetCapture(window->win32.handle);
if (GetCursorPos(&pos))
{
if (WindowFromPoint(pos) == window->win32.handle)
SetCursor(NULL);
}
} }
// Restores the mouse cursor // Restores the mouse cursor
@ -91,15 +85,8 @@ static void restoreCursor(_GLFWwindow* window)
{ {
POINT pos; POINT pos;
ReleaseCapture();
ClipCursor(NULL); ClipCursor(NULL);
if (window->win32.cursorHidden)
{
ShowCursor(TRUE);
window->win32.cursorHidden = GL_FALSE;
}
if (GetCursorPos(&pos)) if (GetCursorPos(&pos))
{ {
if (WindowFromPoint(pos) == window->win32.handle) if (WindowFromPoint(pos) == window->win32.handle)
@ -439,34 +426,23 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
{ {
const int newCursorX = GET_X_LPARAM(lParam); const int x = GET_X_LPARAM(lParam);
const int newCursorY = GET_Y_LPARAM(lParam); const int y = GET_Y_LPARAM(lParam);
if (newCursorX != window->win32.oldCursorX ||
newCursorY != window->win32.oldCursorY)
{
int x, y;
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
{ {
if (_glfw.focusedWindow != window) if (_glfw.focusedWindow != window)
return 0; break;
x = newCursorX - window->win32.oldCursorX; _glfwInputCursorMotion(window,
y = newCursorY - window->win32.oldCursorY; x - window->win32.cursorPosX,
y - window->win32.cursorPosY);
} }
else else
{
x = newCursorX;
y = newCursorY;
}
window->win32.oldCursorX = newCursorX;
window->win32.oldCursorY = newCursorY;
window->win32.cursorCentered = GL_FALSE;
_glfwInputCursorMotion(window, x, y); _glfwInputCursorMotion(window, x, y);
}
window->win32.cursorPosX = x;
window->win32.cursorPosY = y;
if (!window->win32.cursorInside) if (!window->win32.cursorInside)
{ {
@ -1058,13 +1034,11 @@ void _glfwPlatformPollEvents(void)
} }
// Did the cursor move in an focused window that has disabled the cursor // Did the cursor move in an focused window that has disabled the cursor
if (window->cursorMode == GLFW_CURSOR_DISABLED && if (window->cursorMode == GLFW_CURSOR_DISABLED)
!window->win32.cursorCentered)
{ {
int width, height; int width, height;
_glfwPlatformGetWindowSize(window, &width, &height); _glfwPlatformGetWindowSize(window, &width, &height);
_glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); _glfwPlatformSetCursorPos(window, width / 2, height / 2);
window->win32.cursorCentered = GL_TRUE;
} }
} }
} }
@ -1082,14 +1056,31 @@ void _glfwPlatformPostEmptyEvent(void)
PostMessage(window->win32.handle, WM_NULL, 0, 0); PostMessage(window->win32.handle, WM_NULL, 0, 0);
} }
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
{
POINT pos;
if (GetCursorPos(&pos))
{
ScreenToClient(window->win32.handle, &pos);
if (xpos)
*xpos = pos.x;
if (ypos)
*ypos = pos.y;
}
}
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
{ {
POINT pos = { (int) xpos, (int) ypos }; POINT pos = { (int) xpos, (int) ypos };
// Store the new position so it can be recognized later
window->win32.cursorPosX = pos.x;
window->win32.cursorPosY = pos.y;
ClientToScreen(window->win32.handle, &pos); ClientToScreen(window->win32.handle, &pos);
SetCursorPos(pos.x, pos.y); SetCursorPos(pos.x, pos.y);
window->win32.oldCursorX = (int) xpos;
window->win32.oldCursorY = (int) ypos;
} }
void _glfwPlatformApplyCursorMode(_GLFWwindow* window) void _glfwPlatformApplyCursorMode(_GLFWwindow* window)

View File

@ -1066,32 +1066,28 @@ static void processEvent(XEvent *event)
case MotionNotify: case MotionNotify:
{ {
if (event->xmotion.x != window->x11.warpPosX || const int x = event->xmotion.x;
event->xmotion.y != window->x11.warpPosY) const int y = event->xmotion.y;
if (x != window->x11.warpPosX || y != window->x11.warpPosY)
{ {
// The cursor was moved by something other than GLFW // The cursor was moved by something other than GLFW
int x, y;
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
{ {
if (_glfw.focusedWindow != window) if (_glfw.focusedWindow != window)
break; break;
x = event->xmotion.x - window->x11.cursorPosX; _glfwInputCursorMotion(window,
y = event->xmotion.y - window->x11.cursorPosY; x - window->x11.cursorPosX,
y - window->x11.cursorPosY);
} }
else else
{
x = event->xmotion.x;
y = event->xmotion.y;
}
_glfwInputCursorMotion(window, x, y); _glfwInputCursorMotion(window, x, y);
} }
window->x11.cursorPosX = event->xmotion.x; window->x11.cursorPosX = x;
window->x11.cursorPosY = event->xmotion.y; window->x11.cursorPosY = y;
break; break;
} }
@ -1744,6 +1740,23 @@ void _glfwPlatformPostEmptyEvent(void)
XFlush(_glfw.x11.display); XFlush(_glfw.x11.display);
} }
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
{
Window root, child;
int rootX, rootY, childX, childY;
unsigned int mask;
XQueryPointer(_glfw.x11.display, window->x11.handle,
&root, &child,
&rootX, &rootY, &childX, &childY,
&mask);
if (xpos)
*xpos = childX;
if (ypos)
*ypos = childY;
}
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
{ {
// Store the new position so it can be recognized later // Store the new position so it can be recognized later