SetNuiFocusKeepInput in depth: letting the game keep its input
SetNuiFocusKeepInput(true) tells FiveM to keep passing keyboard and mouse input to the game while an NUI page has focus from SetNuiFocus. It does nothing on its own: focus must be on first. Once it is on, the game sees everything, including mouse look, fire and Escape, so run a per-frame loop that either blocks the dangerous controls or, better, blocks everything and re-enables only movement, voice and driving. Turn it off while a text field is focused and on every close path, and check it with IsNuiFocusKeepingInput() when debugging.
Phones, radial menus, radios and target menus all share one requirement: the player should still be able to walk, drive or talk while the interface is on screen. FiveM has exactly one native for that, SetNuiFocusKeepInput, and it is simple to call and surprisingly easy to get wrong. This guide goes past the one-line explanation and covers the control lists, the voice and vehicle cases, text fields, and the bugs that show up once two UIs compete for focus.

#What the native actually changes
The declaration is one line: SetNuiFocusKeepInput(keepInput), a client-only CFX native that takes a boolean. Its partner IsNuiFocusKeepingInput() returns the current state. Neither has any effect until an NUI frame holds focus through SetNuiFocus, which is why the basics are covered first in NUI focus and cursor.
Normally, when your page has focus, FiveM routes the keyboard (and the mouse, if the cursor is on) to the browser and the game stops receiving them. With keep input switched on, input goes to both: the page still gets keydown and mouse events, and the game still sees the same keys as controls. That is the whole feature. Everything else in this article is about living with the consequences.
| Calls | Page receives | Game receives | Typical use |
|---|---|---|---|
SetNuiFocus(true, true) | Keyboard + mouse | Nothing | Inventories, shops, forms |
SetNuiFocus(true, true) + SetNuiFocusKeepInput(true) | Keyboard + mouse | Keyboard + mouse | Phones, radios, radial menus |
SetNuiFocus(true, false) + SetNuiFocusKeepInput(true) | Keyboard | Keyboard + mouse look | Key-driven overlays without a cursor |
SetNuiFocus(false, false) | Nothing | Everything | UI closed or display-only HUD |
The combinations you will actually use
#A correct open and close pair
Keep the three calls together in one function so no code path can forget one of them. The page is told to show itself after focus is set, which avoids a frame where the UI is visible but cannot be clicked.
local isOpen = false
local function setPhone(state)
if state == isOpen then return end
isOpen = state
SetNuiFocus(state, state)
SetNuiFocusKeepInput(state)
SendNUIMessage({ action = 'visible', value = state })
if state then
StartControlLoop()
end
end
RegisterNuiCallback('close', function(_, cb)
setPhone(false)
cb({})
end)
AddEventHandler('onResourceStop', function(name)
if name ~= GetCurrentResourceName() then return end
SetNuiFocusKeepInput(false)
SetNuiFocus(false, false)
end)Resetting keep input on stop matters more than it looks. A resource restarted during development with keep input still on can leave the next UI that takes focus in a strange half state. Treat both flags as something you own and must hand back.
#The block-list approach and its gaps
The first thing players notice with keep input on is the camera: moving the mouse over your phone also swings the view, and clicking an app fires the weapon in their hand. The usual fix is a per-frame thread that disables the controls you do not want.
| ID | Control | Why |
|---|---|---|
| 1, 2 | Look left/right, up/down | Mouse movement over the UI would turn the camera |
| 24, 257 | Attack, attack 2 | Clicking the UI fires the weapon |
| 25 | Aim | Right-click on the UI aims |
| 140, 141, 142 | Melee light, heavy, alternate | Clicks punch people |
| 37 | Weapon wheel (Tab) | Tab opens the wheel over your UI |
| 199, 200 | Pause (P) and pause alternate (Esc) | Escape opens the map instead of closing your UI |
| 245 | Text chat (T) | Typing T opens chat |
| 14, 15, 16, 17 | Weapon scroll next/prev | Mouse wheel over the UI changes weapons |
Controls most keep-input UIs disable (input group 0)
The problem with a block-list is that it is never complete. Every framework adds its own keybinds, and emotes, hands-up or the target eye can still fire through your UI. The list above is a good minimum; the allow-list below is the robust version.
#The allow-list approach (recommended)
Instead of guessing which controls to block, block all of them and re-enable the handful the player should keep. DisableAllControlActions(0) followed by EnableControlAction calls in the same frame gives you exact control.
local ON_FOOT = { 30, 31, 32, 33, 34, 35, 21, 22 }
local IN_VEHICLE = { 59, 63, 64, 71, 72, 76 }
local ALWAYS = { 249 }
function StartControlLoop()
CreateThread(function()
while isOpen do
DisableAllControlActions(0)
for i = 1, #ALWAYS do EnableControlAction(0, ALWAYS[i], true) end
if IsPedInAnyVehicle(PlayerPedId(), false) then
for i = 1, #IN_VEHICLE do EnableControlAction(0, IN_VEHICLE[i], true) end
else
for i = 1, #ON_FOOT do EnableControlAction(0, ON_FOOT[i], true) end
end
Wait(0)
end
end)
end| Group | IDs | Controls |
|---|---|---|
| On foot | 30, 31 | Move left/right, move up/down (analogue axes) |
| On foot | 32, 33, 34, 35 | W, S, A, D as individual controls |
| On foot | 21, 22 | Sprint and jump |
| Vehicle | 59, 63, 64 | Steering axis and steer left/right |
| Vehicle | 71, 72, 76 | Accelerate, brake/reverse, handbrake |
| Always | 249 | Push-to-talk (N) |
Leave the vehicle exit control (75, F) disabled so a mis-click does not throw the player out of a moving car. If you want sprint to stay disabled while a phone is up for roleplay reasons, remove 21 from the list; the point of an allow-list is that these decisions become explicit.
#Reading keys while they are disabled
A disabled control still registers presses; it just stops the game acting on them. That means your Lua loop can listen for Backspace or Escape and close the UI without the pause menu opening. Use the IsDisabledControl… family, because IsControlJustPressed returns false for disabled controls.
if IsDisabledControlJustPressed(0, 200) or IsDisabledControlJustPressed(0, 177) then
setPhone(false)
endControl 200 is the Escape pause alternate and 177 is the phone cancel control (Backspace, Escape or right mouse by default). Handling the close in Lua rather than in the page has a bonus: it also works when the page has lost keyboard focus to an input field, which is the next topic.
#Typing in a text field with keep input on
With keep input on, every letter a player types into a message box also reaches the game. W walks forward, T opens chat and a number key might swap weapons. An allow-list reduces the damage but movement keys are, by design, still enabled. The clean fix is to switch keep input off while any text field has focus and restore it afterwards.
const isTextField = (el) =>
el && (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable);
document.addEventListener('focusin', (e) => {
if (isTextField(e.target)) fetchNui('keepInput', { value: false });
});
document.addEventListener('focusout', (e) => {
if (isTextField(e.target)) fetchNui('keepInput', { value: true });
});RegisterNuiCallback('keepInput', function(data, cb)
if isOpen then
SetNuiFocusKeepInput(data.value == true)
end
cb({})
end)The isOpen guard stops a late focusout (fired as the page hides) from switching keep input back on after the UI has closed. focusin and focusout bubble, unlike focus and blur, so one listener on the document covers every field. The fetchNui helper is the one from NUI callbacks with fetch. More keyboard edge cases are collected in NUI text inputs and keyboard bugs.
#When two UIs compete for focus
Focus is per frame, but the way keep input interacts between frames is less predictable. There is an open report on the FiveM tracker where a first UI sets keep input to true and a second UI then sets it to false, yet input keeps flowing to the game. In practice, three habits avoid most of these problems:
- Always set keep input explicitly when you take focus, even to
false. Never rely on the default. - Always set it back to
falsewhen you release focus, beforeSetNuiFocus(false, false). - Check
IsNuiFocused()before opening; if another UI already holds focus, close it through its own export or event instead of stacking a second focused UI on top.
Frameworks with a central UI manager solve this once: every resource asks the manager to open, and the manager owns the focus flags. If you maintain several of your own UIs, a tiny shared export (requestFocus(name, cursor, keepInput) and releaseFocus(name)) is worth the ten lines it takes.
#Debugging focus state
When a player reports a stuck camera or an unclosable menu, you need to know the state at that moment. A small command prints it:
RegisterCommand('focusdebug', function()
print(('focused=%s keepInput=%s'):format(
tostring(IsNuiFocused()),
tostring(IsNuiFocusKeepingInput())
))
end, false)| Symptom | Likely cause |
|---|---|
| Camera spins while using the UI | Keep input on, look controls (1, 2) not disabled |
| Clicking the UI shoots | Attack controls (24, 257) not disabled |
| Escape opens the map | Pause controls (199, 200) not disabled, or close handled on keydown |
| Player walks while typing | Keep input still on while a text field is focused |
| Cannot talk with phone open | Push-to-talk (249) disabled by DisableAllControlActions |
| Camera stuck after closing | Keep input or focus never released on one close path |
Check the page side too: open the NUI devtools and confirm the keepInput callback requests actually go out when a field gains and loses focus.
Questions
What does SetNuiFocusKeepInput do?
Do I still need SetNuiFocus with SetNuiFocusKeepInput?
SetNuiFocus(true, …). On its own it does nothing.Why does my camera move when I use my phone UI?
DisableAllControlActions(0) and re-enable only what you need.Why can I not use push-to-talk while my UI is open?
EnableControlAction(0, 249, true) each frame.How do I stop the player walking while typing?
focusin of a text field that calls SetNuiFocusKeepInput(false), and switch it back on focusout.How can I check whether keep input is active?
IsNuiFocusKeepingInput() on the client. Pair it with IsNuiFocused() in a debug command.Ready to pick a map?
Twelve themes on three base map styles, $8 each, instant download.
Relevant to what you just read
Look it up while you work
The reference tables this guide leans on, free and without an account.
- All 921 vehicle spawn namesEvery vanilla model with a picture, its display name, its class and the hash CreateVehicle takes.