Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Laptop touchpads are seen as gamepads #59250

Open
thomaslenzi opened this issue Mar 17, 2022 · 22 comments · May be fixed by #59412 or #87925
Open

Laptop touchpads are seen as gamepads #59250

thomaslenzi opened this issue Mar 17, 2022 · 22 comments · May be fixed by #59412 or #87925

Comments

@thomaslenzi
Copy link

Godot version

4.0-alpha4

System information

Linux - Manjaro 21.2.5

Issue description

In Godot 4.0-alpha4, my laptop's touchpads are seen as gamepads. When no actual controllers are attached to my laptop, functions and signals such as Input.get_connected_joypads() and Input.joy_connection_changed.connect see two existing devices. When I add real controllers, they are assigned device ids from 2 and up. In contrast, this is not the case in Godot 3.4.3.

Godot 3 output at start
[blank]
Godot 3 output when I connect a Xbox 360
0 Xbox 360 Controller

Godot 4 output at start
0 SYNA8008:00 06CB:CE58 Touchpad
1 ELAN901C:00 04F3:2C29
Godot 4 output when I connect a Xbox 360
2 Xbox 360 Controller

Note that if the Xbox controller is connected when I launch the "game", it is seen with device id = 0.

A tool such as gamepad-tool yields the same results as Godot 3 (no additional devices detected).

Steps to reproduce

Create an empty project with a single Node2D and the following script attached

extends Node2D

func _ready():
	Input.joy_connection_changed.connect(self._on_joy_connection_changed)
	for device in Input.get_connected_joypads():
		print(device, " ", Input.get_joy_name(device))

func _on_joy_connection_changed(device, connected):
	print(device, " ", Input.get_joy_name(device))

Minimal reproduction project

No response

@thomaslenzi
Copy link
Author

For completeness, I also tested on v3.4.4-rc2 and v3.5-beta2 and both behave as expected.

@akien-mga
Copy link
Member

I didn't bisect, but I have a hunch that #57612 might be the culprit. It hasn't been cherry-picked for 3.x and 3.4 yet.
CC @maiself @madmiraal

@madmiraal
Copy link
Contributor

I cannot reproduce this issue on my laptop (I have an ELAN1401:00 touchpad). So I'm not able to troubleshoot or confirm that #57612 is the culprit.

@madmiraal madmiraal linked a pull request Mar 22, 2022 that will close this issue
@madmiraal
Copy link
Contributor

I've created PR #59412 to increase the restriction on devices that are detected as gamepads that should fix this issue.

@thomaslenzi
Copy link
Author

Solved by #59412. Thank you for your help.
Should I close the issue or wait for the PR to be merged?

@Calinou
Copy link
Member

Calinou commented Mar 22, 2022

Solved by #59412. Thank you for your help. Should I close the issue or wait for the PR to be merged?

The issue won't be fixed in master until the PR is merged. Therefore, we need to wait for the PR to be merged to close the issue.

@vysker
Copy link

vysker commented Oct 11, 2022

For anyone else running into this issue, you can work around the issue by including this in any _ready() function:

if Input.get_connected_joypads().is_empty():
    for action in InputMap.get_actions():
        for event in InputMap.action_get_events(action):
            if event is InputEventJoypadMotion:
                InputMap.action_erase_event(action, event)

This obviously shouldn't be in production code. And it's also not cognizant of the fact that you might have both a joypad and a touchpad connected.

@MegaKeegMan
Copy link

Looking forward to the merge! I see the suggested workaround above, and I don't quite understand it. I am in the process of figuring out how to get local multiplayer to work, and am adding a player instance to the scene for each connected gamepad. So my current workaround looks something like this:

var input_devices = Input.get_connected_joypads()

func _ready() -> void:
  for device in input_devices:
          if not Input.get_joy_name(device).contains("Touchpad"):
	    var new_player = player_scene.instantiate().setup(device)
	    add_child(new_player)

At least that's the relevant bit. Hope this helps someone, or that someone comments on why not to do this. Though ultimately, I don't intend to leave the number of players to be determined by how many devices are connected.

@Drejzer
Copy link

Drejzer commented Jan 22, 2023

This can be seen in Input Map in project settings in beta14
(godot4-bin beta14-1 AUR package installed on Manjaro 22.0.0)

Since "Listening for input" is focused when adding new key to an action, it will immediately detect moving the mouse as Joypad Axis 0,1 or 2

@Calinou
Copy link
Member

Calinou commented Jan 31, 2023

I can confirm this on 4.0.beta16 (Linux) while I was working on godotengine/godot-demo-projects#830, but with a different kind of device. This is not limited to laptop touchpads. Here, it was occurring with a motherboard LED controller:

image

The issue is also present on 3.5.1:

image

I'm using Fedora 37 and don't have OpenRGB installed.

@Zireael07
Copy link
Contributor

#59412 is one of the proposed fixes and has been waiting nearly a year

@bend-n
Copy link
Contributor

bend-n commented Feb 25, 2023

As making the touchpad not usable as a input device is difficult and would make using certain controllers impossible, can we not simply have a way to stop the input system from registering a certain device?

@Calinou
Copy link
Member

Calinou commented Feb 25, 2023

As making the touchpad not usable as a input device is difficult and would make using certain controllers impossible, can we not simply have a way to stop the input system from registering a certain device?

We could have a project setting with a list of device IDs that shouldn't be registered as controllers (plus an environment variable to append to this list), but this will require manual maintenance. We could ship a list of known problematic "not-a-controller" IDs by default too.

@akien-mga akien-mga changed the title [Godot 4] laptop's touchpads seen as gamepads Laptop touchpads are seen as gamepads Jun 22, 2023
@akien-mga akien-mga modified the milestones: 4.1, 4.x Jun 22, 2023
@waynepiekarski
Copy link

I'm running into this problem with Godot 4.1.1 and none of the existing solutions worked to filtering out the joystick events being generated by the trackpad on my Framework laptop with Ubuntu 22.04.

However, I've noticed that Input.is_joy_known() returns false for these trackpads and not real joysticks, and so a workaround in my _input event handler that seems to be working for me is this:

func _input(event):
    if not Input.is_joy_known(event.get_device()):
        # Skip trackpad and only support real USB joysticks
        return
    # print("ID=" + str(event.get_device()) + " NAME=" + Input.get_joy_name(event.get_device()) + " KNOWN=" + str(Input.is_joy_known(event.get_device())))
    # Handle the rest of your InputEventJoypadMotion events here

@bend-n
Copy link
Contributor

bend-n commented Sep 24, 2023

Have you tried using my builds? Ive patched a fix into them.

@malucard

This comment was marked as off-topic.

@Calinou
Copy link
Member

Calinou commented Oct 22, 2023

This is a major issue for any usage of the engine on my laptop. Why is this waiting for so long?

See #59412 (comment). The PR needs to be revised significantly (or even remade from scratch) before it can be merged.

@geekley
Copy link

geekley commented Oct 30, 2023

You can use this script I made before the PR is ready.
I believe it's the best workaround to fix this issue according to the proposed solution:

For the time being, we'd suggest addressing the root issue in a simpler, yet more focused, way: blacklist devices that contain "touchpad" in their name (case-insentive, just in case).

Tested on Godot v4.2.stable.mono.flathub only.
It works to ignore my pointer devices:

  • "SynPS/2 Synaptics TouchPad" - matches touchpad word
  • "Wacom One by Wacom S Pen" - matches pen word

Not sure if you should use this in production. But it can at least help you for now, if you use a laptop for development. Tweak the list of words if needed. You might also want to remove the logging line or uncomment the debug line.

Just add this script as an auto-load in your project settings. The node will just connect to the signal at startup, then self-delete. The callback needs to stay because even a touchpad device may take a few frames to be recognized (e.g. in Flatpak). When the device is disabled, it'll also send input events once to reset all SDL axes and buttons to 0.

Gist: TouchpadIsNotJoypad.gd

Previous simpler version using RegEx (outdated, was for v4.1.3):

It's very simple and self-explanatory. Tweak the regex if needed (it's definitely not exhaustive nor well-tested).
This won't reset input events to 0 when disabling, so axes/buttons will be stuck on whichever state they were.

# Public domain, as per The Unlicense. NO WARRANTY. See https://unlicense.org

extends Node
## Solves a [url=https://github.com/godotengine/godot/issues/59250]bug[/url] where touchpad devices
## can be detected as a joypad.
##
## This script should be autoloaded in the project settings.
## This is merely a workaround, not for use in production code.

func _ready() -> void:
	int(Input.joy_connection_changed.connect(Callable(get_script(), joy_check.get_method())))
	queue_free()

## Pattern of joypad names to disable.
static var pattern := RegEx.create_from_string('\\b(?i:(?:touch|track|click)pad|mouse|pen)\\b')

## Validates a joypad connection. Called for every joypad device connected.
## Device names matching the pattern will be disabled (remapped to an empty mapping).
static func joy_check(device_id: int, connected: bool) -> void:
	if not connected:
		return
	var device_name := Input.get_joy_name(device_id)
	# Uncomment the line below to debug problematic devices:
	# print('Connected device ', device_id, ': ', device_name)
	if not pattern.search(device_name):
		return
	# Device should be ignored.
	var guid := Input.get_joy_guid(device_id)
	var mapping := guid + ',' + device_name.replace(',', '') # not mapping any axes or buttons
	# Replace with empty mapping on this guid. Should ignore all joypad input from this device.
	Input.add_joy_mapping(mapping, true)
	prints('Ignoring joypad device:', mapping) # you can comment out or remove this line

@geekley
Copy link

geekley commented Nov 11, 2023

I've updated the code above to fix an issue.
Please update it if you're using it, and tell me if you get any issues.

The change is because even the touchpad device may take a few frames to appear (e.g. on Flatpak version of Godot), so now the check will run for every device connection instead of assuming the list of devices is ready at startup. Also, devices like drawing tablets can be connected at any time.

I've also updated the regex to match "mouse" and "pen" words as well. Note that this isn't exhaustive. I don't know if words like "pencil", "tablet", "stylus", etc. should be included. Tweak as needed.

EDIT: I've updated the script (on the gist link now) to use a list of banned words instead of RegEx. It should now work even if you compiled Godot with the regex module disabled. See #59412 (comment) .

@geekley
Copy link

geekley commented Dec 12, 2023

I've updated the code in the gist again to fix another issue.
I'm now sending input events once to reset all of the device's SDL axes and buttons to zero upon disabling it.
This ensures it won't be stuck in motion, in case you were moving the touchpad during startup.

Please update if you're using the code (it's for v4.2 now, but should be trivial to port back by removing for type hints).

@mak448a

This comment was marked as off-topic.

@AThousandShips
Copy link
Member

See the linked PR, but otherwise please don't bump things without information, if someone has an update they would have added it here :)

@Calinou Calinou linked a pull request Mar 15, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment