Game pad and joystick support
Dave Higton (1515) 3404 posts |
Prompted by the thread “(Soon to be) New RISC OS Pi user with many questions, mostly about games” in Community Support, I have to ask what support there is for USB game pads and joysticks in RISC OS. And, if there is not enough, how should it be added? In the existing HID drivers, or in (a) separate class driver(s)? |
Jeffrey Lee (213) 6046 posts |
No builtin support, but perhaps some third-party support.
The Joystick module has been the traditional way of allowing programs to interact with gamepads/joysticks, so we should probably stick to using that in some shape or form. I’m not quite sure where things would fit with USB though – i.e. whether it would be easier to implement the code within USBDriver or within the Joystick module. One thing that’s probably worth considering is changing the Joystick module so that it’s just a middleman which sends all its SWIs over a vector (“JoystickV”). That way joysticks from multiple interface types could peacefully coexist – USB joysticks, the builtin gamepad on the Pandora, third-party serial/parallel port solutions, homebrew stuff people knock up using the GPIO header on a Raspberry Pi/Beagleboard, Bluetooth, etc. |
Richard Walker (2090) 416 posts |
I have been thinking about this. All the recent discussion re. USB and the provision of Acorn’s (too late!) joystick API make it an interesting join-the-dots. But I know I will never have time to start anything! It would be cute if any developments could also provide compatibility with the popular 3rd party APIs (RTFM and SP/VTi). I think there may even have been some software back in the day which did this. Joymaster? |
Jon Abbott (1421) 2599 posts |
I plan on shimming all three joystick API modules to a USB Joystick Module in a similar way to how we shimmed Tracker modules to QTM. I just need someone with USB knowledge that can code the USB Joystick Module. The XB360 wired controller was my first thought, as they’re cheap and quite a few people already have them to hand. Anyone interested?
Sounds like a good idea. |
Dave Higton (1515) 3404 posts |
Yes, but with some limitations. I don’t know how to get USB devices to be read repetitively by a system process (as distinct from a user application). If I’m going to contribute, I’m going to need some help from a pretty basic level. I don’t know how to generalise to all game controllers and joysticks either. There’s another problem: game controllers are HIDs, so there may be some unwanted interaction with the existing keyboard/mouse drivers. Many years ago I built myself a joystick podule with its drivers in EPROM, so I’m reasonably familiar with the Joystick module – at least, I will be when I’ve re-read it :-) |
Jeffrey Lee (213) 6046 posts |
As they’re HID devices I’m assuming they’ll be 99% driven using USB interrupt transfers. So you just need to open the pipe and start it running and then read and cache any values as they come in, so that the Joystick SWIs can return the data the next time they’re called. Doing this in USBDriver would be easy (just copy the code that’s used for keyboard/mouse), but as an external module it would be a bit trickier due to the lack of explicit transfers/callbacks in the DeviceFS interface. Perhaps look at the EtherUSB sources, I suspect there’ll be some examples of dealing with interrupt transfers in there and using DeviceFS buffer fill callbacks/events to read data out of the stream as it arrives.
It wouldn’t surprise me if a USB joystick module would have to rely on a set of per-device mapping files to give details of all the controls. The most important thing would be the names of the buttons, for display to the user, but also other information might be needed e.g. which buttons should map to which controls in the legacy Joystick APIs, or the default “use” of the button (OK, cancel, start, select, etc). Potentially even have a sprite file containing icons for all the buttons. Other information (e.g. whether a button is analogue or digital, whether it’s a joystick or thumb stick, axis of movement, etc.) can hopefully be read via the HID descriptors. Of course to start with you should just aim to get something compatible with Acorn’s Joystick API and then add new features (extra buttons, button names, rumble, accelerometers, etc.) later on. |
Tank (53) 373 posts |
Paradise added extra functionality to the Joystick SWI’s for their Parallel Port – PSX interface. |
Jon Abbott (1421) 2599 posts |
I think Jeffrey’s idea of a vector for Joysticks is a good one, leaving the OS Joystick Module to effectively be a veneer to specific Joystick Modules. Generic/Specific HID Joystick modules could then be coded to register themselves on the Vector and I can code shim modules to allow the VotI, RTFM interfaces to work for existing games. I’ll have a chat with Nathan to see if the VotI module source is available, if not I’ll reverse engineer it. I did recently 32 bit the JoyMod module that comes with Krisalis titles, in preparation for Joystick support. That has profiles for keyboard only games to work with Joysticks so can now be easily extended to support more games, I was going to go back to it and add a means to add profiles at runtime, so it’s future proofed. I’m willing to put a bounty forward to make this happen, should the need arise. |
Michael Drake (88) 335 posts |
HID had support for USB Joysticks. http://www.xat.nl/en/riscos/sw/usb/hid/index.htm I’m not sure what the status of HID is now. I don’t think it’s actively developed. |
Jon Abbott (1421) 2599 posts |
That looks like it already does the job, only problem being its shareware and as such no good for an open source project. Might be worth testing though, if it does work I can have a chat with the developers about open sourcing it. |
Holger Palmroth (487) 115 posts |
While I got xat’s HID to work my BeagleBoard, I didn’t had any luck on the Raspberry Pi. |
Alan Buckley (167) 232 posts |
Many years ago I tried the Joystick support that came with HID and it didn’t work for me. I reported the problems at the time, but they didn’t get fixed. However my Joystick was running through a parallel to USB converter to my Iyonix so that may have been a factor. I can’t remember the exact details of what was wrong, but I believe it read the values, but kept getting them wrong or changing them by a large amount even when the joystick was still. If anyone manages to provide a new USB joystick module, I’ll dig my joystick out of a drawer and try it again. And if we get a native copy of ArcElite, with USB Joystick support that runs on a Raspberry PI that would be fantastic! |
Dave Higton (1515) 3404 posts |
I did some experiments in 2010 on a Trust GM-1300 game pad, and I looked again last night. The GM-1300 is seriously rubbish. The two thumb controllers have minimum values in the region of 0×1C, maximum values in the region of 0×80, and middle vales (i.e. fingers off the stick) well off halfway between minimum and maximum. The mechanical gate is circular. If you push the stick away and to the left, neither the X nor Y values get anywhere near the minimum values for left-only or down-only, which suggests that the mechanical gate is the inscribed circle of the electrical gate. Here’s a naive question: do you expect the Y value from a joystick to increase as you pull the stick towards or away from you? If you have multiple gamepads, each of which has more than one X-Y controller, how is the joystick number chosen? Is this a function of the application programme? |
Jeffrey Lee (213) 6046 posts |
The Joystick docs say that negative Y = down. And presumably “down” = “towards you” when using a joystick, as that mapping makes the most sense when you consider the API needs to cope with D-pads and thumbsticks (joysticks are a bit vague as “down” could be interpreted as “push the stick away from you to pitch the aircraft down”). I can probably dig up some source code to verify this interpretation, unless someone has an A3010 and joystick handy to test with.
I’d expect the legacy Joystick API to only read from one of the thumbsticks (whatever you deem to be the “primary” one, usually the left one if there are a bunch of action buttons on the right). But for a new and improved version 2 Joystick API I’d expect us to be able to access all inputs/sensors of a particular controller via one controller ID. |
Dave Higton (1515) 3404 posts |
Really? Why wouldn’t they be simply numbered 1 and 2, 3 and 4, etc.? And the question of how the selection is made still stands – is this done in the application programme? i.e. numerous joysticks exist, and the apps provide a means of mapping them to each player – or leaving them umpapped? (Otherwise what – I don’t know. I’m not a games player!) |
Jeffrey Lee (213) 6046 posts |
Ah, looks like I misread things a bit, and thought you were talking about just having one controller connected. OK then, let’s say you have two controllers connected. One is a simple joystick with one X-Y stick and one action button. The other is a modern gamepad with two X-Y thumbsticks, D-pad, 12 action buttons (some of which will be a mix of analogue and digital), and a bunch of other hypothetical gizmos (accelerometers, touch pads, rumble, smellovision, etc.) As each controller is detected by the system, the USB joystick module will make a call to the new vectored Joystick module to request a joystick ID. For simplicity the joystick module will return the lowest ID which is currently free, so we’ll say that the old joystick is given ID 0 and the new gamepad is given ID 1. The old joystick is nice and simple to handle as it exactly matches the capabilities of the Joystick_Read SWI. So the status of the stick will be returned in bits 0-15 and the action button in bit 16. The new gamepad is a bit trickier as it has capabilities far beyond what Joystick_Read is capable of. Assuming a fairly standard design with most of the action buttons on the right of the controller, you’d probably want to return the state of the left thumbstick (or maybe the combined state of the thumbstick and D-pad?) in bits 0-15. And then pick the 8 most useful action buttons (e.g. A, B, X, Y, start, select, and two shoulder buttons) and return them in bits 16-23, as digital values only. All other features of the controller will be ignored, at least until we start implementing a “version 2” joystick API. If the user is finished with their joystick and unplugs it, ID 0 will become free again, so the next controller which gets plugged in will claim that ID.
Ignore the fact that the Joystick_Read docs say that “R0 = joystick number”. Really what it should say is that “R0 = ID of physical controller intended to be held and operated by a single person at once”. A gamepad with two thumbsticks, even though those thumbsticks could be classified as joysticks, is only designed to be operated by one person at once. Therefore it should only be given one ID for use in R0 of Joystick_Read.
Yes, it’s the role of the application to map joystick IDs to players. Multiplayer games will usually have a screen where players can choose what controls they use. Sometimes this is an explicit choice (a “master controller” such as the keyboard or mouse being used to select which controller other players are using) or an implicit choice (e.g. pressing a button on a controller will automatically add that controller to the game as a new player) One major failing of the original Joystick API is that there’s no way of finding out how many controllers are connected/supported. So a lot of old software which was designed around the A3010 Joystick module will assume that there are only two joystick ports. That will obviously cause issues if people connect three or more controllers and then expect certain ones to be available in an old game. |
Jon Abbott (1421) 2599 posts |
Are we going to define a v2 Joystick API? In which case we can pretty much start from scratch and define an API that supports multiple Joysticks, any type of physical devices and keyboard / mouse mapping. As for backward compatibility, as we’re dealing with multiple vendor API’s and a legacy Acorn Joystick API, I suggest we shim them to the new API and forget about direct backward compatibility. I suppose we could include the shim modules in RISCOS or include support for the Acorn API, but as the games are all 26bit code (with the exception of Zool and TwinWorld), there’s probably little point – I can bundle the shims with ADFFS and have the game boot scripts load the appropriate shim module. |
Dave Higton (1515) 3404 posts |
With USB devices, we have the perennial problem that they can come and go. If someone plugs in two 2-thumbstick controllers, it would be possible to number them as (1 and 2), and (3 and 4). If someone unplugs 1 and 2, the controller at 3 and 4 should continue to respond to 3 and 4 – otherwise apps would get mightily confused. It seems to me that a minimum requirement is a SWI to enumerate devices – in the example above, they can’t be assumed to exist in a contiguous range from 1 (or 0, whichever base it is). But a 2-stick controller is not the same as two 1-stick controllers, so there has to be a concept of grouping, doesn’t there? |
Jeffrey Lee (213) 6046 posts |
Ignore the fact that the Joystick_Read docs say that “R0 = joystick number”. Really what it should say is that “R0 = ID of physical controller intended to be held and operated by a single person at once”. That’s the rule which every game ever written for the Acorn Joystick API has followed. I’d assume the third-party Joystick APIs would operate in a similar way. The “concept of grouping” is something that can come in the version 2 API. E.g. a Joystick_ReadStick SWI that accepts a controller number (0 … number of players) and a stick number (0 … number of sticks on controller). |
Jeffrey Lee (213) 6046 posts |
Code digging complete, negative Y = down = towards you. |
Dave Higton (1515) 3404 posts |
Thank you, Jeffrey. The GM-1300 has Y increasing as I pull the stick towards me. |
Jon Abbott (1421) 2599 posts |
Any API we come up with needs to allow the user to set X / Y inversion. |
Jeffrey Lee (213) 6046 posts |
That’s traditionally handled by the game/software itself, as whether inversion is required will generally be context-specific. E.g. in an FPS game you’d generally want the in-game Y axis inversion to be configurable, but if the game allows the stick to be used to navigate the menus then you’d generally want it using a fixed scheme. (Not that anyone should ever use anything other than keyboard and mouse to play an FPS, of course ;-)) |
Dave Higton (1515) 3404 posts |
That’s what I thought, too. |
Jon Abbott (1421) 2599 posts |
Personally I’d make all that kind of configuration software configurable outside of the game, as 1. You’re assuming the game has configuration options and 2. That all future hardware obeys the same rules as legacy hardware. It’s 5 secs of coding to add a * command to support it, so why not include it? Bare in mind 99.9% of games on RISC OS are legacy, so can’t be changed to match an API, the API/shim need to fit around the games. |