function KeyboardMovement.Enable(c)if not UserInputService.KeyboardEnabled then return end local A=0 local p=0 local l=0 local u=0 local I=function(c)if c==Enum.UserInputState.Cancel then MasterControl:AddToPlayerMovement(-currentMoveVector)currentMoveVector=Vector3.new(0,0,0)else MasterControl:AddToPlayerMovement(-currentMoveVector)currentMoveVector=Vector3.new(l+u,0,A+p)MasterControl:AddToPlayerMovement(currentMoveVector)end end local Z=function(c,p,l)if p==Enum.UserInputState.Begin then A=-1 elseif p==Enum.UserInputState.End or p==Enum.UserInputState.Cancel then A=0 end I(p)end local q=function(c,A,l)if A==Enum.UserInputState.Begin then p=1 elseif A==Enum.UserInputState.End or A==Enum.UserInputState.Cancel then p=0 end I(A)end local h=function(c,A,p)if A==Enum.UserInputState.Begin then l=-1 elseif A==Enum.UserInputState.End or A==Enum.UserInputState.Cancel then l=0 end I(A)end local r=function(c,A,p)if A==Enum.UserInputState.Begin then u=1 elseif A==Enum.UserInputState.End or A==Enum.UserInputState.Cancel then u=0 end I(A)end local T=function(c,A,p)MasterControl:SetIsJumping(A==Enum.UserInputState.Begin)end ContextActionService:BindActionToInputTypes("\102\111\114\119\097\114\100\077\111\118\101\109\101\110\116",Z,false,Enum.PlayerActions.CharacterForward)ContextActionService:BindActionToInputTypes("\098\097\099\107\119\097\114\100\077\111\118\101\109\101\110\116",q,false,Enum.PlayerActions.CharacterBackward)ContextActionService:BindActionToInputTypes("\108\101\102\116\077\111\118\101\109\101\110\116",h,false,Enum.PlayerActions.CharacterLeft)ContextActionService:BindActionToInputTypes("\114\105\103\104\116\077\111\118\101\109\101\110\116",r,false,Enum.PlayerActions.CharacterRight)ContextActionService:BindActionToInputTypes("\106\117\109\112\065\099\116\105\111\110",T,false,Enum.PlayerActions.CharacterJump)local function y()local c=getHumanoid()if c then MasterControl:AddToPlayerMovement(-currentMoveVector)currentMoveVector=Vector3.new(0,0,0)A,p,l,u=0,0,0,0 MasterControl:SetIsJumping(false)end end local function w(c)MasterControl:SetIsJumping(false)end SeatJumpCn=UserInputService.InputBegan:connect(function(c,A)if c.KeyCode==Enum.KeyCode.Backspace and not A then local c=getHumanoid()if c and(c.Sit or c.PlatformStand)then MasterControl:DoJump()end end end)TextFocusReleasedCn=UserInputService.TextBoxFocusReleased:connect(y)TextFocusGainedCn=UserInputService.TextBoxFocused:connect(w)WindowFocusReleasedCn=UserInputService.WindowFocusReleased:connect(y)end function KeyboardMovement.Disable(c)ContextActionService:UnbindAction("\102\111\114\119\097\114\100\077\111\118\101\109\101\110\116")ContextActionService:UnbindAction("\098\097\099\107\119\097\114\100\077\111\118\101\109\101\110\116")ContextActionService:UnbindAction("\108\101\102\116\077\111\118\101\109\101\110\116")ContextActionService:UnbindAction("\114\105\103\104\116\077\111\118\101\109\101\110\116")ContextActionService:UnbindAction("\106\117\109\112\065\099\116\105\111\110")if SeatJumpCn then SeatJumpCn:disconnect()SeatJumpCn=nil end if TextFocusReleasedCn then TextFocusReleasedCn:disconnect()TextFocusReleasedCn=nil end if TextFocusGainedCn then TextFocusGainedCn:disconnect()TextFocusGainedCn=nil end if WindowFocusReleasedCn then WindowFocusReleasedCn:disconnect()WindowFocusReleasedCn=nil end MasterControl:AddToPlayerMovement(-currentMoveVector)currentMoveVector=Vector3.new(0,0,0)MasterControl:SetIsJumping(false)end return KeyboardMovement
--[[ Public API ]]
--
function KeyboardMovement:Enable()
	if not UserInputService.KeyboardEnabled then
		return
	end

	local forwardValue = 0
	local backwardValue = 0
	local leftValue = 0
	local rightValue = 0

	local updateMovement = function(inputState)
		if inputState == Enum.UserInputState.Cancel then
			MasterControl:AddToPlayerMovement(-currentMoveVector)
			currentMoveVector = Vector3.new(0, 0, 0)
		else
			MasterControl:AddToPlayerMovement(-currentMoveVector)
			currentMoveVector = Vector3.new(leftValue + rightValue, 0, forwardValue + backwardValue)
			MasterControl:AddToPlayerMovement(currentMoveVector)
		end
	end

	local moveForwardFunc = function(actionName, inputState, inputObject)
		if inputState == Enum.UserInputState.Begin then
			forwardValue = -1
		elseif inputState == Enum.UserInputState.End or inputState == Enum.UserInputState.Cancel then
			forwardValue = 0
		end
		updateMovement(inputState)
	end

	local moveBackwardFunc = function(actionName, inputState, inputObject)
		if inputState == Enum.UserInputState.Begin then
			backwardValue = 1
		elseif inputState == Enum.UserInputState.End or inputState == Enum.UserInputState.Cancel then
			backwardValue = 0
		end
		updateMovement(inputState)
	end

	local moveLeftFunc = function(actionName, inputState, inputObject)
		if inputState == Enum.UserInputState.Begin then
			leftValue = -1
		elseif inputState == Enum.UserInputState.End or inputState == Enum.UserInputState.Cancel then
			leftValue = 0
		end
		updateMovement(inputState)
	end

	local moveRightFunc = function(actionName, inputState, inputObject)
		if inputState == Enum.UserInputState.Begin then
			rightValue = 1
		elseif inputState == Enum.UserInputState.End or inputState == Enum.UserInputState.Cancel then
			rightValue = 0
		end
		updateMovement(inputState)
	end

	local jumpFunc = function(actionName, inputState, inputObject)
		MasterControl:SetIsJumping(inputState == Enum.UserInputState.Begin)
	end

	-- TODO: remove up and down arrows, these seem unnecessary
	ContextActionService:BindActionToInputTypes(
		"forwardMovement",
		moveForwardFunc,
		false,
		Enum.PlayerActions.CharacterForward
	)
	ContextActionService:BindActionToInputTypes(
		"backwardMovement",
		moveBackwardFunc,
		false,
		Enum.PlayerActions.CharacterBackward
	)
	ContextActionService:BindActionToInputTypes("leftMovement", moveLeftFunc, false, Enum.PlayerActions.CharacterLeft)
	ContextActionService:BindActionToInputTypes(
		"rightMovement",
		moveRightFunc,
		false,
		Enum.PlayerActions.CharacterRight
	)
	ContextActionService:BindActionToInputTypes("jumpAction", jumpFunc, false, Enum.PlayerActions.CharacterJump)
	-- TODO: make sure we check key state before binding to check if key is already down

	local function onFocusReleased()
		local humanoid = getHumanoid()
		if humanoid then
			MasterControl:AddToPlayerMovement(-currentMoveVector)
			currentMoveVector = Vector3.new(0, 0, 0)
			forwardValue, backwardValue, leftValue, rightValue = 0, 0, 0, 0
			MasterControl:SetIsJumping(false)
		end
	end

	local function onTextFocusGained(textboxFocused)
		MasterControl:SetIsJumping(false)
	end

	SeatJumpCn = UserInputService.InputBegan:connect(function(inputObject, isProcessed)
		if inputObject.KeyCode == Enum.KeyCode.Backspace and not isProcessed then
			local humanoid = getHumanoid()
			if humanoid and (humanoid.Sit or humanoid.PlatformStand) then
				MasterControl:DoJump()
			end
		end
	end)

	TextFocusReleasedCn = UserInputService.TextBoxFocusReleased:connect(onFocusReleased)
	TextFocusGainedCn = UserInputService.TextBoxFocused:connect(onTextFocusGained)
	-- TODO: remove pcall when API is live
	WindowFocusReleasedCn = UserInputService.WindowFocusReleased:connect(onFocusReleased)
end

function KeyboardMovement:Disable()
	ContextActionService:UnbindAction("forwardMovement")
	ContextActionService:UnbindAction("backwardMovement")
	ContextActionService:UnbindAction("leftMovement")
	ContextActionService:UnbindAction("rightMovement")
	ContextActionService:UnbindAction("jumpAction")

	if SeatJumpCn then
		SeatJumpCn:disconnect()
		SeatJumpCn = nil
	end
	if TextFocusReleasedCn then
		TextFocusReleasedCn:disconnect()
		TextFocusReleasedCn = nil
	end
	if TextFocusGainedCn then
		TextFocusGainedCn:disconnect()
		TextFocusGainedCn = nil
	end
	if WindowFocusReleasedCn then
		WindowFocusReleasedCn:disconnect()
		WindowFocusReleasedCn = nil
	end

	MasterControl:AddToPlayerMovement(-currentMoveVector)
	currentMoveVector = Vector3.new(0, 0, 0)
	MasterControl:SetIsJumping(false)
end

return KeyboardMovement
