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)
rshoulder2
Settings
Settings3
key_p (Caverns: altar)
ltrigger2
Load world
Page up
key_f3 (save game)
rtrigger2
Reload save
Page down
key_f4 (load save)
lstick2
Home
rstick2
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_right2
Directional actions for the left analog stick. Same behavior as
the dpad actions by default.
r_up, r_down, r_left, and
r_right2
Directional actions for the right analog stick. Same behavior as
the dpad actions by default.
axis_lx and axis_ly2
X and Y axes of the left stick (counter only).
axis_rx and axis_ry2
X and Y axes of the right stick (counter only).
axis_ltrigger and axis_rtrigger2
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.
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:
(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:
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).
Diagram resembling an NDS or 3DS, with buttons and axes labeled.axis_lxaxis_lyup, down,left, rightabxystartselectlshoulderrshoulder(keyboard)ltriggerrtrigger
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.
Diagram resembling a PSP, with buttons and axes labeled.lshoulderrshoulderaxis_lxaxis_lyup, down,left, rightabxyselectstart
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:
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).
Diagram resembling a Switch with buttons and axes labeled.ltriggerlshoulderrtriggerrshoulderstartselectaxis_lxaxis_lylstickaxis_rxaxis_ryrstickupdownleftrightabxy
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.
Diagram resembling a Wii Remote with buttons labeled.lshoulderrshoulderupdownleftrightxselectyba
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.
Diagram resembling a Wii Remote and nunchuck, with buttons and axes labeled.lshoulderltriggeraxis_lxaxis_lyupdownleftrightrtriggerrshoulderyselectxba
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.
Diagram resembling a Wii Classic Controller with buttons and axes labeled.ltriggeraxis_ltriggerrtriggeraxis_rtriggerlshoulderrshoulderup, down,left, rightselectselectstartxyabaxis_lxaxis_lyaxis_rxaxis_ry
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.
Diagram resembling a GP2X with buttons and axes labeled.lshoulderrshoulderup, down,left, right,lstickltriggerrtriggerabxyselectstart
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.