local a={[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}function ControlModule.new()local a=setmetatable({},ControlModule)a.controllers={}a.activeControlModule=nil a.activeController=nil a.touchJumpController=nil a.moveFunction=Players.LocalPlayer.Move a.humanoid=nil a.lastInputType=Enum.UserInputType.None a.cameraRelative=true a.humanoidSeatedConn=nil a.vehicleController=nil a.touchControlFrame=nil a.vehicleController=VehicleController.new(CONTROL_ACTION_PRIORITY)Players.LocalPlayer.CharacterAdded:Connect(function(z)a:OnCharacterAdded(z)end)Players.LocalPlayer.CharacterRemoving:Connect(function(z)a:OnCharacterAdded(z)end)if Players.LocalPlayer.Character then a: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(z)a:OnRenderStepped(z)end)UserInputService.LastInputTypeChanged:Connect(function(z)a:OnLastInputTypeChanged(z)end)local z={(UserGameSettings:GetPropertyChangedSignal("\084\111\117\099\104\077\111\118\101\109\101\110\116\077\111\100\101")):Connect(function()a: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()a: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()a: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()a:OnComputerMovementModeChange()end)}a.playerGui=nil a.touchGui=nil a.playerGuiAddedConn=nil if UserInputService.TouchEnabled then a.playerGui=Players.LocalPlayer:FindFirstChildOfClass("\080\108\097\121\101\114\071\117\105")if a.playerGui then a:CreateTouchGuiContainer()a:OnLastInputTypeChanged(UserInputService:GetLastInputType())else a.playerGuiAddedConn=Players.LocalPlayer.ChildAdded:Connect(function(z)if z:IsA("\080\108\097\121\101\114\071\117\105")then a.playerGui=z a:CreateTouchGuiContainer()a.playerGuiAddedConn:Disconnect()a.playerGuiAddedConn=nil a:OnLastInputTypeChanged(UserInputService:GetLastInputType())end end)end else a:OnLastInputTypeChanged(UserInputService:GetLastInputType())end return a 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,
}

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.cameraRelative = true
	
	-- For Roblox self.vehicleController
	self.humanoidSeatedConn = nil
	self.vehicleController = nil
	
	self.touchControlFrame = nil
	
	self.vehicleController = VehicleController.new(CONTROL_ACTION_PRIORITY)
	
	Players.LocalPlayer.CharacterAdded:Connect(function(char) self:OnCharacterAdded(char) end)
	Players.LocalPlayer.CharacterRemoving:Connect(function(char) self:OnCharacterAdded(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)
	
	local propertyChangeListeners = {
		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

	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
