Can't make warp_mouse to move the mouse cursor

Godot Version

4.3

Question

I’ve been trying to create a right stick moue control in godot and it seems the warp_mouse function is not working. None of them, coming from get_window, get_viewport, Input, seems to work.

The interesting thing is the mouse position seems to be updated internally but the mouse cursor is not moving at all in the screen.

Here it is a simple scene code you can use to reproduce this. Just create a basic scene with whatever root node you want, and add a script with this code. It should work and move the cursor, but in my case the cursor is not moving at all. (Added also commented code I’ve been using but nothing of that worked)

extends Node


#func _ready() -> void:
	#Input.mouse_mode = Input.MOUSE_MODE_CONFINED

#func _process(_delta: float) -> void:
		#var direction = Vector2(0, 0)
		#var speed = 10
		#if Input.is_action_pressed("rs_right") or Input.is_action_pressed("rs_left"):
			#direction.x = Input.get_action_strength("rs_right") - Input.get_action_strength("rs_left")
		#if Input.is_action_pressed("rs_up") or Input.is_action_pressed("rs_down"):
			#direction.y = Input.get_action_strength("rs_down") - Input.get_action_strength("rs_up")
		#if direction != Vector2(0,0):
			#var viewport = get_viewport()
			#var curpos =  viewport.get_mouse_position()
			#var pos = curpos + direction.normalized() * speed
			#print(curpos, " -> ", pos)
			#Input.warp_mouse(pos)

func _process(delta: float) -> void:
	if Input.is_action_pressed("rs_right"):
		var mp := get_window().get_mouse_position()
		print("PRE ", mp)
		Input.warp_mouse(
			Vector2(mp.x + mp.x * delta, mp.y)
		)
		mp = get_window().get_mouse_position()
		print("POST ", mp)

Are you experimenting the same problem? It can be related with my setup (I’m using Linux, wayland and Intel Irix iGPU), but after looking for errors like this one in every place I can’t find anyone with this specific problem, so I do not know if it is a bug or what can it be.

I’ve not checked with your code but this seems to work just fine:

extends Node


func _ready() -> void:
	Input.mouse_mode = Input.MOUSE_MODE_CONFINED


func _process(delta: float) -> void:
	var vector = Input.get_vector(&"ui_left", &"ui_right", &"ui_up", &"ui_down")
	var pos = get_window().get_mouse_position() + vector * 100 * delta
	Input.warp_mouse(pos)

Result:

I’m on Linux x11

Thank you very much for showing it works for you.

I’ve copied your code and tried to execute it in my machine and it didn’t work.

I will try to execute it in a different machine (windows for example) and come back with more info.

Ok. Tested it in windows and it works.

So, the problem is only on my computer it seems. Maybe wayland related.

Should I file an issue to godot github?

I’ve also tested this in Godot 4.4 and in different linux computers (Fedora Workstation with Wayland) and the code do not work in them. It seems it is a bug related with Linux/Wayland

Adding here a workaround using a fake cursor

extends Node

const MOUSE_MOVE_SPEED = 10


func _ready() -> void:
	Input.mouse_mode = Input.MOUSE_MODE_HIDDEN


func _process(_delta: float) -> void:
	var pos = get_window().get_mouse_position()
	var vector = Input.get_vector(&"ui_left", &"ui_right", &"ui_up", &"ui_down")
	
	if vector != Vector2.ZERO:
		var display_size = DisplayServer.window_get_size() # get_viewport().get_visible_rect().size
		pos += vector * MOUSE_MOVE_SPEED
		pos.x = max(min(pos.x, display_size.x - 1), 0)
		pos.y = max(min(pos.y, display_size.y - 1), 0)
		Input.warp_mouse(pos)
	$FakeCursor.position = pos

As I was having similar problems with mouse_warp not working correctly (Cursor did not warp, but game used its position), I fiddled around and found a working solution.

Hide the mouse
Do all the warping
Show again.

Heres the code im using

Input.mouse_mode = Input.MOUSE_MODE_HIDDEN
	
	var crosshair = load("res://entities/Aim/crosshair.png")
	# NOTICE: Changes the cursor only for the shape CURSOR_ARROW
	Input.set_custom_mouse_cursor(crosshair, Input.CURSOR_ARROW, Vector2(52.0, 52.0))
	
	get_viewport().warp_mouse(get_viewport_rect().get_center())
	
	Input.set_mouse_mode(Input.MOUSE_MODE_CONFINED)
	Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)

Works on a QHD display with game resolution of 1920x1080

Debian 12 (Gnome/Wayland). Godot 4.4.1

1 Like

Thanks! That seems to be the same workaround SDL is using Warp mouse on xwayland can be fixed · Issue #9539 · libsdl-org/SDL · GitHub

I’ve investigated a bit more and opened an issue here with more info `Input.warp_mouse()` does not work on xwayland · Issue #105223 · godotengine/godot · GitHub

We basically ended doing the same. A fake mouse module that controls the mouse and moves a sprite while it warps the real mouse position.

The thing with the “software” mouse cursor is that it adds delay.

https://docs.godotengine.org/en/stable/tutorials/inputs/custom_mouse_cursor.html

Says at least one frame. Guess it does not matter much. And as we have a filled bug it will get resolved sometime.