diff --git a/assets/config_menu/general.rml b/assets/config_menu/general.rml
index d23da93..48cbe40 100644
--- a/assets/config_menu/general.rml
+++ b/assets/config_menu/general.rml
@@ -73,6 +73,36 @@
/>
+
+
+
@@ -85,6 +115,11 @@
Controls the sensitivity of gyro when using a controller that supports it. Setting this to zero will disable gyro.
+
+ Allows the game to read controller input when out of focus.
+
+ This setting does not affect keyboard input.
+
diff --git a/include/recomp_input.h b/include/recomp_input.h
index ef6f531..6315f48 100644
--- a/include/recomp_input.h
+++ b/include/recomp_input.h
@@ -143,6 +143,20 @@ namespace recomp {
TargetingMode get_targeting_mode();
void set_targeting_mode(TargetingMode mode);
+ enum class BackgroundInputMode {
+ On,
+ Off,
+ OptionCount
+ };
+
+ NLOHMANN_JSON_SERIALIZE_ENUM(recomp::BackgroundInputMode, {
+ {recomp::BackgroundInputMode::On, "On"},
+ {recomp::BackgroundInputMode::Off, "Off"}
+ });
+
+ BackgroundInputMode get_background_input_mode();
+ void set_background_input_mode(BackgroundInputMode mode);
+
bool game_input_disabled();
bool all_input_disabled();
diff --git a/src/game/config.cpp b/src/game/config.cpp
index 5dcabed..b81a9c9 100644
--- a/src/game/config.cpp
+++ b/src/game/config.cpp
@@ -127,6 +127,7 @@ void save_general_config(const std::filesystem::path& path) {
nlohmann::json config_json{};
recomp::to_json(config_json["targeting_mode"], recomp::get_targeting_mode());
+ recomp::to_json(config_json["background_input_mode"], recomp::get_background_input_mode());
config_json["rumble_strength"] = recomp::get_rumble_strength();
config_json["gyro_sensitivity"] = recomp::get_gyro_sensitivity();
config_json["debug_mode"] = recomp::get_debug_mode_enabled();
@@ -140,6 +141,7 @@ void load_general_config(const std::filesystem::path& path) {
config_file >> config_json;
recomp::set_targeting_mode(from_or_default(config_json, "targeting_mode", recomp::TargetingMode::Switch));
+ recomp::set_background_input_mode(from_or_default(config_json, "background_input_mode", recomp::BackgroundInputMode::On));
recomp::set_rumble_strength(from_or_default(config_json, "rumble_strength", 25));
recomp::set_gyro_sensitivity(from_or_default(config_json, "gyro_sensitivity", 50));
recomp::set_debug_mode_enabled(from_or_default(config_json, "debug_mode", false));
diff --git a/src/ui/ui_config.cpp b/src/ui/ui_config.cpp
index 8104fbd..c92035b 100644
--- a/src/ui/ui_config.cpp
+++ b/src/ui/ui_config.cpp
@@ -249,6 +249,7 @@ struct ControlOptionsContext {
int rumble_strength = 50; // 0 to 100
int gyro_sensitivity = 50; // 0 to 200
recomp::TargetingMode targeting_mode = recomp::TargetingMode::Switch;
+ recomp::BackgroundInputMode background_input_mode = recomp::BackgroundInputMode::On;
};
ControlOptionsContext control_options_context;
@@ -286,6 +287,23 @@ void recomp::set_targeting_mode(recomp::TargetingMode mode) {
}
}
+recomp::BackgroundInputMode recomp::get_background_input_mode() {
+ return control_options_context.background_input_mode;
+}
+
+void recomp::set_background_input_mode(recomp::BackgroundInputMode mode) {
+ control_options_context.background_input_mode = mode;
+ if (general_model_handle) {
+ general_model_handle.DirtyVariable("background_input_mode");
+ }
+ SDL_SetHint(
+ SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
+ mode == recomp::BackgroundInputMode::On
+ ? "1"
+ : "0"
+ );
+}
+
struct SoundOptionsContext {
std::atomic bgm_volume;
std::atomic low_health_beeps_enabled; // RmlUi doesn't seem to like "true"/"false" strings for setting variants so an int is used here instead.
@@ -737,6 +755,7 @@ public:
constructor.Bind("rumble_strength", &control_options_context.rumble_strength);
constructor.Bind("gyro_sensitivity", &control_options_context.gyro_sensitivity);
bind_option(constructor, "targeting_mode", &control_options_context.targeting_mode);
+ bind_option(constructor, "background_input_mode", &control_options_context.background_input_mode);
general_model_handle = constructor.GetModelHandle();
}
diff --git a/src/ui/ui_renderer.cpp b/src/ui/ui_renderer.cpp
index 8ed0729..0b04879 100644
--- a/src/ui/ui_renderer.cpp
+++ b/src/ui/ui_renderer.cpp
@@ -1150,9 +1150,27 @@ int cont_axis_to_key(SDL_ControllerAxisEvent& axis, float value) {
return 0;
}
+void apply_background_input_mode() {
+ static recomp::BackgroundInputMode last_input_mode = recomp::BackgroundInputMode::OptionCount;
+
+ recomp::BackgroundInputMode cur_input_mode = recomp::get_background_input_mode();
+
+ if (last_input_mode != cur_input_mode) {
+ SDL_SetHint(
+ SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
+ cur_input_mode == recomp::BackgroundInputMode::On
+ ? "1"
+ : "0"
+ );
+ }
+ last_input_mode = cur_input_mode;
+}
+
void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* swap_chain_framebuffer) {
std::lock_guard lock {ui_context_mutex};
+ apply_background_input_mode();
+
// Return early if the ui context has been destroyed already.
if (!ui_context) {
return;