|
MAIN MENU
EXTERNAL
|
| A Blocking State Machine Over a Text Console |
|
There's no frame-timed render loop and no custom graphics engine. TempAR's UI draws
directly onto PSPSDK's built-in debug-screen text console, aliased via macros in menu.h:
#define printf(...) pspDebugScreenKprintf(__VA_ARGS__)
#define puts pspDebugScreenPuts
Every screen is a while loop that blocks on controller input, redraws
synchronously, and returns control up the call stack once the user backs out (CIRCLE) or
switches tabs (L/R trigger). There's no dirty-rectangle tracking — screens simply
reprint.
menu_show() is the single entry point into the whole UI, called from button_callback() once menu.visible is set. It performs PSP-specific setup/teardown:
- Hide the system home popup, delay ~150ms.
- Mask controller input from reaching the game.
- Snapshot resume_count (detects a suspend/resume cycle while the menu is open).
- Resolve a VRAM pointer via get_vram() and re-init the debug screen against it.
- Optionally pause the game's other threads.
- Call layout_tab() — the actual UI — which blocks until closed.
- Reverse every step above, in reverse order.
| Order-dependent, no RAII |
|
This setup/teardown must be mirrored exactly. There's no cleanup-on-error here —
it's manual. A layout_* function that adds a new early-return path deep in the
call tree without going through the normal return chain would leave the game's input
permanently masked, or the home-button config in the wrong state. Always return,
never bypass the call stack.
|
get_vram() has a fallback path (hardcoded 0x44000000) when the Impose
plugin's framebuffer can't be resolved — this is the homebrew-without-imposeplugin
compatibility path, and it also force-sets menu.options.force_pause = 1 as a side
effect. Intentional, not a bug, but a non-obvious behavior change from an unrelated-looking
function.
|
| Tab System |
|
layout_tab() is the top-level UI loop: a switch on the global char
tab_selected (0-4: Cheater, Searcher, PRX/Options, Browser/Decoder, Credits/GameID),
dispatching to one of five layout_*() functions, each owning its own inner input
loop and returning a u32 control mask when it exits.
| Function | Tab / role |
| layout_heading() | Draws the tab bar + cheat-engine on/off indicator (shared by every tab) |
| layout_cheats() | Cheater tab — cheat list browsing/toggling |
| layout_cheatmenu(cheat) | TRIANGLE popup submenu (edit/rename/copy/delete/favorite) |
| layout_cheatedit(cheat) | Hex/code editor for a cheat's raw lines |
| layout_searcher() | Searcher tab |
| layout_options() | PRX/Options tab — settings, hotkey rebinding, config save |
| layout_browser() | Memory Browser/Disassembler tab |
| layout_copymenu(...) | Address/value copy-paste dialog shared by browser & disassembler |
Shared drawing helpers: line_print(), line_clear(), line_cursor(), get_print_start_end() (computes the visible scroll-window by centering the current selection — this was the site of the display-order rendering regression, see Cheat Engine), percentage_to_color(), show_error().
|
| Input Handling (ctrl.c) |
|
ctrl_read() is the single point where the raw SceCtrlData is polled and turned into TempAR's augmented button mask:
- A HOME press, or a resume_count mismatch, forces menu.visible = 0 — how the menu auto-closes across suspend/resume.
- Analog stick tilt is synthesized into dpad bits (threshold <50/>200 on the 0-255 axis).
- When the menu isn't visible, PSP_CTRL_CIRCLE is force-set in the returned mask.
- cfg.swap_xo (CROSS/CIRCLE swap) is applied here transparently.
Blocking wait helpers (ctrl_waitany, ctrl_waitkey, ctrl_waitmask,
ctrl_waitrelease) implement key-repeat via ctrl_delay(): while held,
repeat_count increments (capped at 12) to accelerate repeat speed, using 145ms/9ms
by default or a 17ms/1ms "quick" variant for fast-scroll contexts.
Global hotkeys are registered via sceCtrlRegisterButtonCallback at boot and
re-registered three more times inside the options screen whenever the user rebinds a key.
button_callback() checks curr_but against cfg.menu_key,
cfg.screen_key, and cfg.trigger_key.
|
| Config Persistence (config.c) |
|
Config is a single __attribute__((packed)) struct — ver byte,
settings fields, trailing checksum. The struct layout is the file format:
config_load() reads the version byte, and if it matches CONFIG_VER
(currently 0x08), reads the rest of the struct as one raw memory blob straight from the
file. Field order, packing, and alignment must exactly match between whatever wrote the
file and whatever reads it.
| No migration path |
|
A version mismatch, failed checksum, or out-of-range field caught by
config_validate() causes a silent full reset to defaults, not a partial upgrade.
Any time you add, remove, or reorder a Config field, bump CONFIG_VER —
otherwise old config files will be misinterpreted rather than rejected.
|
|
| On-Screen Keyboard (pspdebugkb.c) |
|
A PSPSDK-provided utility (not TempAR-authored) for editing a string in place with the
D-pad instead of the system OSK dialog. Draws a fixed 13-column x 4-row character grid plus
a 5-item command row. pspDebugKbInit(str, len) is the blocking entry point, called
from exactly two places: renaming a cheat, and entering search text.
|
|