Backstory

Feel free to jump to the technical details if you hate stories (you monster).

I’ve always been somewhat interested in racing games. However, the barrier to entry can be pretty high. Racing wheels start at about $120 CAD plus another $60 for a game. I was interested, but not $200 interested.

The past year, my sister introduced me to Amazon return auctions. Auctioneers buy pallets from Amazon full of returned items (which they would otherwise have just tossed away) and auction them off for a decent deal. It’s a nice feeling to be able to hunt for bargains and at the same time reduce harm to the environment.

This time around, there was a Thrustmaster Ferrari 458 Spider Edition listed as one of the lots. Brand new! I was able to win it for a fantastic price, along with a shiny new air fryer and some fancy LED lights. Sweet haul.

Later on during the week, my sister dropped off the haul (thanks, sis!), and I was excited to play with my new toys.

Well you probably see where this is going, or there would be no blog post.
Ferrari 458 Spider Edition

Well you probably see where this is going, or there would be no blog post.

I plugged the racing into my PC, ready to race. I booted up Forza Horizon 4 AAAAAND…

Nothing. The wheel wouldn’t steer. The buttons didn’t work. The acceleration and breaks didn’t do anything. I thought this was PC compatible! Alas, there would be no racing 😢. Tragic day.

Bewildered, I started googling for more details.

On the Thrustmaster support page, it says that the same wheel is not supported on PC:

The Ferrari 458 Spider RW is an Xbox One compliant racing wheel.
It is not supported by Windows platforms, and there are no drivers for it to work on Windows.

False advertisement from Best Buy. Thanks for nothing 😡.

Over the next ten minutes, I rapidly went through the five stages of grief. This sucked! All of my other auction winnings were great. I even researched this wheel, and Best Buy said it was compatible with PC! This one stuck out like a sore thumb. Would I have to sell this steering wheel and buy a new one? Ugh, so much work.

But enough grieving. It was time to act. I wasn’t about to admit defeat. I can accept that there are no drivers on PC… yet.

So, like a completely normal and rational person, I decided that the optimal course of action would be to write a driver for this racing wheel rather than just buying a compatible one. It’s the best use of my time, trust me. I’m totally not being stubborn, right?!

Speaking of positive traits, being the lazy efficient person I am, I knew that the first thing to do when approaching a problem is to find someone else’s solution. After all, “Knowledge is power, France is bacon.”

Back to googling.

The Research

After some searching, I landed upon https://linustechtips.com/topic/576104-how-to-use-thrustmaster-ferrari-458-spyder-steering-wheel-on-pc/. Here, a user named Endend linked to a driver for the Xbox One controller, which supposedly works for the wheel.

I installed it and tested it out. All the buttons worked. Sadly, the steering wheel and the pedals did not. The Windows device manager still showed the wheel as a generic device:

image-20220310002410759

However, scrolling a bit further down in the thread, I found this curiosity:

2020-09-26.thumb.png.ae767536c3ce3a502cd0815bb57ef3f9.png

It looks like this person’s copy of Forza Horizon 4 was able to detect the wheel, and what’s more, it was fully working. How is this possible?

As it turns out, Microsoft games support this racing wheel natively. I had Forza Horizon 4 on Steam, but for whatever reason, that did not work. So I signed up for the $1 trial of Xbox game pass and installed Forza Horizon 5 from the Xbox store:

image-20220310002251996

It works, but how?

As it turns out, Xbox One games can be written using the Universal Windows Platform. Digging into the game programming section, I found specific support for racing wheel and force feedback through an API called Windows.Gaming.Input. The cool thing is that this is also available on Windows.

However, games had to specifically use this API to interact with my racing wheel, and pretty much the only ones that do that are the ones on the Xbox Store and not on Steam.

Technical Details

The Thrustmaster Ferrari 458 Spider doesn’t work on PC for anything other than the Xbox store.

I, however, endeavored to change that. So I did a bunch of research and learned about all the different ways that games could support controllers.

What do games use for controller (and racing wheel) support?

  • DirectInput. A super old interface to communicate and process data from hardware devices. This is not very commonly used as a lot of heavy lifting is required on the game developer’s part to implement device support.
  • XInput. The more modern (but still quite old) way of doing it. This was designed specifically for Xbox 360 controllers, so all the buttons correspond to those on an Xbox 360 controller.
  • Windows.Gaming.Input. This is the most modern one that I just found out about. Most games don’t use this as it comes with a nasty limitation: the game window must be focused to interact with any controllers, and it’s only supported in Windows 10 or newer, and definitely not Linux or macOS.
  • There’s also Steam Input. This is Valve’s way of trying to unify all of these APIs. It works by intercepting the above APIs that games may use and adding a custom layer. This allows Steam to support cool features, like custom controller mappings (so you can change what buttons correspond to what actions, especially helpful for non-Xbox controllers like the PS5 controller) and remote play - using a controller over the internet, so you can play multiplayer games with your friends, or stream to your TV and play from your sofa. Sadly, this doesn’t work with racing wheels, as it’s only meant for controllers.

So now I had a plan. I would write my own version of XInput, which would translate all of the game’s requests to use the new Windows.Gaming.Input API.

The approach was this:

  • Convert the RacingWheelReading.Wheel reading from an angle to the left and right joystick movements on an Xbox 360 controller
  • Translate the acceleration and brake pedals to L and R triggers
  • Map the rest of the buttons to Xbox 360 controls
  • Replace the game’s version of the XInput library to use my translation layer

This required me to get familiar with the XInput API. Luckily, it’s pretty simple and consists only of a few functions.

Perhaps even luckier, someone else had attempted a translation layer from XInput to Windows.Gaming.Input. However, this was for adding force feedback support for the triggers to the Xbox One controller.

Now to adapt that to racing wheel support. I found that this driver uses the XInput subtype of XINPUT_DEVSUBTYPE_GAMEPAD. Since I was implementing a racing wheel, I used XINPUT_DEVSUBTYPE_WHEEL. Microsoft had some extremely helpful documentation here for how to do the proper mappings:

Racing wheel controller. Left Stick X reports the wheel rotation, Right Trigger is the acceleration pedal, and Left Trigger is the brake pedal. Includes Directional Pad and most standard buttons (A, B, X, Y, START, BACK, LB, RB). LSB and RSB are optional.

Perfect. So now, let’s glue it all together. Here’s the snippet of code that takes the wheel rotation and translates it into the left stick’s X value:

		pState->Gamepad.sThumbLX = (state.Wheel >= 0) ?
            state.Wheel * 32767 : state.Wheel * 32768;

And for the acceleration and breaks:

		pState->Gamepad.bRightTrigger = state.Throttle * 255;
		pState->Gamepad.bLeftTrigger = state.Brake * 255;

The rest was just a matter of trial and error to figure out which buttons corresponded to which.

I replaced my Steam version of Forza Horizon 4’s with my custom XInput1_3.dll and booted the game up. I’m happy to report that it all worked perfectly!

As a bonus, I also downloaded the Euro Truck Simulator 2 Demo on Steam and tested it there. They’re using XInput 1.4, but luckily it worked even though I just renamed my wrapper to XInput1_4.dll.

The Result


I cut the video at an awkward time because I’m a terrible driver, and I crashed my car immediately afterward. Also, you should never hold a phone and film while driving. Also, my cat distracted me.

I’ve made the source code available for my project on GitHub. It still needs some cleanup, but there’s enough to get everything going. You’ll have to compile it for yourself, though.

I’m not sure what I’ll write up next, but I have a huge backlog, so worry not, dear reader; there will be plenty more content to come.

Maybe next time, I’ll write up how I got Hexic HD (an Xbox One only game) working on the PC without an emulator. It’s a weird coincidence that these projects are Xbox-related.

Closing

My goal with this blog is to practice communicating in a concise, lighthearted, and engaging way while remaining technical. How’d I do? If you have some suggestions on improving my writing, I’d greatly appreciate it. At any rate, thanks for stopping by.

Bye for now! 👋