-
Notifications
You must be signed in to change notification settings - Fork 0
fix(gamepad): derive Android type_hint from device name (#270) #31
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,6 +26,35 @@ pub const TypeHint = enum(u8) { | |
| generic, | ||
| }; | ||
|
|
||
| /// Best-guess vendor family from a human-readable device name string. | ||
| /// | ||
| /// Shared name→type classifier for any source that only has a name to go on | ||
| /// (Android `InputDevice.getName()`, raylib's `GetGamepadName`, the WebGamepad | ||
| /// `id` string). Backends with a stable USB vendor id (Linux evdev, iOS GC | ||
| /// profile) should classify from that instead — this is the name-only path. | ||
| /// | ||
| /// Matching is case-insensitive substring. A non-empty name that matches no | ||
| /// known family is `.generic`; an empty name is `.unknown`. | ||
| pub fn typeHintFromName(name: []const u8) TypeHint { | ||
| if (containsIgnoreCase(name, "xbox") or | ||
| containsIgnoreCase(name, "microsoft")) return .xbox; | ||
| if (containsIgnoreCase(name, "playstation") or | ||
| containsIgnoreCase(name, "dualsense") or | ||
| containsIgnoreCase(name, "dualshock") or | ||
| containsIgnoreCase(name, "sony") or | ||
| containsIgnoreCase(name, "wireless controller")) return .playstation; | ||
| if (containsIgnoreCase(name, "nintendo") or | ||
| containsIgnoreCase(name, "switch") or | ||
| containsIgnoreCase(name, "joy-con") or | ||
| containsIgnoreCase(name, "pro controller")) return .nintendo; | ||
| if (name.len > 0) return .generic; | ||
| return .unknown; | ||
| } | ||
|
Comment on lines
+38
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because Swapping the order of the Nintendo and PlayStation checks resolves this, ensuring that specific Nintendo keywords like |
||
|
|
||
| fn containsIgnoreCase(haystack: []const u8, needle: []const u8) bool { | ||
| return std.ascii.indexOfIgnoreCase(haystack, needle) != null; | ||
| } | ||
|
|
||
| /// What kind of physical device produced the event. Distinguishes a real | ||
| /// game controller from a TV / set-top "d-pad remote" (Android TV, tvOS), | ||
| /// which should usually be treated differently by menus. | ||
|
|
@@ -161,6 +190,19 @@ test "setName truncates to NAME_CAPACITY and stays NUL-terminated" { | |
| try std.testing.expectEqual(@as(u8, 0), ev.name[NAME_CAPACITY]); // sentinel intact | ||
| } | ||
|
|
||
| test "typeHintFromName classifies known vendor families (name-only path)" { | ||
| try std.testing.expectEqual(TypeHint.xbox, typeHintFromName("Xbox Wireless Controller")); | ||
| try std.testing.expectEqual(TypeHint.xbox, typeHintFromName("XBOX 360 For Windows")); | ||
| try std.testing.expectEqual(TypeHint.xbox, typeHintFromName("Microsoft X-Box pad")); | ||
| try std.testing.expectEqual(TypeHint.playstation, typeHintFromName("Sony DualSense Wireless Controller")); | ||
| try std.testing.expectEqual(TypeHint.playstation, typeHintFromName("PLAYSTATION(R)3 Controller")); | ||
| try std.testing.expectEqual(TypeHint.playstation, typeHintFromName("Wireless Controller")); | ||
| try std.testing.expectEqual(TypeHint.nintendo, typeHintFromName("Nintendo Switch Pro Controller")); | ||
| try std.testing.expectEqual(TypeHint.nintendo, typeHintFromName("Joy-Con (L)")); | ||
| try std.testing.expectEqual(TypeHint.generic, typeHintFromName("Generic USB Joystick")); | ||
| try std.testing.expectEqual(TypeHint.unknown, typeHintFromName("")); | ||
| } | ||
|
Comment on lines
+193
to
+204
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a test case for |
||
|
|
||
| test "disconnected constructor" { | ||
| const ev = GamepadEvent.disconnected(3); | ||
| try std.testing.expectEqual(GamepadEvent.Kind.disconnected, ev.kind); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
X-Box wireless misclassified PlayStation
Medium Severity
In
typeHintFromName, the Xbox branch only matches the contiguous substringxbox, so names likeX-Box Wireless Controllerskip Xbox and Microsoft checks. The PlayStation branch then matches thewireless controllersubstring and returns.playstation, so some Xbox pads get PlayStation glyphs instead of Xbox on Android.Reviewed by Cursor Bugbot for commit 3a7300f. Configure here.