Last active
January 15, 2024 12:30
-
-
Save geekley/5e6daf62d2e86b566c4886f20b604d21 to your computer and use it in GitHub Desktop.
Fix false positives in Godot joypad device detection (e.g. touchpads). See https://github.com/godotengine/godot/issues/59250#issuecomment-1786196830
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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. | |
static var _Self: GDScript = (func() -> void:).get_object() as GDScript | |
func _ready() -> void: | |
int(Input.joy_connection_changed.connect(Callable(_Self, joy_check.get_method()))) | |
queue_free() | |
## 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: int, connected: bool) -> void: | |
if not connected: | |
return | |
var device_name: String = Input.get_joy_name(device) | |
# Uncomment the line below to debug problematic devices: | |
# print('Connected device ', device, ': ', device_name) | |
if not is_banned(device_name): | |
return | |
# If name has matched any banned word, this joypad device should be ignored. | |
var guid: String = Input.get_joy_guid(device) | |
# Disable input by mapping no axes or buttons. Will ignore future joypad input from this device. | |
var mapping: String = guid + ',' + device_name.replace(',', '') | |
Input.add_joy_mapping(mapping, true) | |
# Past input events might have been sent. Reset this device sending 0 on all SDL axes and buttons. | |
for axis: JoyAxis in range(JOY_AXIS_SDL_MAX) as Array[JoyAxis]: | |
var event: InputEventJoypadMotion = InputEventJoypadMotion.new() | |
event.device = device | |
event.axis = axis | |
Input.parse_input_event(event) | |
for button_index: JoyButton in range(JOY_BUTTON_SDL_MAX) as Array[JoyButton]: | |
var event: InputEventJoypadButton = InputEventJoypadButton.new() | |
event.device = device | |
event.button_index = button_index | |
Input.parse_input_event(event) | |
prints('Ignoring joypad device:', mapping) # you can comment out or remove this line | |
## True only if the device name contains a banned word, case-insensitively. | |
## A banned substring only matches if it's guaranteed to be a separate word. | |
static func is_banned(device_name: String) -> bool: | |
for word: String in banned_words: | |
var i: int = device_name.findn(word) | |
if i < 0: | |
continue # this banned word was not found as a substring | |
if i > 0 and not is_ascii_non_letter(device_name[i - 1]): | |
continue # substring found, but it's not guaranteed to start a word | |
var j: int = i + word.length() | |
if j < device_name.length() and not is_ascii_non_letter(device_name[j]): | |
continue # it starts a word, but it's not guaranteed to also end it | |
return true # substring found and guaranteed to form a separate word | |
return false # no banned word found | |
## True only if the character is ASCII and not a letter. | |
static func is_ascii_non_letter(c: String) -> bool: | |
return c.unicode_at(0) < 128 and not (c >= 'a' and c <= 'z' or c >= 'A' and c <= 'Z') | |
## List of words forbidden in joypad names. | |
static var banned_words: PackedStringArray = [ | |
'touchpad', 'trackpad', 'clickpad', | |
'mouse', | |
'pen', 'finger', # drawing tablets | |
] |
Well, neither this list nor this repo's files include this word, so I guess I'll consider it safe to include. I'll update it, thanks @MultisampledNight!
If possible, it would very helpful if you can please confirm it doesn't break accessing multi-touch input as such if desired - e.g. are InputEventScreenTouch and similar events still received?
Btw, if anyone else finds any other devices as false positives or false negatives, please let me know by commenting here too.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi! On the Acer Spin 5 on NixOS,
Wacom HID 495F Finger
is also a joypad registered by godot, which is actually the touchscreen. I guess it might make sense to ban the wordfinger
as well?