[GTK3] Implement hard-coded input handling
This commit is contained in:
parent
404e9dd1d5
commit
5f4e533f2b
139
gtk3/main.c
139
gtk3/main.c
@ -23,6 +23,17 @@ typedef struct{
|
|||||||
uint16_t w, h;
|
uint16_t w, h;
|
||||||
} Rect;
|
} Rect;
|
||||||
|
|
||||||
|
#define BUTTON_MASK_A 0x01
|
||||||
|
#define BUTTON_MASK_B 0x02
|
||||||
|
#define BUTTON_MASK_START 0x04
|
||||||
|
#define BUTTON_MASK_SELECT 0x08
|
||||||
|
#define BUTTON_MASK_UP 0x10
|
||||||
|
#define BUTTON_MASK_DOWN 0x20
|
||||||
|
#define BUTTON_MASK_LEFT 0x40
|
||||||
|
#define BUTTON_MASK_RIGHT 0x80
|
||||||
|
|
||||||
|
static uint8_t pressed_buttons;
|
||||||
|
|
||||||
static void run(GApplication *app, UserData *user_data);
|
static void run(GApplication *app, UserData *user_data);
|
||||||
|
|
||||||
static GtkApplication *main_application;
|
static GtkApplication *main_application;
|
||||||
@ -38,6 +49,7 @@ static GtkWindow *printer;
|
|||||||
|
|
||||||
static shader_t shader;
|
static shader_t shader;
|
||||||
|
|
||||||
|
static UserData user_data = { NULL };
|
||||||
static GB_gameboy_t gb;
|
static GB_gameboy_t gb;
|
||||||
static uint32_t *image_buffers[3];
|
static uint32_t *image_buffers[3];
|
||||||
static unsigned char current_buffer;
|
static unsigned char current_buffer;
|
||||||
@ -90,6 +102,21 @@ static void render_texture(void *pixels, void *previous) {
|
|||||||
render_bitmap_with_shader(&shader, _pixels, previous, GB_get_screen_width(&gb), GB_get_screen_height(&gb), rect.x, rect.y, rect.w, rect.h);
|
render_bitmap_with_shader(&shader, _pixels, previous, GB_get_screen_width(&gb), GB_get_screen_height(&gb), rect.x, rect.y, rect.w, rect.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_events(GB_gameboy_t *gb) {
|
||||||
|
while (gtk_events_pending()) {
|
||||||
|
gtk_main_iteration();
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_set_key_state(gb, GB_KEY_RIGHT, pressed_buttons & BUTTON_MASK_RIGHT);
|
||||||
|
GB_set_key_state(gb, GB_KEY_LEFT, pressed_buttons & BUTTON_MASK_LEFT);
|
||||||
|
GB_set_key_state(gb, GB_KEY_UP, pressed_buttons & BUTTON_MASK_UP);
|
||||||
|
GB_set_key_state(gb, GB_KEY_DOWN, pressed_buttons & BUTTON_MASK_DOWN);
|
||||||
|
GB_set_key_state(gb, GB_KEY_A, pressed_buttons & BUTTON_MASK_A);
|
||||||
|
GB_set_key_state(gb, GB_KEY_B, pressed_buttons & BUTTON_MASK_B);
|
||||||
|
GB_set_key_state(gb, GB_KEY_SELECT, pressed_buttons & BUTTON_MASK_SELECT);
|
||||||
|
GB_set_key_state(gb, GB_KEY_START, pressed_buttons & BUTTON_MASK_START);
|
||||||
|
}
|
||||||
|
|
||||||
static void vblank(GB_gameboy_t *gb) {
|
static void vblank(GB_gameboy_t *gb) {
|
||||||
flip();
|
flip();
|
||||||
GB_set_pixels_output(gb, get_pixels());
|
GB_set_pixels_output(gb, get_pixels());
|
||||||
@ -105,10 +132,6 @@ static void vblank(GB_gameboy_t *gb) {
|
|||||||
// Queue a redraw of the VRAM viewer
|
// Queue a redraw of the VRAM viewer
|
||||||
gtk_widget_queue_draw(GTK_WIDGET(vram_viewer));
|
gtk_widget_queue_draw(GTK_WIDGET(vram_viewer));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (gtk_events_pending()) {
|
|
||||||
gtk_main_iteration();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_viewport(void) {
|
static void update_viewport(void) {
|
||||||
@ -206,17 +229,21 @@ static void quit(GApplication *app) {
|
|||||||
// Tell our own main loop to quit.
|
// Tell our own main loop to quit.
|
||||||
// This will allow our run() and therefore our activate() methods to end.
|
// This will allow our run() and therefore our activate() methods to end.
|
||||||
running = false;
|
running = false;
|
||||||
|
|
||||||
|
// Quit our application properly.
|
||||||
|
// This fires the “shutdown” signal.
|
||||||
|
g_application_quit(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
// app.quit GAction
|
// app.quit GAction
|
||||||
// Exits the application
|
// Exits the application
|
||||||
static void activate_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
static void activate_quit(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||||
quit(G_APPLICATION(user_data));
|
quit(G_APPLICATION(app));
|
||||||
}
|
}
|
||||||
|
|
||||||
// app.about GAction
|
// app.about GAction
|
||||||
// Opens the about dialog
|
// Opens the about dialog
|
||||||
static void activate_about(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
static void activate_about(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||||
GObject *dialog = get_object("about_dialog");
|
GObject *dialog = get_object("about_dialog");
|
||||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||||
gtk_widget_hide(GTK_WIDGET(dialog));
|
gtk_widget_hide(GTK_WIDGET(dialog));
|
||||||
@ -224,38 +251,79 @@ static void activate_about(GSimpleAction *action, GVariant *parameter, gpointer
|
|||||||
|
|
||||||
// app.open_gtk_debugger GAction
|
// app.open_gtk_debugger GAction
|
||||||
// Opens the GTK debugger
|
// Opens the GTK debugger
|
||||||
static void activate_open_gtk_debugger(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
static void activate_open_gtk_debugger(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||||
gtk_window_set_interactive_debugging(true);
|
gtk_window_set_interactive_debugging(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// app.preferences GAction
|
// app.preferences GAction
|
||||||
// Opens the preferences window
|
// Opens the preferences window
|
||||||
static void activate_preferences(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
static void activate_preferences(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||||
gtk_widget_show_all(GTK_WIDGET(get_object("preferences")));
|
gtk_widget_show_all(GTK_WIDGET(get_object("preferences")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// app.open_vram_viewer GAction
|
// app.open_vram_viewer GAction
|
||||||
// Opens the VRAM viewer window
|
// Opens the VRAM viewer window
|
||||||
static void activate_open_vram_viewer(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
static void activate_open_vram_viewer(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||||
gtk_widget_show_all(GTK_WIDGET(vram_viewer));
|
gtk_widget_show_all(GTK_WIDGET(vram_viewer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// app.open_memory_viewer GAction
|
// app.open_memory_viewer GAction
|
||||||
// Opens the memory viewer window
|
// Opens the memory viewer window
|
||||||
static void activate_open_memory_viewer(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
|
static void activate_open_memory_viewer(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||||
gtk_widget_show_all(GTK_WIDGET(memory_viewer));
|
gtk_widget_show_all(GTK_WIDGET(memory_viewer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// app.open GAction
|
||||||
|
// Opens a ROM file
|
||||||
|
static void activate_open(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||||
|
GtkFileChooserNative *native = gtk_file_chooser_native_new("Open File", GTK_WINDOW(main_window), GTK_FILE_CHOOSER_ACTION_OPEN, "_Open", "_Cancel");
|
||||||
|
gint res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native));
|
||||||
|
|
||||||
|
if (res == GTK_RESPONSE_ACCEPT) {
|
||||||
|
g_print("%s\n", gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(native)));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref(native);
|
||||||
|
}
|
||||||
|
|
||||||
// List of GActions for the `app` prefix
|
// List of GActions for the `app` prefix
|
||||||
static GActionEntry app_entries[] = {
|
static GActionEntry app_entries[] = {
|
||||||
{ "quit", activate_quit, NULL, NULL, NULL },
|
{ "quit", activate_quit, NULL, NULL, NULL },
|
||||||
{ "about", activate_about, NULL, NULL, NULL },
|
{ "about", activate_about, NULL, NULL, NULL },
|
||||||
|
{ "open", activate_open, NULL, NULL, NULL },
|
||||||
{ "open_gtk_debugger", activate_open_gtk_debugger, NULL, NULL, NULL },
|
{ "open_gtk_debugger", activate_open_gtk_debugger, NULL, NULL, NULL },
|
||||||
{ "preferences", activate_preferences, NULL, NULL, NULL },
|
{ "preferences", activate_preferences, NULL, NULL, NULL },
|
||||||
{ "open_vram_viewer", activate_open_vram_viewer, NULL, NULL, NULL },
|
{ "open_vram_viewer", activate_open_vram_viewer, NULL, NULL, NULL },
|
||||||
{ "open_memory_viewer", activate_open_memory_viewer, NULL, NULL, NULL },
|
{ "open_memory_viewer", activate_open_memory_viewer, NULL, NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
G_MODULE_EXPORT gboolean on_key_press(GtkWidget *w, GdkEventKey *event, gpointer data) {
|
||||||
|
uint8_t mask;
|
||||||
|
|
||||||
|
// TODO: Allow control remapping in the GUI
|
||||||
|
switch (event->keyval) {
|
||||||
|
case GDK_KEY_w: mask = BUTTON_MASK_UP; break;
|
||||||
|
case GDK_KEY_a: mask = BUTTON_MASK_LEFT; break;
|
||||||
|
case GDK_KEY_s: mask = BUTTON_MASK_DOWN; break;
|
||||||
|
case GDK_KEY_d: mask = BUTTON_MASK_RIGHT; break;
|
||||||
|
|
||||||
|
case GDK_KEY_g: mask = BUTTON_MASK_SELECT; break;
|
||||||
|
case GDK_KEY_h: mask = BUTTON_MASK_START; break;
|
||||||
|
|
||||||
|
case GDK_KEY_k: mask = BUTTON_MASK_B; break;
|
||||||
|
case GDK_KEY_l: mask = BUTTON_MASK_A; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->type == GDK_KEY_PRESS) {
|
||||||
|
pressed_buttons |= mask;
|
||||||
|
}
|
||||||
|
else if (event->type == GDK_KEY_RELEASE) {
|
||||||
|
pressed_buttons &= ~mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
G_MODULE_EXPORT void on_quit(GtkWidget *w, gpointer app) {
|
G_MODULE_EXPORT void on_quit(GtkWidget *w, gpointer app) {
|
||||||
quit(G_APPLICATION(app));
|
quit(G_APPLICATION(app));
|
||||||
}
|
}
|
||||||
@ -473,6 +541,11 @@ static void startup(GApplication *app, gpointer user_data_gptr) {
|
|||||||
set_combo_box_row_separator_func(GTK_CONTAINER(memory_viewer));
|
set_combo_box_row_separator_func(GTK_CONTAINER(memory_viewer));
|
||||||
|
|
||||||
// Connect signal handlers
|
// Connect signal handlers
|
||||||
|
gtk_widget_add_events(GTK_WIDGET(main_window), GDK_KEY_PRESS_MASK);
|
||||||
|
gtk_widget_add_events(GTK_WIDGET(main_window), GDK_KEY_RELEASE_MASK);
|
||||||
|
g_signal_connect(main_window, "key_press_event", G_CALLBACK(on_key_press), NULL);
|
||||||
|
g_signal_connect(main_window, "key_release_event", G_CALLBACK(on_key_press), NULL);
|
||||||
|
|
||||||
g_signal_connect(gl_area, "realize", G_CALLBACK(gl_init), NULL);
|
g_signal_connect(gl_area, "realize", G_CALLBACK(gl_init), NULL);
|
||||||
g_signal_connect(gl_area, "render", G_CALLBACK(gl_draw), NULL);
|
g_signal_connect(gl_area, "render", G_CALLBACK(gl_draw), NULL);
|
||||||
g_signal_connect(gl_area, "resize", G_CALLBACK(gl_resize), NULL);
|
g_signal_connect(gl_area, "resize", G_CALLBACK(gl_resize), NULL);
|
||||||
@ -725,7 +798,7 @@ static void run(GApplication *app, UserData *user_data) {
|
|||||||
GB_set_color_correction_mode(&gb, get_color_correction_mode());
|
GB_set_color_correction_mode(&gb, get_color_correction_mode());
|
||||||
GB_set_highpass_filter_mode(&gb, get_highpass_mode());
|
GB_set_highpass_filter_mode(&gb, get_highpass_mode());
|
||||||
GB_set_rewind_length(&gb, config.rewind_duration);
|
GB_set_rewind_length(&gb, config.rewind_duration);
|
||||||
// GB_set_update_input_hint_callback(&gb, handle_events);
|
GB_set_update_input_hint_callback(&gb, handle_events);
|
||||||
// GB_apu_set_sample_callback(&gb, gb_audio_callback);
|
// GB_apu_set_sample_callback(&gb, gb_audio_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,43 +867,35 @@ static void run(GApplication *app, UserData *user_data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user_data->file != NULL) {
|
if (user_data->file != NULL && GB_load_rom(&gb, g_file_get_path(user_data->file)) == 0) {
|
||||||
GB_load_rom(&gb, g_file_get_path(user_data->file));
|
/* Run emulation */
|
||||||
}
|
while (running) {
|
||||||
|
if (paused || rewind_paused) {
|
||||||
/* Run emulation */
|
while (gtk_events_pending()) {
|
||||||
while (running) {
|
gtk_main_iteration();
|
||||||
if (paused || rewind_paused) {
|
}
|
||||||
while (gtk_events_pending()) {
|
|
||||||
gtk_main_iteration();
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
else {
|
if (do_rewind) {
|
||||||
if (do_rewind) {
|
|
||||||
GB_rewind_pop(&gb);
|
|
||||||
if (turbo_down) {
|
|
||||||
GB_rewind_pop(&gb);
|
GB_rewind_pop(&gb);
|
||||||
|
if (turbo_down) {
|
||||||
|
GB_rewind_pop(&gb);
|
||||||
|
}
|
||||||
|
if (!GB_rewind_pop(&gb)) {
|
||||||
|
rewind_paused = true;
|
||||||
|
}
|
||||||
|
do_rewind = false;
|
||||||
}
|
}
|
||||||
if (!GB_rewind_pop(&gb)) {
|
GB_run(&gb);
|
||||||
rewind_paused = true;
|
|
||||||
}
|
|
||||||
do_rewind = false;
|
|
||||||
}
|
}
|
||||||
GB_run(&gb);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit our application properly.
|
|
||||||
// This fires the “shutdown” signal.
|
|
||||||
g_application_quit(app);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
// Create our GApplication and tell GTK that we are able to handle files
|
// Create our GApplication and tell GTK that we are able to handle files
|
||||||
main_application = gtk_application_new(APP_ID, G_APPLICATION_HANDLES_OPEN);
|
main_application = gtk_application_new(APP_ID, G_APPLICATION_HANDLES_OPEN);
|
||||||
|
|
||||||
UserData user_data = { NULL };
|
|
||||||
|
|
||||||
// Define our command line parameters
|
// Define our command line parameters
|
||||||
GOptionEntry entries[] = {
|
GOptionEntry entries[] = {
|
||||||
{ "version", 'v', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Show the application version", NULL },
|
{ "version", 'v', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Show the application version", NULL },
|
||||||
|
Loading…
Reference in New Issue
Block a user