## Contents

1. General Info

1. A typical controller layout
2. List of available actions

2. Config Usage and Examples

1. Examples for specific games
2. Adding/modifying controller support
3. Config options in versions prior to 2.92

3. Robotic Usage and Examples
4. Controller Layouts for Console Ports

1. NDS and 3DS
2. PSP
3. Switch
4. Wii
5. GP2X

5. License

## General Info

Joystick support in MegaZeux is primarily handled through abstracted buttons and axes called actions. These actions correspond primarily to XInput controls in both name and general physical location on a controller. Actions can interact directly with the UI elements of MegaZeux and may be used by MegaZeux games.

Actions can be used by games in two ways. The simplest method is to bind a key to a given action via a game config file (see Config Usage and Examples). When the joystick action is pressed/released in game, MegaZeux will simulate the press/release of the bound key. Each action has a default game key bound to it initially (see the list of available actions below). Alternatively, the simulated key behavior can be disabled through Robotic and the pressed/released status of an action may be read directly with a counter (see Robotic Usage and Examples).

### A Typical Controller Layout

This figure shows most available actions and a typical placement of them on controllers for most platforms:

NOTE: Not all controllers have the same layout or support all of the same controls; the default layout for a given controller depends on the mapping provided by SDL or gamecontrollerdb.txt, if any. See Adding/modifying controller support for more info on getting new controllers to work in SDL and tweaking existing controllers.

### List of Available Actions

The available joystick actions, their UI behavior, and their default gameplay keybindings are:

Name | Title behavior | Window behavior | Default gameplay key
`up` |  | Element/​cursor up | `key_up` (movement)
`down` |  | Element/​cursor down | `key_down` (movement)
`left` |  | Element/​cursor left | `key_left` (movement)
`right` |  | Element/​cursor right | `key_right` (movement)
`a` | Play game | Select | `key_space` (shoot)
`b` | Main menu | Cancel | `key_delete` (bomb)
`x` | Load world | Select char (text) | `key_return` (game menu)
`y` | Reload save | Backspace (text) | `key_s` (Caverns: spells)
`start` | Play game | Select | Game menu1
`select` | Main menu | Cancel | Game menu1
`lshoulder` | Settings | Next element | `key_insert` (bomb type)
`rshoulder`2 | Settings | Settings3 | `key_p` (Caverns: altar)
`ltrigger`2 | Load world | Page up | `key_f3` (save game)
`rtrigger`2 | Reload save | Page down | `key_f4` (load save)
`lstick`2 |  | Home |
`rstick`2 |  | End |

The following actions are available only through Robotic or are mostly similar to other actions listed above:

Name | Description
`l_up`, `l_down`, `l_left`, and `l_right`2 | Directional actions for the left analog stick. Same behavior as the dpad actions by default.
`r_up`, `r_down`, `r_left`, and `r_right`2 | Directional actions for the right analog stick. Same behavior as the dpad actions by default.
`axis_lx` and `axis_ly`2 | X and Y axes of the left stick (counter only).
`axis_rx` and `axis_ry`2 | X and Y axes of the right stick (counter only).
`axis_ltrigger` and `axis_rtrigger`2 | Axes for the left and right triggers (counter only).

1Gives access to most UI menus such as saving, loading, exiting the game, and settings. This behavior overrides any keys assigned to this action unless both `ENTER_MENU` and `ESCAPE_MENU` are disabled. This occupies both `start` and `select` right now because some controllers may lack one of these buttons.

2The `rshoulder` action is replaced by some consoles with a hardcoded button to open an onscreen keyboard. The availability of some other actions may vary between consoles and controllers (for example, some controllers may have a left analog stick but no dpad, and many controllers lack the stick press `lstick` and `rstick` actions).

3This behavior currently only works on some windows, such as the main menu and game menu.

## Config Usage and Examples

Creating a game config file to give a game compatibility with joystick actions is very easy and, best of all, requires no modification to older games. A game config file is a text file that shares the same filename as a world but with the ".cnf" extension instead of ".mzx" (for example, the the config file for `CAVERNS.MZX` would be `CAVERNS.CNF`). Joystick config file options can be used in this file just as they would be in the regular config file, but they'll only affect their given world.

The main config option worth noting for the purpose of configuring a game.cnf file is

`joy#.ACTION = KEY`

where # is the joystick number (1-16), `ACTION` is the name of a joystick action, and `KEY` is either a key number or a string in the format of `key_NAME` (see keycodes.html for key_pressed numbers and/or key names to use here). For example:

`joy1.lshoulder = key_space`

would assign the space key to the `lshoulder` action of joystick 1. Since up to 16 joysticks can be used with MegaZeux, it may be useful to assign the same action keybinding to multiple joysticks. This can be done by substituting the joystick number with a range. For example:

`joy[1,16].lshoulder = key_space`

will assign the `lshoulder` action on every controller to the space key.

### Examples for Specific Games

#### Forest of Ruin

The default config mostly works for this game, but it would be nice to be able to switch weapons (and `start` is good enough for the menu in this game, which frees up `x`):

`joy[1,16].x = key_w`

#### red

red also mostly works with the default config thanks to `x` being bound to `key_return`. For convenience, we'll go ahead and bind `y` to `key_return` too:

`joy[1,16].y = key_return`

#### Demon Earth

Demon Earth uses different keys for attacking and uses space to hold the player's current facing direction. Because of this, it's useful to put the attack keys on the face buttons and space on the shoulders. Note: because Demon Earth uses swap worlds, you may need to create a game.cnf file for each world.

`joy[1,16].a = key_a joy[1,16].b = key_s joy[1,16].x = key_return joy[1,16].y = key_return joy[1,16].lshoulder = key_space joy[1,16].rshoulder = key_space`

#### Achtung!!

Comments can be added to explain the in-game function of each key:

`# Shoot down; change to B for some consoles # Shoot right; change to A for some consoles # Shoot left; change to Y for some consoles # Shoot up; change to X for some consoles joy[1,16].a = key_s joy[1,16].b = key_d joy[1,16].x = key_a joy[1,16].y = key_w # Shoot up # Shoot down # Shoot left # Shoot right joy[1,16].r_up = key_w joy[1,16].r_down = key_s joy[1,16].r_left = key_a joy[1,16].r_right = key_d # Select menu, bomb joy[1,16].lshoulder = key_space joy[1,16].rshoulder = key_space joy[1,16].ltrigger = key_space joy[1,16].rtrigger = key_space`

### Adding/Modifying Controller Support

Most platforms supported by MegaZeux (excluding consoles) rely on SDL 2. Controller support in MegaZeux for these platforms is based on SDL's game controller API, and any controller supported by the game controller API is automatically detected by MegaZeux. However, many controllers are still missing from SDL and/or gamecontrollerdb.txt.

It should be possible to map most missing USB or Bluetooth controllers, and several utilities for this purpose are available at the SDL_GameControllerDB GitHub repository. When used, these utilities will produce a mapping string that can be added to MZX using the following config setting:

`gamepad_add = 030000005e0400008e02000000007801,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,`

(note: it must be a single line). This will override any existing config for your controller (in either SDL or gamecontrollerdb.txt) with your new mapping. It might also be a good idea to thoroughly test your new mapping and send it to an MZX developer or submit it to SDL or SDL_GameControllerDB yourself if it's a controller that is missing or if the mapping in the database is unusable/broken.

The way MZX uses the SDL game controller API to generate controller mappings can be further configured globally with the following settings:

`gamepad.SDLBUTTON = act_NAME gamepad.+SDLAXIS = act_NAME gamepad.-SDLAXIS = act_NAME`

The first will assign an SDL game controller button to the MZX action `NAME`. The second will assign the positive direction of an SDL axis to `NAME`; the third does the same, for the negative direction. A complete list of SDL buttons that can be customized is in the config file.

Finally, if you'd like to go back to the old and bad joystick support for some reason, you can turn off automatic mappings altogether via the config file:

`gamepad_enable = 0`

### Config Options in Versions Prior to 2.92

MZX versions prior to 2.92 do not have access to any joystick counters, nor to actions in general. Only the following config options are available. The use of these options in versions 2.92 and up is not recommended.

Versions prior to 2.92 are also not capable of using joystick index ranges or binding key names and must use key_pressed values directly. They also do not distinguish global config from game config, meaning a game.cnf file that uses these settings will affect all UIs in MZX permanently until another game.cnf file is loaded.

Most port pad.config files still use these config settings as the physical location of each button/axis/hat is already known and will not change.

`joyXbuttonY = A`

This will assign button Y (1-256) on joystick X (1-16) to key A.

In versions 2.92 and up, A can also be a key name in the format of `key_NAME` or an action name in the format of `act_NAME`. Additionally, X can be a range, e.g. `joy[Z,W]buttonY`.

`joyXaxisY = A, B`

This will assign axis Y (1-16) on joystick X (1-16) to keys A and B. The negative direction of the axis will be assigned to A and the positive direction will be assigned to B.

In versions 2.92 and up, A and B can also be key names in the format of `key_NAME` or action names in the format of `act_NAME`. Additionally, X can be a range, e.g. `joy[Z,W]axisY`.

`joyXhat = A, B, C, D`

This will assign the hat of joystick X (1-16) to keys A, B, C, and D. Up will be assigned to A, down will be assigned to B, left will be assigned to C, and right will be assigned to D.

In versions 2.92 and up, A/B/C/D can also be key names in the format of `key_NAME` or action names in the format of `act_NAME`. Additionally, X can be a range, e.g. `joy[Z,W]hat`.

## Robotic Usage and Examples

Joystick presses can be read directly from Robotic via counters. First, however, it might be useful to turn off the simulated key press behavior for joysticks that is enabled by default:

`set "joy_simulate_keys" to 0`

The `joy#active` counter returns 1 if a joystick is active, 0 if it is not active, and -1 if the provided joystick index is invalid. You can use it if you need to check to see how many joysticks are active or if any are active:

`set "num_active" 0 loop start if "joy&loopcount&active" = 1 then "#is_active" loop for 15 * "&num_active& controllers are active." end : "#is_active" inc "num_active" by 1 goto "#return"`

The `joy#.NAME` counter is probably more useful, however. For action `NAME`, this counter will return the value of that action for a given joystick number, or -1 if either the joystick number or action name are invalid. For button actions, the value is 1 if pressed and 0 if not pressed. For axis actions, the value can be anywhere between -32768 and 32767, though trigger axes are more likely to be between 0 and 32767.

The following example moves a player sprite around with an analog stick:

`lockplayer set "spr0_refx" to "playerx" set "spr0_refy" to "playery" set "spr0_width" to 1 set "spr0_height" to 1 set "spr0_unbound" to 1 put c?? Sprite p00 at 316 168 : "l" inc "spr0_x" by "('joy1.axis_lx'/2500)" inc "spr0_y" by "('joy1.axis_ly'/2500)" wait for 1 goto "l"`

This longer example implements a simple player robot that can move around or shoot by holding the `a` button and pressing a direction:

`lockplayer : "l" if "joy1.a" = 1 then "shoot" if "joy1.up" = 1 then "go_up" if "joy1.down" = 1 then "go_down" if "joy1.right" = 1 then "go_right" if "joy1.left" = 1 then "go_left" wait for 1 goto "l" : "go_up" go NORTH for 1 goto "l" : "go_down" go SOUTH for 1 goto "l" : "go_right" go EAST for 1 goto "l" : "go_left" go WEST for 1 goto "l" : "shoot" if "joy1.up" = 1 "shoot_up" if "joy1.down" = 1 "shoot_down" if "joy1.right" = 1 "shoot_right" if "joy1.left" = 1 "shoot_left" wait for 1 goto "l" : "shoot_up" sfx 28 shoot NORTH wait for 2 goto "l" : "shoot_down" sfx 28 shoot SOUTH wait for 2 goto "l" : "shoot_right" sfx 28 shoot EAST wait for 2 goto "l" : "shoot_left" sfx 28 shoot WEST wait for 2 goto "l"`

The above example can be modified to check the axes, too:

`... if "joy1.up" = 1 then "go_up" if "joy1.l_up" = 1 then "go_up" if "joy1.r_up" = 1 then "go_up" if "joy1.down" = 1 then "go_down" if "joy1.l_down" = 1 then "go_down" if "joy1.r_down" = 1 then "go_down" if "joy1.right" = 1 then "go_right" if "joy1.l_right" = 1 then "go_right" if "joy1.r_right" = 1 then "go_right" if "joy1.left" = 1 then "go_left" if "joy1.l_left" = 1 then "go_left" if "joy1.r_left" = 1 then "go_left" ...`

Ideally, a game should work with both keyboard and rather than joystick inputs alone. However, if you do make a game that is playable only with a joystick, it should probably indicate clearly that a joystick is required.

## Controller Layouts for Console Ports

Diagrams of the default layouts for the console platforms supported by MegaZeux are provided here. These layouts can be further configured for each platform by modifying the "pad.config" file that comes with them.

### NDS and 3DS

The NDS and 3DS ports share the same layout; the only difference is that the 3DS port has extra controls, particularly the New 3DS (note the New 3DS circle stick is reserved for future use and can't be mapped).

Neither console maps `axis_rx`, `axis_ry`, `axis_ltrigger`, `axis_rtrigger`, `lstick`, or `rstick`. The right shoulder button is hardcoded to open the onscreen keyboard, so `rshoulder` is unmapped as well.

Furthermore, the NDS doesn't have the circle pad (`axis_lx`, `axis_ly`) and both the NDS and original 3DS are missing ZL (`ltrigger`) and ZR (`rtrigger`).

### PSP

The PSP port does not map `axis_rx`, `axis_ry`, `axis_ltrigger`, `axis_rtrigger`, `ltrigger`, `rtrigger`, `lstick`, or `rstick`. No button is reserved for a keyboard as the PSP port supports an infrared keyboard.

### Switch

The Nintendo Switch port uses SDL 2 and thus has mappings built into SDL. However, SDL default mappings for `a`, `b`, `x`, and `y` correspond to the XInput positions for these buttons, which Nintendo console users generally don't want. Because of this, the Switch port also ships with a default pad.config that reconfigures the mapping of `a`, `b`, `x`, and `y` globally for all SDL controllers:

`gamepad.a = act_b gamepad.b = act_a gamepad.x = act_y gamepad.y = act_x`

Furthermore, the Switch port may not map `axis_ltrigger` or `axis_rtrigger`, and if it does, they probably only return a value of either 0 or 32767 (this needs to be verified).

### Wii

Button availability for the Wii port varies given which controller or extension controller is being used. Regardless of the available controllers, however, no Wii layout maps `lstick` or `rstick`. No buttons are reserved for a keyboard in any layout as the Wii has multiple built-in USB ports. The home button is hardcoded to `select` when present.

Extensions not otherwise listed below are the Guitar Hero 3 extension controller (supported by MegaZeux) and the Wii Balance Board and Wii Motion Plus (not supported by MegaZeux).

#### Wii Remote (no extension)

The mapping for this layout is fairly arbitrary and may change in future versions (particularly if `start`/`select` become more usable by games). This layout has no axes or mappings for `ltrigger`, `rtrigger`, or `start`. This layout assumes the Wii Remote is held horizontally like an NES controller.

#### Wii Remote (with nunchuck)

The mapping for this layout is fairly arbitrary and may change in future versions (particularly if `start`/`select` become more usable by games). This layout has no mappings for `start`, `axis_rx`, `axis_ry`, `axis_ltrigger`, or `axis_rtrigger`. This layout assumes the Wii Remote is held like a remote in one hand and the nunchuck is held by the other hand.

#### Wii Classic Controller

This layout maps all buttons and axes aside from the aforementioned `lstick` and `rstick`. Input from the Wii Remote is ignored in this configuration (aside from pointing/clicking). Note that L/R are the triggers as they are analog and ZL/ZR are the shoulders (opposite from the New 3DS layout). This is the recommended controller for use with the Wii port.

The NES and SNES classic controllers currently select this layout as well, but (obviously) several buttons will be missing. It is unknown currently whether libogc can/will distinguish between these.

#### Gamecube Controller

This layout maps most buttons but is notably lacking a button for `select` and one shoulder button. Currently `lshoulder` is mapped to Z and `rshoulder` is left unmapped, as `lshoulder` is arguably more useful by default.

### GP2X

Some buttons are unusually mapped on the GP2X due to its non-standard layout. The `a`, `b`, `x`, and `y` actions are assigned using their Nintendo positions rather than the GP2X button names. While the GP2X appears to have an analog stick, it is actually only 8-directional. However, some models have a stick press button, which is mapped to `lstick`. The volume buttons are also mappable and assigned to `ltrigger` and `rtrigger` (for lack of anything better to put there).

The GP2X does not map `axis_lx`, `axis_ly`, `axis_rx`, `axis_ry`, `axis_ltrigger`, `axis_rtrigger`, or `rstick`. No button is reserved for a keyboard as the GP2X has a built-in USB port.

## License

Copyright © 2019-2023 Lachesis — https://github.com/AliceLR/megazeux/

Permission to use, copy, modify, and distribute this document for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE DOCUMENT IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS DOCUMENT INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS DOCUMENT.