I started running Backworlds on a Surface Pro recently in order to determine how much work it would be to port the game to tablets – rather than the porting itself, the big challenges are how we change the controls to feel good on a tablet. The Surface Pro is practically a laptop running Windows 8 which meant I could immediately run the game, which was nice.
Since both of the Surface models come with a pressure-sensitive stylus this also gave me an excuse to connect this to the drawing – so if you are playing the game with a digital drawing tablet or display it would be more responsive. Implementing pressure-sensitivity with SDL in Windows wasn’t a straightforward affair though, so I thought I’d collect some of the things I learned in this post.
First things first – if you can get away with supporting only Wacom hardware, I would recommend simply implementing the Wacom SDK. It is very easy to use, I was up and running in less than an hour after just copying the code from their examples. I did have to remove the windows event queue integration and polled the events manually with WTPacketsGet, a similar structure to how SDL events are handled. Other than that, the only code I changed was to remove X,Y – coordinates from the packet data (as SDL gives us mouse position) and add PK_STATUS to determine if the eraser was used.
If you need to support more than just Wacom tablets, there are a few different interfaces. After looking around MSDN for a few hours I came upon some examples in the Windows SDK, most importantly an example using the RealTimeStylus (RTS) interface. This is not as straightforward as the Wacom API, but it is more versatile and has the added benefit of supporting multi-touch. The following demo will illustrate the basics of our RTS/SDL code:
Essentially, the RTS interface involves creating a stylus object and tying that to a custom stylus plugin class that you create and override relevant functions in. The plugin class will then receive alerts when certain events (such as stylus up/down/move) occur and send you the event information (such as coordinates and pressure) in a sequence of unsigned integers. The Windows SDK example connects a renderer directly to the stylus interface but it was possible to remove the references to the render code and extract the pressure data manually.
The RTS stylus registers input for different tablet contexts depending on how you interact with it – with the Surface Pro it got three contexts, one for the pen, one for the touchpad and one if you were using your fingers on the screen. By using the stylus object, we can query the packet data format of each tablet context using GetPacketDescriptionData and figure out if there is any pressure data, where in the packet it is and what the max and min values are. Note that the stylus must be enabled before the packet description can be queried. We can then override the Packets function in the stylus plugin and use that knowledge to extract the pressure data from the packets we get (all of this is included in the example file).
We also need to connect the RTS object to a window – SDL can be told to pass through window messages by calling SDL_EventState, these can in turn give us a window handle that we can use to initialize the RTS. Be careful though, while SDL does pass through a WM_CREATE message it is not for the main window you are creating so if you pass that window handle to RTS creation it will fail. I opted to go for a lazy initalization routine with the WM_SETFOCUS messages instead and it worked fine, but there may be better ways.
This is an example showing the game running on a Surface Pro with touch controls and pressure sensitivity. Touch controls are nowhere near as good as real buttons/keys in terms of both latency and feedback so moving forward we will have to come up with more tablet-friendly ways of controlling the game without breaking it. If we do decide to do more work on that, I will write more about it at that time.