Skip to content

Commit 54114a4

Browse files
committed
[hid] GamePad support
1 parent 398d6a5 commit 54114a4

File tree

6 files changed

+201
-1
lines changed

6 files changed

+201
-1
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ add_executable(emu
4242
src/x65.c
4343
src/x65-ui-impl.cc
4444
src/args.c
45+
src/hid.c
4546
src/ui/ui_cgia.cc
4647
src/ui/ui_console.cc
4748
src/ui/ui_ria816.cc

ext/firmware

src/chips/ria816.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,103 @@ static uint64_t _ria816_update_irq(ria816_t* c, uint64_t pins) {
148148

149149
static uint8_t HID_dev = 0;
150150

151+
#ifdef NDEBUG
152+
static inline void DBG(const char* fmt, ...) {
153+
(void)fmt;
154+
}
155+
#else
156+
#include "log.h"
157+
#define DBG(...) LOG_INFO(__VA_ARGS__)
158+
#endif
151159
typedef uint32_t DWORD;
152160
#include "hid/hid.c"
153161
static void kbd_queue_char(char ch) {}
154162
static void kbd_queue_key(uint8_t modifier, uint8_t keycode, bool initial_press) {}
155163
#include "hid/kbd.c"
156164
#include "hid/mou.c"
157165
#include "hid/pad.c"
166+
#include <SDL3/SDL.h>
167+
168+
static void pad_synth_report(pad_connection_t* conn, void* data, uint16_t event_type, pad_xram_t* report) {
169+
DBG("Type: 0x%X - %p, slot: %d", event_type, data, conn->slot);
170+
171+
uint8_t dpad = 0;
172+
uint8_t button0 = 0;
173+
uint8_t button1 = 0;
174+
175+
if (event_type >= SDL_EVENT_JOYSTICK_AXIS_MOTION && event_type <= SDL_EVENT_JOYSTICK_UPDATE_COMPLETE) {
176+
// Joystick event
177+
178+
report->lx = SDL_GetJoystickAxis(data, 0) / 256;
179+
report->ly = SDL_GetJoystickAxis(data, 1) / 256;
180+
report->rx = SDL_GetJoystickAxis(data, 2) / 256;
181+
report->ry = SDL_GetJoystickAxis(data, 3) / 256;
182+
report->lt = SDL_GetJoystickAxis(data, 4) / 256;
183+
report->rt = SDL_GetJoystickAxis(data, 5) / 256;
184+
185+
uint8_t hat = SDL_GetJoystickHat(data, 0);
186+
if (hat & SDL_HAT_UP) dpad |= 1;
187+
if (hat & SDL_HAT_DOWN) dpad |= 2;
188+
if (hat & SDL_HAT_LEFT) dpad |= 4;
189+
if (hat & SDL_HAT_RIGHT) dpad |= 8;
190+
191+
uint32_t buttons = 0;
192+
for (int i = 0; i < PAD_MAX_BUTTONS; i++) {
193+
if (SDL_GetJoystickButton(data, conn->button_offsets[i])) {
194+
buttons |= (1 << i);
195+
}
196+
}
197+
button0 = buttons & 0xFF;
198+
button1 = (buttons >> 8) & 0xFF;
199+
}
200+
else if (event_type >= SDL_EVENT_GAMEPAD_AXIS_MOTION && event_type <= SDL_EVENT_GAMEPAD_UPDATE_COMPLETE) {
201+
// Gamepad event
202+
203+
report->lx = SDL_GetGamepadAxis(data, SDL_GAMEPAD_AXIS_LEFTX) / 256;
204+
report->ly = SDL_GetGamepadAxis(data, SDL_GAMEPAD_AXIS_LEFTY) / 256;
205+
report->rx = SDL_GetGamepadAxis(data, SDL_GAMEPAD_AXIS_RIGHTX) / 256;
206+
report->ry = SDL_GetGamepadAxis(data, SDL_GAMEPAD_AXIS_RIGHTY) / 256;
207+
report->lt = SDL_GetGamepadAxis(data, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) / 256;
208+
report->rt = SDL_GetGamepadAxis(data, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) / 256;
209+
210+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_DPAD_UP)) dpad |= (1 << 0);
211+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_DPAD_DOWN)) dpad |= (1 << 1);
212+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_DPAD_LEFT)) dpad |= (1 << 2);
213+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_DPAD_RIGHT)) dpad |= (1 << 3);
214+
215+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_SOUTH)) button0 |= (1 << 0); // A
216+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_EAST)) button0 |= (1 << 1); // B
217+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1)) button0 |= (1 << 2); // C
218+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_WEST)) button0 |= (1 << 3); // X
219+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_NORTH)) button0 |= (1 << 4); // Y
220+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_LEFT_PADDLE1)) button0 |= (1 << 5); // Z
221+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER)) button0 |= (1 << 6); // L1
222+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER)) button0 |= (1 << 7); // R1
223+
224+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_BACK)) button1 |= (1 << 2);
225+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_START)) button1 |= (1 << 3);
226+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_GUIDE)) button1 |= (1 << 4);
227+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_LEFT_STICK)) button1 |= (1 << 5); // L3
228+
if (SDL_GetGamepadButton(data, SDL_GAMEPAD_BUTTON_RIGHT_STICK)) button1 |= (1 << 6); // R3
229+
}
230+
231+
report->dpad |= dpad & 0x0F; // only lower 4 bits are dpad
232+
report->button0 = button0;
233+
report->button1 = button1;
234+
DBG("\t%s: 0x%02X, Sticks: 0x%02X, Buttons: 0x%02X 0x%02X, Sticks: L(%d,%d) R(%d,%d), Triggers: L(%d) R(%d)",
235+
SDL_IsGamepad(SDL_GetGamepadID(data)) ? "Gamepad" : "Joystick",
236+
report->dpad,
237+
report->sticks,
238+
report->button0,
239+
report->button1,
240+
report->lx,
241+
report->ly,
242+
report->rx,
243+
report->ry,
244+
report->lt,
245+
report->rt);
246+
}
247+
158248
uint8_t ria816_hid_read(ria816_t* c, uint8_t reg) {
159249
uint8_t data = 0xFF; // invalid
160250
switch (HID_dev & 0xF) {

src/hid.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#include <SDL3/SDL.h>
2+
3+
#include "./hid.h"
4+
#include "./log.h"
5+
6+
#include "hid/pad.h"
7+
8+
void sdl_init() {
9+
SDL_Init(SDL_INIT_GAMEPAD);
10+
}
11+
12+
void sdl_shutdown() {
13+
SDL_QuitSubSystem(SDL_INIT_GAMEPAD);
14+
}
15+
16+
// SDL3 event handling
17+
void sdl_poll_events(void) {
18+
SDL_Event event;
19+
while (SDL_PollEvent(&event)) {
20+
switch (event.type) {
21+
case SDL_EVENT_JOYSTICK_ADDED: {
22+
if (SDL_IsGamepad(event.jdevice.which)) {
23+
// Let's wait for the gamepad added event
24+
continue;
25+
}
26+
27+
LOG_INFO("SDL Joystick %d added.", event.jdevice.which);
28+
SDL_Joystick* joystick = SDL_OpenJoystick(event.jdevice.which);
29+
if (!joystick) {
30+
LOG_ERROR("SDL_OpenJoystick failed: %s", SDL_GetError());
31+
continue;
32+
}
33+
34+
if (!pad_mount(
35+
event.jdevice.which,
36+
joystick,
37+
0,
38+
SDL_GetJoystickVendor(joystick),
39+
SDL_GetJoystickProduct(joystick))) {
40+
LOG_ERROR("pad_mount failed for joystick %d", event.jdevice.which);
41+
SDL_CloseJoystick(joystick);
42+
}
43+
} break;
44+
case SDL_EVENT_JOYSTICK_REMOVED: {
45+
if (SDL_IsGamepad(event.jdevice.which)) continue;
46+
LOG_INFO("SDL Joystick %d removed", event.jdevice.which);
47+
SDL_CloseJoystick(SDL_GetJoystickFromID(event.jdevice.which));
48+
pad_umount(event.jdevice.which);
49+
} break;
50+
case SDL_EVENT_GAMEPAD_ADDED: {
51+
LOG_INFO("SDL Gamepad %d added", event.gdevice.which);
52+
SDL_Gamepad* gamepad = SDL_OpenGamepad(event.gdevice.which);
53+
if (!gamepad) {
54+
LOG_ERROR("SDL_OpenGamepad failed: %s", SDL_GetError());
55+
continue;
56+
}
57+
58+
if (!pad_mount(
59+
event.gdevice.which,
60+
gamepad,
61+
0,
62+
SDL_GetGamepadVendor(gamepad),
63+
SDL_GetGamepadProduct(gamepad))) {
64+
LOG_ERROR("pad_mount failed for Gamepad %d", event.gdevice.which);
65+
SDL_CloseGamepad(gamepad);
66+
}
67+
} break;
68+
case SDL_EVENT_GAMEPAD_REMOVED: {
69+
LOG_INFO("SDL Gamepad %d removed", event.gdevice.which);
70+
SDL_CloseGamepad(SDL_GetGamepadFromID(event.gdevice.which));
71+
pad_umount(event.gdevice.which);
72+
} break;
73+
74+
case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE:
75+
case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: {
76+
// could use this to update force feedback effects
77+
} break;
78+
79+
default: {
80+
if (event.type >= SDL_EVENT_JOYSTICK_AXIS_MOTION && event.type < SDL_EVENT_JOYSTICK_UPDATE_COMPLETE) {
81+
// Joystick event
82+
if (SDL_IsGamepad(event.jdevice.which)) continue;
83+
pad_report(
84+
event.jdevice.which,
85+
(const void*)SDL_GetJoystickFromID(event.jdevice.which),
86+
event.type);
87+
}
88+
else if (
89+
event.type >= SDL_EVENT_GAMEPAD_AXIS_MOTION && event.type < SDL_EVENT_GAMEPAD_UPDATE_COMPLETE) {
90+
// Gamepad event
91+
pad_report(event.jdevice.which, (const void*)SDL_GetGamepadFromID(event.jdevice.which), event.type);
92+
}
93+
else {
94+
LOG_WARNING("Unhandled SDL event type: 0x%X", event.type)
95+
};
96+
} break;
97+
}
98+
}
99+
}

src/hid.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#pragma once
2+
3+
void sdl_init();
4+
void sdl_shutdown();
5+
6+
void sdl_poll_events();

src/x65.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ extern void segfault_handler(int sig);
3737
#include "log.h"
3838
#include "./args.h"
3939
#include "./dap.h"
40+
#include "./hid.h"
4041

4142
extern const char* GIT_TAG;
4243
extern const char* GIT_REV;
@@ -182,6 +183,7 @@ void app_init(void) {
182183
clock_init();
183184
prof_init();
184185
fs_init();
186+
sdl_init();
185187
#ifdef CHIPS_USE_UI
186188
ui_init(&(ui_desc_t){
187189
.draw_cb = ui_draw_cb,
@@ -310,6 +312,7 @@ void app_frame(void) {
310312
gfx_draw(x65_display_info(&state.x65));
311313
handle_file_loading();
312314
send_keybuf_input();
315+
sdl_poll_events();
313316
#ifdef USE_DAP
314317
dap_process();
315318
#endif
@@ -352,6 +355,7 @@ void app_cleanup(void) {
352355
saudio_shutdown();
353356
gfx_shutdown();
354357
sargs_shutdown();
358+
sdl_shutdown();
355359
#ifdef USE_DAP
356360
dap_shutdown();
357361
#endif

0 commit comments

Comments
 (0)