Cursor atrapado en FiveM o no se mueve después de cerrar un menú: corrección de enfoque NUI
¿Cursor atrapado en la pantalla o no se mueve después de cerrar un menú? Cómo funciona SetNuiFocus, cerrar con un callback de NUI, manejar ESC en JavaScript y encontrar al culpable.
Cierras un menú, y una de estas cosas sucede:
the mouse cursor stays on screen
the character will not move or look around
the keyboard does nothing until you reconnectNada aparece en la consola, porque nada está mal con el código que se ejecuta: simplemente nunca devolvió el enfoque. Aquí está cómo funciona el enfoque, cómo cerrar un menú correctamente y cómo encontrar al culpable.
Cómo funciona el enfoque de NUI
Una NUI es una página web (HTML, CSS y JavaScript) que FiveM dibuja sobre el juego. Mientras tenga enfoque, el mouse y el teclado van a la página en lugar del juego. Un script da y toma el enfoque con un nativo:
SetNuiFocus(hasFocus, hasCursor)SetNuiFocus(true, true): la NUI recibe el teclado y el mouse, y el cursor se muestra.SetNuiFocus(true, false): la NUI recibe el teclado, sin cursor.SetNuiFocus(false, false): el enfoque vuelve al juego y el cursor se oculta.
Si un menú se abre con true, true y ningún código jamás llama a SetNuiFocus(false, false), el juego permanece bloqueado, incluso si la página está oculta.
La solución: siempre cierra con SetNuiFocus(false, false)
Pon el cierre en una función y úsalo para cada forma de cerrar el menú:
local open = false
local function openMenu()
open = true
SetNuiFocus(true, true)
SendNUIMessage({ action = 'open' })
end
local function closeMenu()
open = false
SetNuiFocus(false, false)
SendNUIMessage({ action = 'close' })
endHaz lo mismo si el menú puede ser cerrado por otro código: cuando el jugador muere, entra en un vehículo, o cuando el recurso se detiene.
AddEventHandler('onResourceStop', function(resource)
if resource == GetCurrentResourceName() and open then
SetNuiFocus(false, false)
end
end)Este último importa. Si un recurso se detiene mientras su menú está abierto, el enfoque no se devuelve por ti, y el jugador queda atrapado hasta que se reconecte.
Cierra desde la página: RegisterNUICallback y fetch
Un botón de cierre, o una pulsación de tecla dentro de la página, se ejecuta en JavaScript. JavaScript no puede llamar a un nativo, así que envía una solicitud al lado de Lua, que la maneja:
RegisterNUICallback('close', function(data, cb)
closeMenu()
cb('ok')
end)En tu página, envía la solicitud con fetch a https://<nombre de recurso>/close. GetParentResourceName() te da el nombre del recurso dentro de una página NUI:
function closeMenu() {
fetch(`https://${GetParentResourceName()}/close`, {
method: 'POST',
headers: { 'Content-Type': 'application/json; charset=UTF-8' },
body: JSON.stringify({}),
})
}
document.getElementById('close-button').addEventListener('click', closeMenu)El callback debe llamar a cb. Si nunca responde, la solicitud en la página permanece abierta, y algunas librerías dejan de esperar. Siempre termina un callback con cb('ok') u otra respuesta.
ESC y otras teclas en JavaScript
Mientras la NUI tiene enfoque, el juego no ve el teclado, así que la tecla ESC nunca llega a tu código Lua. La página tiene que escucharla:
window.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
closeMenu()
}
})Añade la misma verificación para cualquier otra tecla que deba cerrar el menú. Si la página tiene un cuadro de entrada, piensa en lo que la tecla hace allí: ESC en un campo de texto aún debe cerrar el menú, pero una letra no debe.
Cuidado: no confíes únicamente en un botón de cierre. Si un jugador presiona ESC y la página no tiene un listener, el menú de pausa puede abrirse, y el menú permanece en la pantalla sin forma de cerrarlo.
Caminar mientras un menú está abierto
Algunas interfaces, como un HUD con un pequeño panel o un teléfono, deberían permitir que el jugador siga moviéndose. Para eso usa SetNuiFocusKeepInput:
SetNuiFocus(true, true)
SetNuiFocusKeepInput(true)Con la entrada de mantenimiento, el juego sigue recibiendo el teclado mientras la NUI tiene enfoque. Si lo enciende, apágalo cuando se cierre el menú, porque permanece encendido hasta que lo hagas:
local function closeMenu()
SetNuiFocusKeepInput(false)
SetNuiFocus(false, false)
endUn SetNuiFocusKeepInput(true) restante da síntomas extraños: el cursor se fue pero algunas teclas se comportan de manera extraña o no hacen nada.
Encuentra el recurso que mantiene el enfoque
A menudo el menú atrapado no es tuyo. Cuando no sabes qué recurso tomó el enfoque, encuéntralo por eliminación:
- Reproduce el problema: abre el menú, ciérralo, y ve el cursor atrapado.
- En la consola del servidor (o la Consola en vivo de txAdmin), escribe
restart resource_namepara un recurso que tiene un menú: un teléfono, inventario, tienda, menú radial o menú de ropa. - Verifica si el cursor y los controles vuelven o si el problema ya no ocurre.
- Repite para el siguiente recurso hasta que el comportamiento cambie.
Cuando un reinicio devuelve el enfoque, ese script lo mantiene. Busca en su código una ruta de cierre que no llame a SetNuiFocus(false, false): un error antes de la línea de cierre, una muerte o un cambio de trabajo que cierre solo el HTML, o un callback que no responda. Un error en la consola en el momento del bug es una pista fuerte: véase how to read a FiveM script error.
Si es un script que compraste, envía a su autor los pasos exactos y el nombre del recurso que encontraste.
Lista de verificación
| Síntoma | Solución |
|---|---|
| Cursor permanece después de cerrar | Llama a SetNuiFocus(false, false) en la función de cierre |
| El botón de cierre no hace nada | Añade RegisterNUICallback('close', ...) y un fetch a https://<recurso>/close |
| ESC no cierra el menú | Escucha Escape en JavaScript y llama al callback de cierre |
| Atrapado después de reiniciar un recurso | Libera el enfoque en onResourceStop |
| El personaje no puede moverse después de cerrar | Apaga SetNuiFocusKeepInput(false) al cerrar |
| No sé qué script lo hace | Reinicia recursos uno a uno hasta que el cursor regrese |
| El callback se cuelga | Siempre responde con cb('ok') |
Respuestas rápidas
¿Por qué mi cursor permanece en la pantalla después de cerrar un menú?
El menú ocultó su HTML, pero nada le dijo al juego que devolviera el enfoque. El script tiene que llamar a SetNuiFocus(false, false) cuando se cierra el menú.
¿Qué hace SetNuiFocusKeepInput?
SetNuiFocusKeepInput(true) permite que el juego reciba entrada de teclado mientras una NUI tiene enfoque, para que el jugador aún pueda caminar. Debe apagarse de nuevo cuando se cierra el menú.
¿Cómo encuentro qué recurso mantiene el enfoque?
Reinicia tus recursos uno a la vez y verifica después de cada uno si el cursor y los controles vuelven. El que sea reiniciado y solucione el problema es el que mantenía el enfoque.
Scripts que evitan este problema
Mic PhoneUn móvil plegable que se abre en tablet y llega al móvil real del jugador.Ver script →
Arcade MachinesSiete juegos arcade jugables en máquinas reales, con clasificaciones y apuestas.Ver script →
Clothing DesignerDiseña ropa dentro de FiveM — pincel, capas, imágenes e IA — y póntela.Ver script →