Joymappings
For a long time the SDL port has had a joystick mappings file. There are 2 sample ones: data/C64/sdl_joymap_thec64.vjm and data/C64/sdl_joymap_ps3.vjm.
These files contain associations between host joystick actions and emulator actions. Possible actions include a corresponding emulated joystick action, a shortcut to an emulator menu action etc.
The file name has the form {sdl,gtk3,headless}-joymap-{C64,C64SC,...}.vjm. Its format is documented in a comment in the sample file itself.
In order to port the feature to the generic code, the event UI_FUNCTION (shortcuts to menu actions) got lost, but it has since been reimplemented. For SDL, it is implemented in a very SDL-specific way. GTK3, instead, uses the new uiactions.[ch], that is cross-platform.
Roadmap
Milestone 1
First the SDL port needs to be "modernized" and use the generic code.
- DONE: generic hotkey parser
move the gtk3/hotkeys.{c,h} files into shared/ and use the same syntax (.vhk) files for SDL
- DONE: make SDL port use the common numeric menu ids for hotkeys
- DONE: make SDL port use the common numeric menu ids for joystick buttons
- DONE: update joystick mapping code to use UI actions and load and save these from/to .vjm file
After this, the SDL port should have fully functional UI, Menu actions can be mapped to Joysticks, Joysticks can be mapped, regular (C64) keys can be mapped, and the controller mappings saved/restored from .vjm files
Milestone 2
Now we need to make the GTK3 port use the generic joystick mapping code, and make .vjm files work
- TODO: load and save the menu actions to .vjm file
The GTK3 port can load/save .vjm files. Joysticks and Menu actions can be mapped via .vjm files. Existing Joystick mapping UI should still function (for the directions)
At this point we can make a release, so people can test the new code. (We'll include a couple mapping files for common controllers)
Milestone 3
The last step will be making a GUI to create the Joystick and Menu action mappings in the GTK3 port
- TODO: make GUI to assign menu actions and joystick directions/buttons to gamecontroller
After this both SDL and GTK3 UIs should have fully functional UIs
Milestone 4
We really want some more modern features. These are mostly independent from the Joystick mapping itself though, so they are listed here. It might make sense to actually implement those separately.
TODO: instead of simply listing controllers by number, we should use a UUID to construct unique resource namesCannot be implemented, best we can do is USB vendor+product ID (which falls apart when two or more of the same controllers are attached, e.g. PS3 controllers) or a device node provided by the OS (which will change for a device once the order of plugging controllers in changes between runs of VICE).- TODO: mapping files could use human readable strings instead of numeric magic values
Tasks
Actions
This will be the list of things to do and the place to keep track of progress:
Action | Milestone | Description | Who | Status | Depends on | Remarks |
---|---|---|---|---|---|---|
UUIDs | 4 | ? | 0% | Cannot be done | ||
SDL UI actions | 1 | Rework SDL menu system to use UI Actions | Compyx | 100% | ? | |
SDL hotkeys | 1 | Rework SDL hotkeys system to use UI Actions | Compyx | 100% | SDL UI actions | Hotkeys now work and use the same syntax as the Gtk3 .vhk files: they can be loaded, saved, cleared and reset to default. Assigning them with the magic 'M' key in the menu is implemented, with the caveat that only items with a UI action ID can be used to assign a hotkey to, unlike the old "Some&menu&item" technique.
The SDL UI currently shows an error message box when trying to assign a hotkey to an item without an action ID. Any items we want to be able to assign to a hotkey or joystick button will have to be assigned a new UI action ID and an action handler implemented for that action. |
SDL joycode | 1 | Make the SDL UI use the new joy mapping code | Fabbo, Compyx | 100% | SDL UI actions | Although the joystick mappings currently work, they use the old "Some&menu&item" menu item references, this needs to be rewritten to use UI actions and the .vjm parser needs to be updated to use UI action names instead of paths to menu items. (DONE) |
Action | Milestone | Description | Who | Status | Depends on | Remarks |
---|---|---|---|---|---|---|
UUIDs | 4 | Figure out how to obtain UUIDs for controllers on Linux, BSD, MacOS and Windows | Compyx (Linux, Windows, FreeBSD, NetBSD), ??? (MacOS) | 25% | The preferred way would be to use the GUIDs used by SDL's mapping (see https://github.com/gabomdq/SDL_GameControllerDB), a 128-bit unsigned integer composed of device bus-type, vendor, product and version. Some test code generating this GUID for Linux with libevdev is available at https://github.com/Compyx/evdev-js-test. See the function dev_info_get_guid() in the file joystick.c for details.
Some new work is being done at Compyx/vice-joydriver-test, along with updated drivers for Linux, BSD and Windows. | |
GTK3 UI actions | 2 | Rework GTK3 menu system to use UI Actions | Compyx | 100% | ? | |
GTK3 joycode | 2 | Make the Gtk3 UI use the new joy mapping code | Compyx | 50% | ? | Basic things like buttons work, but axes and hats need work. The shared code also needs updating to allow for non-sequential, non-zero based button/axis/hat codes, and codes that are larger than uint8_t.
See Compyx/vice-joydriver-test for a new implementation (WIP) of the driver and mapping code (and hopefully calibration as well, soon). |
Action | Milestone | Description | Who | Status | Depends on | Remarks |
---|---|---|---|---|---|---|
Joymap files (generic) | 4 | Update syntax of joymap files to use a human-readable format (text instead of magic numbers). If the files are easier to read and write users can produce joymaps for controllers they own, which we can then include in VICE. This will be especially handy until we have proper UI support for creating the mappings. Provide a joymap file per device identifier that can be loaded/edited/deleted, perhaps auto-load when JoyDevice{N} contains such an identifier. Make the joymap files use (UI) action identifiers (strings) instead of the "menu paths" SDL does or magic numbers. (See UI Actions) | Compyx | 20% | ? | Joymap files now use UI action names instead of "menu paths" for all ports and the parser has been updated to actually validate its input and log warnings on errors in joymap files. Still needs a ton of work. |
Resources (generic) | 4 | Change and add resources to use UUIDs for controllers and mapping joymap files to controllers. Get rid of the 0-4 for 'none', 'numpad', 'keyset A', 'keyset B' and 4+ for whatever controller was plugged in first: change Joy%d to strings. | ? | 0% | UUIDs | |
Hotkeys (generic) | 1 | Move most of the hotkeys code into arch/shared so the hotkey files and the parser can be shared between UIs. The hotkeys code relies on UI Actions, so if we make the hotkeys parser use a callback when it encounters a hotkey definition we can use the hotkeys code for all UIs. | Compyx | 100% | SDL UI actions |
Reminders
Some leftovers from previous "joysticks" related TODOs. Not strictly related to what we are doing here.
General
- keep in mind there needs to be a way to map both "paddles" and "joysticks"
- Dialogs need to written to handle all of this.
- "JoyMapFile", "JoyThreshold", "JoyFuzz" - Use these when implementing the joystick mapping stuff
- Since we'll be using separate joymap files per host device, none of these resources will be useful. Any fuzz, deadzone or threshold values will be specified in the joymap files, per host input. For joymap files we'll need to find a way to associate them with their device, either through GUID (Windows), device node (BSD/Linux) or index (SDL_Joystick and SDL_GameContoller subsystems). Compyx (talk) 09:33, 9 May 2024 (CEST)
SDL UI
- SDL1/2 joystick mapping improvements
- Make the 'extra joystick options' menu show what they are already mapped to
- Add menu joystick actions mapping support to the 'extra joystick options' menu
GTK3 UI
- TODO: we need an interface to map controller buttons and axis to joystick emulation, keyboard input and GUI actions
- at this point, make sure the mapping can be different for each connected joystick
- also make sure support for 2nd and 3rd button is handled correctly
- TODO: joy-osx.c contains a lot of resources and commandline options that should not be there, but live in common code instead. this needs some refactoring to make game controllers work the same in all ports
- similar for at least joy-unix.c, but commented out
in the gtk3 port VICE currently interprets all buttons of a connected joystick as fire button ( https://sourceforge.net/tracker/?func=detail&aid=3292139&group_id=223021&atid=1057620 )This was changed in trunk: now only the first controller button (whichever that may be depends on controller and driver) is assigned to fire, no other buttons are mapped (this includes fire2, fire3 or triggering the menu/settings from a controller).
- in the gtk3 port the 2nd button of C64GS joystick currently only works via keyboard, not real (USB) joysticks
- when selecting "swap joysticks" or "swap userport joysticks" this will actually swap the related resources, which may be surprising when saving settings and loading them later. it also means its impossible to display whether they are swapped or not in the UI.
- TODO: create a "JoysticksAreSwapped" resource, and update the code accordingly. (This is partially solved in the Gtk3 UI by using two internal states, one for controlports and one for userport, and reflecting the state in the menu with checkboxes)
- Add gtk3 ui support for the host joystick mapping system.
joyport_map_desc_t *mappings = joyport_get_mapping(port); /* get the mappings for the given port */ char *port_name = joyport_get_port_name(port); /* get the name of the emulated port */ if (joyport_has_mapping(port)) { /* only if the given port has a device that has pins to map */ char *emulated_joystick_device_name = mappings->name; /* get the name of the emulated device in the given port */ if (mappings->pinmap != NULL) { /* only if the device has pin (digital line) mappings */ for (int i = 0; mappings->pinmap[i].name; i++) { /* go through all the pin mappings, if mapping pin name is NULL then we have reached the end */ char *pin_name = mappings->pinmap[i].name; /* get the pin name */ int pin_nr = mappings->pinmap[i].pin; /* get the pin number */ ... /* build host joystick direction/button dialog based on the above info */ } } if (mappings->potmap != NULL) { /* only if the device has pot (analog line) mappings */ for (int i = 0; mappings->potmap[i].name; i++) { /* go through all the pot mappings, if mapping pot name is NULL then we have reached the end */ char *pin_name = mappings->potmap[i].name; /* get the pot name */ int pin_nr = mappings->potmap[i].pin; /* get the pot number */ ... /* build host joystick analog axis dialog based on the above info */ } } }
Feature Requests
There are a couple open feature requests, some (if not not most) might be solved by the joymapping rework
- use second joystick button as auto fire
- Add support for Paddles and other input devices
- Only one fire on multiple button joystick
- Map any emulator function to controller buttons
- Select Joystick X and Y axis
- Paddle Controller Support in WinVICE64...?
- Custom gamepad buttons
- Use XBox/PS4 controller as multibutton joystick
- gamepad mapping
- Improve GTK3/macOS Joystick Compatibility
- Paddle input settings
Docs
generic API
TODO: Document the API of the generic code here
Source files
TODO: list the relevant files in general section of the code here TODO: list the relevant files in SDL section of the code here TODO: list the relevant files in GTK3 section of the code here
Mapping file
A line has 4 mandatory columns:
- Joystick number (zero-based index of the hardware joystick)
- Input type (enum joystick_input_type_t)
- Axis (JOY_INPUT_AXIS)
- Button (JOY_INPUT_BUTTON)
- Hat (JOY_INPUT_HAT)
- Ball (JOY_INPUT_BALL)
- Input index
- For buttons, it is the zero-based index of the button
- For axes: * if the action is 6 (POT_AXIS), it is the zero-based index of the axis * otherwise, 0 and 1 are respectively the positive and negative directions of axis 0; 2 and 3 are respectively the positive and negative directions of axis 1 etc. In formulas: axis=inputindex/2 (integer division), direction = positive if inputindex % 2 ==0 , negative if inputindex % 2 ==1.
- for hats, 0, 1, 2 and 3 are respectively up, down, left and right of hat 0; 4, 5, 6 and 7 are respectively up, down, left and right of hat 1, etc.
- Action (enum
joystick_action_t
injoystick.h
)- NONE: none
- JOYSTICK: emulated joystick action
- KEYBOARD: emulated keyboard action
- MAP: SDL-only. Only works while the SDL settings menu is active. If a joystick action mapped to this is performed, the user is asked to press a key, which will become a hotkey to select the currently-selected menu
- UI_ACTIVATE: go to the settings menu (SDL) show the settings dialog (Gtk3)
- UI_FUNCTION: shortcut to a specific UI function. A string argument (unquoted) indicating the UI action to trigger. See src/arch/shared/uiactions.c for a list of action names.
- POT_AXIS: (only for axes of hardware joysticks) the analog value of the axis is the value of the emulated potentiometer
For some actions, more columns are present:
- JOYSTICK
- emulated joystick pin. Same values as reading the corresponding CIA register.
- up
- down
- left
- right
- fire
- fire 2
- fire 3
Blacky note: In vice we also emulate snes pads, these need to be able to be controlled as well, and so the emulated joystick pin needs to be renamed (more like emulated joystick input) and extended, some of the old pins/inputs can be reused, and in such a case we get the following:
- joystick up / snes pad up
- joystick down / snes pad down
- joystick left / snes pad left
- joystick right / snes pad right
- joystick fire 1 / snes pad A button
- joystick fire 2 / snes pad B button
- joystick fire 3 / snes pad X button
- snes pad Y button
- snes pad left bumber
- snes pad right bumber
- snes pad select button
- snes pad start button
And this can be extended if other joystick devices become available with more buttons than we currently map for.
- KEYBOARD
- row in the keyboard matrix layout
- column in the keyboard matrix layout
- POT_AXIS
- which potentiometer is affected
- Pot-X
- Pot-Y
Technical
When a hardware joystick action is performed, the selected joystick driver (Gtk3) ui_dispatch_events()
(SDL) call joy_axis_event()
or joy_button_event()
or joy_hat_event()
. These functions read what that joystick action is mapped to, and perform the mapped action.
Mappings are stored in the static array joystick_devices, declared in joystick.c, that has one element per registered hardware joystick. Mappings are stored in each element's axis_mapping, button_mapping and hat_mapping, each an array with one element per axis/button/hat. The mappings are initialised from the joystick mappings file, or with default values if no joystick mappings file is present.
Example
Take this sample line from data/C64/sdl_joymap_ps3.vjm
# O -> Space
0 1 1 2 7 4
First column: HW joystick 0
Second column: input type is button (1)
Third column: input index 1, so button 1
Fourth column: action KEYBOARD (2)
Fifth and sixth columns: Space (7 and 4 in the matrix)