diff --git a/Makefile b/Makefile
index e571d72..75b93fe 100644
--- a/Makefile
+++ b/Makefile
@@ -126,13 +126,6 @@ ifeq ($(SDL_AUDIO_DRIVER),sdl)
GTK_OPTIONS += -DUSE_SDL_AUDIO
endif
-# Use SDL’s haptic feedback subsystem by default, although
-# some controllers only work with the simpler SDL_GameControllerRumble / SDL_JoystickRumble,
-# but SDL’s WUP-028 (Wii U GameCube Controller Adapter) driver rumble handling seems to make the adapter lock up after a while.
-ifneq ($(USE_SDL_HAPTIC),0)
- GTK_OPTIONS += -DUSE_SDL_HAPTIC
-endif
-
GTK3_CFLAGS := $(shell $(PKG_CONFIG) --cflags gio-2.0 gtk+-3.0 epoxy) $(GTK_OPTIONS)
GTK3_LDFLAGS := $(shell $(PKG_CONFIG) --libs gio-2.0 gtk+-3.0 epoxy)
diff --git a/gtk3/main.c b/gtk3/main.c
index 145e408..782bc61 100644
--- a/gtk3/main.c
+++ b/gtk3/main.c
@@ -455,12 +455,10 @@ static gboolean init_controllers(void) {
return false;
}
- #ifdef USE_SDL_HAPTIC
- g_debug("Initializing haptic feedback");
- if (SDL_InitSubSystem(SDL_INIT_HAPTIC) < 0) {
- g_warning("Failed to initialize haptic feedback support: %s", SDL_GetError());
- }
- #endif
+ g_debug("Initializing haptic feedback");
+ if (SDL_InitSubSystem(SDL_INIT_HAPTIC) < 0) {
+ g_warning("Failed to initialize haptic feedback support: %s", SDL_GetError());
+ }
g_debug("Loading custom game controller database");
GError *error = NULL;
@@ -494,23 +492,21 @@ static gboolean init_controllers(void) {
SDL_Joystick *joystick = SDL_GameControllerGetJoystick(s->controller);
SDL_JoystickPowerLevel power_level = SDL_JoystickCurrentPowerLevel(joystick);
- #ifdef USE_SDL_HAPTIC
- if (SDL_JoystickIsHaptic(joystick)) {
- s->haptic = SDL_HapticOpenFromJoystick(joystick);
+ if (SDL_JoystickIsHaptic(joystick)) {
+ s->haptic = SDL_HapticOpenFromJoystick(joystick);
- if (s->haptic && SDL_HapticRumbleSupported(s->haptic)) {
- SDL_HapticRumbleInit(s->haptic);
- }
- else {
- if (s->haptic == NULL) {
- g_warning("%s", SDL_GetError());
- }
-
- SDL_HapticClose(s->haptic);
- s->haptic = NULL;
- }
+ if (s->haptic && SDL_HapticRumbleSupported(s->haptic)) {
+ SDL_HapticRumbleInit(s->haptic);
}
- #endif
+ else {
+ if (s->haptic == NULL) {
+ g_warning("%s", SDL_GetError());
+ }
+
+ SDL_HapticClose(s->haptic);
+ s->haptic = NULL;
+ }
+ }
char guid_str[33];
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
@@ -600,16 +596,15 @@ static void rumble_callback(GB_gameboy_t *gb, double amp) {
struct Controller_t *s = gui_data.last_used_controller;
- #ifdef USE_SDL_HAPTIC
- if (s->haptic) {
- if (amp > 0.0) {
- SDL_HapticRumblePlay(s->haptic, amp, 100.0);
- }
- else {
- SDL_HapticRumbleStop(s->haptic);
- }
+ if (s->haptic) {
+ if (amp > 0.0) {
+ SDL_HapticRumblePlay(s->haptic, amp, 100.0);
}
- #else
+ else {
+ SDL_HapticRumbleStop(s->haptic);
+ }
+ }
+ else {
if (amp == 0.0) {
SDL_GameControllerRumble(s->controller, 0, 0, 0);
}
@@ -617,7 +612,7 @@ static void rumble_callback(GB_gameboy_t *gb, double amp) {
Uint16 intensity = (float) 0xFFFF * amp;
SDL_GameControllerRumble(s->controller, intensity, intensity, 100);
}
- #endif
+ }
}
static void clear_sidebar(void) {
@@ -1408,7 +1403,7 @@ static void init(void) {
GB_set_boot_rom_load_callback(&gb, load_boot_rom);
GB_set_rumble_callback(&gb, rumble_callback);
- GB_set_rumble_mode(&gb, GB_RUMBLE_CARTRIDGE_ONLY); // TODO
+ GB_set_rumble_mode(&gb, get_rumble_mode());
if (get_display_border_mode() <= GB_BORDER_ALWAYS) {
GB_set_border_mode(&gb, get_display_border_mode());
@@ -1572,10 +1567,7 @@ static void quit(void) {
for (unsigned i = 0; i < gui_data.controller_count; i++) {
struct Controller_t *s = &gui_data.controllers[i];
- #ifdef USE_SDL_HAPTIC
- SDL_HapticClose(s->haptic);
- #endif
-
+ SDL_HapticClose(s->haptic);
SDL_GameControllerClose(s->controller);
}
@@ -2604,6 +2596,19 @@ G_MODULE_EXPORT void console_on_enter(GtkWidget *w, gpointer user_data_ptr) {
gtk_entry_set_text(input, "");
}
+G_MODULE_EXPORT void on_rumble_mode_changed(GtkWidget *w, gpointer user_data_ptr) {
+ GtkComboBox *box = GTK_COMBO_BOX(w);
+ config.rumble_mode = (gchar *)gtk_combo_box_get_active_id(box);
+
+ GB_set_rumble_mode(&gb, get_rumble_mode());
+}
+
+G_MODULE_EXPORT void on_analog_speed_controls_changed(GtkWidget *w, gpointer user_data_ptr) {
+ GtkCheckButton *button = GTK_CHECK_BUTTON(w);
+ gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
+ config.analog_speed_controls = value;
+}
+
int main(int argc, char *argv[]) {
gui_data.main_thread = g_thread_self();
diff --git a/gtk3/resources/ui/window.ui b/gtk3/resources/ui/window.ui
index cb258c5..c38ef00 100644
--- a/gtk3/resources/ui/window.ui
+++ b/gtk3/resources/ui/window.ui
@@ -730,6 +730,7 @@ Maximilian Mader https://github.com/max-m
True
True
False
+ start
5
10
True
@@ -747,6 +748,7 @@ Maximilian Mader https://github.com/max-m
True
True
False
+ start
5
10
True
@@ -1064,10 +1066,63 @@ Maximilian Mader https://github.com/max-m
4
+
+
+
+ False
+ False
+ 5
+
+
+
+
+
+ False
+ True
+ 6
+
+
+
+
+
+ False
+ True
+ 7
+
+
diff --git a/gtk3/settings.c b/gtk3/settings.c
index 267ec41..5609ddd 100644
--- a/gtk3/settings.c
+++ b/gtk3/settings.c
@@ -118,6 +118,8 @@ void on_preferences_realize(GtkWidget *w, gpointer builder_ptr) {
gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "aspect_ratio_toggle"), config.keep_aspect_ratio);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "highpass_filter_selector"), config.high_pass_filter_id);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "sample_rate_selector"), g_strdup_printf("%i", config.sample_rate));
+ gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "analog_speed_controls_toggle"), config.analog_speed_controls);
+ gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "rumble_mode_selector"), config.rumble_mode);
#if ! NDEBUG
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "menubar_override_selector"), config.menubar_override);
@@ -420,6 +422,38 @@ void set_highpass_mode(GB_highpass_mode_t mode) {
}
}
+const GB_rumble_mode_t get_rumble_mode(void) {
+ if (config.rumble_mode == NULL) goto default_value;
+
+ if (g_strcmp0(config.rumble_mode, "never") == 0) {
+ return GB_RUMBLE_DISABLED;
+ }
+ else if (g_strcmp0(config.rumble_mode, "rumble_cartridges") == 0) {
+ return GB_RUMBLE_CARTRIDGE_ONLY;
+ }
+ else if (g_strcmp0(config.rumble_mode, "always") == 0) {
+ return GB_RUMBLE_ALL_GAMES;
+ }
+
+ // This should not happen
+ g_warning("Unknown highpass mode: %s\nFalling back to “Never”", config.rumble_mode);
+ default_value: return GB_RUMBLE_DISABLED;
+}
+
+void set_rumble_mode(GB_rumble_mode_t mode) {
+ switch (mode) {
+ case GB_RUMBLE_DISABLED:
+ config.rumble_mode = "never";
+ break;
+ case GB_RUMBLE_CARTRIDGE_ONLY:
+ config.rumble_mode = "rumble_cartridges";
+ break;
+ case GB_RUMBLE_ALL_GAMES:
+ config.rumble_mode = "always";
+ break;
+ }
+}
+
GB_model_t get_dmg_model(void) {
if (config.dmg_revision_name == NULL) goto default_value;
diff --git a/gtk3/settings.h b/gtk3/settings.h
index 00264cd..47dd44f 100644
--- a/gtk3/settings.h
+++ b/gtk3/settings.h
@@ -51,7 +51,8 @@
EXPAND_GROUP_MEMBER(sample_rate, integer, -1) \
) \
EXPAND_GROUP(Controls, \
- \
+ EXPAND_GROUP_MEMBER(analog_speed_controls, boolean, false) \
+ EXPAND_GROUP_MEMBER(rumble_mode, string, "Never") \
)
typedef struct config_t {
@@ -103,6 +104,9 @@ void set_highpass_mode(GB_highpass_mode_t);
const GB_palette_t* get_monochrome_palette(void);
void set_monochrome_palette(const GB_palette_t*);
+const GB_rumble_mode_t get_rumble_mode(void);
+void set_rumble_mode(const GB_rumble_mode_t);
+
GB_model_t get_dmg_model(void);
GB_model_t get_sgb_model(void);
GB_model_t get_cgb_model(void);