Gamepad / Controller Support - OSX / PC / Mobile

@siddharthshekar Controller support is relatively straightforward to add. You just need to make sure your code is efficient since it gets called a lot. Search for “controller” here to see all my controller related commits: https://github.com/Sheado/cocos2d-x/commits/v3-sheado
Here’s a link to API docs you’d need: http://www.glfw.org/docs/latest/input.html#joystick

@Sheado Thanks will look into it. :smiley:

I tried building in ipad and I get this error; glfw3.h file not found!!! :frowning:

SOLVED:: Added CCGLViewImpl-desktop.h and cpp to the ios target by mistake causing errors in ios. Removed it to wrk fine. :smiley:

I tried adding SDL2 to my project, and although it was very easy and straightforward it doesn’t worked for me. I keep getting SDL_NumJoysticks() == 0 and receive no events (including joystick connecting and disconnecting). Could you explain how you managed to make it work?

@Sheado @siddharthshekar

any update on these guys, any advancements ?
it would be really great to support controllers.

As most of the smartphones today supports OTG and game controller support.
please keep this thread updated. :smile:

thanks for support.

Why not just using Gainput?
http://gainput.johanneskuhlmann.de/

It already supports Android NDK, iOS, Linux, Mac OS X, and Windows.

@pabitrapadhy Have you considered trying it?

1 Like

@GGalemb - I went with a GLFW solution since cocos2d-x is already using that. You can see the code for that in my branch here: https://github.com/Sheado/cocos2d-x/commits/v3-sheado

@pabitrapadhy - I’ve been told that cocos2d-x is prioritizing mobile operating systems. The feature request for Windows/Mac/Linux is unassigned: https://github.com/cocos2d/cocos2d-x/issues/9912
If you need a (mostly) working implementation you can use or branch my v3.4 branch at: https://github.com/Sheado/cocos2d-x/commits/v3-sheado (note: there are bugs and custom changes that I’ve made)

@iQD - main reason I went with GLFW is because cocos2d-x is already using it for its desktop implementation. It works well so far, but lacks a few features (such as rumble)

1 Like

I see, and you have a point in not introducing another dependency.
The advantage of Gainput is, that it does not have any dependencies. It’s not even using stl or C++11.
Additionally to that, it comes with great features like gestures, remapping, key replaying, remote syncing…
Oh, and it rumbles :scream:

Nevertheless SDL2 has the best gamepad implementation in terms of supported controllers, but as both libraries are supporting RAW input, every controller should work fine.

@iQD - cool. Thanks for bringing it to my attention… I’ll definitely consider Gainput in a future project.

@Sheado Thanks for your solution for desktop controllers! I hope it gets integrated in a future release, it’s a shame that Cocos2d-x doesn’t support controllers natively.

I managed to make my controller work with SDL2. It’s a bit tricky, however, and it seems a lot of people have trouble with it. The catch is: SDL redefines main(int, char*[]) as SDL_main, and apparently it expects the SDL initialization to happen there. You just have to edit your main.cpp and create a new main() function that will initialize SDL and run your Cocos app:

int main(int argc, char *argv[])
{
    if (SDL_Init(SDL_INIT_JOYSTICK) != 0)
    {
        printf(stderr, "\nUnable to initialize SDL: %s\n", SDL_GetError());
    }
    atexit(SDL_Quit);

    AppDelegate app;
    return Application::getInstance()->run();
}

And call it from _tWinMain:

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    int status;

    SDL_SetMainReady();

    status = SDL_main(NULL, NULL);

    exit(status);

    return 0;
}

I’m using the win32 solution in Visual Studio 2013. In VS2015 SDL gives lots of warnings and some linker errors, but it seems you only have to recompile the SDL lib. Using the winrt solution is a wholly different thing.

1 Like

@GGalemb No problem =] Thanks for sharing your solution too!

Is there any guides how to use gainput?

Look at the Usage section on the github mainpage and the samples.

Just found it.
It seem I have to use cmake.
Thank you.

So, will we get controller support for osx/pc in the v3.10?

We are over a year on, I’m looking to go to steam next year with a new project. Can anyone advise me of the current position regarding joystick/pad support?

1 Like

I´m working with OIS library to support gamepads. I already test on most of gamepads (xbox, ps3/4, generics) and worked.

For Xbox One (UWP apps), you probably need to wrapping c# gamepad class to c++ and then migrate to your solution.

for future ref this is a very good short tutorial on gamepad support!

thanks @SonarSystems

2 Likes

Has anyone on this thread added controller support using GLFW, SDL, Gainput, etc for an x64 build? We are working on an UWP game, targeted for both Win 10 and Xbox One and have not been able to get a Visual Studio 2015 build running yet which targets x64 using GLFW or Gainput. Will likely try SDL next. Microsoft no longer supports Win32 builds on Xbox per the following link:

I created another forum thread to track x64 builds with GLFW (specifically), since that is already bundled with cocos2d-x but is not available in x64 builds.

Thanks!
Mark

It seems like there’s a whole bunch of support for controllers built in on desktop, only the button mappings aren’t created because ControllerImpl::ControllerImpl() in base/CCController-linux-win32.cpp never seems to get called.

I just newed a temp variable in there, and the controller listeners are working. Not sure if this is bug or what, but thought I’d throw my two cents in this old thread

void Controller::startDiscoveryController()
{
    //edit to create the button mapping, dont want to lose it either because its dtor destroys all controllers
    ControllerImpl* temp = new ControllerImpl{}; //leaks this variable

I’m using cocos2d-x 3.16

this was the mapping I had to add to the ctor for ControllerImpl(), to support my wired 360 controller:

			// Prepare variables:
			deviceName = "Xbox 360 Controller";
			buttonInputMap.clear();
			axisInputMap.clear();


			// Map the controller inputs to Controller::Key codes
			buttonInputMap[0] = Controller::Key::BUTTON_A;
			buttonInputMap[2] = Controller::Key::BUTTON_X;
			buttonInputMap[6] = Controller::Key::BUTTON_SELECT;
			buttonInputMap[7] = Controller::Key::BUTTON_START;
			buttonInputMap[13] = Controller::Key::BUTTON_DPAD_UP;
			buttonInputMap[14] = Controller::Key::BUTTON_DPAD_DOWN;
			buttonInputMap[11] = Controller::Key::BUTTON_DPAD_LEFT;
			buttonInputMap[12] = Controller::Key::BUTTON_DPAD_RIGHT;
			buttonInputMap[1] = Controller::Key::BUTTON_B;
			buttonInputMap[3] = Controller::Key::BUTTON_Y;
			buttonInputMap[4] = Controller::Key::BUTTON_LEFT_SHOULDER;
			buttonInputMap[5] = Controller::Key::BUTTON_RIGHT_SHOULDER;
			buttonInputMap[9] = Controller::Key::BUTTON_LEFT_THUMBSTICK;
			buttonInputMap[10] = Controller::Key::BUTTON_RIGHT_THUMBSTICK;
			axisInputMap[4] = Controller::Key::AXIS_LEFT_TRIGGER;
			axisInputMap[5] = Controller::Key::AXIS_RIGHT_TRIGGER;
			axisInputMap[0] = Controller::Key::JOYSTICK_LEFT_X;
			axisInputMap[1] = Controller::Key::JOYSTICK_LEFT_Y;
			axisInputMap[2] = Controller::Key::JOYSTICK_RIGHT_Y;
			axisInputMap[3] = Controller::Key::JOYSTICK_RIGHT_X;


			// Add the controller profile to the map
			s_controllerProfiles.insert(std::make_pair(deviceName, std::make_pair(buttonInputMap, axisInputMap)));

hope this helps someone. Don’t know if there’s going to be a problem with the support down the line but it seems to work for the first little bit I’ve been using it.

Here’s some test code I used to bind the controller in my game’s testing, just to get someone off the ground.

void bind_controller_support(cocos2d::Scene* scene)
{
    auto controller_listener = cocos2d::EventListenerController::create();
    controller_listener->onKeyDown = [](cocos2d::Controller* controller, int key_code, cocos2d::Event* evt) {
        CCLOG("gamepad key pressed %i", key_code);
    };
    controller_listener->onAxisEvent = [](cocos2d::Controller* controller, int key_code, cocos2d::Event* evt) {
        if (controller->getDeviceId() != 0) { return; }

        cocos2d::EventController* casted = dynamic_cast<cocos2d::EventController*>(evt);
        cocos2d::EventController::ControllerEventType type = casted->getControllerEventType();
        if (key_code == cocos2d::Controller::Key::JOYSTICK_LEFT_X || key_code == cocos2d::Controller::Key::JOYSTICK_LEFT_Y) {
            CCLOG("gamepad LEFT axis event %i, and value %f controller id %i", key_code, controller->getKeyStatus(key_code).value, controller->getDeviceId());
        } else if (key_code == cocos2d::Controller::Key::JOYSTICK_RIGHT_X || key_code == cocos2d::Controller::Key::JOYSTICK_RIGHT_Y) {
            CCLOG("gamepad RIGHT axis event %i, and value %f controller id %i", key_code, controller->getKeyStatus(key_code).value, controller->getDeviceId());
        } else {
            CCLOG("gamepad unknown axis event %i, and value %f controller id %i", key_code, controller->getKeyStatus(key_code).value, controller->getDeviceId());
        }

    };
    controller_listener->onConnected = [](cocos2d::Controller* controller, cocos2d::Event* evt) {
    };

    cocos2d::Controller::startDiscoveryController();
    //cocos2d::Controller::stopDiscoveryController();

    std::vector<cocos2d::Controller*> controllers = cocos2d::Controller::getAllController();
    for (const auto& controller : controllers) {
        CCLOG("%s", controller->getDeviceName().c_str());
    }
    scene->getEventDispatcher()->addEventListenerWithSceneGraphPriority(controller_listener, scene);
}
2 Likes