Input mouse button event click doesn't work with scaled viewports

Godot Version

Godot 4.2.2

Problem

I’m trying to create a virtual mouse cursor that works for clicking on objects in the world as well as for UI interaction. Here’s how I’ve gotten it to work so far:

var click_event = InputEventMouseButton.new()

if interactableCursor.visible and Input.is_action_just_pressed(“Interaction”):
click_event.button_index = MOUSE_BUTTON_LEFT
get_viewport().warp_mouse(interactableCursor.get_global_transform_with_canvas().origin)
click_event.global_position = interactableCursor.get_global_transform_with_canvas().origin
click_event.position = interactableCursor.get_global_transform_with_canvas().origin
click_event.pressed = true
Input.parse_input_event(click_event)
print("Cursor: ", interactableCursor.get_global_transform_with_canvas().origin, " click event: ", click_event.global_position)

Problem is, it only works if the viewport is at 1x scale - it won’t work at all if the scale is any other factor, including fullscreen. Which is odd, because normal mouse clicks work just fine, and the actual button press brings the mouse to the right location.

Any idea on how I can fix this?

You are mixing different coordinate systems.

  • interactableCursor.get_global_transform_with_canvas().origin is in the coordinate system of the viewport
  • Input.parse_input_event(click_event) assumes, that the click_event.position is in screen coordinates

The section Feeding custom input events in the docs explains how to do, what you want.

I get the general gist of it, but I can’t get it to work, mostly because I cannot for the life of me figure out where you’re supposed to get local_pos from or how to determine it, something the docs completely leaves out.

Under the assumption, that interactableCursor is a Control-node with the mouse pointer in the top left corner, the local position would be (0, 0).
For other locations of the pointer, you would have to use other values.

1 Like

Unfortunately, so far that doesn’t seem to be working. Also, interactableCursor is not a Control-node, but an AnimatedSprite2D for particular reasons that I won’t get into here.

var local_pos = Vector2(0, 0)
		click_event.position = get_viewport().get_screen_transform() * interactableCursor.get_global_transform_with_canvas() * local_pos
		click_event.pressed = true
		Input.parse_input_event(click_event)

For AnimatedSprite2D, if I remember correctly, (0, 0) is in the center of the sprite, so you would have to adjust that value according to the size of the sprite.
(-interactableCursor.size.x / 2, -interactableCursor.size.y / 2) should probably point to the top-left corner of the sprite.

1 Like

Actually, I do want the center of the sprite, so (0,0) is correct in this instance.

I did some further testing, along with some tweaking of certain relevant entities (mainly the interaction menu pop-up control and the TextureButton inside the interactable entity, and it kinda works now? Albeit somewhat weirdly. It’s like the click event is focused on the button on the interactable entity no matter where the cursor goes after ‘clicking’ it, even if there are UI elements above it that should otherwise block the click input. Any idea why this might be happening?

There could be so many different reasons for this, that without having a look at the project it would be a guessing game.

1 Like

Ah, okay.

I’m not sure if I managed to figure out a proper solution or just a workaround, but I’ve managed to get it working as intended now, at least for the most part. At the very least using screen coordinates made it work better. Thanks for the help!