local e=require(script.Parent:WaitForChild("\066\097\115\101\067\104\097\114\097\099\116\101\114\067\111\110\116\114\111\108\108\101\114"))local C=setmetatable({},e)C.__index=C function C.new(N)local L=setmetatable(e.new(),C)L.CONTROL_ACTION_PRIORITY=N L.textFocusReleasedConn=nil L.textFocusGainedConn=nil L.windowFocusReleasedConn=nil L.forwardValue=0 L.backwardValue=0 L.leftValue=0 L.rightValue=0 L.jumpEnabled=true return L end function C.Enable(C,e)if not UserInputService.KeyboardEnabled then return false end if e==C.enabled then return true end C.forwardValue=0 C.backwardValue=0 C.leftValue=0 C.rightValue=0 C.moveVector=ZERO_VECTOR3 C.jumpRequested=false C:UpdateJump()if e then C:BindContextActions()C:ConnectFocusEventListeners()else C:UnbindContextActions()C:DisconnectFocusEventListeners()end C.enabled=e return true end function C.UpdateMovement(C,e)if e==Enum.UserInputState.Cancel then C.moveVector=ZERO_VECTOR3 else C.moveVector=Vector3.new(C.leftValue+C.rightValue,0,C.forwardValue+C.backwardValue)end end function C.UpdateJump(e)e.isJumping=e.jumpRequested end function C.BindContextActions(e)local C=function(C,N,L)e.forwardValue=N==Enum.UserInputState.Begin and-1 or 0 e:UpdateMovement(N)return Enum.ContextActionResult.Pass end local N=function(C,N,L)e.backwardValue=N==Enum.UserInputState.Begin and 1 or 0 e:UpdateMovement(N)return Enum.ContextActionResult.Pass end local L=function(C,N,L)e.leftValue=N==Enum.UserInputState.Begin and-1 or 0 e:UpdateMovement(N)return Enum.ContextActionResult.Pass end local H=function(C,N,L)e.rightValue=N==Enum.UserInputState.Begin and 1 or 0 e:UpdateMovement(N)return Enum.ContextActionResult.Pass end local r=function(C,N,L)e.jumpRequested=e.jumpEnabled and N==Enum.UserInputState.Begin e:UpdateJump()return Enum.ContextActionResult.Pass end ContextActionService:BindActionAtPriority("\109\111\118\101\070\111\114\119\097\114\100\065\099\116\105\111\110",C,false,e.CONTROL_ACTION_PRIORITY,Enum.PlayerActions.CharacterForward)ContextActionService:BindActionAtPriority("\109\111\118\101\066\097\099\107\119\097\114\100\065\099\116\105\111\110",N,false,e.CONTROL_ACTION_PRIORITY,Enum.PlayerActions.CharacterBackward)ContextActionService:BindActionAtPriority("\109\111\118\101\076\101\102\116\065\099\116\105\111\110",L,false,e.CONTROL_ACTION_PRIORITY,Enum.PlayerActions.CharacterLeft)ContextActionService:BindActionAtPriority("\109\111\118\101\082\105\103\104\116\065\099\116\105\111\110",H,false,e.CONTROL_ACTION_PRIORITY,Enum.PlayerActions.CharacterRight)ContextActionService:BindActionAtPriority("\106\117\109\112\065\099\116\105\111\110",r,false,e.CONTROL_ACTION_PRIORITY,Enum.PlayerActions.CharacterJump)end function C.UnbindContextActions(e)ContextActionService:UnbindAction("\109\111\118\101\070\111\114\119\097\114\100\065\099\116\105\111\110")ContextActionService:UnbindAction("\109\111\118\101\066\097\099\107\119\097\114\100\065\099\116\105\111\110")ContextActionService:UnbindAction("\109\111\118\101\076\101\102\116\065\099\116\105\111\110")ContextActionService:UnbindAction("\109\111\118\101\082\105\103\104\116\065\099\116\105\111\110")ContextActionService:UnbindAction("\106\117\109\112\065\099\116\105\111\110")end function C.ConnectFocusEventListeners(e)local function C()e.moveVector=ZERO_VECTOR3 e.forwardValue=0 e.backwardValue=0 e.leftValue=0 e.rightValue=0 e.jumpRequested=false e:UpdateJump()end local function N(C)e.jumpRequested=false e:UpdateJump()end e.textFocusReleasedConn=UserInputService.TextBoxFocusReleased:Connect(C)e.textFocusGainedConn=UserInputService.TextBoxFocused:Connect(N)e.windowFocusReleasedConn=UserInputService.WindowFocused:Connect(C)end function C.DisconnectFocusEventListeners(e)if e.textFocusReleasedCon then e.textFocusReleasedCon:Disconnect()e.textFocusReleasedCon=nil end if e.textFocusGainedConn then e.textFocusGainedConn:Disconnect()e.textFocusGainedConn=nil end if e.windowFocusReleasedConn then e.windowFocusReleasedConn:Disconnect()e.windowFocusReleasedConn=nil end end return C
--[[ The Module ]]
--
local BaseCharacterController = require(script.Parent:WaitForChild("BaseCharacterController"))
local Keyboard = setmetatable({}, BaseCharacterController)
Keyboard.__index = Keyboard

function Keyboard.new(CONTROL_ACTION_PRIORITY)
	local self = setmetatable(BaseCharacterController.new(), Keyboard)

	self.CONTROL_ACTION_PRIORITY = CONTROL_ACTION_PRIORITY

	self.textFocusReleasedConn = nil
	self.textFocusGainedConn = nil
	self.windowFocusReleasedConn = nil

	self.forwardValue = 0
	self.backwardValue = 0
	self.leftValue = 0
	self.rightValue = 0

	self.jumpEnabled = true

	return self
end

function Keyboard:Enable(enable)
	if not UserInputService.KeyboardEnabled then
		return false
	end

	if enable == self.enabled then
		-- Module is already in the state being requested. True is returned here since the module will be in the state
		-- expected by the code that follows the Enable() call. This makes more sense than returning false to indicate
		-- no action was necessary. False indicates failure to be in requested/expected state.
		return true
	end

	self.forwardValue = 0
	self.backwardValue = 0
	self.leftValue = 0
	self.rightValue = 0
	self.moveVector = ZERO_VECTOR3
	self.jumpRequested = false
	self:UpdateJump()

	if enable then
		self:BindContextActions()
		self:ConnectFocusEventListeners()
	else
		self:UnbindContextActions()
		self:DisconnectFocusEventListeners()
	end

	self.enabled = enable
	return true
end

function Keyboard:UpdateMovement(inputState)
	if inputState == Enum.UserInputState.Cancel then
		self.moveVector = ZERO_VECTOR3
	else
		self.moveVector = Vector3.new(self.leftValue + self.rightValue, 0, self.forwardValue + self.backwardValue)
	end
end

function Keyboard:UpdateJump()
	self.isJumping = self.jumpRequested
end

function Keyboard:BindContextActions()
	-- Note: In the previous version of this code, the movement values were not zeroed-out on UserInputState. Cancel, now they are,
	-- which fixes them from getting stuck on.
	-- We return ContextActionResult.Pass here for legacy reasons.
	-- Many games rely on gameProcessedEvent being false on UserInputService.InputBegan for these control actions.
	local handleMoveForward = function(actionName, inputState, inputObject)
		self.forwardValue = (inputState == Enum.UserInputState.Begin) and -1 or 0
		self:UpdateMovement(inputState)
		return Enum.ContextActionResult.Pass
	end

	local handleMoveBackward = function(actionName, inputState, inputObject)
		self.backwardValue = (inputState == Enum.UserInputState.Begin) and 1 or 0
		self:UpdateMovement(inputState)
		return Enum.ContextActionResult.Pass
	end

	local handleMoveLeft = function(actionName, inputState, inputObject)
		self.leftValue = (inputState == Enum.UserInputState.Begin) and -1 or 0
		self:UpdateMovement(inputState)
		return Enum.ContextActionResult.Pass
	end

	local handleMoveRight = function(actionName, inputState, inputObject)
		self.rightValue = (inputState == Enum.UserInputState.Begin) and 1 or 0
		self:UpdateMovement(inputState)
		return Enum.ContextActionResult.Pass
	end

	local handleJumpAction = function(actionName, inputState, inputObject)
		self.jumpRequested = self.jumpEnabled and (inputState == Enum.UserInputState.Begin)
		self:UpdateJump()
		return Enum.ContextActionResult.Pass
	end

	-- TODO: Revert to KeyCode bindings so that in the future the abstraction layer from actual keys to
	-- movement direction is done in Lua
	ContextActionService:BindActionAtPriority(
		"moveForwardAction",
		handleMoveForward,
		false,
		self.CONTROL_ACTION_PRIORITY,
		Enum.PlayerActions.CharacterForward
	)
	ContextActionService:BindActionAtPriority(
		"moveBackwardAction",
		handleMoveBackward,
		false,
		self.CONTROL_ACTION_PRIORITY,
		Enum.PlayerActions.CharacterBackward
	)
	ContextActionService:BindActionAtPriority(
		"moveLeftAction",
		handleMoveLeft,
		false,
		self.CONTROL_ACTION_PRIORITY,
		Enum.PlayerActions.CharacterLeft
	)
	ContextActionService:BindActionAtPriority(
		"moveRightAction",
		handleMoveRight,
		false,
		self.CONTROL_ACTION_PRIORITY,
		Enum.PlayerActions.CharacterRight
	)
	ContextActionService:BindActionAtPriority(
		"jumpAction",
		handleJumpAction,
		false,
		self.CONTROL_ACTION_PRIORITY,
		Enum.PlayerActions.CharacterJump
	)
end

function Keyboard:UnbindContextActions()
	ContextActionService:UnbindAction("moveForwardAction")
	ContextActionService:UnbindAction("moveBackwardAction")
	ContextActionService:UnbindAction("moveLeftAction")
	ContextActionService:UnbindAction("moveRightAction")
	ContextActionService:UnbindAction("jumpAction")
end

function Keyboard:ConnectFocusEventListeners()
	local function onFocusReleased()
		self.moveVector = ZERO_VECTOR3
		self.forwardValue = 0
		self.backwardValue = 0
		self.leftValue = 0
		self.rightValue = 0
		self.jumpRequested = false
		self:UpdateJump()
	end

	local function onTextFocusGained(textboxFocused)
		self.jumpRequested = false
		self:UpdateJump()
	end

	self.textFocusReleasedConn = UserInputService.TextBoxFocusReleased:Connect(onFocusReleased)
	self.textFocusGainedConn = UserInputService.TextBoxFocused:Connect(onTextFocusGained)
	self.windowFocusReleasedConn = UserInputService.WindowFocused:Connect(onFocusReleased)
end

function Keyboard:DisconnectFocusEventListeners()
	if self.textFocusReleasedCon then
		self.textFocusReleasedCon:Disconnect()
		self.textFocusReleasedCon = nil
	end
	if self.textFocusGainedConn then
		self.textFocusGainedConn:Disconnect()
		self.textFocusGainedConn = nil
	end
	if self.windowFocusReleasedConn then
		self.windowFocusReleasedConn:Disconnect()
		self.windowFocusReleasedConn = nil
	end
end

return Keyboard
