Did you know that you can program your X52 Pro Joystick in C/C++? I finally figured out how the SDK works and I want to share it with you.
If you want to see a working program making use of this SDK, check out my Post:
https://forums.frontier.co.uk/showt...face-amp-X52-Pro-integration-with-Journal-API
If you prefer a video tutorial, you can watch this:
[video=youtube_share;m2rc7zAOR7w]https://youtu.be/m2rc7zAOR7w[/video]
So, now how to use the DirectOutput SDK.
First you will need the DirectOutput.dll and the DirectOutput.h files. For comfort I also created a .lib file. You can download all this here:
https://1drv.ms/u/s!Aq8Kg0iqxkdrgfxXZBc5CL-a9-SAaQ
Now create an empty C/C++ project in Visual Studio. Go to
Project > [Project Name] Properties > C/C++ > General
Make sure you are on All Configurations and x64
Then add the include folder that you downloaded into the Additional Include Directories
Then Go to
Linker > General
Add the lib folder to Additional Library Directories.
Finally go to Linker > Input
And add DirectOutput.lib; to Additional Dependencies
When you use C++ for programming you have to write
In order for it to work, as the SDK is written in pure C.
Then create a new const wchar_t * and assign it the name of your app, for example
With this you can call
In order to initialize the SDK.
You will then have to create two functions which will act as callback functions when a new device is added. They will look something like this:
In both these functions you are getting a void * hDevice. You will have to use this later in order to set the LEDs. To save these values, create a new global vector<void*>.
With that you can call in both callback functions [vector_name].push_back(hDevice), so that you will get these functions:
Notice the if statement in the first function, there is another bool indicating wether the device is added or removed.
Now that we have these two callback functions, we can pass them to the DirectOutput SDK by calling
With that, we completed the initialization of the SDK, and now we can go on to the good stuff.
The whole system work with a page system, so we will also have to add a new page:
The Debug Name has no real purpose fo us, so set it to anything you want. the DWORD for the page however will be needed for further calls on this page (setting LEDs and so on).
With FLAG_SET_AS_ACTIVE we are setting the new page as active page.
Now, first let's take a look at the LEDs.
Most buttons consists of two components, a red and a green one. Here you are controlling every LED as a individual LED. Here are all IDs ready to be copied into your project:
You can also turn on or off each LED by setting its state either to 1 or 0.
So, when we for example want to make our Fire A button yellow, we call:
As you can see, the function gets four parameters. Device, page, led, state.
At this point, you now can compile your program and watch the LED change its color (don't forget that the program will close immediatley, so without stopping the program at the end, you will see nothing) Tip:
Use this so that your program stays open until you put in a number and press enter
The MFD works in a very similar way. First create a const wchar_t * with the text you want to show.
Notice that the MFD has three lines with 16 characters each. however you can put in longer text, it will then scroll through the display.
You will also have to pass in the length of your text (And of course device and page)
So the full call will look like this:
In a similar style to how we created the callbacks above, we also can create callbacks for the so called soft buttons on the device, which basically is the right scrolling wheel, but I haven't used it so far.
My whole sample code now looks like this:
This is it! I hope I could help you out with that tutorial and happy coding!
If you have any further questions or need help, feel free to ask me for help!
If you want to see a working program making use of this SDK, check out my Post:
https://forums.frontier.co.uk/showt...face-amp-X52-Pro-integration-with-Journal-API
If you prefer a video tutorial, you can watch this:
[video=youtube_share;m2rc7zAOR7w]https://youtu.be/m2rc7zAOR7w[/video]
So, now how to use the DirectOutput SDK.
First you will need the DirectOutput.dll and the DirectOutput.h files. For comfort I also created a .lib file. You can download all this here:
https://1drv.ms/u/s!Aq8Kg0iqxkdrgfxXZBc5CL-a9-SAaQ
Now create an empty C/C++ project in Visual Studio. Go to
Project > [Project Name] Properties > C/C++ > General
Make sure you are on All Configurations and x64
Then add the include folder that you downloaded into the Additional Include Directories
Then Go to
Linker > General
Add the lib folder to Additional Library Directories.
Finally go to Linker > Input
And add DirectOutput.lib; to Additional Dependencies
When you use C++ for programming you have to write
Code:
extern "C" {
#include "DirectOutput.h"
}
Then create a new const wchar_t * and assign it the name of your app, for example
Code:
const wchar_t * name = L"TestApp";
With this you can call
Code:
DirectOutput_Initialize(name);
You will then have to create two functions which will act as callback functions when a new device is added. They will look something like this:
Code:
void __stdcall DirectOutput_Device_Callback(void* hDevice, bool bAdded, void* pvContext) {}
Code:
void __stdcall DirectOutput_Enumerate_Callback(void* hDevice, void* pvContext) {}
In both these functions you are getting a void * hDevice. You will have to use this later in order to set the LEDs. To save these values, create a new global vector<void*>.
With that you can call in both callback functions [vector_name].push_back(hDevice), so that you will get these functions:
Code:
void __stdcall DirectOutput_Device_Callback(void* hDevice, bool bAdded, void* pvContext) {
if (bAdded) {
devices.push_back(hDevice);
}
else {
}
}
void __stdcall DirectOutput_Enumerate_Callback(void* hDevice, void* pvContext) {
devices.push_back(hDevice);
}
Now that we have these two callback functions, we can pass them to the DirectOutput SDK by calling
Code:
DirectOutput_RegisterDeviceCallback(*DirectOutput_Device_Callback, nullptr);
DirectOutput_Enumerate(*DirectOutput_Enumerate_Callback, nullptr);
With that, we completed the initialization of the SDK, and now we can go on to the good stuff.
The whole system work with a page system, so we will also have to add a new page:
Code:
DWORD dwPage = 1;
const wchar_t * pageDebugName = L"TestPage";
DirectOutput_AddPage(devices[0], dwPage, pageDebugName, FLAG_SET_AS_ACTIVE);
With FLAG_SET_AS_ACTIVE we are setting the new page as active page.
Now, first let's take a look at the LEDs.
Most buttons consists of two components, a red and a green one. Here you are controlling every LED as a individual LED. Here are all IDs ready to be copied into your project:
Code:
DWORD LED_FIRE = 0;
DWORD LED_FIRE_A_RED = 1;
DWORD LED_FIRE_A_GREEN = 2;
DWORD LED_FIRE_B_RED = 3;
DWORD LED_FIRE_B_GREEN = 4;
DWORD LED_FIRE_D_RED = 5;
DWORD LED_FIRE_D_GREEN = 6;
DWORD LED_FIRE_E_RED = 7;
DWORD LED_FIRE_E_GREEN = 8;
DWORD LED_TOGGLE_1_2_RED = 9;
DWORD LED_TOGGLE_1_2_GREEN = 10;
DWORD LED_TOGGLE_3_4_RED = 11;
DWORD LED_TOGGLE_3_4_GREEN = 12;
DWORD LED_TOGGLE_5_6_RED = 13;
DWORD LED_TOGGLE_5_6_GREEN = 14;
DWORD LED_POV_2_RED = 15;
DWORD LED_POV_2_GREEN = 16;
DWORD LED_CLUTCH_RED = 17;
DWORD LED_CLUTCH_GREEN = 18;
DWORD LED_THROTTLE = 19;
You can also turn on or off each LED by setting its state either to 1 or 0.
So, when we for example want to make our Fire A button yellow, we call:
Code:
DirectOutput_SetLed(devices[0], dwPage, LED_FIRE_A_RED, 1);
DirectOutput_SetLed(devices[0], dwPage, LED_FIRE_A_GREEN, 1);
As you can see, the function gets four parameters. Device, page, led, state.
At this point, you now can compile your program and watch the LED change its color (don't forget that the program will close immediatley, so without stopping the program at the end, you will see nothing) Tip:
Code:
int x;
std::cin >> x;
The MFD works in a very similar way. First create a const wchar_t * with the text you want to show.
Notice that the MFD has three lines with 16 characters each. however you can put in longer text, it will then scroll through the display.
Code:
DWORD MFD_STRING_TOP = 0;
DWORD MFD_STRING_MIDDLE = 1;
DWORD MFD_STRING_BOTTOM = 2;
You will also have to pass in the length of your text (And of course device and page)
So the full call will look like this:
Code:
const wchar_t * text = L"Test App";
DWORD textLength = 8;
DirectOutput_SetString(devices[0], dwPage, MFD_STRING_MIDDLE, textLength, text);
In a similar style to how we created the callbacks above, we also can create callbacks for the so called soft buttons on the device, which basically is the right scrolling wheel, but I haven't used it so far.
My whole sample code now looks like this:
Code:
extern "C" {
#include "DirectOutput.h"
}
#include <vector>
#include <iostream>
DWORD LED_FIRE = 0;
DWORD LED_FIRE_A_RED = 1;
DWORD LED_FIRE_A_GREEN = 2;
DWORD LED_FIRE_B_RED = 3;
DWORD LED_FIRE_B_GREEN = 4;
DWORD LED_FIRE_D_RED = 5;
DWORD LED_FIRE_D_GREEN = 6;
DWORD LED_FIRE_E_RED = 7;
DWORD LED_FIRE_E_GREEN = 8;
DWORD LED_TOGGLE_1_2_RED = 9;
DWORD LED_TOGGLE_1_2_GREEN = 10;
DWORD LED_TOGGLE_3_4_RED = 11;
DWORD LED_TOGGLE_3_4_GREEN = 12;
DWORD LED_TOGGLE_5_6_RED = 13;
DWORD LED_TOGGLE_5_6_GREEN = 14;
DWORD LED_POV_2_RED = 15;
DWORD LED_POV_2_GREEN = 16;
DWORD LED_CLUTCH_RED = 17;
DWORD LED_CLUTCH_GREEN = 18;
DWORD LED_THROTTLE = 19;
DWORD MFD_STRING_TOP = 0;
DWORD MFD_STRING_MIDDLE = 1;
DWORD MFD_STRING_BOTTOM = 2;
std::vector<void*> devices;
void __stdcall DirectOutput_Device_Callback(void* hDevice, bool bAdded, void* pvContext) {
if (bAdded) {
devices.push_back(hDevice);
}
else {
}
}
void __stdcall DirectOutput_Enumerate_Callback(void* hDevice, void* pvContext) {
devices.push_back(hDevice);
}
int main()
{
const wchar_t * name = L"TestApp";
DirectOutput_Initialize(name);
DirectOutput_RegisterDeviceCallback(*DirectOutput_Device_Callback, nullptr);
DirectOutput_Enumerate(*DirectOutput_Enumerate_Callback, nullptr);
DWORD dwPage = 1;
const wchar_t * pageDebugName = L"TestPage";
DirectOutput_AddPage(devices[0], dwPage, pageDebugName, FLAG_SET_AS_ACTIVE);
DirectOutput_SetLed(devices[0], dwPage, LED_FIRE_A_RED, 1);
DirectOutput_SetLed(devices[0], dwPage, LED_FIRE_A_GREEN, 1);
const wchar_t * value = L"Test App";
DirectOutput_SetString(devices[0], dwPage, 1, 8, value);
int x;
std::cin >> x;
DirectOutput_Deinitialize();
return 0;
}
This is it! I hope I could help you out with that tutorial and happy coding!
If you have any further questions or need help, feel free to ask me for help!