Basic Joypad support
This commit is contained in:
parent
3f9d62ceee
commit
c03ccba8db
201
SDL/gui.c
201
SDL/gui.c
@ -174,8 +174,12 @@ static enum {
|
|||||||
SHOWING_MENU,
|
SHOWING_MENU,
|
||||||
SHOWING_HELP,
|
SHOWING_HELP,
|
||||||
WAITING_FOR_KEY,
|
WAITING_FOR_KEY,
|
||||||
|
WAITING_FOR_JBUTTON,
|
||||||
} gui_state;
|
} gui_state;
|
||||||
|
|
||||||
|
unsigned auto_detect_progress = 0;
|
||||||
|
unsigned auto_detect_inputs[3];
|
||||||
|
|
||||||
static void item_exit(unsigned index)
|
static void item_exit(unsigned index)
|
||||||
{
|
{
|
||||||
pending_command = GB_SDL_QUIT_COMMAND;
|
pending_command = GB_SDL_QUIT_COMMAND;
|
||||||
@ -190,11 +194,13 @@ static void item_help(unsigned index)
|
|||||||
|
|
||||||
static void enter_graphics_menu(unsigned index);
|
static void enter_graphics_menu(unsigned index);
|
||||||
static void enter_controls_menu(unsigned index);
|
static void enter_controls_menu(unsigned index);
|
||||||
|
static void enter_joypad_menu(unsigned index);
|
||||||
|
|
||||||
static const struct menu_item paused_menu[] = {
|
static const struct menu_item paused_menu[] = {
|
||||||
{"Resume", NULL},
|
{"Resume", NULL},
|
||||||
{"Graphic Options", enter_graphics_menu},
|
{"Graphic Options", enter_graphics_menu},
|
||||||
{"Controls", enter_controls_menu},
|
{"Keyboard", enter_controls_menu},
|
||||||
|
{"Joypad", enter_joypad_menu},
|
||||||
{"Help", item_help},
|
{"Help", item_help},
|
||||||
{"Exit", item_exit},
|
{"Exit", item_exit},
|
||||||
{NULL,}
|
{NULL,}
|
||||||
@ -202,7 +208,8 @@ static const struct menu_item paused_menu[] = {
|
|||||||
|
|
||||||
static const struct menu_item nonpaused_menu[] = {
|
static const struct menu_item nonpaused_menu[] = {
|
||||||
{"Graphic Options", enter_graphics_menu},
|
{"Graphic Options", enter_graphics_menu},
|
||||||
{"Controls", enter_controls_menu},
|
{"Keyboard", enter_controls_menu},
|
||||||
|
{"Joypad", enter_joypad_menu},
|
||||||
{"Help", item_help},
|
{"Help", item_help},
|
||||||
{"Exit", item_exit},
|
{"Exit", item_exit},
|
||||||
{NULL,}
|
{NULL,}
|
||||||
@ -316,10 +323,102 @@ static void enter_controls_menu(unsigned index)
|
|||||||
current_selection = 0;
|
current_selection = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned joypad_index = 0;
|
||||||
|
SDL_Joystick *joystick = NULL;
|
||||||
|
const char *current_joypad_name(unsigned index)
|
||||||
|
{
|
||||||
|
static char name[23] = {0,};
|
||||||
|
const char *orig_name = joystick? SDL_JoystickName(joystick) : NULL;
|
||||||
|
if (!orig_name) return "Not Found";
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
// SDL returns a name with repeated and trailing spaces
|
||||||
|
while (*orig_name && i < sizeof(name) - 2) {
|
||||||
|
if (orig_name[0] != ' ' || orig_name[1] != ' ') {
|
||||||
|
name[i++] = *orig_name;
|
||||||
|
}
|
||||||
|
orig_name++;
|
||||||
|
}
|
||||||
|
if (i && name[i - 1] == ' ') {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
name[i] = 0;
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cycle_joypads(unsigned index)
|
||||||
|
{
|
||||||
|
joypad_index++;
|
||||||
|
if (joypad_index >= SDL_NumJoysticks()) {
|
||||||
|
joypad_index = 0;
|
||||||
|
}
|
||||||
|
if (joystick) {
|
||||||
|
SDL_JoystickClose(joystick);
|
||||||
|
}
|
||||||
|
joystick = SDL_JoystickOpen(joypad_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned fix_joypad_button(unsigned button)
|
||||||
|
{
|
||||||
|
if (configuration.div_joystick) {
|
||||||
|
button >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button < 4) {
|
||||||
|
if (configuration.swap_joysticks_bits_1_and_2) {
|
||||||
|
button = (int[]){0, 2, 1, 3}[button];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuration.flip_joystick_bit_1) {
|
||||||
|
button ^= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cycle_joypads_backwards(unsigned index)
|
||||||
|
{
|
||||||
|
joypad_index++;
|
||||||
|
if (joypad_index >= SDL_NumJoysticks()) {
|
||||||
|
joypad_index = SDL_NumJoysticks() - 1;
|
||||||
|
}
|
||||||
|
if (joystick) {
|
||||||
|
SDL_JoystickClose(joystick);
|
||||||
|
}
|
||||||
|
joystick = SDL_JoystickOpen(joypad_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void detect_joypad_layout(unsigned index)
|
||||||
|
{
|
||||||
|
gui_state = WAITING_FOR_JBUTTON;
|
||||||
|
auto_detect_progress = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct menu_item joypad_menu[] = {
|
||||||
|
{"Joypad:", cycle_joypads, current_joypad_name, cycle_joypads_backwards},
|
||||||
|
{"Detect layout", detect_joypad_layout},
|
||||||
|
{NULL,}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void enter_joypad_menu(unsigned index)
|
||||||
|
{
|
||||||
|
current_menu = joypad_menu;
|
||||||
|
current_selection = 0;
|
||||||
|
}
|
||||||
|
|
||||||
extern void set_filename(const char *new_filename, bool new_should_free);
|
extern void set_filename(const char *new_filename, bool new_should_free);
|
||||||
void run_gui(bool is_running)
|
void run_gui(bool is_running)
|
||||||
{
|
{
|
||||||
/* Draw the "Drop file" screen */
|
if (joystick && !SDL_NumJoysticks()) {
|
||||||
|
SDL_JoystickClose(joystick);
|
||||||
|
joystick = NULL;
|
||||||
|
}
|
||||||
|
else if (!joystick && SDL_NumJoysticks()) {
|
||||||
|
joystick = SDL_JoystickOpen(0);
|
||||||
|
}
|
||||||
|
/* Draw the background screen */
|
||||||
static SDL_Surface *converted_background = NULL;
|
static SDL_Surface *converted_background = NULL;
|
||||||
if (!converted_background) {
|
if (!converted_background) {
|
||||||
SDL_Surface *background = SDL_LoadBMP(executable_relative_path("background.bmp"));
|
SDL_Surface *background = SDL_LoadBMP(executable_relative_path("background.bmp"));
|
||||||
@ -340,6 +439,63 @@ void run_gui(bool is_running)
|
|||||||
current_menu = root_menu = is_running? paused_menu : nonpaused_menu;
|
current_menu = root_menu = is_running? paused_menu : nonpaused_menu;
|
||||||
current_selection = 0;
|
current_selection = 0;
|
||||||
do {
|
do {
|
||||||
|
/* Convert Joypad events (We only generate down events) */
|
||||||
|
if (gui_state != WAITING_FOR_KEY && gui_state != WAITING_FOR_JBUTTON) {
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_JOYBUTTONDOWN:
|
||||||
|
event.type = SDL_KEYDOWN;
|
||||||
|
event.jbutton.button = fix_joypad_button(event.jbutton.button);
|
||||||
|
if (event.jbutton.button < 4) {
|
||||||
|
event.key.keysym.scancode = (event.jbutton.button & 1) ? SDL_SCANCODE_RETURN : SDL_SCANCODE_ESCAPE;
|
||||||
|
}
|
||||||
|
else if (event.jbutton.button == 8 || event.jbutton.button == 9) {
|
||||||
|
event.key.keysym.scancode = SDL_SCANCODE_ESCAPE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_JOYAXISMOTION: {
|
||||||
|
static bool axis_active[2] = {false, false};
|
||||||
|
if ((event.jaxis.axis >> configuration.div_joystick) & 1) {
|
||||||
|
if (event.jaxis.value > 0x4000) {
|
||||||
|
if (!axis_active[1]) {
|
||||||
|
event.type = SDL_KEYDOWN;
|
||||||
|
event.key.keysym.scancode = SDL_SCANCODE_DOWN;
|
||||||
|
}
|
||||||
|
axis_active[1] = true;
|
||||||
|
}
|
||||||
|
else if (event.jaxis.value < -0x4000) {
|
||||||
|
if (!axis_active[0]) {
|
||||||
|
event.type = SDL_KEYDOWN;
|
||||||
|
event.key.keysym.scancode = SDL_SCANCODE_UP;
|
||||||
|
}
|
||||||
|
axis_active[1] = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
axis_active[1] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (event.jaxis.value > 0x4000) {
|
||||||
|
if (!axis_active[0]) {
|
||||||
|
event.type = SDL_KEYDOWN;
|
||||||
|
event.key.keysym.scancode = SDL_SCANCODE_RIGHT;
|
||||||
|
}
|
||||||
|
axis_active[0] = true;
|
||||||
|
}
|
||||||
|
else if (event.jaxis.value < -0x4000) {
|
||||||
|
if (!axis_active[0]) {
|
||||||
|
event.type = SDL_KEYDOWN;
|
||||||
|
event.key.keysym.scancode = SDL_SCANCODE_LEFT;
|
||||||
|
}
|
||||||
|
axis_active[0] = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
axis_active[0] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_QUIT: {
|
case SDL_QUIT: {
|
||||||
if (!is_running) {
|
if (!is_running) {
|
||||||
@ -365,6 +521,36 @@ void run_gui(bool is_running)
|
|||||||
pending_command = GB_SDL_NEW_FILE_COMMAND;
|
pending_command = GB_SDL_NEW_FILE_COMMAND;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case SDL_JOYBUTTONDOWN:
|
||||||
|
{
|
||||||
|
if (gui_state == WAITING_FOR_JBUTTON) {
|
||||||
|
should_render = true;
|
||||||
|
auto_detect_inputs[auto_detect_progress++] = event.jbutton.button;
|
||||||
|
if (auto_detect_progress == 3) {
|
||||||
|
gui_state = SHOWING_MENU;
|
||||||
|
|
||||||
|
configuration.div_joystick =
|
||||||
|
((auto_detect_inputs[0] | auto_detect_inputs[1] | auto_detect_inputs[2]) & 1) == 0 &&
|
||||||
|
auto_detect_inputs[0] > 9;
|
||||||
|
|
||||||
|
if (configuration.div_joystick) {
|
||||||
|
auto_detect_inputs[0] >>= 1;
|
||||||
|
auto_detect_inputs[1] >>= 1;
|
||||||
|
auto_detect_inputs[2] >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration.swap_joysticks_bits_1_and_2 =
|
||||||
|
(auto_detect_inputs[1] & 1) == (auto_detect_inputs[2] & 1);
|
||||||
|
|
||||||
|
if (configuration.swap_joysticks_bits_1_and_2) {
|
||||||
|
auto_detect_inputs[1] = (int[]){0, 2, 1, 3}[auto_detect_inputs[1]];
|
||||||
|
auto_detect_inputs[2] = (int[]){0, 2, 1, 3}[auto_detect_inputs[2]];
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration.flip_joystick_bit_1 = auto_detect_inputs[2] & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) {
|
if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) {
|
||||||
if (is_running) {
|
if (is_running) {
|
||||||
@ -470,6 +656,15 @@ void run_gui(bool is_running)
|
|||||||
case WAITING_FOR_KEY:
|
case WAITING_FOR_KEY:
|
||||||
draw_text_centered(pixels, 68, "Press a Key", gui_palette_native[3], gui_palette_native[0], DECORATION_NONE);
|
draw_text_centered(pixels, 68, "Press a Key", gui_palette_native[3], gui_palette_native[0], DECORATION_NONE);
|
||||||
break;
|
break;
|
||||||
|
case WAITING_FOR_JBUTTON:
|
||||||
|
draw_text_centered(pixels, 68, (const char *[])
|
||||||
|
{
|
||||||
|
"Press button for Start",
|
||||||
|
"Press button for A",
|
||||||
|
"Press button for B",
|
||||||
|
} [auto_detect_progress],
|
||||||
|
gui_palette_native[3], gui_palette_native[0], DECORATION_NONE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_UpdateTexture(texture, NULL, pixels, 160 * sizeof (uint32_t));
|
SDL_UpdateTexture(texture, NULL, pixels, 160 * sizeof (uint32_t));
|
||||||
|
@ -33,11 +33,16 @@ typedef struct {
|
|||||||
SDL_Scancode keys[9];
|
SDL_Scancode keys[9];
|
||||||
GB_color_correction_mode_t color_correction_mode;
|
GB_color_correction_mode_t color_correction_mode;
|
||||||
enum scaling_mode scaling_mode;
|
enum scaling_mode scaling_mode;
|
||||||
|
|
||||||
|
bool div_joystick;
|
||||||
|
bool flip_joystick_bit_1;
|
||||||
|
bool swap_joysticks_bits_1_and_2;
|
||||||
} configuration_t;
|
} configuration_t;
|
||||||
|
|
||||||
extern configuration_t configuration;
|
extern configuration_t configuration;
|
||||||
|
|
||||||
void update_viewport(void);
|
void update_viewport(void);
|
||||||
|
|
||||||
void run_gui(bool is_running);
|
void run_gui(bool is_running);
|
||||||
|
unsigned fix_joypad_button(unsigned button);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
34
SDL/main.c
34
SDL/main.c
@ -96,8 +96,42 @@ static void handle_events(GB_gameboy_t *gb)
|
|||||||
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||||
update_viewport();
|
update_viewport();
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SDL_JOYBUTTONUP:
|
||||||
|
case SDL_JOYBUTTONDOWN:
|
||||||
|
event.jbutton.button = fix_joypad_button(event.jbutton.button);
|
||||||
|
if (event.jbutton.button < 4) {
|
||||||
|
GB_set_key_state(gb, (event.jbutton.button & 1) ? GB_KEY_A : GB_KEY_B,
|
||||||
|
event.type == SDL_JOYBUTTONDOWN);
|
||||||
|
}
|
||||||
|
else if (event.jbutton.button == 8) {
|
||||||
|
GB_set_key_state(gb, GB_KEY_SELECT, event.type == SDL_JOYBUTTONDOWN);
|
||||||
|
}
|
||||||
|
else if (event.jbutton.button == 9) {
|
||||||
|
GB_set_key_state(gb, GB_KEY_START, event.type == SDL_JOYBUTTONDOWN);
|
||||||
|
}
|
||||||
|
else if (event.jbutton.button & 1) {
|
||||||
|
GB_set_turbo_mode(gb, event.type == SDL_JOYBUTTONDOWN, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
run_gui(true);
|
||||||
|
GB_set_color_correction_mode(gb, configuration.color_correction_mode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_JOYAXISMOTION:
|
||||||
|
if ((event.jaxis.axis >> configuration.div_joystick) & 1) {
|
||||||
|
GB_set_key_state(gb, GB_KEY_DOWN, event.jaxis.value > 0x4000);
|
||||||
|
GB_set_key_state(gb, GB_KEY_UP, event.jaxis.value < -0x4000);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GB_set_key_state(gb, GB_KEY_RIGHT, event.jaxis.value > 0x4000);
|
||||||
|
GB_set_key_state(gb, GB_KEY_LEFT, event.jaxis.value < -0x4000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
switch (event.key.keysym.scancode) {
|
switch (event.key.keysym.scancode) {
|
||||||
case SDL_SCANCODE_ESCAPE:
|
case SDL_SCANCODE_ESCAPE:
|
||||||
|
Loading…
Reference in New Issue
Block a user