emulators.ppsspp.Ppsspp
Sony PSP sessions on PPSSPPQt.
Sony PSP sessions on PPSSPPQt.
The broker launches PPSSPPQt --fullscreen -- <rom> after patching both
of PPSSPP's inis: ppsspp.ini so a fresh container never shows the setup
wizard or an update toast and so the working state slot is pinned, and
controls.ini so Save State and Load State are bound to the bracket keys,
the only hotkeys that reach PPSSPP through this container's input stack.
Both files carry a UTF-8 BOM that the patcher strips and restores. Save
and load are hotkey only: the game window is activated, the key is sent
through XTEST, and for a save the state directory is polled until the
file settles, since the hotkey gives no acknowledgement. There is no
boot-time state-load flag, so a resume always goes through a deferred
thread that waits for the state file and then sends the load hotkey once
the window has been up long enough.
Save data (SAVEDATA) and states (PPSSPP_STATE) both ride the save
archive. A state is named for the game id and version, so pushed names
are restamped into the broker's slot and the working slot is cleared
before a boot. PPSSPP writes a .jpg screenshot beside every state, so
the thumbnail comes from that file rather than the streamed canvas, and
clearing a state drops its screenshot too.
Attributes
attributename= 'ppsspp'RomM platform key, ppsspp.
attributedisplay_name= 'PPSSPP'Human-readable name shown in the UI.
attributesave_root= PSP_DIRThe emulated memory stick root, which the save subtrees hang off.
attributesave_subtrees= ('SAVEDATA', 'PPSSPP_STATE')SAVEDATA and PPSSPP_STATE, the directories the save archive carries.
attributerom_extensions= ROM_EXTENSIONSBootable ROM formats, best first.
attributesupports_states= TrueTrue, states are saved and loaded over the bracket hotkeys.
attributestate_slot= STATE_SLOTThe one slot the broker works in, echoed back as the effective slot.
attributestate_dir= STATE_DIRWhere PPSSPP writes .ppst files.
attributelog_path= PPSSPP_LOG_PATHThe PPSSPP log the broker exposes.
attribute_launch_seq= 0Functions
func__init__(self) -> NoneSet up the process state and the launch sequence counter that fences deferred loads.
paramselfReturns
Nonefuncresolve_rom_file(self, path) -> Optional[Path]Resolve a RomM path to the ROM to boot.
A file is taken as is. A directory is searched one level deep for the
best candidate by _pick_rom_file.
paramselfparampathPathThe ROM file or folder RomM handed over.
Returns
typing.OptionalThe ROM to pass to PPSSPPQt, or None when there is nothing bootable.
func_xdotool(self, *args) -> Optional[str]Run one xdotool command against the session display.
paramselfparamargsstr= ()Returns
typing.OptionalIts stdout, or None if it could not be run, timed out, or exited non-zero.
func_game_window(self) -> Optional[str]Find the window PPSSPP is running the game in.
Picked by title rather than the first match: before a game is loaded the same class is a menu window a hotkey does nothing useful to.
paramselfReturns
typing.OptionalThe X window id as xdotool prints it, or None when no game window is up.
func_send_key(self, key) -> boolFocus the game window and send key through XTEST.
Activating first is what makes this survive the player clicking back into the page: XTEST delivers to whatever holds focus, so a key sent at an unfocused PPSSPP goes to the desktop instead.
paramselfparamkeystrThe key name in xdotool's syntax, for example bracketleft.
Returns
boolTrue when the window was found, activated and the key sent, False otherwise.
funclaunch(self, rom_path, resume_slot) -> NoneStop any running instance, patch the inis, and start PPSSPPQt.
The binary comes from env PPSSPP_BIN (default PPSSPPQt). With
resume_slot set, a deferred thread waits for the state file and
loads it over the hotkey once the window is up.
paramselfparamrom_pathPathThe ROM to boot.
paramresume_slotOptional[int]Slot to resume from, or None to boot clean.
Returns
Nonefunc_deferred_load_state(self, seq) -> NoneWait for the resume state to arrive, then load it over the hotkey.
Gives the file RESUME_LOAD_WAIT to appear, then RESUME_LOAD_SETTLE
for the window to be ready. Abandons itself whenever seq no longer
matches the current launch, so a superseded launch never gets a stray
load.
paramselfparamseqintThe launch sequence number this load belongs to.
Returns
Nonefuncsave_state(self, slot) -> boolSave a state into the broker's slot over the hotkey and wait for it to land.
slot is what RomM asked for and is ignored: this saves into
STATE_SLOT and the caller reads the effective slot back off
state_slot.
paramselfparamslotintThe slot RomM requested; not used.
Returns
boolTrue once the state file has been written and settled within STATE_WAIT, False if
funcload_state(self, slot) -> boolLoad the broker's slot over the hotkey.
The hotkey is silent on an empty slot, so an absent file has to be caught here or the caller reads a no-op as success.
paramselfparamslotintThe slot RomM requested; the broker's STATE_SLOT is what gets loaded.
Returns
boolTrue when a state file exists and the hotkey was sent, False otherwise.
funcstate_path(self) -> Optional[Path]Return the newest state file in the broker's slot, or None when it holds nothing.
paramselfReturns
typing.Optional[pathlib.Path]funcstate_screenshot_path(self) -> Optional[Path]Return the .jpg PPSSPP wrote beside the current state, or None when there is none.
paramselfReturns
typing.Optional[pathlib.Path]funcclear_working_slot(self) -> NoneDelete every state in the broker's slot, and its screenshot, before a new session boots.
A state is named for the game it was taken from, and the game id only comes off the running disc, so a leftover cannot be told apart from the state of the game about to boot. Anything still here belongs to a session that has already exited and whose states RomM holds.
paramselfReturns
Nonefuncstate_target(self, filename) -> Optional[Path]Map a pushed state's filename to where it may be written.
With the slot already holding a state, a pushed name has to match it;
otherwise the game id is taken on trust, bounded to a
<game>_<slot>.ppst basename in the state dir.
paramselfparamfilenamestrThe basename RomM is pushing.
Returns
typing.OptionalThe path to write to, or None when the name is not a state name, carries a path
funcsave_and_exit(self, slot) -> dict[str, Any]Save a state if asked, then stop the emulator.
paramselfparamslotOptional[int]Slot RomM asked to save into (resolved to STATE_SLOT), or None to exit
without saving a state.
Returns
dictA dict with state_saved (bool), state_slot (the effective slot, or None when no
funcstop(self) -> NoneInvalidate any in-flight deferred state load before the kill.
paramselfReturns
None