godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.45k stars 21.27k forks source link

Pen/stylus input is not responsive enough for hand writing #75903

Open nlupugla opened 1 year ago

nlupugla commented 1 year ago

Godot version

v4.0.stable.official [92bee43ad]

System information

Windows 11, Lenovo Yoga 7i (14'' Intel), Lenovo Digital Pen 2

Issue description

I'm making a simple productivity app in Godot that needs to support hand writing via pen/stylus.

When I write slowly, the writing is displayed accurately. However, when I write at my normal handwriting speed, which involves my pen coming on and off the screen several times per second, the writing is not displayed accurately.

Here is an example of me writing an "H" slowly: image

And a log of all the input events: SlowH.txt

Here is an example me writing an "H" at normal handwriting speed: image

And a log of all the input events: FastH.txt

There's a few odd things I've noticed about the fast "H" log.

  1. There are only InputEventMouseMotion events, no InputEventMouseButton events.
  2. There are many InputEventMouseMotion events with identical positions but different pressures.

Steps to reproduce

  1. Make a new project
  2. Set the main scene as a single control node.
  3. Attach the following script.
  4. (optional) uncomment print(event) to see a log of all the input events.
  5. Run the project.
  6. Try writing something quickly with a pen/stylus.
  7. Try writing the same thing but slowly.
extends Control

var stroke : Line2D

func _ready() -> void:
    Input.use_accumulated_input = false # issue occurs whether this is true or false
    start_stroke()

func _input(event: InputEvent) -> void:
    # uncomment the print statement to see a log of events
    # print(event)
    if event is InputEventMouseMotion:
        var event_mouse_motion := event as InputEventMouseMotion
        if event_mouse_motion.pressure <= 0 && stroke.points.size() > 1:
            start_stroke()
        if event_mouse_motion.pressure > 0:
            stroke.add_point(event_mouse_motion.position)

func start_stroke() -> void:
    var new_stroke := Line2D.new()
    add_child(new_stroke)
    new_stroke.owner = self
    stroke = new_stroke

Minimal reproduction project

N/A

nlupugla commented 1 year ago

Just to add a bit more information, I don't encounter the same issue when I use mouse or touch input, although it's hard to do an exact 1 to 1 comparison. For mouse input, I can't draw with the mouse as fast as I can write with a pen. For touch input, I have to remove the event_mouse_motion.pressure > 0 check because touch inputs don't have a pressure field.

vnen commented 1 year ago

I can't reproduce this. I'm not really the fastest with handwriting but I could not make it break like in your example.

For the record, I'm testing with a Huion H430P on Linux (using a debug build of current master).

nlupugla commented 1 year ago

Interesting! Thanks for testing it out. Would you mind pasting or uploading the log of events you get when you get a chance?

Riteo commented 1 year ago

@vnen

For the record, I'm testing with a Huion H430P on Linux

The OP uses Windows, I wonder if it might be a problem of the Windows platform code.

bruvzg commented 1 year ago

Are you using wintab or winink driver (input_devices/pen_tablet/driver project setting)? Try switching it to winink.

nlupugla commented 1 year ago

I believe it's wintab. If I switch to winink, I can't draw at all. I've just been leaving that field untouched, so I assume it defaulted to whichever one "worked," which I guess is wintab. I might be making too many assumptions here though. To be clear though, if I set it to wintab explicitly, I still have the same responsiveness issue.

capnm commented 1 year ago

IIRC some our users had issues with the absolute mode. On Linux, Wacom tablets work fine in both relative and absolute modes and with the correct pressure sizes: grafik

extends Control

var stroke : Line2D
var p_scale := 10.0

func _ready() -> void:
    Input.use_accumulated_input = false 
    # issue occurs whether this is true or false
    start_stroke()

func _input(event: InputEvent) -> void:
    # uncomment the print statement to see a log of events
    # print(event)
    if event is InputEventMouseMotion:
        var event_mouse_motion := event as InputEventMouseMotion
        if event_mouse_motion.pressure <= 0 && stroke.points.size() > 1:
            start_stroke()
        if event_mouse_motion.pressure > 0:
            if stroke.points.size() < 100:
                stroke.width = event_mouse_motion.pressure * p_scale
            stroke.add_point(event_mouse_motion.position)

func start_stroke() -> void:
    var new_stroke := Line2D.new()
    add_child(new_stroke)
    new_stroke.owner = self
    stroke = new_stroke

(In absolute mode in 3D view, you must manually disable the _editors/3d/navigation/warped_mousepanning option to disable mouse pointer ghosting)

nlupugla commented 1 year ago

Can you clarify what you mean by "absolute mode"?

capnm commented 1 year ago

Most graphics tablets let you switch between absolute and relative(~mouse) positioning: https://support.wacom.com/hc/en-us/articles/1500006340122-What-is-Absolute-Positioning-

nlupugla commented 1 year ago

Ah, that makes sense. I am using my laptop's touch screen, not a pen tablet attachment. I imagine it is absolute positioning then as where I put my pen to the screen always corresponds to where the cursor shows up on the screen.

nlupugla commented 1 year ago

I did a bit more testing last night and I found I get a very different log of input events if I export to web. This makes me think it is definitely a Windows issue, although it's worth mentioning that my pen works just fine in apps like MsPaint and OneNote.

Here are some of the things I noticed in my web build. I got a mix of InputEventMouseMotion, InputEventMouseButton, InputEventScreenTouch, and InputEventScreenDrag events. These events correspond pretty well to what I'm doing with my pen, although there's a few confusing things.

  1. All of the InputEventMouseMotion events have pressure == 0.
  2. I'm not sure why there are InputEventScreenTouch and InputEventScreenDrag events at all when I'm just using my pen. I tried exporting to web again, but with emulate_mouse_from_touch = false, and I found most of the InputEventMouse events were replaced by InputEventScreen events, which makes sense, although they still didn't have a useful pressure field.
Tx-redcore commented 1 year ago

I don't know if this is related, but I currently have a xp-pen tablet set up to my pc and normally I just use it as a monitor when I'm not drawing, but Godot doesn't seem to be able to pick up left click with the mouse on my project which is on a different monitor, it only picks up InputEventMouseNotion, it only happens on left click not on any other input. I have my suspicion that the drawing tablets input is messing with the Godot inputs somehow. I'm relatively new to godot, so I'm just following tutorials at the moment, and it clearly seems like its Input issue only on my pc because my tablet is connected possibly.

Zireael07 commented 1 year ago

Please open a separate issue @Tx-redcore this is not related to pen input responsiveness