I have an application with different input maps for different app states, specifically an UI input map and a World input map, I have wrote a code that enbale and disable this maps also triggering a function that free and locks the cursor depending on this states.
void ChangeActionMap(AppState newState)
{
if (newState == AppState.UI)
{
userInput.SwitchCurrentActionMap("UI");
Cursor.lockState = CursorLockMode.None;
}
else if (newState == AppState.World)
{
userInput.SwitchCurrentActionMap("User");
Cursor.lockState = CursorLockMode.Locked;
}
}
When I make the build and open it locally on my pc theres this error in which when the user exit de unity canvas and try to click in it immediatly the explorar collapse and drops the following pop up: Uncaught (in promise) SecurityError: Pointer lock cannot be acquired immediately after the user has exited the lock.
Is there any way to control whether the focus is inside or outside the unity application, and, is there a way to avoid this error either by C# Unity code or by JS web code?
I’d say you may be calling ChangeActionMap multiple times per frame. The message indicates a fast toggle is the problem. Add Debug.Log($"[{Time.frameCount}] Changed to: {newState}") to monitor if you’re switching cursor state in the same frame.
An easy fix would be to use a coroutine that first yields null before changing the lock state, and the ChangeActionMap starts the coroutine but also always stops the running one, if any, or simply stops all coroutines if it’s the only coroutine in that script.
PS: Moved to Unity Engine section with Unity-for-Web tag as Web Resources is for Unity’s websites (Discussions, Learn, Play, the homepage).
Hi! First of all, thanks for editing the question, I’m still getting used to this platform, sorry for the mistake.
About the problem, it doesn’t seem to be something “triggered by my code per se,” let me explain. I debugged it like you said, but no message appeared in the console, yet the error persisted.
It seems that when you lock the cursor in the Unity WebGL build and press Esc to lose focus on the Unity canvas, the game state remains the same (which means the cursor is still locked in the game), but since focus is lost to the page per se, the cursor is freed there. This way, when trying to regain focus on the Unity canvas, since the cursor is still locked, it will try to take it immediately (not because of my code, but because of the game state before losing focus), resulting in the error.
I tried the coroutine but the error kept appearing. It seems to be due to how WebGL works; I’ll keep trying to find a solution.
Thanks for the help.
Are you absolutely sure that nothing sets the Cursor state multiple times in quick succession? Maybe search for “Cursor.” in the codebase and check every line, perhaps adding a Debug.Log to any code that’s either yours or from an asset or non-Unity (readonly) package.
It may be helpful to create a blank project with a cursor lock/unlock toggle button, and another button that runs the same toggle twice or more often to see if you can forcefully trigger the issue.
I have cursor lock/unlock in my game when menus appear (pause, or between runs) and didn’t observe those errors in builds made with 6.3 and 6.4.
Yes!! I checked it and this is the only class that manages user input on the project.
The good news is that I was able to fix it with the help of javascript, adding a listener to check whether the pointer is locked or free
document.addEventListener("pointerlockchange", () =>
{
if (!document.pointerLockElement)
window.unityInstance.SendMessage("AppManager", "SetAppState", 2);
});
With this function, I can communicate with Unity to release the cursor (with a message from the web that has the focus) and then lock it again with a coroutine like you said when regaining focus on the canvas
public void RegainFocus(InputAction.CallbackContext context)
{
if (context.action.phase != InputActionPhase.Performed)
return;
StartCoroutine(WaitSecs());
}
//wait a little time before locking again the cursor so that webgl doesn't complain
IEnumerator WaitSecs()
{
yield return _waitForSeconds0_5;
AppManager.instance.SetAppState(1);
}
(Appstate will then trigger a delegate that will change the input map on the function above on the first post).
With this approach, it works!!! If anyone comes across this problem and solves it in a better way, I’d be happy to hear it. I find it curious, however, that you haven’t had this problem if your project also locks and releases the cursor. I’ll review my implementation again to see if there’s something I’m missing.
Thanks for the help!