godotengine / godot

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

Xbox One Controller not detected by Godot Engine macOS #53329

Open lukekras opened 2 years ago

lukekras commented 2 years ago

Godot version

3.3.3.stable (b973f997f), 3.3.4.stable (faf3f883d), 3.3.5.rc (820b1ae4b), 3.4.beta (90a734211)

System information

macOS Big Sur 11.6, Xbox One Controller (Vendor: 045e Product: 02dd)

Issue description

Godot Engine doesn't detect Xbox One Controller (STANDARD GAMEPAD Vendor: 045e Product: 02dd)

macOS Big Sur (Version 11.6) System Information shows the controller in the USB Device Tree. Apple -> About This Mac -> System Report... -> Hardware -> USB -> USB 3.0 Bus -> Controller Controller:

Product ID: 0x02dd Vendor ID: 0x045e (Microsoft Corporation) Version: 2.03 ... Speed: Up to 12 Mb/s Manufacturer: Microsoft Location ID: 0x14300000 / 3 ...

Opening a Chrome browser to Gamepad Tester shows the controller, and you can interactively see the buttons and hats working.

Xbox Controller Xbox One Controller (STANDARD GAMEPAD Vendor: 045e Product: 02dd)

Steps to reproduce

Steps

Checkout and open Godot Demo Projects - Joypads.

The XBox Controller is not recognised. Press the Remap and the Godot console output prints "Unable to find controller". Disconnect and reconnect the controller from the USB port. Still not detected in Godot.

This was tested in the following versions with the same result. Godot Engine v3.3.3.stable.official [b973f997f] Godot Engine v3.3.4.stable.official [faf3f883d] Godot Engine v3.3.5.rc.custom_build [820b1ae4b] Godot Engine v3.4.beta.custom_build [90a734211]

Comments

Looking at game controller db, the UID looks to have the Vendor: 045e and Product: 02dd numbers (if you swap the bytes around). The tests were done on an Intel Mac (little endian), so swapped bytes fits, but it's not a closed case.

I tracked the code to running some macOS IOKit code in joypad_osx.cpp. I suspect that the IOHIDManager* calls maybe are broken in Big Sur, or my version of Big Sur (Version 11.6).

void JoypadOSX::config_hid_manager(CFArrayRef p_matching_array) const {

    CFRunLoopRef runloop = CFRunLoopGetCurrent();
    IOReturn ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
    ERR_FAIL_COND(ret != kIOReturnSuccess);

    IOHIDManagerSetDeviceMatchingMultiple(hid_manager, p_matching_array);
    IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, joypad_added_callback, NULL);
    IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, joypad_removed_callback, NULL);
    IOHIDManagerScheduleWithRunLoop(hid_manager, runloop, GODOT_JOY_LOOP_RUN_MODE);

    while (CFRunLoopRunInMode(GODOT_JOY_LOOP_RUN_MODE, 0, TRUE) == kCFRunLoopRunHandledSource) {
        /* no-op. Callback fires once per existing device. */
    }
}

I did some searches on "The Internet Machine" and there was some discussion around Apple's changes to IOKit and the introduction of DriverKit in Big Sur and beyond. Reimplementing controllers with DriverKit seems like the only way forward on Apple devices, but I suspect a nontrivial change. DriverKit may even be already on the Godot roadmap. DriverKit Sample Code. It would be good to get a controller DriverKit example from Apple. Maybe with a DriverKit implementation in Godot, most of the controller bugs on Mac platform might just go away.

Minimal reproduction project

No response

lukekras commented 2 years ago

Minimal reproduction project Checkout and open Godot Demo Projects - Joypads.

akien-mga commented 2 years ago

CC @godotengine/macos

bruvzg commented 2 years ago

Disconnect and reconnect the controller from the USB port

Do you have some sort of third-party controller driver installed? AFAIK Big Sur supports only Bluetooth Xbox controllers, USB one should not work at all. At least, none of my Xbox controllers are detected.

USB PS 3 controller seems to be working fine with the current 3.x on Big Sur 11.6 (M1 MacBook), old API is still supported. DriverKit is required to implement custom controller drivers, I do not think it's necessary to use it.

lukekras commented 2 years ago

I'm just using plain vanilla macOS Big Sur 11.6 Intel (no 3rd party drivers). I can see the Xbox controller in Mac System Information USB Device Tree (via USB). Also when viewing with Chrome browser Gamepad Tester site, I can see the controller and interact with it. So that means to me that it is working all the way through Big Sur and into the Chrome stack.

When I disconnected and reconnected the Xbox controller (via USB), I expected callbacks joypad_removed_callback and joypad_added_callback to be fired (in Godot), but they weren't. So that is why I suspected that something might be broken (in Apple IOKit) in the IOHIDManager calls. The Godot code (joypad_osx.cpp) appears correct, that is at least visually.

I read some more on IOKit, and I think that you're right that there is no need for DriverKit as the Apple drivers are sufficient for joysticks, and therefore no need for special drivers as kernel extensions or DriverKit.

My next step is to have a play with some IOKit code based on HID LED test tool to see if I can see what is going on.

bruvzg commented 2 years ago

I can see the Xbox controller in Mac System Information USB Device Tree (via USB).

My controller it is displayed in the devices, but not detected as a controller by any software (it's an older Xbox controller with the custom wireless adapter and different device ID, maybe Bluetooth enabled controllers work in both wireless and wired modes).

In addition to IOKit, there's also GameController API we use on iOS (https://github.com/godotengine/godot/blob/master/platform/iphone/joypad_iphone.mm). Maybe we should try enabling it on the macOS as well (SDL seems to use both).

lukekras commented 2 years ago

I'll look at the GameController API - good idea. Just reviewed the SDL implementation of IOKit and it looks almost the same as the Godot implementation. It'll be worth me spinning up a test of the controller in SDL to see which code path the controller is hitting.

lukekras commented 2 years ago

SDL build system is so broken. I was hoping to run some SDL code that worked with my Xbox controller. Then I could hopefully make similar changes in Godot in the form of a PR. But I just wasted hours trawling through Stackoverflow issues about building SDL on macOS, and failed. Godot's build system works, which sadly is not the case for most open source.

lukekras commented 2 years ago

Use internal implementation of the Gamepad API. #45078 has merged a PR. I connected to the test link which runs the joypads demo deployed to HTML5/Webassembly. So I'm optimistic that some of those changes could be also put into the macOS area.

lukekras commented 2 years ago

I tested my PS4 controller with Joypads demo just to see if another type of controller would work, and it was detected as PS4 Controller 030000004c050000c405000000010000. This gets around my immediate issue of having a working controller, but I'd like to see this issue (Xbox controller) through to completion. I did a remap wizard with my Xbox controller using the test link (ref: #45078) and got:

[standard,Standard Gamepad Mapping,a:b0,b:b1,y:b3,x:b2,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:b12,dpleft:b14,dpdown:b13,dpright:b15,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a6,righttrigger:a7,platform:Javascript]

I'm a little unsure on how to proceed - a missing entry in game controller db, or GameController API (suggested by bruvzg), or Gamepad API as in fix #45078.

lukekras commented 2 years ago

I tested the XBox One Controller on a PC with Windows 10, Godot 3.3.4.stable, and the controller was detected in Joypads demo as a Gamepad device. __XINPUT_DEVICE__ ,XInput Gamepad See code ref godotcontrollerdb.txt

lukekras commented 2 years ago

I put some logging in JoypadOSX::_device_added and JoypadOSX::_device_removed MacOS Godot 3.3.4.stable. Then I disconnected and reconnected both XBox One Controller and the PS4 Controllers. In all occasions the PS4 Controller was detected as IOKit Usage Page code kHIDPage_GenericDesktop (0x01) with Usage code kHIDUsage_GD_GamePad (0x05) The XBox One Controller didn't trigger the callbacks at all. This seems to be IOKit missing support for this controller, and I don't see Apple caring enough to change that. I'm hoping that Game Controller has support for the XBox One Controller (suggested by @bruvzg earlier).

bruvzg commented 2 years ago

Try using this branch https://github.com/bruvzg/godot/tree/macos_gcontroller

It has iOS Game Controller code copy-pasted to macOS alongside old HID code, so it might detect some controllers twice.

lukekras commented 2 years ago

Thanks @bruvzg for writing that branch and making it available. I added some logging, built it, ran it, and then added and removed both the PS4 and XBox One controllers. Only the PS4 controller showed any logging output. It looks like the PS4 controller is detected by both Game Controller, and IOKit frameworks. The XBox One controller is detected by neither.

Connected PS4 Controller Entry - JoypadOSX::_device_added Entry - controllerWasConnected Entry - addiOSJoypad Entry - JoypadOSX::get_unused_joy_id Entry - getFreePlayerIndex Entry - JoypadOSX::joy_connection_changed Entry - setControllerInputHandler

Disconnected PS4 Controller Entry - JoypadOSX::_device_removed Entry - controllerWasDisconnected Entry - JoypadOSX::joy_connection_changed

Connected XBox One Controller no output

Disconnected XBox One Controller no output

bruvzg commented 2 years ago

Seems like instead of using system controller APIs, Chrome is communicating with the Xbox controllers directly, using low level IOUSBLib API.

https://github.com/chromium/chromium/blob/master/device/gamepad/xbox_controller_mac.mm

lukekras commented 2 years ago

Excellent - thanks. I'll have a look at the Chrome code.

robinduckett commented 2 years ago

Just a me too comment here, Xbox One controller works fine upon HTML export but it makes testing in native extremely difficult