Skip to content

Commit 5a03819

Browse files
author
GH Action
committed
1 parent 5b9c590 commit 5a03819

File tree

1 file changed

+134
-93
lines changed

1 file changed

+134
-93
lines changed

src/sokol/c/sokol_app.h

Lines changed: 134 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -432,14 +432,15 @@
432432
433433
if (sapp_mouse_locked()) { ... }
434434
435-
On native platforms, the sapp_lock_mouse() and sapp_mouse_locked()
436-
functions work as expected (mouse lock is activated or deactivated
437-
immediately when sapp_lock_mouse() is called, and sapp_mouse_locked()
438-
also immediately returns the new state after sapp_lock_mouse()
439-
is called.
435+
Note that mouse-lock state may not change immediately after sapp_lock_mouse(true/false)
436+
is called, instead on some platforms the actual state switch may be delayed
437+
to the end of the current frame or even to a later frame.
440438
441-
On the web platform, sapp_lock_mouse() and sapp_mouse_locked() behave
442-
differently, as dictated by the limitations of the HTML5 Pointer Lock API:
439+
The mouse may also be unlocked automatically without calling sapp_lock_mouse(false),
440+
most notably when the application window becomes inactive.
441+
442+
On the web platform there are further restrictions to be aware of, caused
443+
by the limitations of the HTML5 Pointer Lock API:
443444
444445
- sapp_lock_mouse(true) can be called at any time, but it will
445446
only take effect in a 'short-lived input event handler of a specific
@@ -491,6 +492,13 @@
491492
}
492493
}
493494
495+
For a 'first person shooter mouse' the following code inside the sokol-app event handler
496+
is recommended somewhere in your frame callback:
497+
498+
if (!sapp_mouse_locked()) {
499+
sapp_lock_mouse(true);
500+
}
501+
494502
CLIPBOARD SUPPORT
495503
=================
496504
Applications can send and receive UTF-8 encoded text data from and to the
@@ -2631,18 +2639,24 @@ typedef struct {
26312639
HICON small_icon;
26322640
HCURSOR cursors[_SAPP_MOUSECURSOR_NUM];
26332641
UINT orig_codepage;
2634-
LONG mouse_locked_x, mouse_locked_y;
2635-
bool mouse_locked_pos_valid;
26362642
RECT stored_window_rect; // used to restore window pos/size when toggling fullscreen => windowed
26372643
bool is_win10_or_greater;
26382644
bool in_create_window;
26392645
bool iconified;
2640-
bool mouse_tracked;
2641-
uint8_t mouse_capture_mask;
26422646
_sapp_win32_dpi_t dpi;
2643-
bool raw_input_mousepos_valid;
2644-
LONG raw_input_mousepos_x;
2645-
LONG raw_input_mousepos_y;
2647+
struct {
2648+
struct {
2649+
LONG pos_x, pos_y;
2650+
bool pos_valid;
2651+
} lock;
2652+
struct {
2653+
LONG pos_x, pos_y;
2654+
bool pos_valid;
2655+
} raw_input;
2656+
bool requested_lock;
2657+
bool tracked;
2658+
uint8_t capture_mask;
2659+
} mouse;
26462660
uint8_t raw_input_data[256];
26472661
} _sapp_win32_t;
26482662

@@ -7194,16 +7208,16 @@ _SOKOL_PRIVATE void _sapp_win32_update_cursor(sapp_mouse_cursor cursor, bool sho
71947208
}
71957209

71967210
_SOKOL_PRIVATE void _sapp_win32_capture_mouse(uint8_t btn_mask) {
7197-
if (0 == _sapp.win32.mouse_capture_mask) {
7211+
if (0 == _sapp.win32.mouse.capture_mask) {
71987212
SetCapture(_sapp.win32.hwnd);
71997213
}
7200-
_sapp.win32.mouse_capture_mask |= btn_mask;
7214+
_sapp.win32.mouse.capture_mask |= btn_mask;
72017215
}
72027216

72037217
_SOKOL_PRIVATE void _sapp_win32_release_mouse(uint8_t btn_mask) {
7204-
if (0 != _sapp.win32.mouse_capture_mask) {
7205-
_sapp.win32.mouse_capture_mask &= ~btn_mask;
7206-
if (0 == _sapp.win32.mouse_capture_mask) {
7218+
if (0 != _sapp.win32.mouse.capture_mask) {
7219+
_sapp.win32.mouse.capture_mask &= ~btn_mask;
7220+
if (0 == _sapp.win32.mouse.capture_mask) {
72077221
ReleaseCapture();
72087222
}
72097223
}
@@ -7214,76 +7228,107 @@ _SOKOL_PRIVATE bool _sapp_win32_is_foreground_window(void) {
72147228
}
72157229

72167230
_SOKOL_PRIVATE void _sapp_win32_lock_mouse(bool lock) {
7217-
if (lock == _sapp.mouse.locked) {
7218-
return;
7231+
_sapp.win32.mouse.requested_lock = lock;
7232+
}
7233+
7234+
_SOKOL_PRIVATE void _sapp_win32_do_lock_mouse(void) {
7235+
_sapp.mouse.locked = true;
7236+
7237+
// hide mouse cursor (NOTE: this maintains a hidden counter, but since
7238+
// only mouse-lock uses ShowCursor this doesn't matter)
7239+
ShowCursor(FALSE);
7240+
7241+
// reset dx/dy and release any active mouse capture
7242+
_sapp.mouse.dx = 0.0f;
7243+
_sapp.mouse.dy = 0.0f;
7244+
_sapp_win32_release_mouse(0xFF);
7245+
7246+
// store current mouse position so that it can be restored when unlocked
7247+
POINT pos;
7248+
if (GetCursorPos(&pos)) {
7249+
_sapp.win32.mouse.lock.pos_valid = true;
7250+
_sapp.win32.mouse.lock.pos_x = pos.x;
7251+
_sapp.win32.mouse.lock.pos_y = pos.y;
7252+
} else {
7253+
_sapp.win32.mouse.lock.pos_valid = false;
7254+
}
7255+
7256+
// while mouse is locked, restrict cursor movement to the client
7257+
// rectangle so that we don't loose any mouse movement events
7258+
RECT client_rect;
7259+
GetClientRect(_sapp.win32.hwnd, &client_rect);
7260+
POINT mid_point;
7261+
mid_point.x = (client_rect.right - client_rect.left) / 2;
7262+
mid_point.y = (client_rect.bottom - client_rect.top) / 2;
7263+
ClientToScreen(_sapp.win32.hwnd, &mid_point);
7264+
RECT clip_rect;
7265+
clip_rect.left = clip_rect.right = mid_point.x;
7266+
clip_rect.top = clip_rect.bottom = mid_point.y;
7267+
ClipCursor(&clip_rect);
7268+
7269+
// enable raw input for mouse, starts sending WM_INPUT messages to WinProc (see GLFW)
7270+
const RAWINPUTDEVICE rid = {
7271+
0x01, // usUsagePage: HID_USAGE_PAGE_GENERIC
7272+
0x02, // usUsage: HID_USAGE_GENERIC_MOUSE
7273+
0, // dwFlags
7274+
_sapp.win32.hwnd // hwndTarget
7275+
};
7276+
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
7277+
_SAPP_ERROR(WIN32_REGISTER_RAW_INPUT_DEVICES_FAILED_MOUSE_LOCK);
72197278
}
7279+
// in case the raw mouse device only supports absolute position reporting,
7280+
// we need to skip the dx/dy compution for the first WM_INPUT event
7281+
_sapp.win32.mouse.raw_input.pos_valid = false;
7282+
}
7283+
7284+
_SOKOL_PRIVATE void _sapp_win32_do_unlock_mouse(void) {
7285+
_sapp.mouse.locked = false;
7286+
7287+
// make mouse cursor visible
7288+
ShowCursor(TRUE);
7289+
7290+
// reset dx/dy and release any active mouse capture
72207291
_sapp.mouse.dx = 0.0f;
72217292
_sapp.mouse.dy = 0.0f;
72227293
_sapp_win32_release_mouse(0xFF);
7223-
if (lock) {
7224-
// don't allow locking the mouse unless we're the active window
7225-
if (!_sapp_win32_is_foreground_window()) {
7226-
return;
7227-
}
72287294

7229-
_sapp.mouse.locked = true;
7230-
/* store the current mouse position, so it can be restored when unlocked */
7231-
POINT pos;
7232-
BOOL res = GetCursorPos(&pos);
7233-
if (res) {
7234-
_sapp.win32.mouse_locked_x = pos.x;
7235-
_sapp.win32.mouse_locked_y = pos.y;
7236-
_sapp.win32.mouse_locked_pos_valid = true;
7295+
// disable raw input for mouse
7296+
const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL };
7297+
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
7298+
_SAPP_ERROR(WIN32_REGISTER_RAW_INPUT_DEVICES_FAILED_MOUSE_UNLOCK);
7299+
}
72377300

7238-
/* while the mouse is locked, make the mouse cursor invisible and
7239-
confine the mouse movement to a small rectangle inside our window
7240-
(so that we don't miss any mouse up events)
7241-
*/
7242-
RECT client_rect = {
7243-
_sapp.win32.mouse_locked_x,
7244-
_sapp.win32.mouse_locked_y,
7245-
_sapp.win32.mouse_locked_x,
7246-
_sapp.win32.mouse_locked_y
7247-
};
7248-
ClipCursor(&client_rect);
7249-
} else {
7250-
_sapp.win32.mouse_locked_pos_valid = false;
7251-
}
7301+
// unrestrict mouse movement
7302+
ClipCursor(NULL);
72527303

7253-
/* make the mouse cursor invisible, this will stack with sapp_show_mouse() */
7254-
ShowCursor(FALSE);
7304+
// restore the 'pre-locked' mouse position
7305+
if (_sapp.win32.mouse.lock.pos_valid) {
7306+
SetCursorPos(_sapp.win32.mouse.lock.pos_x, _sapp.win32.mouse.lock.pos_y);
7307+
_sapp.win32.mouse.lock.pos_valid = false;
7308+
}
7309+
}
72557310

7256-
/* enable raw input for mouse, starts sending WM_INPUT messages to WinProc (see GLFW) */
7257-
const RAWINPUTDEVICE rid = {
7258-
0x01, // usUsagePage: HID_USAGE_PAGE_GENERIC
7259-
0x02, // usUsage: HID_USAGE_GENERIC_MOUSE
7260-
0, // dwFlags
7261-
_sapp.win32.hwnd // hwndTarget
7262-
};
7263-
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
7264-
_SAPP_ERROR(WIN32_REGISTER_RAW_INPUT_DEVICES_FAILED_MOUSE_LOCK);
7265-
}
7266-
/* in case the raw mouse device only supports absolute position reporting,
7267-
we need to skip the dx/dy compution for the first WM_INPUT event
7268-
*/
7269-
_sapp.win32.raw_input_mousepos_valid = false;
7270-
} else {
7271-
_sapp.mouse.locked = false;
7272-
/* disable raw input for mouse */
7273-
const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL };
7274-
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
7275-
_SAPP_ERROR(WIN32_REGISTER_RAW_INPUT_DEVICES_FAILED_MOUSE_UNLOCK);
7311+
_SOKOL_PRIVATE void _sapp_win32_update_mouse_lock(void) {
7312+
// mouse lock can only be active when we're the active window
7313+
if (!_sapp_win32_is_foreground_window()) {
7314+
// unlock mouse if currently locked
7315+
if (_sapp.mouse.locked) {
7316+
_sapp_win32_do_unlock_mouse();
72767317
}
7318+
return;
7319+
}
72777320

7278-
/* let the mouse roam freely again */
7279-
ClipCursor(NULL);
7280-
ShowCursor(TRUE);
7321+
// nothing to do if requested lock state matches current lock state
7322+
const bool lock = _sapp.win32.mouse.requested_lock;
7323+
if (lock == _sapp.mouse.locked) {
7324+
return;
7325+
}
72817326

7282-
/* restore the 'pre-locked' mouse position */
7283-
if (_sapp.win32.mouse_locked_pos_valid) {
7284-
SetCursorPos(_sapp.win32.mouse_locked_x, _sapp.win32.mouse_locked_y);
7285-
_sapp.win32.mouse_locked_pos_valid = false;
7286-
}
7327+
// otherwise change into desired state
7328+
if (lock) {
7329+
_sapp_win32_do_lock_mouse();
7330+
} else {
7331+
_sapp_win32_do_unlock_mouse();
72877332
}
72887333
}
72897334

@@ -7582,8 +7627,8 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM
75827627
case WM_MOUSEMOVE:
75837628
if (!_sapp.mouse.locked) {
75847629
_sapp_win32_mouse_update(lParam);
7585-
if (!_sapp.win32.mouse_tracked) {
7586-
_sapp.win32.mouse_tracked = true;
7630+
if (!_sapp.win32.mouse.tracked) {
7631+
_sapp.win32.mouse.tracked = true;
75877632
TRACKMOUSEEVENT tme;
75887633
_sapp_clear(&tme, sizeof(tme));
75897634
tme.cbSize = sizeof(tme);
@@ -7617,13 +7662,13 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM
76177662
*/
76187663
LONG new_x = raw_mouse_data->data.mouse.lLastX;
76197664
LONG new_y = raw_mouse_data->data.mouse.lLastY;
7620-
if (_sapp.win32.raw_input_mousepos_valid) {
7621-
_sapp.mouse.dx = (float) (new_x - _sapp.win32.raw_input_mousepos_x);
7622-
_sapp.mouse.dy = (float) (new_y - _sapp.win32.raw_input_mousepos_y);
7665+
if (_sapp.win32.mouse.raw_input.pos_valid) {
7666+
_sapp.mouse.dx = (float) (new_x - _sapp.win32.mouse.raw_input.pos_x);
7667+
_sapp.mouse.dy = (float) (new_y - _sapp.win32.mouse.raw_input.pos_y);
76237668
}
7624-
_sapp.win32.raw_input_mousepos_x = new_x;
7625-
_sapp.win32.raw_input_mousepos_y = new_y;
7626-
_sapp.win32.raw_input_mousepos_valid = true;
7669+
_sapp.win32.mouse.raw_input.pos_x = new_x;
7670+
_sapp.win32.mouse.raw_input.pos_y = new_y;
7671+
_sapp.win32.mouse.raw_input.pos_valid = true;
76277672
}
76287673
else {
76297674
/* mouse reports movement delta (this seems to be the common case) */
@@ -7638,7 +7683,7 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM
76387683
if (!_sapp.mouse.locked) {
76397684
_sapp.mouse.dx = 0.0f;
76407685
_sapp.mouse.dy = 0.0f;
7641-
_sapp.win32.mouse_tracked = false;
7686+
_sapp.win32.mouse.tracked = false;
76427687
_sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID);
76437688
}
76447689
break;
@@ -8133,12 +8178,8 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) {
81338178
if (_sapp.quit_requested) {
81348179
PostMessage(_sapp.win32.hwnd, WM_CLOSE, 0, 0);
81358180
}
8136-
// unlock mouse if window doesn't have focus
8137-
if (_sapp.mouse.locked) {
8138-
if (!_sapp_win32_is_foreground_window()) {
8139-
_sapp_win32_lock_mouse(false);
8140-
}
8141-
}
8181+
// update mouse-lock state
8182+
_sapp_win32_update_mouse_lock();
81428183
}
81438184
_sapp_call_cleanup();
81448185

0 commit comments

Comments
 (0)