[How-to] Advanced RegisterKeyMapping with NuiFocus in true

Hello
I have seen that in the forum there are a lot of questions about RegisterKeyMapping, and the guide only mentions it in passing.
And personally you should let a user edit the keys he is continuously using.
That it would be nice if FiveM would allow multiple categories in the future to be able to configure it correctly and always have a prefix of “Fivem -”.

Misuse of IsControlPressed

There are many resources that use something similar to this:


Citizen.CreateThread(function()
    while true do
        Citizen.Wait(0)
        if IsControlPressed(1, 75) then
            -- Code
        end
    end
end)

It is true that sometimes it is necessary, for example for the interact key, but not for adding new functionalities, Such as opening your custom nui or the menu you want.
I want to make this clear

This also causes your resource to always be consuming 0.2ms and in many cases unnecessarily adding a RegisterKeyMapping.

Use of RegisterKeyMapping

Some of you may already know the use of RegisterKeyMapping, ut I haven’t seen much in depth information or questions except RegisterKeyMapping - Get the right hash to read the current binding or Get_key_mapping or Create GET_KEY_MAPPING.

The truth is that it is a pity that it is not used so much, since in the RP servers you generally cannot modify the keys.

And if you don’t like where is the key to talk on the radio?
Or do you prefer to have an interaction menu on a key “away” from the “common keys” because you don’t use it?

This in most servers does not allow you to configure almost nothing, and I say almost nothing, because the resource programmers are gradually modifying their resources.

(I speak always from my experience with RP servers).

I will put the typical ways of how to do a RegisterKeyMapping, although this is not a mystery and there are other tutorials that cover it. Example: Using the new console key bindings – FiveM Cookbook

Typical ways of how to do a RegisterKeyMapping

Normal use of RegisterKeyMapping

RegisterKeyMapping("handsup", "Hands Up", "keyboard", "i")
RegisterCommand("handsup",function(source)
  -- Code
end)

“Toggle” use
+ Command → When key down
- Command → When key up

RegisterCommand('+handsup', function()
    -- Code
end, false)
RegisterCommand('-handsup', function()
    -- Code
end, false)
RegisterKeyMapping('+handsup', 'Hands Up', 'keyboard', 'i')

But this does not resolve several issues.

  • How to obtain the actual key mapping configuration
  • How we manage it with a NUI with SetNuiFocus(true, true)

Obtain actual key mapping

This is mainly taken from: RegisterKeyMapping - Get the right hash to read the current binding
Although it really doesn’t make it very clear what it does and can be confusing.
I would also like to thank the creator of the post, since he has solved my doubts. @Markus1812

  1. Get name command and put in FiveM Hash Generator
    This is for get hash key.
  2. Use GetControlInstructionalButton to return input
RegisterKeyMapping("handsup", "Hands Up", "keyboard", "i")
RegisterCommand("handsup",function(source)
  -- If you like use string can use: ~INPUT_7066E9F8~
  -- Remove INPUT_ and get 7066E9F8. This is in hex, and if you put 0x the code treats it as hexadecimal
  local button = GetControlInstructionalButton(2, 0x7066E9F8 , 1)
end)

If you like use in AddTextComponentString you can use INPUT_7066E9F8. See RegisterKeyMapping - Get the right hash to read the current binding for a more detailed example

If page down this is script to get hash, if you like made in lua or c#, enjoy

Javascript function to get hash
      function HashString(command) {
        let hash = 0;
        let string = command.toLowerCase();
        for(i=0; i < string.length; i++) {
          let letter = string[i].charCodeAt();
          hash = hash + letter;
          hash += (hash << 10 >>> 0);
          hash ^= (hash >>> 6);
          hash = hash >>> 0
        }

        hash += (hash << 3);
        if (hash < 0) {
          hash = hash >>> 0
        }
        hash ^= (hash >>> 11);
        hash += (hash << 15);
        if (hash < 0) {
          hash = hash >>> 0
        }
        return hash.toString(16).toUpperCase();
      }

GetControlInstructionalButton get for example b_1015 or t_V.

  • t_...’ is character
  • b_...’ is special character

The problem of special character: on different keyboards, have different numbers

I use one diccionary strings to convert special characters in javascript key code i use: https://keycode.info/ for getter key codes.
Why use javascript names key? Because if you like send to nui interface, but we will see that in the next point

I leave my list, but some people may need to add their own or change them.

Special key codes

WheelMouseMove and MouseClick is to differentiate events in NUI

SpecialkeyCodes={
['b_116']='WheelMouseMove.Up',
['b_115']='WheelMouseMove.Up',
['b_100']='MouseClick.LeftClick',
['b_101']='MouseClick.RightClick',
['b_102']='MouseClick.MiddleClick',
['b_103']='MouseClick.ExtraBtn1',
['b_104']='MouseClick.ExtraBtn2',
['b_105']='MouseClick.ExtraBtn3',
['b_106']='MouseClick.ExtraBtn4',
['b_107']='MouseClick.ExtraBtn5',
['b_108']='MouseClick.ExtraBtn6',
['b_109']='MouseClick.ExtraBtn7',
['b_110']='MouseClick.ExtraBtn8',
['b_1015']='AltLeft',
['b_1000']='ShiftLeft',
['b_2000']='Space',
['b_1013']='ControlLeft',
['b_1002']='Tab',
['b_1014']='ControlRight',
['b_140']='Numpad4',
['b_142']='Numpad6',
['b_144']='Numpad8',
['b_141']='Numpad5',
['b_143']='Numpad7',
['b_145']='Numpad9',
['b_200']='Insert',
['b_1012']='CapsLock',
['b_170']='F1',
['b_171']='F2',
['b_172']='F3',
['b_173']='F4',
['b_174']='F5',
['b_175']='F6',
['b_176']='F7',
['b_177']='F8',
['b_178']='F9',
['b_179']='F10',
['b_180']='F11',
['b_181']='F12',
['b_194']='ArrowUp',
['b_195']='ArrowDown',
['b_196']='ArrowLeft',
['b_197']='ArrowRight',
['b_1003']='Enter',
['b_1004']='Backspace',
['b_198']='Delete',
['b_199']='Escape',
['b_1009']='PageUp',
['b_1010']='PageDown',
['b_1008']='Home',
['b_131']='NumpadAdd',
['b_130']='NumpadSubstract',
['b_1002']='CapsLock',
['b_211']='Insert',
['b_210']='Delete',
['b_212']='End',
['b_1055']='Home',
['b_1056']='PageUp',
}

Okay, this is very good. But how do I connect it to my nui interface?

With this information, let’s get down to work. I made one function for “translate” keys into something readable for javascript

function translateKey(key)
    if (string.find(key, "t_")) then
        return string.gsub(key, "t_", "")
    else
        -- My global variable of special characters call SpecialkeyCodes
        return "SpecialCharacter."..SpecialkeyCodes[key]
    end
end

Modify RegisterKeyMapping for “toggle” system.
Why? when you use setNuiFocus, the keyup event in javascript is fired as well. this event is the one we are going to use to close the NUI, what we want is to keep it until we press again.
For this reason we have to control when we stop pressing to start listening to the keyUp event.


RegisterCommand('+handsup', function()
    local key = GetControlInstructionalButton(2, 0xF53DC64D, true)
    local keyName = translateKey(key)
    SetNuiFocus(true, true)
    SendNUIMessage({
       type="open",
       closeCharacterName=keyName
    })
end, false)
RegisterCommand('-handsup', function()
    SendNUIMessage({
        type="keyupFinish"
    })
end, false)
RegisterKeyMapping('+handsup', 'Hands Up', 'keyboard', 'i')

In javascript listen

disableCheckKey=true;
window.addEventListener("message",(ev)=>{
    if(event.type=="open"){
       this.disableCheckKey=true;
       /*Your code for show UI*/
    }
    if(event.type=="keyupFinish"){
     /*
        setTimeout? Why? -> The event is triggered too quickly, so it is a limitation to avoid failures
     */
      setTimeout(() => {
        this.disableCheckKey=false;
      }, 500);
    }
})
window.addEventListener("keyup",(ev)=>{
   if(this.disableCheckKey){return;}
   if(this.keyString.includes("SpecialCharacter")){
     /* This need control with:
         - MouseClick -> mouse up event
         - WheelMouseMove -> wheel event
         To avoid repeating code, I am not going to put it
     */
     if(this.keyString.includes("WheelMouseMove")||this.keyString.includes("MouseClick")){
        return;
     }
     if(ev.code==this.keyString.replace("SpecialCharacter.","")){
       /* Your code to close ui */
     }
   }else{
      if(ev.key.toLocaleLowerCase()==this.keyString.toLocaleLowerCase()){
        /* Your code to close ui */
      }
   }
})

Goodbye and thx for reading to end

13 Likes

Nice tutorial bro :slight_smile:

1 Like

Great work.