11#include "frontend.h"
2- #include "SDL3/SDL_iostream.h"
32#include "control.h"
43#include "cpu.h"
54#include "game_boy.h"
65#include "log.h"
76#include "sdl.h"
87#include "stdinc.h"
9- #include <SDL3/SDL_dialog.h>
10- #include <SDL3/SDL_error.h>
11- #include <SDL3/SDL_events.h>
12- #include <SDL3/SDL_keycode.h>
13- #include <SDL3/SDL_pixels.h>
14- #include <SDL3/SDL_rect.h>
15- #include <SDL3/SDL_render.h>
16- #include <SDL3/SDL_surface.h>
17- #include <SDL3/SDL_timer.h>
8+ #include <SDL3/SDL.h>
189#include <stddef.h>
1910#include <stdio.h>
2011#include <stdlib.h>
@@ -59,7 +50,7 @@ static const u8 PALETTE_RGB[PALETTE_RGB_LEN][3] = {
5950 * \brief Maps an index in the range 0-3 (inclusive) to its corresponding RGB
6051 * color.
6152 *
62- * Will bail if color_index > 3 .
53+ * Will bail if color_index >= PALETTE_RGB_LEN .
6354 *
6455 * \param color_index the index of the desired color (must be in the range 0-3
6556 * inclusive).
@@ -80,32 +71,51 @@ static u32 map_color_index(const size_t color_index,
8071 color_rgb [2 ]);
8172}
8273
83- static bool * get_joypad_key (GameBoy * const gb , const SDL_Keycode key )
74+ /**
75+ * \brief Maps a combination of SDL_Keycode and SDL_Keymod to their
76+ * corresponding bool flag in a JoypadState.
77+ *
78+ * Will return NULL if key+mod combination does not map to a valid button.
79+ *
80+ * \param joypad the JoypadState whose joypad the key will be mapped onto.
81+ * \param key the key to be mapped.
82+ * \param mod the key to be mapped.
83+ *
84+ * \return a pointer to the bool flag of the button that corresponds to key.
85+ *
86+ * \sa SDL_Keycode
87+ */
88+ static bool * map_joypad_btn (JoypadState * const joypad , const SDL_Keycode key ,
89+ const SDL_Keymod mod )
8490{
91+ if (mod != SDL_KMOD_NONE )
92+ return nullptr ;
93+
8594 switch (key ) {
8695 case SDLK_RETURN :
87- return & gb -> joypad . start ;
96+ return & joypad -> start ;
8897 case SDLK_SPACE :
89- return & gb -> joypad . select ;
98+ return & joypad -> select ;
9099 case SDLK_UP :
91- return & gb -> joypad . up ;
100+ return & joypad -> up ;
92101 case SDLK_DOWN :
93- return & gb -> joypad . down ;
102+ return & joypad -> down ;
94103 case SDLK_RIGHT :
95- return & gb -> joypad . right ;
104+ return & joypad -> right ;
96105 case SDLK_LEFT :
97- return & gb -> joypad . left ;
106+ return & joypad -> left ;
98107 case SDLK_X :
99- return & gb -> joypad . a ;
108+ return & joypad -> a ;
100109 case SDLK_Z :
101- return & gb -> joypad . b ;
110+ return & joypad -> b ;
102111 default :
103112 return nullptr ;
104113 }
105114}
106115
107- static void file_callback (void * const data , const char * const * const files ,
108- [[maybe_unused ]] const int filter )
116+ static void rom_select_callback (void * const data ,
117+ const char * const * const files ,
118+ [[maybe_unused ]] const int filter )
109119{
110120 if (files == nullptr ) {
111121 log_error ("Error selecting ROM file: %s" , SDL_GetError ());
@@ -130,6 +140,14 @@ static void file_callback(void *const data, const char *const *const files,
130140
131141 GameBoy_load_rom (gb , rom , rom_len );
132142 GameBoy_log_cartridge_info (gb );
143+
144+ SDL_free (rom );
145+ }
146+
147+ static inline SDL_Keymod mask_relevant_mod (const SDL_Keymod mod )
148+ {
149+ return mod &
150+ (SDL_KMOD_CTRL | SDL_KMOD_SHIFT | SDL_KMOD_ALT | SDL_KMOD_CAPS );
133151}
134152
135153static void handle_event (State * const state , const SDL_Event * const event )
@@ -143,22 +161,29 @@ static void handle_event(State *const state, const SDL_Event *const event)
143161 state -> window_height = event -> window .data2 ;
144162 break ;
145163 case SDL_EVENT_KEY_DOWN : {
146- bool * const state_key = get_joypad_key (& state -> gb , event -> key .key );
147- if (state_key != nullptr ) {
164+ const SDL_Keymod relevant_mod = mask_relevant_mod (event -> key .mod );
165+ bool * const joypad_btn =
166+ map_joypad_btn (& state -> gb .joypad , event -> key .key , relevant_mod );
167+
168+ if (joypad_btn != nullptr ) {
169+ * joypad_btn = true;
148170 break ;
149- * state_key = true;
150171 }
151172
152- if (event -> key .mod & SDL_KMOD_CTRL && event -> key .key == SDLK_O ) {
153- SDL_ShowOpenFileDialog (file_callback , & state -> gb , nullptr , nullptr ,
154- 0 , nullptr , false);
173+ // <C-o> to select ROM
174+ if (relevant_mod & SDL_KMOD_CTRL && event -> key .key == SDLK_O ) {
175+ SDL_ShowOpenFileDialog (rom_select_callback , & state -> gb , nullptr ,
176+ nullptr , 0 , nullptr , false);
155177 }
156178 break ;
157179 }
158180 case SDL_EVENT_KEY_UP : {
159- bool * const state_key = get_joypad_key (& state -> gb , event -> key .key );
160- if (state_key != nullptr )
161- * state_key = false;
181+ const SDL_Keymod relevant_mod = mask_relevant_mod (event -> key .mod );
182+ bool * const joypad_btn =
183+ map_joypad_btn (& state -> gb .joypad , event -> key .key , relevant_mod );
184+
185+ if (joypad_btn != nullptr )
186+ * joypad_btn = false;
162187
163188 break ;
164189 }
@@ -178,8 +203,9 @@ static void update(State *const state, const double delta)
178203
179204 const double total_frame_cycles = GB_CPU_FREQUENCY_HZ * delta ;
180205
181- const double VFRAME_DURATION = 1.0 / GB_VBLANK_FREQ ;
182- const int DIV_FREQUENCY_CYCLES = GB_CPU_FREQUENCY_HZ / DIV_FREQUENCY_HZ ;
206+ static constexpr double VFRAME_DURATION = 1.0 / GB_VBLANK_FREQ ;
207+ static constexpr int DIV_FREQUENCY_CYCLES =
208+ GB_CPU_FREQUENCY_HZ / DIV_FREQUENCY_HZ ;
183209
184210 while (state -> cycle_accumulator < total_frame_cycles ) {
185211 const double actual_vframe_time =
0 commit comments