Plan for improved joystick support
Everything here right now is just a proposal, nothing has been decided on yet.
Contents
Two Levels Of Mapping[edit]
We need two levels of mapping. The first level of mapping is axis-order and button order. This mapping needs to be joystick-specific. it does not need to be game-specific. The second level of mapping is axis/button to keyboard scancode.
Axis and Button order[edit]
Every joystick provides 2 or more axisis and some number of buttons. It is likely that axis 0 is a good axis for horizontal movement, and it is likely that axis 1 is a good axis for vertical movement, but these are by no means certain. On joysticks with many axises the best pair of axises for movement is impossible to guess for certain. The same holds true of buttons. you can sometimes assume that buttons 0 and 1 would make good Confirm/Cancel buttons, but this is never certain.
Here is an example mapping for a simple 2-axis 6-button joystick:
[joy::Joystick Name] a0 = 0 a1 = 1 b0 = 3 b1 = 2 b2 = 1 b3 = 0 b4 = 4 b5 = 5
Mapping Buttons to keys[edit]
It should be possible to map axis changes and buttons to keyboard scancodes. Here is an example config
[joykey] a0- = Left a0+ = Right a1- = Up a1+ = Down b0 = SPACE b1 = ESC
Where to handle the mapping?[edit]
joystick-to-keyboard mapping should definitely be handled in the engine.
joystick axis and button order might make more sense to handle in the backend, especially if different backends use different strings to identify specific joytick hardware, or if the joystick already has some remapping handled by the operating system (Can't Windows/DirectX do this?)
Joysticks are snowflakes[edit]
Each model of joystick may be different. If the backends could provide the model name of a joystick, then configurations could be saved specifically for certain models. I know SDL has SDL_JoystickName() and I am guessing that DirectX probably has something similar. If these names are universal, then that is a good argument in favor of global joystick configuration. If SDL and DirectX give different names to the same joysticks, that is an argument in favor of backend-specific joystick configs.
It might even be possible to distribute a collection of default configurations for common joystick models.
Identifying joysticks by name also means that if a new joystick is detected that has never been configured before, the user can be dumped directly into the joystick configuration screen.
Backcompat With old Games[edit]
Virtually all old games were playable with joysticks (if you were lucky enough to have a joystick where axis 0 and 1 made a reasonable x and y and button 0 and 1 made a reasonable accept/cancel, and if you could stand the oversensitive buttons)
The vast majority of games will not require any special backcompat thought to make them compatible with improved joystick support
A very small number of games used plotscripted joystick input. These might be a backcompat concern... except there are so few of them. Bell of Chaos is one of them. What are the others?
- Known Games That Use Plotscripted Joystick Support
- Bell of Chaos
A config file proposal[edit]
We don't have a config file for persistent settings yet. If we decide joystick config should be global, then it ought to go into the global config file, but if the joystick config is going to be backend specific, it might be better to have separate config files (although having separate sections in the global config file for each backend would be pretty nifty too)
I would like a config file format that resembles windows INI files
[sectionname] key=value foo=bar
A possible file layout might look something like this:
[joy::Joymon6ButtonPro] a0 = 0 a1 = 1 b0 = 4 b1 = 6 b2 = 2 b3 = 1 [joy::OmegaMultiInfinibutton99] a0 = 4 a1 = 5 b0 = 12 b1 = 15 [joykeys] a0- = Left a0+ = Right a1- = Up a1+ = Down b0 = SPACE b1 = ESC [joykeys:bellchaos] a0- = Left a0+ = Right a1- = Up a1+ = Down b0 = Z b1 = X b2 = ESC
Config User-Interface[edit]
These two levels of mapping might make for a somewhat confusing user interface for joystick configuration. That is probably somewhat unavoidable. Here are a few thoughts about how to make config less painful.
ui that encourages snes-centric button mapping[edit]
I would like it if the button mapping user-interface was snes-centric. It could encourage players to map their buttons in an order resembling snes controllers.
ui that encourages modern console-centric button mapping[edit]
I haven't tested this myself, but I have read that the controllers for consoles such as PS3, Xbox360, and OUYA all map buttons and axises in the same way, and can be used almost interchangeably. These controllers are even more likely to be in use than a snes-inspired controller, so it might make sense to use a button mapping scheme that matches them by default.
joystick database[edit]
We should build a database of default configs for as many joystick models as we can, and distribute it along with the engine. We can even have instructions in the mapping user interface that explain how the user can submit their own mappings for our database.
game authors can provide default joykeys mappings for their games[edit]
A single joykeys mapping will probably be appropriate for the vast majority of all OHR games, but we can allow game authors to provide their own suggested default mapping that is included inside the RPG file. (this would also be a great way to indicate in a standardized way which special extra keys a game uses in its plotscripts)
A Different Approach[edit]
This view is different in that the engine is treated as a limited system, and the backends are viewed as emulators.
This section details how the backend/s and engine could interact with respect joystick input. The engine is tasked with everything that is abstracted from the operating system, including graphics, input, sound, and windowing. The backends' tasks include synthesizing operating system/api-specific events into an appropriate block of data the engine would be able to interpret.
Engine side[edit]
The engine should impose limits as to what is expected for input. For example, a maximum of 5 axises and 15 buttons. Each axis and each button should have a definite purpose, like a virtual joystick. This is already done with the mouse and keyboard. The engine does not provide for more than the 118 possible keys on the virtual keyboard, nor does it provide for more than 3 mouse buttons. So an imposed limitation on a virtual joystick is logical.
This will allow for focused development as to usage of joystick in editing and playing.
Joystick styles[edit]
The Atari 2600 had 1 button, 2 axises. The SNES had 8 buttons, 2 axises (calling the D-pad 2 axises for simplification). Modern system joysticks can have 15+ buttons and 5+ axises. The engine should allow the largest amount of data to be sent to it for interpretation, like 15 buttons, 5 axises. The games may be designed with a certain smaller joystick in mind. Any game that wants to take advantage of a certain type of joystick could set in plotscript (or in custom) a joystick style. One style could interpret joystick input as an Atari 2600. Another style may interpret it as the SNES. Another may be the PSX. By configuring different styles, the engine could consistently guarantee appropriate behavior.
What if the joystick does not have all the buttons/axises that the engine expects? Perhaps a fallback mechanism until a reasonable configuration, or style, is reckoned.
Backend side[edit]
The backend will function much like an emulator that synthesizes input into the virtual joystick. The backend should control how the physical joystick is configured. It can set the buttons and axises to the virtual buttons and axises that the engine expects. The backend can also report up to what level joystick styles the physical joystick actually measures up to.
Configuration files[edit]
In this approach, configuration files are only needed by the backends to remember physical to virtual mappings. A config file should store at least the following information:
id=SomeIdentifyingName maxStyle=HighestJoystickLevelSupported
The actual physical to virtual mapped keys can follow in the format virtual=physical (where virtual is some virtual id, like "axis0", and physical is some physical id, like "ID_AXIS0").
The backends should write and read the configuration files the same way. If there is worry about inconsistency, the engine could send a function pointer to read/write the file.