Mouse Cursor moves Up when switching to a controller

Is there a reason why the mouse cursor moves up when switching to a controller on PC? It happens in shiftlock mode, you can see the cursor moving up and down when I switch from mouse to controller.

Example:

1 Like

Could you share a link to a game you are having this issue in? It could also be a controller drift problem. Is it happening only in Roblox? A specific game maybe?

I don’t appear to be having this issue using my Xbox One controller and laptop. At least, I’m not noticing anything.

1 Like

https://www.roblox.com/games/17191083560/Shonen-Storm
I’m testing a PS4 Controller in this game. Could you check it out with yours and on the shiftlock mode as well? To enter shift lock mode you use your L3/ press in your L3. Or your left joystick press in I believe for XBOX.

The game is private:
image

Sorry about that, can you try now? I also provided an example of what I mean on the first post.

1 Like

When in Shiftlock Mode, yes I notice the issue. Are you using a custom or Roblox’s shift-lock system? I notice the icon is different.


I looked around and I think this person had the same issue, nobody had a fix: Make sure Gamepad mouse go center. I don’t think this is a Gamepad Virtual Cursor issue, since that doesn’t seem to be enabled.

So, I assume the issue is something internal inside Roblox’s CoreScripts. It could be Player → PlayerName → PlayerScripts → Player Module → Camera Module → MouseLockController.

Code for that CoreScript Module (dropdown)
--!nonstrict
--[[
	MouseLockController - Replacement for ShiftLockController, manages use of mouse-locked mode
	2018 Camera Update - AllYourBlox
--]]

--[[ Constants ]]--

local CommonUtils = script.Parent.Parent:WaitForChild("CommonUtils")
local FlagUtil = require(CommonUtils:WaitForChild("FlagUtil"))
local DEFAULT_MOUSE_LOCK_CURSOR = "rbxasset://textures/MouseLockedCursor.png"

local CONTEXT_ACTION_NAME = "MouseLockSwitchAction"
local MOUSELOCK_ACTION_PRIORITY = Enum.ContextActionPriority.Medium.Value
local CAMERA_OFFSET_DEFAULT = Vector3.new(1.75,0,0)  

--[[ Services ]]--
local PlayersService = game:GetService("Players")
local ContextActionService = game:GetService("ContextActionService")
local Settings = UserSettings()	-- ignore warning
local GameSettings = Settings.GameSettings

--[[ Imports ]]
local CameraUtils = require(script.Parent:WaitForChild("CameraUtils"))

local FFlagUserFixCameraOffsetJitter = FlagUtil.getUserFlag("UserFixCameraOffsetJitter2")

--[[ The Module ]]--
local MouseLockController = {}
MouseLockController.__index = MouseLockController

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

	self.isMouseLocked = false
	self.savedMouseCursor = nil
	self.boundKeys = {Enum.KeyCode.LeftShift, Enum.KeyCode.RightShift} -- defaults

	self.mouseLockToggledEvent = Instance.new("BindableEvent")

	local boundKeysObj = script:FindFirstChild("BoundKeys")
	if (not boundKeysObj) or (not boundKeysObj:IsA("StringValue")) then
		-- If object with correct name was found, but it's not a StringValue, destroy and replace
		if boundKeysObj then
			boundKeysObj:Destroy()
		end

		boundKeysObj = Instance.new("StringValue")
		-- Luau FIXME: should be able to infer from assignment above that boundKeysObj is not nil
		assert(boundKeysObj, "")
		boundKeysObj.Name = "BoundKeys"
		boundKeysObj.Value = "LeftShift,RightShift"
		boundKeysObj.Parent = script
	end

	if boundKeysObj then
		boundKeysObj.Changed:Connect(function(value)
			self:OnBoundKeysObjectChanged(value)
		end)
		self:OnBoundKeysObjectChanged(boundKeysObj.Value) -- Initial setup call
	end

	-- Watch for changes to user's ControlMode and ComputerMovementMode settings and update the feature availability accordingly
	GameSettings.Changed:Connect(function(property)
		if property == "ControlMode" or property == "ComputerMovementMode" then
			self:UpdateMouseLockAvailability()
		end
	end)

	-- Watch for changes to DevEnableMouseLock and update the feature availability accordingly
	PlayersService.LocalPlayer:GetPropertyChangedSignal("DevEnableMouseLock"):Connect(function()
		self:UpdateMouseLockAvailability()
	end)

	-- Watch for changes to DevEnableMouseLock and update the feature availability accordingly
	PlayersService.LocalPlayer:GetPropertyChangedSignal("DevComputerMovementMode"):Connect(function()
		self:UpdateMouseLockAvailability()
	end)

	self:UpdateMouseLockAvailability()

	return self
end

function MouseLockController:GetIsMouseLocked()
	return self.isMouseLocked
end

function MouseLockController:GetBindableToggleEvent()
	return self.mouseLockToggledEvent.Event
end

function MouseLockController:GetMouseLockOffset()
	if FFlagUserFixCameraOffsetJitter then
		return CAMERA_OFFSET_DEFAULT 
	else
		local offsetValueObj: Vector3Value = script:FindFirstChild("CameraOffset") :: Vector3Value
		if offsetValueObj and offsetValueObj:IsA("Vector3Value") then
			return offsetValueObj.Value
		else
			-- If CameraOffset object was found but not correct type, destroy
			if offsetValueObj then
				offsetValueObj:Destroy()
			end
			offsetValueObj = Instance.new("Vector3Value")
			assert(offsetValueObj, "")
			offsetValueObj.Name = "CameraOffset"
			offsetValueObj.Value = Vector3.new(1.75,0,0) -- Legacy Default Value
			offsetValueObj.Parent = script
		end

		if offsetValueObj and offsetValueObj.Value then
			return offsetValueObj.Value
		end

		return Vector3.new(1.75,0,0)
	end
end

function MouseLockController:UpdateMouseLockAvailability()
	local devAllowsMouseLock = PlayersService.LocalPlayer.DevEnableMouseLock
	local devMovementModeIsScriptable = PlayersService.LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.Scriptable
	local userHasMouseLockModeEnabled = GameSettings.ControlMode == Enum.ControlMode.MouseLockSwitch
	local userHasClickToMoveEnabled =  GameSettings.ComputerMovementMode == Enum.ComputerMovementMode.ClickToMove
	local MouseLockAvailable = devAllowsMouseLock and userHasMouseLockModeEnabled and not userHasClickToMoveEnabled and not devMovementModeIsScriptable

	if MouseLockAvailable~=self.enabled then
		self:EnableMouseLock(MouseLockAvailable)
	end
end

function MouseLockController:OnBoundKeysObjectChanged(newValue: string)
	self.boundKeys = {} -- Overriding defaults, note: possibly with nothing at all if boundKeysObj.Value is "" or contains invalid values
	for token in string.gmatch(newValue,"[^%s,]+") do
		for _, keyEnum in pairs(Enum.KeyCode:GetEnumItems()) do
			if token == keyEnum.Name then
				self.boundKeys[#self.boundKeys+1] = keyEnum :: Enum.KeyCode
				break
			end
		end
	end
	self:UnbindContextActions()
	self:BindContextActions()
end

--[[ Local Functions ]]--
function MouseLockController:OnMouseLockToggled()
	self.isMouseLocked = not self.isMouseLocked

	if self.isMouseLocked then
		local cursorImageValueObj: StringValue? = script:FindFirstChild("CursorImage") :: StringValue?
		if cursorImageValueObj and cursorImageValueObj:IsA("StringValue") and cursorImageValueObj.Value then
			CameraUtils.setMouseIconOverride(cursorImageValueObj.Value)
		else
			if cursorImageValueObj then
				cursorImageValueObj:Destroy()
			end
			cursorImageValueObj = Instance.new("StringValue")
			assert(cursorImageValueObj, "")
			cursorImageValueObj.Name = "CursorImage"
			cursorImageValueObj.Value = DEFAULT_MOUSE_LOCK_CURSOR
			cursorImageValueObj.Parent = script
			CameraUtils.setMouseIconOverride(DEFAULT_MOUSE_LOCK_CURSOR)
		end
	else
		CameraUtils.restoreMouseIcon()
	end

	self.mouseLockToggledEvent:Fire()
end

function MouseLockController:DoMouseLockSwitch(name, state, input)
	if state == Enum.UserInputState.Begin then
		self:OnMouseLockToggled()
		return Enum.ContextActionResult.Sink
	end
	return Enum.ContextActionResult.Pass
end

function MouseLockController:BindContextActions()
	ContextActionService:BindActionAtPriority(CONTEXT_ACTION_NAME, function(name, state, input)
		return self:DoMouseLockSwitch(name, state, input)
	end, false, MOUSELOCK_ACTION_PRIORITY, unpack(self.boundKeys))
end

function MouseLockController:UnbindContextActions()
	ContextActionService:UnbindAction(CONTEXT_ACTION_NAME)
end

function MouseLockController:IsMouseLocked(): boolean
	return self.enabled and self.isMouseLocked
end

function MouseLockController:EnableMouseLock(enable: boolean)
	if enable ~= self.enabled then

		self.enabled = enable

		if self.enabled then
			-- Enabling the mode
			self:BindContextActions()
		else
			-- Disabling
			-- Restore mouse cursor
			CameraUtils.restoreMouseIcon()

			self:UnbindContextActions()

			-- If the mode is disabled while being used, fire the event to toggle it off
			if self.isMouseLocked then
				self.mouseLockToggledEvent:Fire()
			end

			self.isMouseLocked = false
		end

	end
end

return MouseLockController

Edit: more specifically, it could be the MouseLockController:GetMouseLockOffset() and maybe including the MouseLockController:OnMouseLockToggled() functions.

2 Likes

Using ROBLOX’s built in shift lock system. And will definitely take a look into those scripts. Thank you for the help :). After messing around with it if I can solve it i’ll select this as the solution.

1 Like

I removed PlayerModule and made my own code for input output, it’s still offsetting the cursor and changing its appearance when switching to gamepad. There needs to be a setting to adjust this, baddd

1 Like

Yes but I am try make script but problem it Roblox the cursor mouse is ~= cursor Xbox but it have select buttons but I think with button it can switch from camera players to movement to cursor control like click right mouse and mouse mouse left change to mouse interaction ui like :

local UserInputService = game:GetService(“UserInputService”)
local RunService = game:GetService(“RunService”)
local player = game.Players.LocalPlayer
local camera = game.Workspace.CurrentCamera

– Cursor Settings
local cursorSpeed = 5 – Adjust this speed to control cursor responsiveness
local cursor = nil – Variable to store the cursor ImageLabel
local isCursorMode = false – Track if we’re in cursor mode

– Initialize the cursor
local function initializeCursor()
local gui = player:WaitForChild(“PlayerGui”)
cursor = gui:WaitForChild(“CursorImage”)
cursor.Visible = false – Start with cursor hidden
cursor.Position = UDim2.new(0.5, 0, 0.5, 0) – Center of screen
end

– Toggle function to switch between camera and cursor control
local function toggleCursorMode()
isCursorMode = not isCursorMode
cursor.Visible = isCursorMode

if isCursorMode then
    camera.CameraType = Enum.CameraType.Scriptable  -- Lock the camera in place
else
    camera.CameraType = Enum.CameraType.Custom  -- Restore normal camera control
end

end

– Update cursor position based on thumbstick input
local function updateCursorPosition(deltaX, deltaY)
– Scale the thumbstick input to move the cursor
local newPosX = cursor.Position.X.Scale + (deltaX * cursorSpeed / 100)
local newPosY = cursor.Position.Y.Scale - (deltaY * cursorSpeed / 100)

-- Clamp cursor position to the screen edges
newPosX = math.clamp(newPosX, 0, 1)
newPosY = math.clamp(newPosY, 0, 1)

cursor.Position = UDim2.new(newPosX, 0, newPosY, 0)

end

– Listen for L3 button press to toggle cursor mode
UserInputService.InputBegan:Connect(function(input)
if input.KeyCode == Enum.KeyCode.ButtonL3 then
toggleCursorMode()
end
end)

– Right thumbstick controls cursor position in cursor mode only
UserInputService.InputChanged:Connect(function(input)
if isCursorMode and input.UserInputType == Enum.UserInputType.Gamepad1 and input.KeyCode == Enum.KeyCode.Thumbstick2 then
local delta = input.Position – Position provides x and y for thumbstick movement
updateCursorPosition(delta.X, delta.Y)
end
end)

– Set up the cursor on player join
initializeCursor()