From 98c229ef79e1fa8465cea7f31bbaa39c7a722f4f Mon Sep 17 00:00:00 2001 From: visarhoxha Date: Fri, 18 Sep 2026 20:29:36 +0200 Subject: android: add global hotkeys --- .../dolphinemu/features/input/model/Hotkeys.kt | 11 ++++++++ .../model/controlleremu/EmulatedController.kt | 6 ++++ .../dolphinemu/features/settings/ui/MenuTag.kt | 4 ++- .../features/settings/ui/SettingsActivity.kt | 5 ++++ .../settings/ui/SettingsFragmentPresenter.kt | 33 ++++++++++++++++++++++ 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/Hotkeys.kt (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/Hotkeys.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/Hotkeys.kt new file mode 100644 index 0000000000..7f0100238b --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/Hotkeys.kt @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model + +object Hotkeys { + /** + * Stops or resumes the native hotkey scheduler acting on presses. + */ + @JvmStatic + external fun setEnabled(enabled: Boolean) +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.kt index e0938b975d..00c06cb896 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.kt @@ -55,6 +55,12 @@ class EmulatedController private constructor(private val pointer: Long) : Contro @JvmStatic external fun getWiimote(controllerIndex: Int): EmulatedController + @JvmStatic + external fun getHotkeys(): EmulatedController + + @JvmStatic + external fun getSupportedHotkeyIndices(): IntArray + @JvmStatic external fun getWiimoteAttachment( controllerIndex: Int, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.kt index 74556b07d9..3a6089144f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.kt @@ -26,6 +26,7 @@ enum class MenuTag { STATISTICS("statistics"), ADVANCED_GRAPHICS("advanced_graphics"), GCPAD_TYPE("gc_pad_type"), + HOTKEYS("hotkeys"), WIIMOTE("wiimote"), WIIMOTE_EXTENSION("wiimote_extension"), GCPAD_1("gcpad", 0), @@ -77,7 +78,8 @@ enum class MenuTag { val correspondingEmulatedController: EmulatedController get() = if (isGCPadMenu) EmulatedController.getGcPad(subType) else if (isWiimoteMenu) EmulatedController.getWiimote( subType - ) else throw UnsupportedOperationException() + ) else if (this == HOTKEYS) EmulatedController.getHotkeys() + else throw UnsupportedOperationException() val isSerialPort1Menu: Boolean get() = this == CONFIG_SERIALPORT1 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 19c08b9a05..6a99d1365c 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,6 +27,7 @@ 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 @@ -180,6 +181,8 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView, ThemeProvide override fun onStart() { super.onStart() presenter!!.onStart() + + Hotkeys.setEnabled(false) } override fun onResume() { @@ -199,6 +202,8 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView, ThemeProvide override fun onStop() { super.onStop() presenter!!.onStop(isFinishing) + + Hotkeys.setEnabled(true) } override fun onDestroy() { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt index 210a34b23f..0bc651fe3c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt @@ -303,6 +303,7 @@ class SettingsFragmentPresenter( ) MenuTag.GCPAD_TYPE -> addGcPadSettings(sl) + MenuTag.HOTKEYS -> addHotkeySettings(sl) MenuTag.WIIMOTE -> addWiimoteSettings(sl) MenuTag.ENHANCEMENTS -> addEnhanceSettings(sl) MenuTag.COLOR_CORRECTION -> addColorCorrectionSettings(sl) @@ -354,6 +355,11 @@ class SettingsFragmentPresenter( sl.add(SubmenuSetting(context, R.string.wiimote_settings, MenuTag.WIIMOTE)) } + // Hotkeys live in Hotkeys.ini and are global, so there is nothing to edit per game. + if (gameId.isNullOrEmpty()) { + sl.add(SubmenuSetting(context, R.string.hotkey_settings, MenuTag.HOTKEYS)) + } + sl.add(HeaderSetting(context, R.string.setting_clear_info, 0)) } @@ -2503,6 +2509,33 @@ class SettingsFragmentPresenter( ) } + /** + * Lists a subset of the hotkeys the native HotkeyScheduler dispatches. + */ + private fun addHotkeySettings(sl: ArrayList) { + val hotkeys = EmulatedController.getHotkeys() + + addControllerMetaSettings(sl, hotkeys) + + // Flattened {group index, control index} pairs. Each control group gets a header the first + // time one of its hotkeys shows up. + val indices = EmulatedController.getSupportedHotkeyIndices() + var currentGroupIndex = -1 + var i = 0 + while (i < indices.size) { + val groupIndex = indices[i] + val group = hotkeys.getGroup(groupIndex) + + if (groupIndex != currentGroupIndex) { + sl.add(HeaderSetting(group.getUiName(), "")) + currentGroupIndex = groupIndex + } + + sl.add(InputMappingControlSetting(group.getControl(indices[i + 1]), hotkeys)) + i += 2 + } + } + private fun addGcPadSubSettings( sl: ArrayList, gcPadNumber: Int, gcPadType: Int ) { -- cgit v1.2.3 From f0ef80016182ef0a79fd8b100b35ed906f954044 Mon Sep 17 00:00:00 2001 From: visarhoxha Date: Thu, 24 Sep 2026 00:30:54 +0200 Subject: 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. --- .../org/dolphinemu/dolphinemu/activities/EmulationActivity.kt | 8 ++++++++ .../dolphinemu/features/settings/ui/SettingsActivity.kt | 5 ----- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'Source/Android/app/src/main/java') 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() { -- cgit v1.2.3