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

[rcore] Gamepad not working on macOS #3651

Open
4 tasks done
NitroPlum opened this issue Dec 18, 2023 · 25 comments
Open
4 tasks done

[rcore] Gamepad not working on macOS #3651

NitroPlum opened this issue Dec 18, 2023 · 25 comments
Labels
help needed - please! I need help with this issue platform: macOS macOS platform

Comments

@NitroPlum
Copy link

Please, before submitting a new issue verify and check:

  • I tested it on latest raylib version from master branch
  • I checked there is no similar issue already reported
  • I checked the documentation on the wiki
  • My code has no errors or misuse of raylib

Issue description

Gamepad input not working. I tried 2 different controllers.

  • Xbox One Series X connected via USB
    • IsGamepadAvailable(0) returns false.
  • Nintendo Switch Pro Controller connected via USB
    • IsGamepadAvailable(0) returns true.
    • No button input is ever detected

Environment

MacOSX Ventura on an M2 Mac.

Issue Screenshot

Can't really show this.

Code Example

#include "raylib.h"
#include <stdio.h>

int main(void)
{
    const int screenWidth = 800;
    const int screenHeight = 450;

    InitWindow(screenWidth, screenHeight, "Gamepads Broken");

    SetTargetFPS(60);               

    while (!WindowShouldClose()) 
    {
        BeginDrawing();

            ClearBackground(RAYWHITE);

            if(IsGamepadAvailable(0)) {
                DrawText("FOUND GAMEPAD TEST", 190, 275, 20, PURPLE);
                
                if(IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) {
                    DrawText("BUTTON PRESSED", 190, 350, 20, PURPLE);
                }
            }

        EndDrawing();
    }
    CloseWindow();        

    return 0;
}

Provide minimal reproduction code to test the issue. Please, format the code properly and try to keep it as simple as possible, just focusing on the experienced issue.

@ghost
Copy link

ghost commented Dec 18, 2023

@NitroPlum GLFW or SDL?

Either way:

  1. Regarding Nintendo Switch Pro Controller, it's on the mappings list (L950-L951) for Mac OS X.
    No button input being detected could be a binding issue.

  2. Regarding Xbox One Series X, couldn't find it on the mappings list and neither on the SDL_GameControllerDB.
    Probably why it's not being detected.

Edits: 1. added more information; 2. updated info, formatting.

@NitroPlum
Copy link
Author

After GLFW, I also tried the SDL backend. Is there a way for me to fix the binding issue locally @ubkp ?

@NitroPlum
Copy link
Author

Oh, another bit of info that may help. I did try in the browser examples on the Raylib site and both controllers work there.

@ghost
Copy link

ghost commented Dec 18, 2023

After GLFW, I also tried the SDL backend. Is there a way for me to fix the binding issue locally @ubkp ?

@NitroPlum Sure, create your own binds (you may want to take a look at SDL_GameControllerDB) and add it to your local src/external/glfw/src/mappings.h file.

Oh, another bit of info that may help. I did try in the browser examples on the Raylib site and both controllers work there.

AFAIK, the web browser gamepad API is a completely different thing (ref1, ref2).

Edit 1: AFAIK sometimes firmware updates end up changing the device GUID, which causes it to no longer match the DB. I could be wrong, but I think that happened to some Xbox controllers.

Edit 2: Apparently you can even use Steam's Big Picture mode to generate binds these days (ref).

@raysan5 raysan5 changed the title [Core] Gamepad not working on MacOSX [rcore] Gamepad not working on macOS Dec 19, 2023
@SoloByte
Copy link
Contributor

SoloByte commented Jan 30, 2024

I have similar problems. I am using the c# bindings of raylib on MacOSX 14.2.1 Sonoma and gamepad input is no longer working. Raylib detects the connected gamepads but does not trigger any button/ trigger/ axis functions.

I have tested Xbox Elite Controller 2 & Xbox Series X Controller.

  • I can connect them fine to my mac
  • The input works with the raylib example in the browsers
  • The input works with a gamepad test online
  • Both gamepads work on windows with various games
  • I have used the exact same setup before (in october I think) and everything has worked fine.

At same point it just stopped working for me....

The example I am using to test this all out works fine on windows (the gamepad is detected & the input is detected)

I think the only thing I did was update the firmware on my elite controller but the other controller I did not update...

I have tried to use custom bindings and bindings from SDL_GameControllerDB with the SetGamepadMappings function but it did not change anything.

@raysan5 raysan5 added the platform: macOS macOS platform label Jan 31, 2024
@raysan5
Copy link
Owner

raysan5 commented Apr 21, 2024

@SoloByte Thanks for reporting. Could you try with raylib latest master branch version?

raylib 5.0 (November 2023) implemented a big redesign for desktop platforms and despite everything was carefully tested, some things could not work as expected.

I don't have a macOS, neither those mentioned gamepads, I need help to fix this issue.

@raysan5 raysan5 added the help needed - please! I need help with this issue label Apr 21, 2024
@SoloByte
Copy link
Contributor

SoloByte commented Apr 21, 2024

@raysan5
I have just tested it on my MacBook with raylib cs 6.0.0. (I can only test raylib cs) I have used 3 xbox one controllers (elite series2, new-ish xbox one, old xbox one).

All three are detected by my MacBook, all three work on windows, all three work with a gamepad tester. I have tested them with the raylib input gamepad example and they are detected and the input works (even when more than 1 is connected) but it seems that the triggers are not detected at all (Left/Right Trigger). The joystick axis work fine.

I have tested it with my simple raylib cs gamepad tester project and the controllers are detected but no input is registered.

  • Raylib.IsGamepadAvailable(0) returns true (also for 2nd, 3rd connected gamepad)
  • Raylib.IsGamepadButtonDown(0, GamepadButton.RightFaceDown) always returns false
  • Raylib.GetGamepadButtonPressed() > 0 always returns false

It would be helpful if someone could test this on a Mac with raylib, because I can only test it with raylib C# bindings.

I will post my simple project here. It is possible that I am doing something wrong or missing a step.

//Using Raylib Cs 6.0.0 (Released 20 January 2024)
using Raylib_cs;


namespace GamepadCs
{
    public static class Program
    {
        public static int Main(string[] args)
        {
            //Init
            Raylib.InitWindow(800, 800, "Raylib cs Gamepad Test");
            Raylib.InitAudioDevice();
            Raylib.ClearWindowState(ConfigFlags.VSyncHint);
            Raylib.SetTargetFPS(60);

            var defaultFont = Raylib.GetFontDefault();
            
            //Gameloop
            while (!Raylib.WindowShouldClose())
            {
                Raylib.BeginDrawing();

                //Gamepad connected
                if (Raylib.IsGamepadAvailable(0))
                {
                    
                    //Xbox A button down
                    if (Raylib.IsGamepadButtonDown(0, GamepadButton.RightFaceDown))
                    {
                        Raylib.ClearBackground(Color.Green);
                    }
                    //any gamepad button pressed
                    else if (Raylib.GetGamepadButtonPressed() > 0)
                    {
                        Raylib.ClearBackground(Color.Yellow);
                    }
                    else //no gamepad button pressed
                    {
                        
                        //Left Mouse Button or Space is held down
                        if (Raylib.IsMouseButtonDown(MouseButton.Left) || Raylib.IsKeyDown(KeyboardKey.Space))
                        {
                            Raylib.ClearBackground(Color.Blue);
                        }
                        
                        //nothing pressed 
                        else
                        {
                            Raylib.ClearBackground(Color.DarkGray);
                        }
                    }
                }
                
                // no gamepad connected
                else 
                {

                    //Left Mouse Button or Space is held down
                    if (Raylib.IsMouseButtonDown(MouseButton.Left) || Raylib.IsKeyDown(KeyboardKey.Space))
                    {
                        Raylib.ClearBackground(Color.Purple);
                    }
                    
                    //nothing pressed 
                    else 
                    {
                        Raylib.ClearBackground(Color.Black);
                    }
                }
                
                Raylib.EndDrawing();
            }
            
            
            //End
            Raylib.CloseAudioDevice();
            Raylib.CloseWindow();
            return 0;
        }
    }
}

@JupiterRider
Copy link
Contributor

@SoloByte
Your Raylib-cs example works fine on Linux.

I also cannot find any platform specific macos code in raylib. Maybe a newer version of GFLW will fix this.

@raysan5
Copy link
Owner

raysan5 commented Aug 24, 2024

It seems this issue is specific to a binding, I'm afraid I'm closing it for raylib C side.

@raysan5 raysan5 closed this as completed Aug 24, 2024
@konsumer
Copy link

konsumer commented Dec 10, 2024

I have a similar issue with plain C, on mac M1 (Sonoma.) On web, it works fine, but with this code, I only get the name, but no button-events, on native raylib 5.5:

#include "raylib.h"

int main(void) {
  InitWindow(320, 240, "gamepad test");
  SetTargetFPS(60);

  while (!WindowShouldClose()) {
    BeginDrawing();
    ClearBackground(RAYWHITE);

    char* gpText = "No gampepad";
    
    for (int gamepad=0; gamepad < 5; gamepad++) {
      if (IsGamepadAvailable(gamepad)) {
        gpText = TextFormat("GP%d: %s", gamepad, GetGamepadName(gamepad));
        for (int gamepadButton = GAMEPAD_BUTTON_UNKNOWN; gamepadButton <= GAMEPAD_BUTTON_RIGHT_THUMB; gamepadButton++) {
          if (IsGamepadButtonDown(gamepad, gamepadButton)) {
            DrawCircle((gamepadButton*17) + 9, 120, 8, RED);
          } else {
            DrawCircle((gamepadButton*17) + 9, 120, 8, GRAY);          }
        }
      }
    }

    DrawText(gpText, 10, 10, 10, BLACK);
    
    EndDrawing();
  }

  CloseWindow();
  return 0;
}

I tested with 2 controllers:

official PS5 controller, paired over bluetooth

Screenshot 2024-12-10 at 2 41 33 PM

PXN-P50S, connected over bluetooth, as "Pro Controller"

Screenshot 2024-12-10 at 2 15 12 PM

I am happy to test anything you like. I have 2 macs for testing (intel and M1.)

Update, after re-pairing a couple times, I got the PS5 controller to work, but not the PXN-P50S:

Screenshot 2024-12-10 at 2 58 39 PM

Update

I made a similar tester in GLFW (3.4) and got similar results.

#include <GLFW/glfw3.h>
#include <stdio.h>

#ifdef EMSCRIPTEN
#include <emscripten.h>
#endif

void joystick_connect_callback(int jid, int event) {
  if (event == GLFW_CONNECTED) {
    printf("connected: %d: %s\n", jid, glfwGetJoystickName(jid));
  } else if (event == GLFW_DISCONNECTED){
    printf("disconnected: %d: %s\n", jid, glfwGetJoystickName(jid));
  }
}

GLFWwindow *window = NULL;

void mainLoop() {
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);
  glfwSwapBuffers(window);
  glfwPollEvents();

  for (int jid = GLFW_JOYSTICK_1; jid<GLFW_JOYSTICK_4;jid++) {
    if (glfwJoystickPresent(jid)) {
      int count = 0;
      const unsigned char* buttons = glfwGetJoystickButtons(jid, &count);
      for (int b=0;b<count;b++) {
        if (buttons[b]) {
          printf("%d %u: DOWN\n", jid, b);
        } else {
          printf("%d %u: UP\n", jid, b);
        }
      }
    }
  }
}

int main() {
  if (!glfwInit()) {
    return 1;
  }

  window = glfwCreateWindow(320, 240, "gamepad tester", NULL, NULL);
  if (!window) {
    glfwTerminate();
    return 1;
  }

  glfwMakeContextCurrent(window);
  glfwSetJoystickCallback(joystick_connect_callback);

  for (int jid = GLFW_JOYSTICK_1; jid<GLFW_JOYSTICK_4;jid++) {
    if (glfwJoystickPresent(jid)) {
      printf("present: %d: %s\n", jid, glfwGetJoystickName(jid));
    }
  }


#ifdef EMSCRIPTEN
  emscripten_set_main_loop(&mainLoop, 0, 1);
#else
  while (!glfwWindowShouldClose(window)) {
    mainLoop();
  }
#endif

  glfwDestroyWindow(window);
  glfwTerminate();

  return 0;
}

Both were seen initially, but only PS5 updated it's buttons. Like, I saw this, with some buttons pressed on both:

present: 0: Pro Controller
present: 1: DualSense Wireless Controller
0 0: UP
0 1: UP
0 2: UP
0 3: UP
0 4: UP
0 5: UP
0 6: UP
0 7: UP
0 8: UP
0 9: UP
0 10: UP
0 11: UP
0 12: UP
0 13: UP
0 14: UP
0 15: UP
0 16: UP
0 17: UP
0 18: UP
0 19: UP

1 0: DOWN
1 1: UP
1 2: UP
1 3: DOWN
1 4: UP
1 5: UP
1 6: UP
1 7: UP
1 8: UP
1 9: UP
1 10: UP
1 11: UP
1 12: UP
1 13: UP
1 14: UP
1 15: UP
1 16: UP
1 17: UP

@konsumer
Copy link

konsumer commented Dec 11, 2024

If you're getting the controllers names but not the button presses, then it's probably missing bindings.

That makes sense, but the weird thing is it does work correctly for a short-while in GLFW, when it first pairs. Also, I thought those mappings were just for named-buttons, but without them it will still send whatever button-int the controller sends. Maybe I am misunderstanding that part.

I setup this code so I could see what was happening a bit better, without any other layers (just glfw.) For about 4 seconds after it pairs, it works fine, and the buttons are mapped correctly.

Screenshot 2024-12-10 at 5 54 26 PM

@konsumer
Copy link

konsumer commented Dec 11, 2024

Would it be possible for you to test it with PLATFORM_DESKTOP_SDL (SDL2 preferably)?

Yep, I can setup a raylib tester with PLATFORM_DESKTOP_SDL with SDL2, and a no-raylib SDL2 tester.

Also, looked the doc to see if there were some sort of "keep alive" call, but found nothing.

Yeh, and this all works in Linux, too, so I think it's some mac-specific bug. It may just be that joystick, or Mac's handling of switch controllers, I am not sure.

@konsumer
Copy link

konsumer commented Dec 11, 2024

Ok, I did a bunch of testing here. The glfw demo needs more work, It's kinda complicated to do graphics on web and native with same code! I keep getting hung up on different deps I need for each target, and finding a balance has been a bit tricky. I settled on a very old version of glsl, so i need to work out the rest of code for that. I also need to flesh out the plain SDL demo a bit more, and I want to also try manually loading a new gamepad-map on glfw to see if that helps (although my understanding is it shouldn't matter, and it will return button-numbers without it, which are not mapped to correct position for xbox controller, but otherwise work.)

Here is what I know so far:

  • my joystick works (steam, a few games I tested, unaffiliated web-tester, raylib web-tester, etc) so I don't think it's a driver/os/hardware problem
  • raylib web is fine
  • same code in raylib SDL native is fine on mac, with my joystick
  • raylib glfw native is broke (with this particular joystick, on mac)
  • from earlier test: plain glfw is broke (with this particular joystick, on mac)
  • everything works with PS5 controller, even native GLFW/raylib-glfw

I'm going to try to finish all the tests, just because I like having the test-suite, and I have been thinking about evaluating input & graphics on glfw/sdl anyway (for my game engine) but I think I can confidently call it, in terms of raylib: glfw has issues with this (otherwise working) controller on mac, but SDL is ok. It seems like a GLFW problem, not raylib, since plain glfw has issues, but maybe something we should track and try to help with (since it effects raylib users on mac, and is probably not specific to this 1 gamepad.)

@konsumer
Copy link

konsumer commented Dec 11, 2024

Have you tested them connected through USB cable (if possible)?

This particular controller does not work over USB here, at least that I could figure out. The manual indicates it should work, but it never shows up in OSX settings panel, unless I pair with bluetooth.

This controller is also fine over bluetooth with SDL and several other apps (browser, steam, etc) and PS5 controller is ok over bluetooth with everything (even native glfw.)

I think it's a good troubleshooting step, but the controller may just not work that way, even when all is well.

@raysan5 raysan5 reopened this Dec 11, 2024
@raysan5
Copy link
Owner

raysan5 commented Dec 11, 2024

Reopening for further review.

@konsumer
Copy link

konsumer commented Dec 11, 2024

If I had to guess, perhaps GLFW has some TTL issue

I think so too. The plain GLFW thing is especially weird, and I found it kinda by accident.

If I do this it works fine for about 4 seconds, then stops:

  • unpair the controller
  • run plain GLFW program
  • pair controller
  • mash buttons

Try some breaks around here and here.

I will try this out, later. I think would like to test with raylib's copy of glfw, because my plain glfw demo is in a bit of a broken state (trying to get it working on web & native with same code.) Maybe I should drop web target, since that seems to work ok, from other tests, or just use the raylib-wrapped demo, so it can all run from same simple code.

@konsumer
Copy link

The web gamepad support is superb. But it's basically completely independent (note how it even identify the controller name string differently).

yep, I mention it only as a contrast like "this controller works in this other thing" similar to native SDL testing. Chrome seems to work great with this controller, in raylib, and out.

Btw, somewhat related glfw/glfw#2526.

Interesting. That does seem possibly related.

@konsumer
Copy link

konsumer commented Dec 11, 2024

Ok, yeh, I am going to make a decision about the demos, to stay in scope, and not get overwhelmed with all the stuff needed to get not-as-helpful demos running:

  • only native glfw joystick tester. web glfw works, and supporting both in a hand-rolled 2D lib, or writing a compat shader for both is a serious pain.
  • drop native/web SDL. it seems to work ok, but I don't really need to fill in the demo
  • build raylib-sdl (for comparison) but don't worry about web, since we established it works
  • build raylib-glfw but don't worry about web, since we established it works

Playing with this really makes me appreciate raylib & sdl, and how much they abstract away!

@konsumer
Copy link

konsumer commented Dec 11, 2024

Does that make sense?

yeh, I am no expert, but it definitely seems like a timing/threading thing to me because of the works-for-4-seconds thing.

I was mistyping earlier, though ("glsl" when I meant "glfw") I think I fried my brain a lil going deep on this stuff :) and also I am dyslexic and mix up similar words a lot.

I don't think the prob is specific to glsl/3d, as it seems to happen in glfw with or without using any opengl stuff.

@konsumer
Copy link

konsumer commented Dec 11, 2024

Gotcha. Definitely worth looking into.

Ok, so I simplified my examples a lot, and it's much easier to play around with.

raylib SDL

uses a different (maybe more correct, since this controller is supposed to pretend to be a switch pro controller) name, and it works fine:

Screenshot 2024-12-11 at 2 18 33 PM

plain GLFW

Screenshot 2024-12-11 at 2 23 53 PM

Freezes after 4secs, if I pair after program is started. It seems "stuck" in the last buttons I pressed.

raylib GLFW

Has same freeze-4-secs problem.

Screenshot 2024-12-11 at 2 22 09 PM

The buttons have different indexes, it looks like, but same 3 buttons are "stuck"

@konsumer
Copy link

ok, I did this:

void _glfwTerminateJoysticksCocoa(void)
{
    printf("trying to terminate joy\n");

    for (int jid = 0;  jid <= GLFW_JOYSTICK_LAST;  jid++)
    {
        if (_glfw.joysticks[jid].connected)
            closeJoystick(&_glfw.joysticks[jid]);
    }

    if (_glfw.ns.hidManager)
    {
        CFRelease(_glfw.ns.hidManager);
        _glfw.ns.hidManager = NULL;
        printf("releasing joy\n");
    }
}

on plain glfw, it outputs both lines when I close window:

trying to terminate joy
releasing joy

but not before.

@konsumer
Copy link

konsumer commented Dec 11, 2024

Based on name/platform I narrowed the map lines down to these:

  const char* mappings = "030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,\
030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,\
030000007e0500000920000010020000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X,\
050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X,";
  
  int mapstatus = SetGamepadMappings(mappings);
  TraceLog(LOG_INFO, "mapping: %d", mapstatus);

I get same issue, with mapping: 1 output.

It still shows "Pro Controller" so mapping might not be working right.

I also tried adding same lines to mappings.h in glfw, with same results (wrong name, etc.)

Running a tester program, I got this from SDL2:

0300d71f7e0500000920000001006803 "Nintendo Switch Pro Controller" axes:6 buttons:20 hats:0 balls:0

Searching through the existing mapping these are already in there, and have "correct" name:

030000007e0500000920000000000000
030000007e0500000920000001000000

and these were not in there:

030000007e0500000920000010020000
050000007e05000009200000ff070000

Nothing seems to pick up these mappings, though. Like I also added this:

  const char* mappings = "0300d71f7e0500000920000001006803,DK Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X,";
  int mapstatus = SetGamepadMappings(mappings);
  TraceLog(LOG_INFO, "JS: mapping: %d", mapstatus);

and for both SDL & GLFW, it uses names that are not "DK Switch Controller"

@MikeshCZ
Copy link

Hi,
I have a same/similar issue with MacBook Air M3 (Mac OS 15.1.1 (24B91)) and Xbox Wireless controller.

Tried this example . Works on web with no issues. But same code run under Raylib 5.5 on Mac not working. It found properly controller, but neither buttons nor axis are working.

@konsumer
Copy link

konsumer commented Dec 30, 2024

@MikeshCZ would you mind compiling/running this tester (it has instructions at top for compiling, for mac/linux with SDL2 installed, but lemme know if you need help.) This will give us the SDL id/name which might help narrow down the issue, and it also helps identify that it's not just my cheapo controller, but other popular controllers, that work fine in SDL.

@MikeshCZ
Copy link

MikeshCZ commented Jan 5, 2025

@konsumer This is returned value from your code:

0300c6515e040000130b000015056800 "Xbox Series X Controller" axes:6 buttons:16 hats:0 balls:0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help needed - please! I need help with this issue platform: macOS macOS platform
Projects
None yet
Development

No branches or pull requests

6 participants