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

	-- 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: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)

	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
