mirror of
https://github.com/glfw/glfw.git
synced 2024-11-21 17:45:10 +00:00
Add cursor mode GLFW_CURSOR_CAPTURED
This adds a cursor mode that provides a visible cursor confined to the content area of the window. Fixes #58
This commit is contained in:
parent
a46f829de8
commit
488008e0a2
@ -139,6 +139,8 @@ information on what to include when reporting a bug.
|
||||
- Added `GLFW_POINTING_HAND_CURSOR` alias for `GLFW_HAND_CURSOR` (#427)
|
||||
- Added `GLFW_MOUSE_PASSTHROUGH` window hint for letting mouse input pass
|
||||
through the window (#1236,#1568)
|
||||
- Added `GLFW_CURSOR_CAPTURED` cursor mode to confine the cursor to the window
|
||||
content area (#58)
|
||||
- Added `GLFW_PLATFORM_UNAVAILABLE` error for platform detection failures (#1958)
|
||||
- Added `GLFW_FEATURE_UNAVAILABLE` error for platform limitations (#1692)
|
||||
- Added `GLFW_FEATURE_UNIMPLEMENTED` error for incomplete backends (#1692)
|
||||
|
@ -312,6 +312,16 @@ glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
|
||||
This mode puts no limit on the motion of the cursor.
|
||||
|
||||
If you wish the cursor to be visible but confined to the content area of the
|
||||
window, set the cursor mode to `GLFW_CURSOR_CAPTURED`.
|
||||
|
||||
@code
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_CAPTURED);
|
||||
@endcode
|
||||
|
||||
The cursor will behave normally inside the content area but will not be able to
|
||||
leave unless the window loses focus.
|
||||
|
||||
To exit out of either of these special modes, restore the `GLFW_CURSOR_NORMAL`
|
||||
cursor mode.
|
||||
|
||||
@ -319,6 +329,8 @@ cursor mode.
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
@endcode
|
||||
|
||||
If the cursor was disabled, this will move it back to its last visible position.
|
||||
|
||||
|
||||
@anchor GLFW_RAW_MOUSE_MOTION
|
||||
@subsection raw_mouse_motion Raw mouse motion
|
||||
|
@ -58,6 +58,14 @@ requesting a specific rendering backend when using
|
||||
contexts.
|
||||
|
||||
|
||||
@subsubsection captured_cursor_34 Captured cursor mode
|
||||
|
||||
GLFW now supports confining the cursor to the window content area with the @ref
|
||||
GLFW_CURSOR_CAPTURED cursor mode.
|
||||
|
||||
For more information see @ref cursor_mode.
|
||||
|
||||
|
||||
@subsubsection features_34_init_allocator Support for custom memory allocator
|
||||
|
||||
GLFW now supports plugging a custom memory allocator at initialization with @ref
|
||||
@ -234,6 +242,7 @@ then GLFW will fail to initialize.
|
||||
- @ref GLFW_ANGLE_PLATFORM_TYPE_VULKAN
|
||||
- @ref GLFW_ANGLE_PLATFORM_TYPE_METAL
|
||||
- @ref GLFW_X11_XCB_VULKAN_SURFACE
|
||||
- @ref GLFW_CURSOR_CAPTURED
|
||||
|
||||
|
||||
@section news_archive Release notes for earlier versions
|
||||
|
@ -1134,6 +1134,7 @@ extern "C" {
|
||||
#define GLFW_CURSOR_NORMAL 0x00034001
|
||||
#define GLFW_CURSOR_HIDDEN 0x00034002
|
||||
#define GLFW_CURSOR_DISABLED 0x00034003
|
||||
#define GLFW_CURSOR_CAPTURED 0x00034004
|
||||
|
||||
#define GLFW_ANY_RELEASE_BEHAVIOR 0
|
||||
#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001
|
||||
@ -4566,6 +4567,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
|
||||
* - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual
|
||||
* and unlimited cursor movement. This is useful for implementing for
|
||||
* example 3D camera controls.
|
||||
* - `GLFW_CURSOR_CAPTURED` makes the cursor visible and confines it to the
|
||||
* content area of the window.
|
||||
*
|
||||
* If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to
|
||||
* enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are
|
||||
|
@ -1619,8 +1619,16 @@ void _glfwSetCursorPosCocoa(_GLFWwindow* window, double x, double y)
|
||||
void _glfwSetCursorModeCocoa(_GLFWwindow* window, int mode)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
||||
if (mode == GLFW_CURSOR_CAPTURED)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
|
||||
"Cocoa: Captured cursor mode not yet implemented");
|
||||
}
|
||||
|
||||
if (_glfwWindowFocusedCocoa(window))
|
||||
updateCursorMode(window);
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
|
@ -596,7 +596,8 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||
{
|
||||
if (value != GLFW_CURSOR_NORMAL &&
|
||||
value != GLFW_CURSOR_HIDDEN &&
|
||||
value != GLFW_CURSOR_DISABLED)
|
||||
value != GLFW_CURSOR_DISABLED &&
|
||||
value != GLFW_CURSOR_CAPTURED)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid cursor mode 0x%08X",
|
||||
|
@ -238,7 +238,8 @@ static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
|
||||
//
|
||||
static void updateCursorImage(_GLFWwindow* window)
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL ||
|
||||
window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
{
|
||||
if (window->cursor)
|
||||
SetCursor(window->cursor->win32.handle);
|
||||
@ -586,6 +587,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
disableCursor(window);
|
||||
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
captureCursor(window);
|
||||
|
||||
window->win32.frameAction = GLFW_FALSE;
|
||||
}
|
||||
@ -604,6 +607,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
disableCursor(window);
|
||||
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
captureCursor(window);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -612,6 +617,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
enableCursor(window);
|
||||
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
releaseCursor();
|
||||
|
||||
if (window->monitor && window->autoIconify)
|
||||
_glfwIconifyWindowWin32(window);
|
||||
@ -981,6 +988,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
// resizing the window or using the window menu
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
enableCursor(window);
|
||||
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
releaseCursor();
|
||||
|
||||
break;
|
||||
}
|
||||
@ -995,6 +1004,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
// resizing the window or using the menu
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
disableCursor(window);
|
||||
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
captureCursor(window);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -2166,7 +2177,7 @@ void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode)
|
||||
disableRawMouseMotion(window);
|
||||
}
|
||||
|
||||
if (mode == GLFW_CURSOR_DISABLED)
|
||||
if (mode == GLFW_CURSOR_DISABLED || mode == GLFW_CURSOR_CAPTURED)
|
||||
captureCursor(window);
|
||||
else
|
||||
releaseCursor();
|
||||
|
@ -269,6 +269,7 @@ typedef struct _GLFWwindowWayland
|
||||
|
||||
struct zwp_relative_pointer_v1* relativePointer;
|
||||
struct zwp_locked_pointer_v1* lockedPointer;
|
||||
struct zwp_confined_pointer_v1* confinedPointer;
|
||||
|
||||
struct zwp_idle_inhibitor_v1* idleInhibitor;
|
||||
|
||||
|
@ -1860,6 +1860,9 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window)
|
||||
if (window->wl.lockedPointer)
|
||||
zwp_locked_pointer_v1_destroy(window->wl.lockedPointer);
|
||||
|
||||
if (window->wl.confinedPointer)
|
||||
zwp_confined_pointer_v1_destroy(window->wl.confinedPointer);
|
||||
|
||||
if (window->context.destroy)
|
||||
window->context.destroy(window);
|
||||
|
||||
@ -2538,6 +2541,43 @@ static void lockPointer(_GLFWwindow* window)
|
||||
window);
|
||||
}
|
||||
|
||||
static void confinedPointerHandleConfined(void* userData,
|
||||
struct zwp_confined_pointer_v1* confinedPointer)
|
||||
{
|
||||
}
|
||||
|
||||
static void confinedPointerHandleUnconfined(void* userData,
|
||||
struct zwp_confined_pointer_v1* confinedPointer)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct zwp_confined_pointer_v1_listener confinedPointerListener =
|
||||
{
|
||||
confinedPointerHandleConfined,
|
||||
confinedPointerHandleUnconfined
|
||||
};
|
||||
|
||||
static void confinePointer(_GLFWwindow* window)
|
||||
{
|
||||
window->wl.confinedPointer =
|
||||
zwp_pointer_constraints_v1_confine_pointer(
|
||||
_glfw.wl.pointerConstraints,
|
||||
window->wl.surface,
|
||||
_glfw.wl.pointer,
|
||||
NULL,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
||||
|
||||
zwp_confined_pointer_v1_add_listener(window->wl.confinedPointer,
|
||||
&confinedPointerListener,
|
||||
window);
|
||||
}
|
||||
|
||||
static void unconfinePointer(_GLFWwindow* window)
|
||||
{
|
||||
zwp_confined_pointer_v1_destroy(window->wl.confinedPointer);
|
||||
window->wl.confinedPointer = NULL;
|
||||
}
|
||||
|
||||
void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
{
|
||||
if (!_glfw.wl.pointer)
|
||||
@ -2553,17 +2593,29 @@ void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
// Update pointer lock to match cursor mode
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
if (window->wl.confinedPointer)
|
||||
unconfinePointer(window);
|
||||
if (!window->wl.lockedPointer)
|
||||
lockPointer(window);
|
||||
}
|
||||
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
{
|
||||
if (window->wl.lockedPointer)
|
||||
unlockPointer(window);
|
||||
if (!window->wl.confinedPointer)
|
||||
confinePointer(window);
|
||||
}
|
||||
else if (window->cursorMode == GLFW_CURSOR_NORMAL ||
|
||||
window->cursorMode == GLFW_CURSOR_HIDDEN)
|
||||
{
|
||||
if (window->wl.lockedPointer)
|
||||
unlockPointer(window);
|
||||
else if (window->wl.confinedPointer)
|
||||
unconfinePointer(window);
|
||||
}
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL ||
|
||||
window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
{
|
||||
if (cursor)
|
||||
setCursorImage(window, &cursor->wl);
|
||||
|
@ -453,7 +453,8 @@ static char* convertLatin1toUTF8(const char* source)
|
||||
//
|
||||
static void updateCursorImage(_GLFWwindow* window)
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL ||
|
||||
window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
{
|
||||
if (window->cursor)
|
||||
{
|
||||
@ -1705,6 +1706,8 @@ static void processEvent(XEvent *event)
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
disableCursor(window);
|
||||
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
captureCursor(window);
|
||||
|
||||
if (window->x11.ic)
|
||||
XSetICFocus(window->x11.ic);
|
||||
@ -1725,6 +1728,8 @@ static void processEvent(XEvent *event)
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
enableCursor(window);
|
||||
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
releaseCursor();
|
||||
|
||||
if (window->x11.ic)
|
||||
XUnsetICFocus(window->x11.ic);
|
||||
@ -2831,7 +2836,7 @@ void _glfwSetCursorModeX11(_GLFWwindow* window, int mode)
|
||||
disableRawMouseMotion(window);
|
||||
}
|
||||
|
||||
if (mode == GLFW_CURSOR_DISABLED)
|
||||
if (mode == GLFW_CURSOR_DISABLED || mode == GLFW_CURSOR_CAPTURED)
|
||||
captureCursor(window);
|
||||
else
|
||||
releaseCursor();
|
||||
@ -3003,7 +3008,8 @@ void _glfwDestroyCursorX11(_GLFWcursor* cursor)
|
||||
|
||||
void _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL ||
|
||||
window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
{
|
||||
updateCursorImage(window);
|
||||
XFlush(_glfw.x11.display);
|
||||
|
@ -172,7 +172,8 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
|
||||
|
||||
case GLFW_KEY_ESCAPE:
|
||||
{
|
||||
if (glfwGetInputMode(window, GLFW_CURSOR) != GLFW_CURSOR_DISABLED)
|
||||
const int mode = glfwGetInputMode(window, GLFW_CURSOR);
|
||||
if (mode != GLFW_CURSOR_DISABLED && mode != GLFW_CURSOR_CAPTURED)
|
||||
{
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
break;
|
||||
@ -197,6 +198,11 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
|
||||
printf("(( cursor is hidden ))\n");
|
||||
break;
|
||||
|
||||
case GLFW_KEY_C:
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_CAPTURED);
|
||||
printf("(( cursor is captured ))\n");
|
||||
break;
|
||||
|
||||
case GLFW_KEY_R:
|
||||
if (!glfwRawMouseMotionSupported())
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user