diff options
| author | visarhoxha <vhoxha08@gmail.com> | 2026-09-24 00:30:54 +0200 |
|---|---|---|
| committer | visarhoxha <vhoxha08@gmail.com> | 2026-10-19 12:22:32 +0200 |
| commit | f0ef80016182ef0a79fd8b100b35ed906f954044 (patch) | |
| tree | 7f2f1cca208245bc270bd4abfb72e84ca0ca1b3e | |
| parent | 301182532074dae57a4b23ff508308485c122ea8 (diff) | |
Android: Avoid constant hotkey polling to save battery
Only poll for hotkeys while EmulationActivity is resumed and at least
one supported hotkey is mapped. Otherwise the scheduler thread waits on
an event instead of polling.
4 files changed, 90 insertions, 18 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt index 23ffe96cd6..0678c97724 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt @@ -42,6 +42,7 @@ import org.dolphinemu.dolphinemu.features.infinitybase.ui.FigureSlot import org.dolphinemu.dolphinemu.features.infinitybase.ui.FigureSlotAdapter import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface import org.dolphinemu.dolphinemu.features.input.model.DolphinSensorEventListener +import org.dolphinemu.dolphinemu.features.input.model.Hotkeys import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting import org.dolphinemu.dolphinemu.utils.ContentHandler import org.dolphinemu.dolphinemu.features.settings.model.IntSetting @@ -319,6 +320,13 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider { } DolphinSensorEventListener.setDeviceRotation(windowManager.defaultDisplay.rotation) + + Hotkeys.setEnabled(true) + } + + override fun onPause() { + Hotkeys.setEnabled(false) + super.onPause() } override fun onStop() { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.kt index 6a99d1365c..19c08b9a05 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.kt @@ -27,7 +27,6 @@ import org.dolphinemu.dolphinemu.NativeLibrary import org.dolphinemu.dolphinemu.R import org.dolphinemu.dolphinemu.databinding.ActivitySettingsBinding import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface -import org.dolphinemu.dolphinemu.features.input.model.Hotkeys import org.dolphinemu.dolphinemu.features.settings.model.Settings import org.dolphinemu.dolphinemu.features.settings.ui.SettingsFragment.Companion.newInstance import org.dolphinemu.dolphinemu.ui.main.MainPresenter @@ -181,8 +180,6 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView, ThemeProvide override fun onStart() { super.onStart() presenter!!.onStart() - - Hotkeys.setEnabled(false) } override fun onResume() { @@ -202,8 +199,6 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView, ThemeProvide override fun onStop() { super.onStop() presenter!!.onStop(isFinishing) - - Hotkeys.setEnabled(true) } override fun onDestroy() { diff --git a/Source/Android/jni/HotkeyScheduler.cpp b/Source/Android/jni/HotkeyScheduler.cpp index bb360d1e2a..85d981f755 100644 --- a/Source/Android/jni/HotkeyScheduler.cpp +++ b/Source/Android/jni/HotkeyScheduler.cpp @@ -3,6 +3,7 @@ #include "jni/HotkeyScheduler.h" +#include <chrono> #include <cmath> #include <jni.h> #include <thread> @@ -13,6 +14,7 @@ #include "AudioCommon/AudioCommon.h" #include "Common/CommonTypes.h" #include "Common/Config/Config.h" +#include "Common/Event.h" #include "Common/Flag.h" #include "Common/Thread.h" #include "Core/Config/GraphicsSettings.h" @@ -22,6 +24,8 @@ #include "Core/State.h" #include "Core/System.h" #include "InputCommon/ControlReference/ControlReference.h" +#include "InputCommon/ControllerEmu/Control/Control.h" +#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/VideoConfig.h" @@ -34,6 +38,8 @@ constexpr int POLL_INTERVAL_MS = 5; std::thread s_thread; Common::Flag s_stop_requested; +Common::Flag s_any_hotkey_set; +Common::Event s_wakeup; int s_state_slot = 1; @@ -42,6 +48,43 @@ bool IsHotkey(int id, bool held = false) return HotkeyManagerEmu::IsPressed(id, held); } +bool IsAnyHotkeySet() +{ + InputConfig* const config = HotkeyManagerEmu::GetConfig(); + if (config == nullptr || config->ControllersNeedToBeCreated()) + return false; + + auto* const hotkeys = static_cast<HotkeyManager*>(config->GetController(0)); + + for (const int hotkey : GetSupportedHotkeys()) + { + const int group = hotkeys->FindGroupByID(hotkey); + const int index = hotkeys->GetIndexForGroup(group, hotkey); + const auto* const control_group = + HotkeyManagerEmu::GetHotkeyGroup(static_cast<HotkeyGroup>(group)); + + if (!control_group->controls[index]->control_ref->GetExpression().empty()) + return true; + } + + return false; +} + +bool ShouldPoll() +{ + if (!s_any_hotkey_set.IsSet() || !HotkeyManagerEmu::IsEnabled()) + return false; + + return Core::GetState(Core::System::GetInstance()) != Core::State::Stopping; +} + +// Buttons already held when polling resumes must not count as new presses +void ConsumePendingPresses() +{ + for (const int hotkey : GetSupportedHotkeys()) + IsHotkey(hotkey); +} + void ShowVolumeOSD() { OSD::AddMessage( @@ -196,19 +239,24 @@ void Run() { Common::SetCurrentThreadName("HotkeyScheduler"); + bool was_polling = false; + while (!s_stop_requested.IsSet()) { - Common::SleepCurrentThread(POLL_INTERVAL_MS); + if (!ShouldPoll()) + { + was_polling = false; + s_wakeup.Wait(); + continue; + } - ControllerInterface::SetCurrentInputChannel(ciface::InputChannel::Host); - g_controller_interface.UpdateInput(); + s_wakeup.WaitFor(std::chrono::milliseconds(POLL_INTERVAL_MS)); - if (!HotkeyManagerEmu::IsEnabled()) - continue; + if (s_stop_requested.IsSet()) + break; - Core::System& system = Core::System::GetInstance(); - if (Core::GetState(system) == Core::State::Stopping) - continue; + ControllerInterface::SetCurrentInputChannel(ciface::InputChannel::Host); + g_controller_interface.UpdateInput(); ControlReference::SetInputGate(true); @@ -217,6 +265,15 @@ void Run() HotkeyManagerEmu::GetStatus(false); HotkeyManagerEmu::GetStatus(true); + if (!was_polling) + { + ConsumePendingPresses(); + was_polling = true; + continue; + } + + Core::System& system = Core::System::GetInstance(); + HandleGeneralHotkeys(); HandleEmulationSpeedHotkeys(); HandleVolumeHotkeys(system); @@ -231,9 +288,10 @@ void Start() if (s_thread.joinable()) return; - HotkeyManagerEmu::Enable(true); s_state_slot = 1; + s_any_hotkey_set.Set(IsAnyHotkeySet()); s_stop_requested.Clear(); + s_wakeup.Reset(); s_thread = std::thread(Run); } @@ -243,11 +301,18 @@ void Stop() return; s_stop_requested.Set(); + s_wakeup.Set(); s_thread.join(); Core::SetIsThrottlerTempDisabled(false); } +void RefreshActiveHotkeys() +{ + s_any_hotkey_set.Set(IsAnyHotkeySet()); + s_wakeup.Set(); +} + const std::vector<int>& GetSupportedHotkeys() { static const std::vector<int> supported = [] { @@ -294,5 +359,6 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_input_model_Hotke JNIEnv*, jclass, jboolean enabled) { HotkeyManagerEmu::Enable(enabled == JNI_TRUE); + HotkeyScheduler::RefreshActiveHotkeys(); } } diff --git a/Source/Android/jni/HotkeyScheduler.h b/Source/Android/jni/HotkeyScheduler.h index c904139d6b..d98d637991 100644 --- a/Source/Android/jni/HotkeyScheduler.h +++ b/Source/Android/jni/HotkeyScheduler.h @@ -5,10 +5,13 @@ #include <vector> -namespace HotkeyScheduler { - void Start(); +namespace HotkeyScheduler +{ +void Start(); - void Stop(); +void Stop(); - const std::vector<int> &GetSupportedHotkeys(); +void RefreshActiveHotkeys(); + +const std::vector<int>& GetSupportedHotkeys(); } // namespace HotkeyScheduler |
