Hidden mouse cursor escapes window (win32)

lonesock wrote on Friday, April 27, 2007:

In my simple windowed app I’m hiding the mouse cursor using glfwDisable( GLFW_MOUSE_CURSOR ); This is working as expected, until I ran it on a PC with SW OpenGL…muuuuch slower. At that point the mouse would often escape the window if moved too fast. I checking into the code and it seems that internally GLFW is warping the mouse back to the center of the window, but if the delta is too great (relative to the window size) then it will escape. So this could be a problem for very slow apps or very small windows.

I’m not sure about other operating systems, but I know it would be a simple matter to call ClipCursor under Windows to guarantee mouse captivity. Does this even need fixing on the other OS’s, and if so, how hard would it be to implement? I’d be happy to do the Windows patch and submit it, just let me know.

Jonathan

peterpp wrote on Friday, April 27, 2007:

I posted this bug a long time ago:

http://sourceforge.net/tracker/index.php?func=detail&aid=1262764&group_id=72569&atid=534938

I would be happy if somebody will fix this.

lonesock wrote on Friday, April 27, 2007:

OK, after a tiny bit of digging:

macosx_window.c implements CGAssociateMouseAndMouseCursorPosition
x11_window.c implements XGrabPointer

So, of the big 3 OS’s, only Windows is missing ClipCursor. I’ll drop it in this weekend then post back, unless somebody beats me to it :wink:

Jonathan

kohaistyle wrote on Saturday, April 28, 2007:

It’s be as easy as to clip the mouse yourself, with a “glfwSetMousePos( int xpos, int ypos )” call …

Or am i wrong ? Cos i doesn’t really look like a bug, but a pb of the the app ( or rather win32 callback system ) to poll the mouse position.

melekor wrote on Saturday, April 28, 2007:

No, because once you detect it’s out of bounds, it’s already too late. ClipCursor is the correct solution.

lonesock wrote on Tuesday, May 01, 2007:

OK, here is my "patch" (sorry, not in any standard diff format)
All of this applies to the CVS HEAD version of win32_window.c

the simple functions here are shown in their entirety, just
Copy-N-Paste over the old versions.

void _glfwPlatformHideMouseCursor( void )
{
// Hide cursor
ShowCursor( FALSE );

// clip cursor to the window
RECT ClipWindowRect;
if\( GetWindowRect\( \_glfwWin.Wnd, &ClipWindowRect \) \)
\{
	ClipCursor\( &ClipWindowRect \);
\}

// Capture cursor to user window
SetCapture\( \_glfwWin.Wnd \);

}

void _glfwPlatformShowMouseCursor( void )
{
// Un-capture cursor
ReleaseCapture();

//	unclip cursor from the window
ClipCursor\( NULL \);

// Show cursor
ShowCursor\( TRUE \);

}

These two work great for clipping the mouse cursor to the _exsting_
window, however you need to update the clip rectangle any time the
coordinates of the window change, so in the
_glfwWindowCallback
function, I needed to modify the
case WM_SIZE:
and I needed to add the
case WM_MOVE:

Here are the relevant snippets:

// Resize the window?
case WM_SIZE:
// get the new size
_glfwWin.Width = LOWORD(lParam);
_glfwWin.Height = HIWORD(lParam);
// if the mouse is locked, I need to update the locking coordinates
if( _glfwWin.MouseLock )
{
RECT ClipWindowRect;
if( GetWindowRect( _glfwWin.Wnd, &ClipWindowRect ) )
{
ClipCursor( &ClipWindowRect );
}
}
// and call the user-supplied function, if it exists
if( _glfwWin.WindowSizeCallback )
{
_glfwWin.WindowSizeCallback( LOWORD(lParam),
HIWORD(lParam) );
}
return 0;

	// Move the window?
    case WM\_MOVE:
		//	if the mouse is locked, I need to update the locking coordinates
        if\( \_glfwWin.MouseLock \)
        \{
        	RECT ClipWindowRect;
			if\( GetWindowRect\( \_glfwWin.Wnd, &ClipWindowRect \) \)
			\{
				ClipCursor\( &ClipWindowRect \);
			\}
        \}
		//	do I return something? or just break?
		return 0;

Please Note that I did not know how to finish the WM_MOVE case…sometimes there was a return 0 or 1, and sometimes a break. I defaulted to the same behavior as the WM_SIZE case, which was to return 0, though that may be wrong…please help, somebody?

Oh, and while I’m here, one more plug for my custom ICON patch [8^)
inside _glfwPlatformOpenWindow()

// modifying this to load a user-specified Icon, if available
wc.hIcon = LoadIcon( wc.hInstance, "GLFW_ICON" ); // Load default icon
if( !wc.hIcon )
wc.hIcon = LoadIcon( NULL, IDI_WINLOGO ); // Load default icon

melekor wrote on Tuesday, May 01, 2007:

Nice job! I’ll definitely be adding this code to my customized version of glfw. About the return/break question, return 0 is the correct behavior.

elmindreda wrote on Tuesday, May 01, 2007:

Cool, I’ll integrate this into my tree and test it. Thank you.

lonesock wrote on Tuesday, May 01, 2007:

@melekor: thanks!

@elmindreda: you’re welcome!

elmindreda wrote on Wednesday, May 02, 2007:

I’ve caught up somewhat and now it’s time to merge this. Could you please submit a proper patch from your tree? You said that you’re working against CVS HEAD, so it should be very simple to generate a patch with whatever CVS client you’re using.

lonesock wrote on Thursday, May 03, 2007:

Done! "Adds ClipCursor to win32_window.c"

elmindreda wrote on Saturday, May 05, 2007:

Thank you. Merged and committed, except for the icon thingy, which I’m still considering. It’s sufficiently low impact that I’ll probably let it through, however.