C++ Mac OS X Joystick Reader and Calibrator

1. Introduction

You can download a piece of source code for reading joystick axes and buttons, a sample code, and an application program for joystick calibration.  Unlike Win 32 API, in which you can read joystick axes and buttons simply by calling one function called joyGetPosEx, you have to write a relatively complex code to read joystick axes and buttons.  Also, Windows comes with a joystick calibrator which can be accessed from Control Panel.  However, as far as I searched, Mac OS X does not have a calibrator.  If the joystick vendor is nice, the joystick may come with its own calibrator.  Each application is responsible for joystick calibration otherwise.  Writing relatively complex joystick-reading function plus own joystick calibrator may be discouraging enough for those who are interested in porting a Windows program to Mac OS X.

I had the same problem, and wrote more easy-to-use joystick-reading function and my own joystick calibrator.  If you are having the same problem, you may find them useful.

The condition for using the source codes and programs available on this page is as follows: you take responsibility for any consequence of using the source codes and/or the programs available on this page, and I will not take responsibility.  If you agree with this condition, you can use the source codes available on this page in your program, modify them as necessary, and also bundle the joystick calibrator also available in this web site to your program, regardless of free or commercial, open source or proprietary.  If you do not agree this condition, please do not use anything you download from this web site.  Let me make clear one thing.  Using source code available from this page will NOT obligate you to disclose your source code.

Donations are welcome

I greatly appreciate if you can donate some money for development and contents creation for ysflight.com.  For making donation, please send some money via PayPal using the following button.

I will use the donated money for upgrading my developing environment, buying books for learning new programming techniques, maintaining and adding contents in YSFLIGHT.COM.  Thank you for your support!  

2. Download

Joystick Reader, Calibrator, and Source files (for MacOSX)

Joystick Reader, Calibrator, and Source files (for Linux)

3. Brief Explanation of the Joystick Reader

Joystick reader consists of the following three files:

  • ysjoyreader.h
  • ysjoyreader.cpp
  • ysjoyreader-objc.m

At the beginning of the program, you need to call:

YsJoyReaderSetUpJoystick

to initialize joysticks.  You define an array of YsJoyReader class, and give it to this function as well as the length of the array, which is the maximum number of joysticks that your program can support, and this function will tell you how many joysticks are detected.

Then, call:

YsJoyReaderLoadJoystickCalibrationInfo

with the number of detected joysticks and the array of YsJoyReader class as parameters.  This function will read the joystick calibration information created by the calibrator.  The file is ~/.ysjoycalib.  It is just a text file.  You can open it and see if you are interested.

YsJoyReader class has member variables:

YsJoyReaderAxis axis[YsJoyReaderMaxNumAxis];
YsJoyReaderButton button[YsJoyReaderMaxNumButton];
YsJoyReaderHatSwitch hatSwitch[YsJoyReaderMaxNumHatSwitch];

YsJoyReaderMaxNumAxis, YsJoyReaderMaxNumButton, YsJoyReaderMaxNumHatSwitch are defined in ysjoyreader.h.  Each variable has a member called "exist".  Which is non-zero if an element exists, or zero if not.  For example, you can check if the joystick has the third axis by:

if(reader.axis[2].exist!=0)
{
    // The third axis exists.
}

Use member function Read() to update the values stored in these member variables.  If you want to get calibrated value of an axis, say the first axis, you can write as:

double axis0;
axis0=reader.axis[0].GetCalibratedValue();

You will receive the calibrated value ranging from -1.0 to 1.0.  A button state can be checked as:

if(reader.button[0].value!=0)
{
    // Button is pressed!
}

State of a hat switch can be accessed by:

switch(reader.hatSwitch[0])
{
case 0: // hat switch neutral
    break;
case 1: // up
    break;
case 2: // up-right
    break;
case 3: // right
    break;
case 4: // down-right
    break;
case 5: // down
    break;
case 6: // down-left
    break;
case 7: // left
    break;
case 8: // left-up
    break;
}

I have never seen any joystick that has more than one hat switches, but if there are, it supports up to 4 hat switches.

Before your program exits, you may want to release resources assigned for the YsJoyReader objects by calling ReleaseInterface function, but it's up to you.  The operating system must be keeping track of what resource (to be more precise it is a COM interface) are assigned to what program, and as soon as the program quits, the system should be able to identify what resources can be released.

To compile this joystick reader, it requires the following frameworks:

  • IOKit
  • Foundation

If you compile your program from Xcode, you will get link errors unless you add these two frameworks in your project.

The sample code, sample.cpp, can be compiled as:

g++ sample.cpp ysjoyreader.cpp ysjoyreader-objc.m -framework IOKit -framework Foundation

The sample code is a simple console program.  If you run it, it will show joystick axes, buttons, and hat switch status once a second.

(sample.cpp)

#include <stdio.h>
#include <ysjoyreader.h>
#include <unistd.h>

const int maxNumJoystick=4;
int numJoystick;
YsJoyReader joystick[maxNumJoystick];

int main(void)
{
    YsJoyReaderSetUpJoystick(numJoystick,joystick,maxNumJoystick);
    YsJoyReaderLoadJoystickCalibrationInfo(numJoystick,joystick);

    while(1)
    {
        int i,j;
        for(i=0; i<numJoystick; i++)
        {
            joystick[i].Read();

            printf("Joy[%d]",i);
            for(j=0; j<YsJoyReaderMaxNumAxis; j++)
            {
                if(joystick[i].axis[j].exist!=0)
                {
                    printf(" Ax%d:%+5.2lf",j,joystick[i].axis[j].GetCalibratedValue());
                }
            }
            for(j=0; j<YsJoyReaderMaxNumButton; j++)
            {
                if(joystick[i].button[j].exist!=0)
                {
                    printf(" Bt%d:%d",j,joystick[i].button[j].value);
                }
            }
            for(j=0; j<YsJoyReaderMaxNumHatSwitch; j++)
            {
                if(joystick[i].hatSwitch[j].exist!=0)
                {
                    printf(" POV%d:%d",j,joystick[i].hatSwitch[j].GetDiscreteValue());
                }
            }
            printf("\n");
        }

        sleep(1);
    }

    return 0;
}

4. Joystick Calibrator

Plug your joystick before starting this joystick calibrator (YsJoystickCalibrator). If the joystick has been recognized by Mac OS X, the calibrator will show the axis conditions and button status.

Before starting the calibration, please select the type of your joystick. If it has only one stick and some buttons, select "Only One Stick/Yoke". Or, if it is a stick and a throttle lever, select "1:Stick 2:Throttle".

Then select "Calibrate" from "Calibrate (C) menu", and follow the instruction. After the calibration is done, the program will save the calibration information in .ysjscal file located in your home directory.

If you get a new joystick and if the new joystick comes with its own calibrator, you may want to delete the calibration information by selecting "Erase All Calibration Information" from "Calibrate (C) menu". Or, you can manually delete .ysjscal file in your home directory.


Screenshot of the calibrator (Click to enlarge)

[Update Information]

2015/04/03

  • Compiled with XCode 6.  Apparently the binary compiled by XCode 3 cannot run on Mac OSX Yosemite.
  • Fixed the problem that the program mistakes Microsoft Keyboard as a joystick.
  • Changed the build environment to CMake.

2010/01/27

The joystick reader now works on Mac OS 10.6.  Also, apparently the raw value from a hat switch differs from joystick to joystick.  I have added GetDiscreteValue member function that returns  0:Neutral  1:Forward  2:Forward Right  3:Right  4:Backward Right  5:Backward  6:Backward Left  7:Left  8:Forward Left.  I searched on Apple Developer Connection.  However, I was not able to find

2009/10/17

First release.