Redot-Engine / redot-engine

Redot Engine – Multi-platform 2D and 3D game engine
https://redotengine.org/
MIT License
4.78k stars 214 forks source link

Touchpad gestures are detected in input map, but don't work when project is run. #763

Open TimeVeteran opened 1 month ago

TimeVeteran commented 1 month ago

Tested versions

-Reproducible since 4.2, can't check on 4.0 due to scene parsing issues.

System information

Redot v4.4.dev (5e7e5fc60) - Windows 10.0.22631 - Multi-window, 1 monitor - OpenGL 3 (Compatibility) - Intel(R) UHD Graphics 600 (Intel Corporation; 31.0.101.2128) - Intel(R) Celeron(R) N4120 CPU @ 1.10GHz (4 threads)

Issue description

On the input map, it detects scroll zoom and scroll pan (ctrl+scroll wheel on a regular mouse) gestures on a touchpad, but does not recognize them project is running.

Steps to reproduce

All these steps require a touchpad. -Add scroll up/down for all devices(when listening for input, gestures are detected) -Make an event where scrolling up or down triggers something. -When project is run, touchpad gestures do not work

Minimal reproduction project (MRP)

When you scroll up or down, it is supposed to hide, which does not work with laptop gestures. Just to make sure my code works, when "E" is pressed it is supposed to make it hide, which works. gesture test.zip

MrDoboz commented 2 weeks ago

scrolling is not a continuous thing. I'm using .net and am more familiar with input events, but to me it seems like you really shouldn't check if you are scrolling or not in the process method, unless of course scrolling input is accumulated but I have no idea about that. what about scrolling with an actual mouse? does that work? if not, I'm probably right and you should find another way of processing input. however if it does work, then I have no idea

EDIT: I tried it, it doesn't work with a mouse. so I'm probably right EDIT2: I'm absolutely right. if you remove the statement responsible for showing the sprite then scroll vigorously, eventually a scroll event will just hit the frame and the sprite will hide and not show up again. you could try this too: func _unhandled_input(event): if event is InputEventMouseButton: if event.pressed and event.button_index == MouseButton.MOUSE_BUTTON_WHEEL_UP: hide() as you can see, this won't show the sprite again either, you need a timer for that. but this will catch the scroll immediately, regardless of the process method. what you need to understand is that scrolling is interpreted as a very short mouse click with the scroll up button, as that is actually what is happening inside the mouse hardware, and the touchpad is emulating that too. that means, you can scroll, but can't be scrolling. I have no idea if you can tell the engine not to forget about actions between frames, but even if you can, a scroll will only last a single frame

MrDoboz commented 2 weeks ago

replace your script with this to see what I'm talking about

extends AnimatedSprite2D

var scroll = false

func _process(delta):
        if scroll:
                hide()
                scroll = false
        else:
                show()

func _unhandled_input(event):
        if event is InputEventMouseButton:
                if event.pressed and event.button_index == MouseButton.MOUSE_BUTTON_WHEEL_UP:
                        scroll = true;

this has a scroll flag that will be set any time a scroll up event is detected, the flag is read at next frame and reset after processing. this means you won't lose a scroll between frames. you will however miss the amount of scrolls, and this is scroll up only, so you could replace the flag with an integer buffer, have events count it up or down respectively, process the data accordingly, then reset to 0

TimeVeteran commented 2 weeks ago

I've found a fix, replacing "pressed" to "just_pressed" This is kind of weird input side, as you think when you move the scroll wheel, it registers your input in a frame, but it does it after the frame, Also I've tried this before in Godot 4.2 with a dev build, by replacing pressed with just_pressed and it didn't work, but now in Redot it works with just_pressed.

TimeVeteran commented 2 weeks ago

replace your script with this to see what I'm talking about

extends AnimatedSprite2D

var scroll = false

func _process(delta):
        if scroll:
                hide()
                scroll = false
        else:
                show()

func _unhandled_input(event):
        if event is InputEventMouseButton:
                if event.pressed and event.button_index == MouseButton.MOUSE_BUTTON_WHEEL_UP:
                        scroll = true;

this has a scroll flag that will be set any time a scroll up event is detected, the flag is read at next frame and reset after processing. this means you won't lose a scroll between frames. you will however miss the amount of scrolls, and this is scroll up only, so you could replace the flag with an integer buffer, have events count it up or down respectively, process the data accordingly, then reset to 0

I've found a fix above, but I'm wondering, why does it work this way?