This tutorial covers reading SNES controllers including button detection and multi-player support.
SNES Controller Layout
L R
┌───────────────────────────────────────┐
│ ┌───┐ ┌───┐ │
│ │ ↑ │ (X) │ X │ │
│ ┌───┼───┼───┐ (Y) (A)├───┤ │
│ │ ← │ │ → │ [SEL][STA] │ Y │ A │ │
│ └───┼───┼───┘ ├───┼───┤ │
│ │ ↓ │ │ B │ │
│ └───┘ └───┘ │
└───────────────────────────────────────┘
Button Constants
OpenSNES defines these button masks in input.h:
#define KEY_UP 0x0800
#define KEY_DOWN 0x0400
#define KEY_LEFT 0x0200
#define KEY_RIGHT 0x0100
#define KEY_A 0x0080
#define KEY_B 0x8000
#define KEY_X 0x0040
#define KEY_Y 0x4000
#define KEY_L 0x0020
#define KEY_R 0x0010
#define KEY_START 0x1000
#define KEY_SELECT 0x2000
Reading Controllers
Direct Register Access (Recommended)
while (1) {
continue;
}
}
}
}
void WaitForVBlank(void)
Wait for next VBlank period.
static u16 bx
Definition main.c:159
#define REG_JOY1H
Joypad 1 data high (R)
Definition registers.h:328
#define REG_JOY1L
Joypad 1 data low (R)
Definition registers.h:325
#define REG_HVBJOY
H/V blank and joypad status (R)
Definition registers.h:301
unsigned short u16
16-bit unsigned integer (0 to 65535)
Definition types.h:52
Reading Controller 2
#define REG_JOY2H
Joypad 2 data high (R)
Definition registers.h:334
#define REG_JOY2L
Joypad 2 data low (R)
Definition registers.h:331
Edge Detection
Detect button presses (not just held state):
while (1) {
}
}
}
}
static s16 player_x
Player X position in screen coordinates.
Definition main.c:55
Movement Example
}
}
}
}
}
static s16 player_y
Player Y position in screen coordinates.
Definition main.c:57
Two-Player Example
while (1) {
}
}
}
void oamSet(u16 id, u16 x, u16 y, u16 tile, u16 palette, u16 priority, u16 flags)
Set sprite properties.
void oamUpdate(void)
Copy OAM buffer to hardware.
Button Combinations
}
}
#define COMBO_HADOUKEN (KEY_DOWN | KEY_RIGHT | KEY_A)
}
Menu Navigation
}
}
}
}
}
}
unsigned char u8
8-bit unsigned integer (0 to 255)
Definition types.h:46
Hardware Registers
For reference, the joypad registers:
| Register | Address | Description |
| REG_JOY1L | $4218 | Controller 1, low byte |
| REG_JOY1H | $4219 | Controller 1, high byte |
| REG_JOY2L | $421A | Controller 2, low byte |
| REG_JOY2H | $421B | Controller 2, high byte |
| REG_JOY3L | $421C | Controller 3 (multitap) |
| REG_JOY3H | $421D | Controller 3 (multitap) |
| REG_JOY4L | $421E | Controller 4 (multitap) |
| REG_JOY4H | $421F | Controller 4 (multitap) |
| REG_HVBJOY | $4212 | Status (bit 0 = auto-read busy) |
Tips
- Always wait for auto-joypad - Check
REG_HVBJOY & 0x01 before reading
- Check for disconnected controllers -
0xFFFF means no controller
- Use edge detection for menus - Prevents rapid-fire selection
- Use held state for movement - Smoother continuous motion
Example
See examples/input/two_players/ for a complete two-player demo.
Next Steps