How to change keybind without invoking function?

Hello. So, I’m trying to make it so that when I change the keybind, it doesn’t invoke the function.

Here’s the code I wrote:

    CAS:UnbindAction(actionName)

    local input, process = UIS.InputBegan:Wait()
    
    local keyText = tostring(input.KeyCode)
    local actualText = string.sub(keyText, 14, #keyText)
    
    Keybind.Key.Text = "<b>" .. actualText .. "</b>"
    
    CAS:BindAction(actionName, funcName, true, input.KeyCode)

The script works fine; I just can’t seem to get rid of this weird behaviour. If you think you know what’s going on, feel free to share your thoughts.

If I understand right, you’re trying to make an input mapping system? Where you can select an input and then press a button to rebind it? But you don’t want to trigger the functionality of that key when you do so?

1 Like

yea, pretty much. i have a TextButton, then when I click that TextButton, it waits for me to press a key, then it sets the keybind to that new key. and yea, i don’t want to invoke the function once i set the keybind.

So this is the method that I use to get the key pressed. It’s not my intention to hand over code, however, I figured I’d include this here so you could see the method I use to do so. It’s already in a module so hypothetically speaking it should be copy and paste.

-- Services
local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")

-- Reference
local module = {}
local isListeningForInput = false
function module:GetNextKey(inputType)
	assert(isListeningForInput == false, "InputMap:GetNextKey() can only initiate one session at a time.")
	if isListeningForInput then return end -- We can only listen for one key at a time.

	isListeningForInput = true -- Debounce.
	print("Listening for key input.")
	local connection = nil	
	local bindableEvent = Instance.new("BindableEvent")	

	local Disconnect = function()
		if not connection then return end
		connection:Disconnect() -- Stop listening for key presses.
		bindableEvent:Destroy() -- Destroy bindable event for cleanup.
		isListeningForInput = false -- Allow a new session to be created.
	end

	connection = UserInputService.InputEnded:Connect(function(inputObject, gameProcessed)
		local keyCode = inputObject.KeyCode
		if gameProcessed then 
			Disconnect()
			return
 		end

		if inputObject.UserInputType ~= inputType then return end				
		if keyCode == Enum.KeyCode.Escape or keyCode == Enum.KeyCode.ButtonB then Disconnect() return end

		local modifiers = {
			["LeftControl"] = UserInputService:IsKeyDown(Enum.KeyCode.LeftControl),
			["LeftAlt"] = UserInputService:IsKeyDown(Enum.KeyCode.LeftAlt),
			["LeftShift"] = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift),
			["RightShift"] = UserInputService:IsKeyDown(Enum.KeyCode.RightShift),
			["RightControl"] = UserInputService:IsKeyDown(Enum.KeyCode.RightControl),
			["RightAlt"] = UserInputService:IsKeyDown(Enum.KeyCode.RightAlt)
		}

		print("Listened and found key", keyCode)
		bindableEvent:Fire(keyCode, modifiers)
		Disconnect()		
	end)

	return bindableEvent.Event
end

--[[
local keyCode1, modifiers1 = module:GetNextKey(Enum.UserInputType.Keyboard):Wait() 
ContextActionService:BindAction("TestBind", function(actionName, inputState, inputObject)
	print("We binded to", inputObject.KeyCode)
	print("The key that was pressed is", inputObject.KeyCode, modifiers1)
end, false, keyCode1)
]]--

--[[

	Example 1

	-- Services
	local ReplicatedStorage = game:GetService("ReplicatedStorage")

	-- Reference
	local Retro = require(ReplicatedStorage:WaitForChild("Retro.Client")) 
	local InputMap = Retro.InputMap
	
	local KeyCode, Modifiers = InputMap:GetNextKey(Enum.UserInputType.Keyboard):Wait()
	print("The key that was pressed is", KeyCode, Modifiers)

	Example 2

	-- Services
	local ReplicatedStorage = game:GetService("ReplicatedStorage")

	-- Reference
	local Retro = require(ReplicatedStorage:WaitForChild("Retro.Client")) 
	
	local KeyCode, Modifiers = Retro.InputMap:GetNextKey(Enum.UserInputType.Keyboard):Wait()
	print("The key that was pressed is", KeyCode, Modifiers)
	
]]--

return module
1 Like

sorry to bother you, but I can’t quite understand what your code does.

It creates a bindable event. A BindableEvent works only on the context it’s called from. So if you use it on a local script it only works in local scripts and if you use it on the server then it only works on the server.

When I want to get the next key pressed, I call a function that connects to the UserInputService.InputEnded event. It then caches the RobloxScriptSignal as the variable connection.

Afterward, it creates the bindable event and returns the event. Once you press a key, the event is then fired and the RobloxScriptSignal for UserInputService.InputEnded is disconnected to prevent any more key strokes from being mapped.

local KeyCode, Modifiers = Retro.InputMap:GetNextKey(Enum.UserInputType.Keyboard):Wait()

So here I connect to the bindable event that’s returned and wait for it to be fired. Once it’s fired KeyCode and Modifiers are populated.

You can then call ContextActionService:BindAction() with the KeyCode that’s returned. You can ignore Retro.InputMap that’s basically the module that’s returned at the end of the module script.

1 Like

oh, ok. I still have a few more questions.
1.

do I need this “Retro” thing?

  1. What does the modifiers thing do?

Modifiers just return a list of keys I consider to be modifiers. The keys in the table are true if the button was pressed down at the time of mapping. (Modifiers are unfinished so… I can’t guarantee anything lol)

Retro is the custom framework my game runs on. You don’t need it. I use it to get the module script from my framework without having to make a bunch of variables.

To use the modifiers properly you can check if a particular modifier is down when you bind the action using UserInputService:IsKeyDown. It lets you do things like hold alt and press Q for instance.

1 Like

aight, looks like I’ve solved it. In the function (which is basically the 2nd argument in CAS:BindAction()), you need to check if your input state is equal to Enum.UserInputState.Begin, before running any code.
Example:

local function funcName(actionName, inputState, inputObject)
    if inputState == Enum.UserInputState.Begin then
        -- run code
    end
end

appreciate the help though.