mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	android: add quicksave hotkeys
This commit is contained in:
		
							parent
							
								
									e90795b616
								
							
						
					
					
						commit
						ee9dae4ca2
					
				
					 10 changed files with 96 additions and 18 deletions
				
			
		|  | @ -527,12 +527,28 @@ object NativeLibrary { | |||
| 
 | ||||
|     external fun removeAmiibo() | ||||
| 
 | ||||
|     const val SAVESTATE_SLOT_COUNT = 10 | ||||
|     const val SAVESTATE_SLOT_COUNT = 11 | ||||
|     const val QUICKSAVE_SLOT = 0 | ||||
| 
 | ||||
|     external fun getSavestateInfo(): Array<SaveStateInfo>? | ||||
| 
 | ||||
|     external fun saveState(slot: Int) | ||||
| 
 | ||||
|     fun loadStateIfAvailable(slot: Int): Boolean { | ||||
|         var available = false | ||||
|         getSavestateInfo()?.forEach { | ||||
|             if (it.slot == slot){ | ||||
|                 available = true | ||||
|                 return@forEach | ||||
|             } | ||||
|         } | ||||
|         if (available) { | ||||
|             loadState(slot) | ||||
|             return true | ||||
|         } | ||||
|         return false | ||||
|     } | ||||
| 
 | ||||
|     external fun loadState(slot: Int) | ||||
| 
 | ||||
|     /** | ||||
|  |  | |||
|  | @ -66,7 +66,7 @@ class EmulationActivity : AppCompatActivity() { | |||
| 
 | ||||
|         binding = ActivityEmulationBinding.inflate(layoutInflater) | ||||
|         screenAdjustmentUtil = ScreenAdjustmentUtil(windowManager, settingsViewModel.settings) | ||||
|         hotkeyUtility = HotkeyUtility(screenAdjustmentUtil) | ||||
|         hotkeyUtility = HotkeyUtility(screenAdjustmentUtil, this) | ||||
|         setContentView(binding.root) | ||||
| 
 | ||||
|         val navHostFragment = | ||||
|  |  | |||
|  | @ -8,5 +8,7 @@ enum class Hotkey(val button: Int) { | |||
|     SWAP_SCREEN(10001), | ||||
|     CYCLE_LAYOUT(10002), | ||||
|     CLOSE_GAME(10003), | ||||
|     PAUSE_OR_RESUME(10004); | ||||
|     PAUSE_OR_RESUME(10004), | ||||
|     QUICKSAVE(10005), | ||||
|     QUICKLOAD(10006); | ||||
| } | ||||
|  |  | |||
|  | @ -4,10 +4,14 @@ | |||
| 
 | ||||
| package org.citra.citra_emu.features.hotkeys | ||||
| 
 | ||||
| import android.content.Context | ||||
| import android.widget.Toast | ||||
| import org.citra.citra_emu.NativeLibrary | ||||
| import org.citra.citra_emu.R | ||||
| import org.citra.citra_emu.utils.EmulationLifecycleUtil | ||||
| import org.citra.citra_emu.display.ScreenAdjustmentUtil | ||||
| 
 | ||||
| class HotkeyUtility(private val screenAdjustmentUtil: ScreenAdjustmentUtil) { | ||||
| class HotkeyUtility(private val screenAdjustmentUtil: ScreenAdjustmentUtil, private val context: Context) { | ||||
| 
 | ||||
|     val hotkeyButtons = Hotkey.entries.map { it.button } | ||||
| 
 | ||||
|  | @ -18,6 +22,23 @@ class HotkeyUtility(private val screenAdjustmentUtil: ScreenAdjustmentUtil) { | |||
|                 Hotkey.CYCLE_LAYOUT.button -> screenAdjustmentUtil.cycleLayouts() | ||||
|                 Hotkey.CLOSE_GAME.button -> EmulationLifecycleUtil.closeGame() | ||||
|                 Hotkey.PAUSE_OR_RESUME.button -> EmulationLifecycleUtil.pauseOrResume() | ||||
|                 Hotkey.QUICKSAVE.button -> { | ||||
|                     NativeLibrary.saveState(NativeLibrary.QUICKSAVE_SLOT) | ||||
|                     Toast.makeText(context, | ||||
|                         context.getString(R.string.quicksave_saving), | ||||
|                         Toast.LENGTH_SHORT).show() | ||||
|                 } | ||||
|                 Hotkey.QUICKLOAD.button -> { | ||||
|                     val wasLoaded = NativeLibrary.loadStateIfAvailable(NativeLibrary.QUICKSAVE_SLOT) | ||||
|                     val stringRes = if(wasLoaded) { | ||||
|                         R.string.quickload_loading | ||||
|                     } else { | ||||
|                         R.string.quickload_not_found | ||||
|                     } | ||||
|                     Toast.makeText(context, | ||||
|                         context.getString(stringRes), | ||||
|                         Toast.LENGTH_SHORT).show() | ||||
|                 } | ||||
|                 else -> {} | ||||
|             } | ||||
|             return true | ||||
|  |  | |||
|  | @ -136,6 +136,8 @@ class Settings { | |||
|         const val HOTKEY_CYCLE_LAYOUT = "hotkey_toggle_layout" | ||||
|         const val HOTKEY_CLOSE_GAME = "hotkey_close_game" | ||||
|         const val HOTKEY_PAUSE_OR_RESUME = "hotkey_pause_or_resume_game" | ||||
|         const val HOTKEY_QUICKSAVE = "hotkey_quickload" | ||||
|         const val HOTKEY_QUICKlOAD = "hotkey_quickpause" | ||||
| 
 | ||||
|         val buttonKeys = listOf( | ||||
|             KEY_BUTTON_A, | ||||
|  | @ -187,13 +189,17 @@ class Settings { | |||
|             HOTKEY_SCREEN_SWAP, | ||||
|             HOTKEY_CYCLE_LAYOUT, | ||||
|             HOTKEY_CLOSE_GAME, | ||||
|             HOTKEY_PAUSE_OR_RESUME | ||||
|             HOTKEY_PAUSE_OR_RESUME, | ||||
|             HOTKEY_QUICKSAVE, | ||||
|             HOTKEY_QUICKlOAD | ||||
|         ) | ||||
|         val hotkeyTitles = listOf( | ||||
|             R.string.emulation_swap_screens, | ||||
|             R.string.emulation_cycle_landscape_layouts, | ||||
|             R.string.emulation_close_game, | ||||
|             R.string.emulation_toggle_pause | ||||
|             R.string.emulation_toggle_pause, | ||||
|             R.string.emulation_quicksave, | ||||
|             R.string.emulation_quickload, | ||||
|         ) | ||||
| 
 | ||||
|         const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" | ||||
|  |  | |||
|  | @ -133,6 +133,8 @@ class InputBindingSetting( | |||
|                 Settings.HOTKEY_CYCLE_LAYOUT -> Hotkey.CYCLE_LAYOUT.button | ||||
|                 Settings.HOTKEY_CLOSE_GAME -> Hotkey.CLOSE_GAME.button | ||||
|                 Settings.HOTKEY_PAUSE_OR_RESUME -> Hotkey.PAUSE_OR_RESUME.button | ||||
|                 Settings.HOTKEY_QUICKSAVE -> Hotkey.QUICKSAVE.button | ||||
|                 Settings.HOTKEY_QUICKlOAD -> Hotkey.QUICKLOAD.button | ||||
|                 else -> -1 | ||||
|             } | ||||
| 
 | ||||
|  |  | |||
|  | @ -481,12 +481,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram | |||
|         popupMenu.setOnMenuItemClickListener { | ||||
|             when (it.itemId) { | ||||
|                 R.id.menu_emulation_save_state -> { | ||||
|                     showSaveStateSubmenu() | ||||
|                     showStateSubmenu(true) | ||||
|                     true | ||||
|                 } | ||||
| 
 | ||||
|                 R.id.menu_emulation_load_state -> { | ||||
|                     showLoadStateSubmenu() | ||||
|                     showStateSubmenu(false) | ||||
|                     true | ||||
|                 } | ||||
| 
 | ||||
|  | @ -497,7 +497,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram | |||
|         popupMenu.show() | ||||
|     } | ||||
| 
 | ||||
|     private fun showSaveStateSubmenu() { | ||||
|     private fun showStateSubmenu(isSaving: Boolean) { | ||||
| 
 | ||||
|         val savestates = NativeLibrary.getSavestateInfo() | ||||
| 
 | ||||
|         val popupMenu = PopupMenu( | ||||
|  | @ -507,19 +508,40 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram | |||
| 
 | ||||
|         popupMenu.menu.apply { | ||||
|             for (i in 0 until NativeLibrary.SAVESTATE_SLOT_COUNT) { | ||||
|                 val slot = i + 1 | ||||
|                 val text = getString(R.string.emulation_empty_state_slot, slot) | ||||
|                 add(text).setEnabled(true).setOnMenuItemClickListener { | ||||
|                     displaySavestateWarning() | ||||
|                     NativeLibrary.saveState(slot) | ||||
|                 val slot = i | ||||
|                 var enableClick = isSaving | ||||
|                 val text = if (slot == NativeLibrary.QUICKSAVE_SLOT) { | ||||
|                     enableClick = false | ||||
|                     getString(R.string.emulation_quicksave_slot) | ||||
|                 } else { | ||||
|                     getString(R.string.emulation_empty_state_slot, slot) | ||||
|                 } | ||||
| 
 | ||||
|                 add(text).setEnabled(enableClick).setOnMenuItemClickListener { | ||||
|                     if(isSaving) { | ||||
|                         NativeLibrary.saveState(slot) | ||||
|                     } else { | ||||
|                         NativeLibrary.loadState(slot) | ||||
|                         binding.drawerLayout.close() | ||||
|                         Toast.makeText(context, | ||||
|                             getString(R.string.quickload_loading), | ||||
|                             Toast.LENGTH_SHORT).show() | ||||
|                     } | ||||
|                     true | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         savestates?.forEach { | ||||
|             val text = getString(R.string.emulation_occupied_state_slot, it.slot, it.time) | ||||
|             popupMenu.menu.getItem(it.slot - 1).setTitle(text) | ||||
|             var enableClick = true | ||||
|             val text = if(it.slot == NativeLibrary.QUICKSAVE_SLOT) { | ||||
|                 // do not allow saving in quicksave slot | ||||
|                 enableClick = !isSaving | ||||
|                 getString(R.string.emulation_occupied_quicksave_slot, it.time) | ||||
|             } else{ | ||||
|                 getString(R.string.emulation_occupied_state_slot, it.slot, it.time) | ||||
|             } | ||||
|             popupMenu.menu.getItem(it.slot).setTitle(text).setEnabled(enableClick) | ||||
|         } | ||||
| 
 | ||||
|         popupMenu.show() | ||||
|  |  | |||
|  | @ -692,4 +692,13 @@ | |||
|     <string name="delay_render_thread">Delay game render thread</string> | ||||
|     <string name="delay_render_thread_description">Delay the game render thread when it submits data to the GPU. Helps with performance issues in the (very few) dynamic-fps games.</string> | ||||
| 
 | ||||
|     <!-- Quickload&Save--> | ||||
|     <string name="emulation_quicksave_slot">Quicksave</string> | ||||
|     <string name="emulation_quicksave">Quicksave</string> | ||||
|     <string name="emulation_quickload">Quickload</string> | ||||
|     <string name="emulation_occupied_quicksave_slot">Quicksave - %1$tF %1$tR</string> | ||||
|     <string name="quicksave_saving">Saving…</string> | ||||
|     <string name="quickload_loading">Loading…</string> | ||||
|     <string name="quickload_not_found">No Quicksave available.</string> | ||||
| 
 | ||||
| </resources> | ||||
|  |  | |||
|  | @ -90,7 +90,7 @@ static bool ValidateSaveState(const CSTHeader& header, SaveStateInfo& info, u64 | |||
| std::vector<SaveStateInfo> ListSaveStates(u64 program_id, u64 movie_id) { | ||||
|     std::vector<SaveStateInfo> result; | ||||
|     result.reserve(SaveStateSlotCount); | ||||
|     for (u32 slot = 1; slot <= SaveStateSlotCount; ++slot) { | ||||
|     for (u32 slot = 0; slot <= SaveStateSlotCount; ++slot) { | ||||
|         const auto path = GetSaveStatePath(program_id, movie_id, slot); | ||||
|         if (!FileUtil::Exists(path)) { | ||||
|             continue; | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ struct SaveStateInfo { | |||
|     std::string build_name; | ||||
| }; | ||||
| 
 | ||||
| constexpr u32 SaveStateSlotCount = 10; // Maximum count of savestate slots
 | ||||
| constexpr u32 SaveStateSlotCount = 11; // Maximum count of savestate slots
 | ||||
| 
 | ||||
| std::vector<SaveStateInfo> ListSaveStates(u64 program_id, u64 movie_id); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue