local N={[Enum.UserInputType.Keyboard]=Keyboard,[Enum.UserInputType.MouseButton1]=Keyboard,[Enum.UserInputType.MouseButton2]=Keyboard,[Enum.UserInputType.MouseButton3]=Keyboard;[Enum.UserInputType.MouseWheel]=Keyboard,[Enum.UserInputType.MouseMovement]=Keyboard;[Enum.UserInputType.Gamepad1]=Gamepad,[Enum.UserInputType.Gamepad2]=Gamepad;[Enum.UserInputType.Gamepad3]=Gamepad,[Enum.UserInputType.Gamepad4]=Gamepad}local U function ControlModule.new()local N=setmetatable({},ControlModule)N.controllers={}N.activeControlModule=nil N.activeController=nil N.touchJumpController=nil N.moveFunction=Players.LocalPlayer.Move N.humanoid=nil N.lastInputType=Enum.UserInputType.None N.controlsEnabled=true N.humanoidSeatedConn=nil N.vehicleController=nil N.touchControlFrame=nil if FFlagUserHideControlsWhenMenuOpen then GuiService.MenuOpened:Connect(function()if N.touchControlFrame and N.touchControlFrame.Visible then N.touchControlFrame.Visible=false end end)GuiService.MenuClosed:Connect(function()if N.touchControlFrame then N.touchControlFrame.Visible=true end end)end N.vehicleController=VehicleController.new(CONTROL_ACTION_PRIORITY)Players.LocalPlayer.CharacterAdded:Connect(function(U)N:OnCharacterAdded(U)end)Players.LocalPlayer.CharacterRemoving:Connect(function(U)N:OnCharacterRemoving(U)end)if Players.LocalPlayer.Character then N:OnCharacterAdded(Players.LocalPlayer.Character)end RunService:BindToRenderStep("\067\111\110\116\114\111\108\083\099\114\105\112\116\082\101\110\100\101\114\115\116\101\112",Enum.RenderPriority.Input.Value,function(U)N:OnRenderStepped(U)end)UserInputService.LastInputTypeChanged:Connect(function(U)N:OnLastInputTypeChanged(U)end);(UserGameSettings:GetPropertyChangedSignal("\084\111\117\099\104\077\111\118\101\109\101\110\116\077\111\100\101")):Connect(function()N:OnTouchMovementModeChange()end);(Players.LocalPlayer:GetPropertyChangedSignal("\068\101\118\084\111\117\099\104\077\111\118\101\109\101\110\116\077\111\100\101")):Connect(function()N:OnTouchMovementModeChange()end);(UserGameSettings:GetPropertyChangedSignal("\067\111\109\112\117\116\101\114\077\111\118\101\109\101\110\116\077\111\100\101")):Connect(function()N:OnComputerMovementModeChange()end);(Players.LocalPlayer:GetPropertyChangedSignal("\068\101\118\067\111\109\112\117\116\101\114\077\111\118\101\109\101\110\116\077\111\100\101")):Connect(function()N:OnComputerMovementModeChange()end)N.playerGui=nil N.touchGui=nil N.playerGuiAddedConn=nil;(GuiService:GetPropertyChangedSignal("\084\111\117\099\104\067\111\110\116\114\111\108\115\069\110\097\098\108\101\100")):Connect(function()N:UpdateTouchGuiVisibility()N:UpdateActiveControlModuleEnabled()end)if UserInputService.TouchEnabled then N.playerGui=Players.LocalPlayer:FindFirstChildOfClass("\080\108\097\121\101\114\071\117\105")if N.playerGui then N:CreateTouchGuiContainer()N:OnLastInputTypeChanged(UserInputService:GetLastInputType())else N.playerGuiAddedConn=Players.LocalPlayer.ChildAdded:Connect(function(U)if U:IsA("\080\108\097\121\101\114\071\117\105")then N.playerGui=U N:CreateTouchGuiContainer()N.playerGuiAddedConn:Disconnect()N.playerGuiAddedConn=nil N:OnLastInputTypeChanged(UserInputService:GetLastInputType())end end)end else N:OnLastInputTypeChanged(UserInputService:GetLastInputType())end return N end

local computerInputTypeToModuleMap = {
	[Enum.UserInputType.Keyboard] = Keyboard,
	[Enum.UserInputType.MouseButton1] = Keyboard,
	[Enum.UserInputType.MouseButton2] = Keyboard,
	[Enum.UserInputType.MouseButton3] = Keyboard,
	[Enum.UserInputType.MouseWheel] = Keyboard,
	[Enum.UserInputType.MouseMovement] = Keyboard,
	[Enum.UserInputType.Gamepad1] = Gamepad,
	[Enum.UserInputType.Gamepad2] = Gamepad,
	[Enum.UserInputType.Gamepad3] = Gamepad,
	[Enum.UserInputType.Gamepad4] = Gamepad,
}

local lastInputType

function ControlModule.new()
	local self = setmetatable({},ControlModule)

	-- The Modules above are used to construct controller instances as-needed, and this
	-- table is a map from Module to the instance created from it
	self.controllers = {}

	self.activeControlModule = nil	-- Used to prevent unnecessarily expensive checks on each input event
	self.activeController = nil
	self.touchJumpController = nil
	self.moveFunction = Players.LocalPlayer.Move
	self.humanoid = nil
	self.lastInputType = Enum.UserInputType.None
	self.controlsEnabled = true

	-- For Roblox self.vehicleController
	self.humanoidSeatedConn = nil
	self.vehicleController = nil

	self.touchControlFrame = nil

	if FFlagUserHideControlsWhenMenuOpen then
		GuiService.MenuOpened:Connect(function()
			if self.touchControlFrame and self.touchControlFrame.Visible then
				self.touchControlFrame.Visible = false
			end
		end)

		GuiService.MenuClosed:Connect(function()
			if self.touchControlFrame then
				self.touchControlFrame.Visible = true
			end
		end)
	end

	self.vehicleController = VehicleController.new(CONTROL_ACTION_PRIORITY)

	Players.LocalPlayer.CharacterAdded:Connect(function(char) self:OnCharacterAdded(char) end)
	Players.LocalPlayer.CharacterRemoving:Connect(function(char) self:OnCharacterRemoving(char) end)
	if Players.LocalPlayer.Character then
		self:OnCharacterAdded(Players.LocalPlayer.Character)
	end

	RunService:BindToRenderStep("ControlScriptRenderstep", Enum.RenderPriority.Input.Value, function(dt)
		self:OnRenderStepped(dt)
	end)

	UserInputService.LastInputTypeChanged:Connect(function(newLastInputType)
		self:OnLastInputTypeChanged(newLastInputType)
	end)


	UserGameSettings:GetPropertyChangedSignal("TouchMovementMode"):Connect(function()
		self:OnTouchMovementModeChange()
	end)
	Players.LocalPlayer:GetPropertyChangedSignal("DevTouchMovementMode"):Connect(function()
		self:OnTouchMovementModeChange()
	end)

	UserGameSettings:GetPropertyChangedSignal("ComputerMovementMode"):Connect(function()
		self:OnComputerMovementModeChange()
	end)
	Players.LocalPlayer:GetPropertyChangedSignal("DevComputerMovementMode"):Connect(function()
		self:OnComputerMovementModeChange()
	end)

	--[[ Touch Device UI ]]--
	self.playerGui = nil
	self.touchGui = nil
	self.playerGuiAddedConn = nil

		GuiService:GetPropertyChangedSignal("TouchControlsEnabled"):Connect(function()
			self:UpdateTouchGuiVisibility()
			self:UpdateActiveControlModuleEnabled()
		end)

	if UserInputService.TouchEnabled then
		self.playerGui = Players.LocalPlayer:FindFirstChildOfClass("PlayerGui")
		if self.playerGui then
			self:CreateTouchGuiContainer()
			self:OnLastInputTypeChanged(UserInputService:GetLastInputType())
		else
			self.playerGuiAddedConn = Players.LocalPlayer.ChildAdded:Connect(function(child)
				if child:IsA("PlayerGui") then
					self.playerGui = child
					self:CreateTouchGuiContainer()
					self.playerGuiAddedConn:Disconnect()
					self.playerGuiAddedConn = nil
					self:OnLastInputTypeChanged(UserInputService:GetLastInputType())
				end
			end)
		end
	else
		self:OnLastInputTypeChanged(UserInputService:GetLastInputType())
	end

	return self
end
