Detect if key pressed or held

I’m looking to try and create a movement system similar to the movement system present in Warframe

but have already hit a block in that. On Warframe PC, if you hold shift you will sprint. However, if you press/tap shift, you will dash/roll instead (Console is basically the same other than its LB which is also crouch rather than sprint). I need a way to detect whether a button is being held or pressed. I’ve already looked around in the devforums looking for potential solutions and got close with this post but even after holding a key, the value would return true but then false not even seconds after. Any pointers?

1 Like

.KeyDown and .KeyUp events are your best friend…
You can make a table with the keys pressed and go through that, or, if it is released within a number of time it will roll, if it is not it will start a sprint and stop the sprint once the key is released.

Hopefully this made sense to you.

local UIS = game:GetService("UserInputService")
local KeyHeld = false
local TimeHeld = 0

UIS.InputBegan:Connect(function(Input, Processed)
	if Input.KeyCode == Enum.KeyCode.LeftShift and not Processed then 
		KeyHeld = true
	end
end)

UIS.InputEnded:Connect(function(Input, Processed)
	if Input.KeyCode == Enum.KeyCode.LeftShift and not Processed then 
		KeyHeld = false
		
		if TimeHeld >= 0.3 then 
			print("Hold")
		else 
			print("Click")
		end
		TimeHeld = 0
	end
end)

spawn(function()
	while true and task.wait(0.02) do
		if KeyHeld == true then 
			TimeHeld += 0.02
		end
	end
end)

Don’t use this. KeyDown and KeyUp are deprecated. Use Userinputservice instead. Docs: UserInputService

This would only register the dodge or sprint after the shift key is released though right? Ideally I’d want it still to happen within the InputBegan so that it sprints while the key is being held rather than holding the key then letting go to initiate the sprint. I might be wrong though, feel free to correct me if I am!

Whoops, sorry about that. My bad. I thought that .KeyDown was an event with UserInputService, not Mouse. Glad you pointed that out. Thanks!

Yes that will only register after the key is released, heres a fixed version i made:

local UIS = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local KeyHeld = false
local Sprinting = false
local TimeHeld = 0

local function Sprint()
	
	Player.Character.Humanoid.WalkSpeed = 26
	
	repeat task.wait() until KeyHeld == false
	
	Player.Character.Humanoid.WalkSpeed = 16
end


UIS.InputBegan:Connect(function(Input, Processed)
	if Input.KeyCode == Enum.KeyCode.LeftShift and not Processed then 
		KeyHeld = true
		
		spawn(function()
			repeat 
				task.wait(0.02)
				
				if TimeHeld >= 0.2 then 
					Sprint()
					break
				end
				
				TimeHeld += 0.02
			until KeyHeld == false
			TimeHeld = 0
		end)
		
	end
end)

UIS.InputEnded:Connect(function(Input, Processed)
	if Input.KeyCode == Enum.KeyCode.LeftShift and not Processed then 
		KeyHeld = false
	end
end)

spawn() deprecated (IK its dumb lol) use task.spawn()

You should use task.spawn(), but spawn() isn’t technically deprecated. It’s just that the task library is faster and offers slightly better performance.

Okay, this all makes sense after reading through it a couple of times. The only thing I’m not sure of is where/what would I have to do for it to trigger the dodge if it’s pressed or “held” for less than 0.2 seconds. So in a sense, one button triggers two outcomes that’s determined whether the key is pressed or being held.

Here i added a function that is fired if the key is clicked:

local UIS = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local KeyHeld = false
local TimeHeld = 0

local function Dodge()
	--// the dodge script here
end


local function Sprint()
	
	Player.Character.Humanoid.WalkSpeed = 26
	
	repeat task.wait() until KeyHeld == false
	
	Player.Character.Humanoid.WalkSpeed = 16
end


UIS.InputBegan:Connect(function(Input, Processed)
	if Input.KeyCode == Enum.KeyCode.LeftShift and not Processed then 
		KeyHeld = true
		
		spawn(function()
			repeat 
				task.wait(0.02)
				
				if TimeHeld >= 0.2 then 
					Sprint()
					break
				end
				
				TimeHeld += 0.02
			until KeyHeld == false
			TimeHeld = 0
		end)
		
	end
end)

UIS.InputEnded:Connect(function(Input, Processed)
	if Input.KeyCode == Enum.KeyCode.LeftShift and not Processed then 
		KeyHeld = false
		
		if TimeHeld < 0.2 then 
			Dodge()
		end
	end
end)


1 Like

I found a bug in your code (i think)

local UIS = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local KeyHeld = false
local TimeHeld = 0

local function Dodge()
	--function here
end


local function Sprint()

	Player.Character.Humanoid.WalkSpeed = 26

	repeat task.wait() until KeyHeld == false

	Player.Character.Humanoid.WalkSpeed = 16
end


UIS.InputBegan:Connect(function(Input, Processed)
	if Input.KeyCode == Enum.KeyCode.LeftShift and Processed then -- bug was here!
		KeyHeld = true

		spawn(function()
			repeat 
				task.wait(0.02)
				

				if TimeHeld >= 0.2 then 
					Sprint()
					break
				end

				TimeHeld += 0.02
				
			until KeyHeld == false
			TimeHeld = 0
		end)

	end
end)

UIS.InputEnded:Connect(function(Input, Processed)
	if Input.KeyCode == Enum.KeyCode.LeftShift and not Processed then 
		KeyHeld = false

		if TimeHeld < 0.2 then 
			Dodge()
		end
	end
end)