SFML community forums

General => SFML wiki => Topic started by: mateandmetal on July 09, 2013, 12:08:44 am

Title: XBox 360 Controller support for SFML games
Post by: mateandmetal on July 09, 2013, 12:08:44 am
Hi there!
I´m writing a wrapper around XInput (http://msdn.microsoft.com/en-us/library/windows/desktop/ee417001(v=vs.85).aspx), trying to keep the interface as similar to the SFML API (http://www.sfml-dev.org/documentation/2.0/classsf_1_1Joystick.php) as possible.
If you guys like this code and find it usefull, I will add it to the wiki page  8)

The code compiles and works fine with MinGW
It works with my wired X360 controller, I don´t know if it will work with the wireless controller

Of course you will need the DirectX SDK installed  :'(
Note that this will work only with XBox 360 compatible devices, for another kind of gamepads you still need to use the SFML Joystick API

Ok, here is the code:


#include <SFML/System/Vector2.hpp>

namespace xb {

class Joystick {


        // Typedefs
        typedef unsigned int    t_joyNum;
        typedef unsigned short  t_buttonNum;

        // Enums
        enum {
            Count = 4       // Player 0-3

        enum {
            DPAD_UP       = 0x0001,
            DPAD_DOWN = 0x0002,
            DPAD_LEFT    = 0x0004,
            DPAD_RIGHT  = 0x0008,
            START            = 0x0010,
            BACK              = 0x0020,
            LEFT_THUMB   = 0x0040,
            RIGHT_THUMB = 0x0080,
            LB                   = 0x0100,
            RB                  = 0x0200,
            A                   = 0x1000,
            B                  = 0x2000,
            X                  = 0x4000,
            Y                  = 0x8000,

        // Functions (similar to SFML API)
        static bool isConnected (t_joyNum joyNum);
        static unsigned int getButtonCount (t_joyNum joyNum) { return 14; }
        static bool isButtonPressed (t_joyNum joyNum, t_buttonNum buttonNum);

        // X360 specific functions
        static bool isAnyXBox360ControllerConnected();

        static void getTriggers (t_joyNum joyNum, float &left, float &right);
        static void getSticksPosition (t_joyNum joyNum, sf::Vector2f &left, sf::Vector2f &right);

        static void setVibration (t_joyNum, float leftMotor = 0.0f, float rightMotor = 0.0f);

}; // class

} // ns

#endif // X360_CONTROLLER_HPP

#include "X360Controller.hpp"

#ifdef __MINGW32__
    // Useless MS defines (needed to compile under MinGW)
    #define __in
    #define __out
    #define __reserved

// This define makes your program compile faster by excluding things we are not using

#include <windows.h>
#include <XInput.h>

namespace xb {

// Returns true if the joystick is connected (and is an XBox 360 Controller)
bool Joystick::isConnected (t_joyNum joyNum)

    XINPUT_STATE state;
    ZeroMemory (&state, sizeof (XINPUT_STATE));

    auto result = XInputGetState (joyNum, &state);
    return  (result == ERROR_SUCCESS);


// Convenience function: Returns true if there is at least one X360 controller connected
bool Joystick::isAnyXBox360ControllerConnected()

    return  (isConnected(0) || isConnected(1) || isConnected(2) || isConnected(3));


// Returns true if the device supports audio capabilities (headset)
// Uncomment if you need this function
bool Joystick::voiceSupported (t_joyNum joyNum)

    ZeroMemory (&caps, sizeof (XINPUT_CAPABILITIES));

    auto result = XInputGetCapabilities (joyNum, XINPUT_FLAG_GAMEPAD, &caps);

    if (result != ERROR_SUCCESS)
        return false;

    return  (caps.Flags & XINPUT_CAPS_VOICE_SUPPORTED);


// Returns true if the specified button is pressed
// Note that the triggers are NOT recognized as buttons.. You must use
// the getTriggers function for reading the triggers state
bool Joystick::isButtonPressed (t_joyNum joyNum, t_buttonNum buttonNum)

    XINPUT_STATE state;
    ZeroMemory (&state, sizeof (XINPUT_STATE));

    XInputGetState (joyNum, &state);
    return  (state.Gamepad.wButtons & buttonNum);


// This function returns nothing
// It fills the variables left and right with the current state of the triggers (LT and RT)
// The values will always be in the range 0..1
// TODO: TAKE CARE OF THE DEAD ZONE ??????????????????????????????????
void Joystick::getTriggers (t_joyNum joyNum, float &left, float &right)

    XINPUT_STATE state;
    ZeroMemory (&state, sizeof (XINPUT_STATE));

    XInputGetState (joyNum, &state);

    // Normalize and take care of the Dead Zone
    left  = static_cast <float> (state.Gamepad.bLeftTrigger)  / 255;
    right = static_cast <float> (state.Gamepad.bRightTrigger) / 255;


// This function returns nothing
// It fills the vectors left and right with the stick positions,
// wich are in the range -100..100, similar to the SFML function
// getAxisPosition
void Joystick::getSticksPosition (t_joyNum joyNum, sf::Vector2f &left, sf::Vector2f &right)

    XINPUT_STATE state;
    ZeroMemory (&state, sizeof (XINPUT_STATE));

    XInputGetState (joyNum, &state);

    // Check for the "DEAD ZONE"
    // Left Stick
    if ( (state.Gamepad.sThumbLX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE &&
              state.Gamepad.sThumbLX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) &&
             (state.Gamepad.sThumbLY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE &&
              state.Gamepad.sThumbLY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) ) {

        state.Gamepad.sThumbLX = 0;
        state.Gamepad.sThumbLY = 0;


    // Right Stick
    if ( (state.Gamepad.sThumbRX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE &&
              state.Gamepad.sThumbRX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) &&
             (state.Gamepad.sThumbRY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE &&
              state.Gamepad.sThumbRY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) ) {

        state.Gamepad.sThumbRX = 0;
        state.Gamepad.sThumbRY = 0;


    // Convert values to SFML style (-100..100)
    left.x  = static_cast <float> (state.Gamepad.sThumbLX / 327);
    left.y  = static_cast <float> (state.Gamepad.sThumbLY / 327);
    right.x = static_cast <float> (state.Gamepad.sThumbRX / 327);
    right.y = static_cast <float> (state.Gamepad.sThumbRY / 327);


// Set vibration (0.0 to 1.0)
// 0 stops the vibration
void Joystick::setVibration (t_joyNum joyNum, float leftMotor, float rightMotor)

    ZeroMemory (&vib, sizeof (XINPUT_VIBRATION));

    vib.wLeftMotorSpeed  = static_cast <WORD> (leftMotor  * 65535.0f);
    vib.wRightMotorSpeed = static_cast <WORD> (rightMotor * 65535.0f);

    XInputSetState (joyNum, &vib);


} // ns

Test (main.cpp)
#include <iostream>
using std::cout;
using std::endl;

#include <string>
#include <sstream>

#include <SFML/Graphics.hpp>

// CodeBlocks:
// Linker settings, link libraries, add "XInput" without ".lib"
#include "X360Controller.hpp"

template <class T>
std::string numberToString (const T& t) {

    std::stringstream ss;
    ss << t;

    return ss.str();


int main ()

    // If not X360 controllers found, exit
    if (!xb::Joystick::isAnyXBox360ControllerConnected()) {
        cout << "Error: XBox 360 controllers not detected!" << endl;
        return 1;

    // Create the main window
    sf::RenderWindow window (sf::VideoMode (800, 600), "XBox 360 Controller for SFML");

    // Load font
    sf::Font myFont;
    if (!myFont.loadFromFile("steelfish_rg.ttf")) {
        cout << "Error loading font file!" << endl;
        return 1;

    sf::Text buttonText ("Press any button", myFont);
    sf::Text triggerText ("", myFont);
    sf::Text stickText ("", myFont);

    triggerText.setPosition(0.0f, 50.0f);
    stickText.setPosition(0.0f, 150.0f);

    // Start the game loop
    while (window.isOpen()) {

        // Process events
        sf::Event event;

        while (window.pollEvent(event)) {

            // Close window : exit
            if (event.type == sf::Event::Closed)

        // Check for buttons
        if (xb::Joystick::isButtonPressed (0, xb::Joystick::A))
            buttonText.setString ("A");
        if (xb::Joystick::isButtonPressed (0, xb::Joystick::B))
            buttonText.setString ("B");
        if (xb::Joystick::isButtonPressed (0, xb::Joystick::X))
            buttonText.setString ("X");
        if (xb::Joystick::isButtonPressed (0, xb::Joystick::Y))
            buttonText.setString ("Y");
        if (xb::Joystick::isButtonPressed (0, xb::Joystick::LB))
            buttonText.setString ("LB");
        if (xb::Joystick::isButtonPressed (0, xb::Joystick::RB))
            buttonText.setString ("RB");

        // Check for the triggers (LT and RT)
        float lt, rt;
        xb::Joystick::getTriggers(0, lt, rt);
        triggerText.setString("Left trigger: " + numberToString(lt) + "\nRight trigger: " + numberToString(rt));

        // Triggers controls the vibration
        xb::Joystick::setVibration(0, lt, rt);

        // Get sticks positions
        sf::Vector2f ls, rs;
        xb::Joystick::getSticksPosition(0, ls, rs);
        stickText.setString("Left stick: " + numberToString(ls.x) + "," + numberToString(ls.y) +
                            "\nRight stick: " + numberToString(rs.x) + "," + numberToString(rs.y));

        // Clear screen

        // Dibujar

        // Update the window


    // Stop vibration

    return 0;

Title: Re: XBox 360 Controller support for SFML games
Post by: pdinklag on July 31, 2013, 08:44:16 am
I have never had any problems with SFML's joystick API and joystick events in combination with (wireless) XBox 360 controllers, what advantages does your API provide over it?
Title: Re: XBox 360 Controller support for SFML games
Post by: Jebbs on August 01, 2013, 10:03:25 am
I think there was a thread that was active around the same time as this was posted that mentioned how on Windows the triggers for the 360 controller don't register properly, or something like that. Using XInput fixes that issue if I remember correctly.
Title: Re: XBox 360 Controller support for SFML games
Post by: Ixrec on August 04, 2013, 09:24:10 pm
The triggers worked fine for me when I tested a wired 360 controller with my program.  Dunno if that counts.

afaik the only advantage you'd get by having this much code for a specific kind of 'joystick' would be allowing the program to say "Fire Primary Weapon is bound to Right Trigger" instead of the rather cryptic "Fire Primary Weapon is bound to negative movement along joystick axis 2".
Title: Re: XBox 360 Controller support for SFML games
Post by: Foaly on August 05, 2013, 08:10:43 am
Also this code allows you to give force feedback (vibrate), which is not possible in current SFML.
Title: Re: XBox 360 Controller support for SFML games
Post by: Ixrec on August 05, 2013, 11:34:37 am
Wow, how did I miss that.

Too bad that part's Windows-only. =(
Title: Re: XBox 360 Controller support for SFML games
Post by: mateandmetal on August 08, 2013, 12:48:06 am
Thanks for the comments!
I'm planning to implement joystick force feedback support for Linux too  8)