RegisterCommand and RegisterKeyMapping: rebindable keys in FiveM
Create FiveM commands and let players rebind them: RegisterCommand with ACE, RegisterKeyMapping, hold actions with +/- commands, and why a new default key is ignored.
You want a command like /garage that anyone can type, a key like E that does the same, and a way for each player to change that key. FiveM gives you RegisterCommand for the command and RegisterKeyMapping for the key. This article shows both, how to restrict a command to admins, how to make an action that works while a key is held, and why changing a default key later does nothing for existing players.
A simple command
A command is a name and a function:
RegisterCommand('garage', function(source, args, rawCommand)
print('garage opened')
end, false)On the client, source is not useful. The args table holds the words typed after the command, and rawCommand is the full text. On the server, source is the player id, or 0 when the command comes from the server console.
The same on the server, with an argument:
RegisterCommand('heal', function(source, args)
local target = tonumber(args[1]) or source
TriggerClientEvent('my_script:heal', target)
end, true)Restrict a command with ACE
The last argument of RegisterCommand is restricted. With true, nobody can run the command unless they hold the ACE permission command.<name>. Give it to your admins in server.cfg:
add_ace group.admin command.heal allow
add_principal identifier.license:your_license_here group.adminPlayers without it get a permission error and the command never runs. How ACE groups and principals work is covered in ACE permissions for FiveM admins.
Warning: a
falsecommand can be typed by everyone, including cheaters who call it by hand. Never rely on a client-side command to guard something valuable. Do the real permission check on the server.
Bind the command to a key
RegisterKeyMapping ties a command to a key, on the client. The command must exist, so register both:
RegisterCommand('garage', function()
print('garage opened')
end, false)
RegisterKeyMapping('garage', 'Open the garage', 'keyboard', 'F5')The four arguments are the command name, the description shown to the player, the input device ('keyboard' here) and the default key. The key name is written like E, F5 or LSHIFT.
Players can now press F5, or type /garage, and both do the same thing.
Where players rebind it
The default key is only a suggestion. Players open the game Settings > Key Bindings > FiveM and find your action there, listed by the description text. They can change the key to whatever they like.
Write a clear description ('Open the garage', not 'garage'), since that is all the player sees. Keep it short and unique, so two scripts do not show the same label.
Hold actions with + and - commands
For something that lasts while a key is held, such as a push-to-talk or a rope, register a pair of commands: one starting with + and one with -. The game runs +name when the key goes down and -name when it comes up:
local holding = false
RegisterCommand('+my_hold', function()
holding = true
end, false)
RegisterCommand('-my_hold', function()
holding = false
end, false)
RegisterKeyMapping('+my_hold', 'Hold to aim the tool', 'keyboard', 'G')
CreateThread(function()
while true do
if holding then
-- do the held action here
Wait(0)
else
Wait(250)
end
end
end)Map the + name. Both the + and the - command must be registered, or the release is never seen.
Why a new default key does nothing
This catches a lot of developers. You release version 1 with 'F5', then switch to 'F6' in version 2. Players who already ran version 1 still press F5.
The reason: the default key from RegisterKeyMapping is applied only the first time the game sees that mapping. After that the binding lives in the player's own settings, and the new default is not used. So:
- New players get the new key.
- Existing players keep the old one, or whatever they picked themselves.
There is no clean way to force a key onto players who already have the binding. Your options:
- Tell players to rebind in Settings > Key Bindings > FiveM. Put it in your update notes.
- Use a new command name for the action, for example
garage_v2instead ofgarage. It is a new mapping, so the new default applies. Players will see both entries until the old one is removed. - Do not rely on the default. Show the actual key in your UI instead of a fixed letter, or tell players how to rebind.
This is also why you should test key changes on a fresh profile, or after removing the binding in the settings. Otherwise you keep testing your old key.
Keep the command logic small
A command handler should do one thing: call a function. Then the key, the command and a target interaction (see ox_target: how to add targets) all call the same function:
local function openGarage()
print('garage opened')
end
RegisterCommand('garage', openGarage, false)
RegisterKeyMapping('garage', 'Open the garage', 'keyboard', 'F5')Avoid keys that other things already use. Checking IsControlJustPressed in a loop for the same key as a mapped command makes both fire. Use the mapping alone.
Checklist
| Symptom | Fix |
|---|---|
| Command works for everyone | Pass true as the third argument and grant command.<name> with add_ace |
| Key does nothing | Register the command first, then RegisterKeyMapping with the same name |
| Hold action never releases | Register both +name and -name, and map the + name |
| Changed default key ignored | Defaults apply once: players rebind, or use a new command name |
| Players cannot find the binding | Settings > Key Bindings > FiveM; use a clear description |
| Server command breaks on the console | source is 0 there; handle that case |
Quick answers
Where do players change a key set with RegisterKeyMapping?
In the game's Settings, under Key Bindings, in the FiveM section. Your description text is the label they see there.
I changed the default key in my script but players still have the old one. Why?
The default is only applied the first time the mapping is registered. After that the player's own stored binding wins. Either ask players to rebind, or register the action under a new command name.
How do I restrict a command to admins?
Pass true as the third argument of RegisterCommand, then give your admin group the ACE command.yourcommand in server.cfg with add_ace.

