[GTK3] Add rumble mode setting

Also we now fall back to SDL_GameControllerRumble if a controller
doesn’t support the haptic feedback API.
This still poses problems with the WUP-028 but for now cou can disable
rumble completely if you want to use this controller adapter.
This commit is contained in:
Maximilian Mader 2020-05-04 01:41:14 +02:00
parent 8c3154a061
commit b6c949fa82
Signed by: Max
GPG Key ID: F71D56A3151C4FB3
5 changed files with 136 additions and 45 deletions

View File

@ -126,13 +126,6 @@ ifeq ($(SDL_AUDIO_DRIVER),sdl)
GTK_OPTIONS += -DUSE_SDL_AUDIO GTK_OPTIONS += -DUSE_SDL_AUDIO
endif endif
# Use SDLs haptic feedback subsystem by default, although
# some controllers only work with the simpler SDL_GameControllerRumble / SDL_JoystickRumble,
# but SDLs 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_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) GTK3_LDFLAGS := $(shell $(PKG_CONFIG) --libs gio-2.0 gtk+-3.0 epoxy)

View File

@ -455,12 +455,10 @@ static gboolean init_controllers(void) {
return false; return false;
} }
#ifdef USE_SDL_HAPTIC g_debug("Initializing haptic feedback");
g_debug("Initializing haptic feedback"); if (SDL_InitSubSystem(SDL_INIT_HAPTIC) < 0) {
if (SDL_InitSubSystem(SDL_INIT_HAPTIC) < 0) { g_warning("Failed to initialize haptic feedback support: %s", SDL_GetError());
g_warning("Failed to initialize haptic feedback support: %s", SDL_GetError()); }
}
#endif
g_debug("Loading custom game controller database"); g_debug("Loading custom game controller database");
GError *error = NULL; GError *error = NULL;
@ -494,23 +492,21 @@ static gboolean init_controllers(void) {
SDL_Joystick *joystick = SDL_GameControllerGetJoystick(s->controller); SDL_Joystick *joystick = SDL_GameControllerGetJoystick(s->controller);
SDL_JoystickPowerLevel power_level = SDL_JoystickCurrentPowerLevel(joystick); SDL_JoystickPowerLevel power_level = SDL_JoystickCurrentPowerLevel(joystick);
#ifdef USE_SDL_HAPTIC if (SDL_JoystickIsHaptic(joystick)) {
if (SDL_JoystickIsHaptic(joystick)) { s->haptic = SDL_HapticOpenFromJoystick(joystick);
s->haptic = SDL_HapticOpenFromJoystick(joystick);
if (s->haptic && SDL_HapticRumbleSupported(s->haptic)) { if (s->haptic && SDL_HapticRumbleSupported(s->haptic)) {
SDL_HapticRumbleInit(s->haptic); SDL_HapticRumbleInit(s->haptic);
}
else {
if (s->haptic == NULL) {
g_warning("%s", SDL_GetError());
}
SDL_HapticClose(s->haptic);
s->haptic = NULL;
}
} }
#endif else {
if (s->haptic == NULL) {
g_warning("%s", SDL_GetError());
}
SDL_HapticClose(s->haptic);
s->haptic = NULL;
}
}
char guid_str[33]; char guid_str[33];
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 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; struct Controller_t *s = gui_data.last_used_controller;
#ifdef USE_SDL_HAPTIC if (s->haptic) {
if (s->haptic) { if (amp > 0.0) {
if (amp > 0.0) { SDL_HapticRumblePlay(s->haptic, amp, 100.0);
SDL_HapticRumblePlay(s->haptic, amp, 100.0);
}
else {
SDL_HapticRumbleStop(s->haptic);
}
} }
#else else {
SDL_HapticRumbleStop(s->haptic);
}
}
else {
if (amp == 0.0) { if (amp == 0.0) {
SDL_GameControllerRumble(s->controller, 0, 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; Uint16 intensity = (float) 0xFFFF * amp;
SDL_GameControllerRumble(s->controller, intensity, intensity, 100); SDL_GameControllerRumble(s->controller, intensity, intensity, 100);
} }
#endif }
} }
static void clear_sidebar(void) { 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_boot_rom_load_callback(&gb, load_boot_rom);
GB_set_rumble_callback(&gb, rumble_callback); 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) { if (get_display_border_mode() <= GB_BORDER_ALWAYS) {
GB_set_border_mode(&gb, get_display_border_mode()); 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++) { for (unsigned i = 0; i < gui_data.controller_count; i++) {
struct Controller_t *s = &gui_data.controllers[i]; struct Controller_t *s = &gui_data.controllers[i];
#ifdef USE_SDL_HAPTIC SDL_HapticClose(s->haptic);
SDL_HapticClose(s->haptic);
#endif
SDL_GameControllerClose(s->controller); 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, ""); 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[]) { int main(int argc, char *argv[]) {
gui_data.main_thread = g_thread_self(); gui_data.main_thread = g_thread_self();

View File

@ -730,6 +730,7 @@ Maximilian Mader https://github.com/max-m</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">False</property> <property name="receives_default">False</property>
<property name="halign">start</property>
<property name="margin_top">5</property> <property name="margin_top">5</property>
<property name="margin_bottom">10</property> <property name="margin_bottom">10</property>
<property name="draw_indicator">True</property> <property name="draw_indicator">True</property>
@ -747,6 +748,7 @@ Maximilian Mader https://github.com/max-m</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">False</property> <property name="receives_default">False</property>
<property name="halign">start</property>
<property name="margin_top">5</property> <property name="margin_top">5</property>
<property name="margin_bottom">10</property> <property name="margin_bottom">10</property>
<property name="draw_indicator">True</property> <property name="draw_indicator">True</property>
@ -1064,10 +1066,63 @@ Maximilian Mader https://github.com/max-m</property>
<property name="position">4</property> <property name="position">4</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkCheckButton" id="analog_speed_controls_toggle">
<property name="label" translatable="yes">Analog turbo and slow-motion controls</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">start</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_analog_speed_controls_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">8</property>
<property name="label" translatable="yes">Enable Rumble:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="rumble_mode_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<property name="active">0</property>
<items>
<item id="never" translatable="yes">Never</item>
<item id="rumble_cartridges" translatable="yes">For rumble-enabled cartridges</item>
<item id="always" translatable="yes">Always</item>
</items>
<signal name="changed" handler="on_rumble_mode_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">10</property>
<child> <child>
<object class="GtkButton"> <object class="GtkButton">
<property name="label" translatable="yes">Configure Joypad</property> <property name="label" translatable="yes">Configure Joypad</property>
@ -1102,7 +1157,7 @@ Maximilian Mader https://github.com/max-m</property>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">5</property> <property name="position">8</property>
</packing> </packing>
</child> </child>
</object> </object>

View File

@ -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_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, "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_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 #if ! NDEBUG
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "menubar_override_selector"), config.menubar_override); 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) { GB_model_t get_dmg_model(void) {
if (config.dmg_revision_name == NULL) goto default_value; if (config.dmg_revision_name == NULL) goto default_value;

View File

@ -51,7 +51,8 @@
EXPAND_GROUP_MEMBER(sample_rate, integer, -1) \ EXPAND_GROUP_MEMBER(sample_rate, integer, -1) \
) \ ) \
EXPAND_GROUP(Controls, \ EXPAND_GROUP(Controls, \
\ EXPAND_GROUP_MEMBER(analog_speed_controls, boolean, false) \
EXPAND_GROUP_MEMBER(rumble_mode, string, "Never") \
) )
typedef struct config_t { typedef struct config_t {
@ -103,6 +104,9 @@ void set_highpass_mode(GB_highpass_mode_t);
const GB_palette_t* get_monochrome_palette(void); const GB_palette_t* get_monochrome_palette(void);
void set_monochrome_palette(const GB_palette_t*); 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_dmg_model(void);
GB_model_t get_sgb_model(void); GB_model_t get_sgb_model(void);
GB_model_t get_cgb_model(void); GB_model_t get_cgb_model(void);