[GTK3] Implement hard-coded input handling

This commit is contained in:
Maximilian Mader 2019-09-28 23:34:18 +02:00
parent a243325b8c
commit 6c5dfece40
Signed by: Max
GPG Key ID: F71D56A3151C4FB3
1 changed files with 102 additions and 37 deletions

View File

@ -23,6 +23,17 @@ typedef struct{
uint16_t w, h;
} 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 GtkApplication *main_application;
@ -38,6 +49,7 @@ static GtkWindow *printer;
static shader_t shader;
static UserData user_data = { NULL };
static GB_gameboy_t gb;
static uint32_t *image_buffers[3];
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);
}
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) {
flip();
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
gtk_widget_queue_draw(GTK_WIDGET(vram_viewer));
}
while (gtk_events_pending()) {
gtk_main_iteration();
}
}
static void update_viewport(void) {
@ -206,17 +229,21 @@ static void quit(GApplication *app) {
// Tell our own main loop to quit.
// This will allow our run() and therefore our activate() methods to end.
running = false;
// Quit our application properly.
// This fires the “shutdown” signal.
g_application_quit(app);
}
// app.quit GAction
// Exits the application
static void activate_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
quit(G_APPLICATION(user_data));
static void activate_quit(GSimpleAction *action, GVariant *parameter, gpointer app) {
quit(G_APPLICATION(app));
}
// app.about GAction
// 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");
gtk_dialog_run(GTK_DIALOG(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
// 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);
}
// app.preferences GAction
// 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")));
}
// app.open_vram_viewer GAction
// 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));
}
// app.open_memory_viewer GAction
// 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));
}
// 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
static GActionEntry app_entries[] = {
{ "quit", activate_quit, 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 },
{ "preferences", activate_preferences, NULL, NULL, NULL },
{ "open_vram_viewer", activate_open_vram_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) {
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));
// 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, "render", G_CALLBACK(gl_draw), 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_highpass_filter_mode(&gb, get_highpass_mode());
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);
}
@ -794,10 +867,7 @@ static void run(GApplication *app, UserData *user_data) {
}
}
if (user_data->file != NULL) {
GB_load_rom(&gb, g_file_get_path(user_data->file));
}
if (user_data->file != NULL && GB_load_rom(&gb, g_file_get_path(user_data->file)) == 0) {
/* Run emulation */
while (running) {
if (paused || rewind_paused) {
@ -819,18 +889,13 @@ static void run(GApplication *app, UserData *user_data) {
GB_run(&gb);
}
}
// Quit our application properly.
// This fires the “shutdown” signal.
g_application_quit(app);
}
}
int main(int argc, char *argv[]) {
// Create our GApplication and tell GTK that we are able to handle files
main_application = gtk_application_new(APP_ID, G_APPLICATION_HANDLES_OPEN);
UserData user_data = { NULL };
// Define our command line parameters
GOptionEntry entries[] = {
{ "version", 'v', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Show the application version", NULL },