diff --git a/port/include/input.h b/port/include/input.h index d09e1dbdf..b0a38298f 100644 --- a/port/include/input.h +++ b/port/include/input.h @@ -81,6 +81,12 @@ enum contkey { CK_TOTAL_COUNT }; +enum mouselockmode { + MLOCK_OFF = 0, + MLOCK_ON = 1, + MLOCK_AUTO = 2 +}; + // returns bitmask of connected controllers or -1 if failed s32 inputInit(void); @@ -201,8 +207,14 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode); void inputClearLastKey(void); s32 inputGetLastKey(void); -// get/set Input.MouseDefaultLocked -s32 inputGetMouseDefaultLocked(void); -void inputSetMouseDefaultLocked(s32 defaultLocked); +// get/set Input.MouseLockMode +s32 inputGetMouseLockMode(void); +void inputSetMouseLockMode(s32 lockmode); + +// same as inputLockMouse but works only if mouse is enabled and lockmode == MLOCK_AUTO +s32 inputAutoLockMouse(s32 wantlock); + +// show/hide mouse cursor; if mouse lock is on the cursor is always hidden +void inputMouseShowCursor(s32 show); #endif diff --git a/port/src/input.c b/port/src/input.c index bf0ab413e..13f192b42 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -28,6 +28,9 @@ #define WHEEL_UP_MASK SDL_BUTTON(VK_MOUSE_WHEEL_UP - VK_MOUSE_BEGIN + 1) #define WHEEL_DN_MASK SDL_BUTTON(VK_MOUSE_WHEEL_DN - VK_MOUSE_BEGIN + 1) +#define CURSOR_HIDE_THRESHOLD 1 +#define CURSOR_HIDE_TIME 3000000 // us + static SDL_GameController *pads[INPUT_MAX_CONTROLLERS]; #define CONTROLLERCFG_DEFAULT { \ @@ -70,13 +73,16 @@ static s32 connectedMask = 0; static s32 numJoysticks = 0; static s32 mouseEnabled = 1; -static s32 mouseLocked = 0; -static s32 mouseDefaultLocked = 0; static s32 mouseX, mouseY; static s32 mouseDX, mouseDY; static u32 mouseButtons; static s32 mouseWheel = 0; +static s32 mouseLocked = 0; +static s32 mouseLockMode = MLOCK_AUTO; +static u64 mouseCursorTime = 0; +static s32 mouseShowCursor = 1; + static f32 mouseSensX = 1.5f; static f32 mouseSensY = 1.5f; @@ -672,7 +678,9 @@ s32 inputInit(void) inputSetDefaultKeyBinds(i, 0); } - inputLockMouse(mouseDefaultLocked); + if (mouseLockMode != MLOCK_AUTO) { + inputLockMouse(mouseLockMode); + } // update the axis maps // NOTE: by default sticks get swapped for 1.2: "right stick" here means left stick on your controller @@ -803,6 +811,20 @@ static inline void inputUpdateMouse(void) mouseX = mx; mouseY = my; + + // if MLOCK_AUTO is enabled, disable cursor if mouse is unlocked + // and we haven't moved it for a few seconds + if (mouseLockMode == MLOCK_AUTO && !mouseLocked) { + if (abs(mouseDX) > CURSOR_HIDE_THRESHOLD || abs(mouseDY) > CURSOR_HIDE_THRESHOLD) { + if (!mouseShowCursor) { + inputMouseShowCursor(1); + } + } else if (sysGetMicroseconds() > mouseCursorTime) { + if (mouseShowCursor) { + inputMouseShowCursor(0); + } + } + } } void inputUpdate(void) @@ -1171,20 +1193,42 @@ s32 inputMouseIsEnabled(void) void inputMouseEnable(s32 enabled) { mouseEnabled = !!enabled; - if (!mouseEnabled && mouseLocked) { + if (!mouseEnabled && mouseLockMode != MLOCK_ON && mouseLocked) { inputLockMouse(0); } } -s32 inputGetMouseDefaultLocked(void) +s32 inputAutoLockMouse(s32 wantlock) +{ + if (mouseEnabled && mouseLockMode == MLOCK_AUTO) { + inputLockMouse(wantlock); + return 1; + } + return 0; +} + +void inputMouseShowCursor(s32 show) { - return mouseDefaultLocked; + mouseShowCursor = !!show; + SDL_ShowCursor(mouseShowCursor); + if (show) { + mouseCursorTime = sysGetMicroseconds() + CURSOR_HIDE_TIME; + } } -void inputSetMouseDefaultLocked(s32 defaultLocked) +s32 inputGetMouseLockMode(void) { - mouseDefaultLocked = !!defaultLocked; - inputLockMouse(mouseDefaultLocked); + return mouseLockMode; +} + +void inputSetMouseLockMode(s32 lockmode) +{ + mouseLockMode = lockmode; + if (lockmode == MLOCK_ON) { + inputLockMouse(1); + } else { + inputLockMouse(0); + } } const char *inputGetContKeyName(u32 ck) @@ -1264,7 +1308,7 @@ s32 inputGetLastKey(void) PD_CONSTRUCTOR static void inputConfigInit(void) { configRegisterInt("Input.MouseEnabled", &mouseEnabled, 0, 1); - configRegisterInt("Input.MouseDefaultLocked", &mouseDefaultLocked, 0, 1); + configRegisterInt("Input.MouseLockMode", &mouseLockMode, MLOCK_OFF, MLOCK_AUTO); configRegisterFloat("Input.MouseSpeedX", &mouseSensX, -10.f, 10.f); configRegisterFloat("Input.MouseSpeedY", &mouseSensY, -10.f, 10.f); configRegisterInt("Input.FakeGamepads", &fakeControllers, 0, 4); diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index 92908711d..c3f2ae048 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -119,14 +119,25 @@ static MenuItemHandlerResult menuhandlerMouseAimLock(s32 operation, struct menui return 0; } -static MenuItemHandlerResult menuhandlerMouseDefaultLocked(s32 operation, struct menuitem *item, union handlerdata *data) +static MenuItemHandlerResult menuhandlerMouseLockMode(s32 operation, struct menuitem *item, union handlerdata *data) { + static const char *opts[] = { + "Always Off", + "Always On", + "Auto" + }; + switch (operation) { - case MENUOP_GET: - return inputGetMouseDefaultLocked(); + case MENUOP_GETOPTIONCOUNT: + data->dropdown.value = ARRAYCOUNT(opts); + break; + case MENUOP_GETOPTIONTEXT: + return (intptr_t)opts[data->dropdown.value]; case MENUOP_SET: - inputSetMouseDefaultLocked(data->checkbox.value); + inputSetMouseLockMode(data->checkbox.value); break; + case MENUOP_GETSELECTEDINDEX: + data->dropdown.value = inputGetMouseLockMode(); } return 0; @@ -274,12 +285,12 @@ struct menuitem g_ExtendedMouseMenuItems[] = { menuhandlerMouseAimLock, }, { - MENUITEMTYPE_CHECKBOX, + MENUITEMTYPE_DROPDOWN, 0, MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Grab Mouse Input by Default", + (uintptr_t)"Mouse Lock Mode", 0, - menuhandlerMouseDefaultLocked, + menuhandlerMouseLockMode, }, { MENUITEMTYPE_CHECKBOX, diff --git a/src/game/menu.c b/src/game/menu.c index db2a30001..26c839f0a 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -3473,9 +3473,7 @@ void menuClose(void) g_Menus[g_MpPlayerNum].openinhibit = 10; #ifndef PLATFORM_N64 - if (inputMouseIsEnabled()) { - inputLockMouse(true); - } + inputAutoLockMouse(true); #endif if (g_MenuData.root == MENUROOT_MPPAUSE) { @@ -3589,9 +3587,7 @@ void menuPushRootDialog(struct menudialogdef *dialogdef, s32 root) g_PlayersWithControl[g_Menus[g_MpPlayerNum].playernum] = false; #ifndef PLATFORM_N64 - if (inputMouseIsEnabled()) { - inputLockMouse(false); - } + inputAutoLockMouse(false); #endif func0f0f1494(); diff --git a/src/game/menustop.c b/src/game/menustop.c index d86344a46..35b39372b 100644 --- a/src/game/menustop.c +++ b/src/game/menustop.c @@ -33,9 +33,7 @@ void menuStop(void) { #ifndef PLATFORM_N64 - if (inputMouseIsEnabled()) { - inputLockMouse(true); - } + inputAutoLockMouse(true); #endif if (var80062944) {