Input pipeline has issues with multikey Shift handling

System Information: AMD Ryzen 5 2600 3.40 GHz, 32 GB, NVIDIA GeForce 2070 SUPER

The input pipeline has issues with multikey handling, e.g., InputBegan/InputEnded or Pressed/Released doesn’t fire when it should for “UserInputService”, “ContextActionService” and “InputActionSystem”

How to reproduce:

UserInputService:

local UserInputService = game:GetService("UserInputService")

UserInputService.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.RightShift then
		print("InputBegan:", input.KeyCode)
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.RightShift then
		print("InputEnded:", input.KeyCode)
	end
end)

ContextActionService:

local ContextActionService = game:GetService("ContextActionService")

ContextActionService:BindAction("ShiftTest", function(_, state, input)
	if input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.RightShift then
		if state == Enum.UserInputState.Begin then
			print("InputBegan:", input.KeyCode)
		elseif state == Enum.UserInputState.End then
			print("InputEnded:", input.KeyCode)
		end
	end
	return Enum.ContextActionResult.Pass
end, false, Enum.KeyCode.LeftShift, Enum.KeyCode.RightShift)

InputActionSystem:

local inputAction = script.Parent

inputAction.Pressed:Connect(function()
	print("Pressed")
end)
inputAction.Released:Connect(function()
	print("Released")
end)

I am uncertain if this is a bug on my end with my hardware

Expected behavior

I’m currently using RightShift and LeftShift simultaneously, and I’m uncertain about the impact on other keys. What I expect is that when pressing LeftShift, it fires, which happens, but while holding LeftShift and pressing RightShift, there’s no fire. Releasing the LeftShift doesn’t fire the InputEnded/Released and then releasing RightShift doses fire an InputEnded/Released but then the weird thing is now that LeftShift is acting as if it’s still being held until it’s pressed again and it resets it and the same happens if the order is the other way with RightShift first

1 Like

Afaik this is a common limitation of keyboard hardware, not our Engine. It can be found across desktop platforms and manufacturers.

This is a known limitation with modifier keys (Shift, Ctrl, Alt) in Roblox’s input pipeline. The issue occurs because modifier keys are treated differently than standard keys—they don’t always fire InputBegan and InputEnded consistently across all input services.**What’s happening:**Shift is a modifier key, and Roblox’s input system prioritizes it for input state tracking rather than discrete key events. When you hold Shift and press another key, the pipeline may suppress the individual Shift event to avoid redundant firing.Practical workarounds:Use InputChanged instead of InputBegan/InputEnded for modifier keys specifically. InputChanged fires reliably when modifier states change:luaUserInputService.InputChanged:Connect(function(input, gameProcessed) if input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.RightShift then print("Shift state changed:", UserInputService:IsKeyDown(input.KeyCode)) endend)Check modifier state directly instead of relying on events. Poll IsKeyDown() in your input handling:luaif UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) then -- Shift is heldendAvoid ContextActionService for modifier-only binds. Use it for combined inputs instead (Shift+W, etc.) by checking IsKeyDown() inside your action callback.• BindAction with modifier detection:luaContextActionService:BindAction("ShiftAction", function(_, state) if state == Enum.UserInputState.Begin and UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) then -- Fire your logic end return Enum.ContextActionResult.Sinkend, false, Enum.KeyCode.W)This approach bypasses the modifier key event quirk entirely. The limitation exists because Roblox’s input system deprioritizes modifier events to prevent cascading issues in complex input chains.

Well, I laster tested the issue on the client, and it’s not on the client; it’s only in the studio if that changes things