The wait shows as frame_limit in the VideoOut.Flip timing, so a title held
by ANYPS5_FPS_LIMIT is told apart from one held by the vblank wait in the
trace and in the phases of the performance overlay's second page.
With ANYPS5_FPS_LIMIT set, processFlip waits for the pacer's deadline after
the flip's vblank wait and before the frame is presented, so the delay
falls on the presentation and on the flip's completion event, which is
what paces the title. The wait takes no lock, sleeps with PreciseSleepUs in
slices of 20 ms and re-checks between slices whether the output was closed
or failed. The limit is read at the first flip, where an invalid value
stops the title with the error that names it. Without the variable the
pacer does not exist and processFlip does what it did. Flips of the overlay
bus are not paced.
When ANYPS5_PAD_IDENTIFY is connect or always, a controller that is
bound to a player slot gets a short pulse pattern once the title has
been quiet for 500 ms: one pulse for player 1, two for player 2 and so
on up to four. The scheduler runs in the existing output pass, so a
title's own rumble, its refreshes and its stop always take precedence,
and the pulse is scaled by ANYPS5_RUMBLE. A controller without rumble
support logs one line and gets no pulse. The keyboard and mouse never
get a pulse, since they are not bound to a slot. The mode is read when
the pad input starts, so an invalid value stops the title there. With
the default off, the output pass sends exactly what it sent before.
libSceVideoOut reads and changes the shared host volume state, and linking libSceAudioOut for it puts a second shared library with its own static SDL2 into libSceVideoOut. Both libraries already link libScePad, so the headers that describe that state move there first; the include paths and guards follow.
With the option on, a window that opens behind another one starts silent instead of waiting for a first focus event that never comes. With the option off this changes nothing.
The display window's focus events drive the shared host volume. With ANYPS5_MUTE_ON_FOCUS_LOSS unset or 0 they change nothing; with 1 the audio is silent from focus lost until focus gained, and each change prints one line on stderr.
The requests are handled only for key events of the display window, like fullscreen, the overlay and the screenshot, and each handled press prints one line with the resulting level or mute.
PadInput applies ANYPS5_VOLUME and ANYPS5_MUTE_ON_FOCUS_LOSS next to the input mapping, so an invalid value stops the game at the same point as an invalid mapping file, with an error naming the variable.
The action takes keyboard keys only, like ToggleFullscreen, TogglePerformanceOverlay and Screenshot, and has no built-in binding yet. The input mapper lists it as keyboard-only and its source-contract test follows the native table.
The action takes keyboard keys only, like ToggleFullscreen, TogglePerformanceOverlay and Screenshot, and has no built-in binding yet. The input mapper lists it as keyboard-only and its source-contract test follows the native table.
The action takes keyboard keys only, like ToggleFullscreen, TogglePerformanceOverlay and Screenshot, and has no built-in binding yet. The input mapper lists it as keyboard-only and its source-contract test follows the native table.
Only a first keyboard key-down counts: key repeat and the release ask for nothing, and a mouse button bound to it is ignored, like the other host requests.
Only a first keyboard key-down counts: key repeat and the release ask for nothing, and a mouse button bound to it is ignored, like the other host requests.
Only a first keyboard key-down counts: key repeat and the release ask for nothing, and a mouse button bound to it is ignored, like the other host requests.
VolumeUp, VolumeDown and ToggleMute join the controls that never reach the title's pad state: Compose ignores them like the fullscreen, overlay and screenshot controls.
With ANYPS5_PAD_PORT0_STATE=controller, port 0 follows the controller bound to
slot 0: the presence rule commits a change after the hold, and the commit
sets libScePad's port 0 state and user 0's login state. Keyboard and mouse
do not count as a pad there, so while port 0 is withdrawn their input is not
composed into it and titles see the withdrawn port.
Opening or closing a controller no longer sets port 0 directly; slots 1 to 3
keep their immediate updates. The default mode never commits a change, so
port 0 stays connected and user 0 logged in as before.
APS5_PAD_INPUT_FILE input was merged only into guest pad reads. While a
modal dialog or the IME held the pad, the title saw the intercepted
state and the dialog saw only host SDL input, and without a controller
video out did not publish slot 0 at all. A message dialog opened by the
title (Void Terrarium++ "System data not found" on a fresh profile)
could then never be answered in a scripted run.
Merge the injected input into the host state handed to the capturing
dialog, publish slot 0 every frame while the pad is captured, and once
more when the capture ends so the title stops reading the intercepted
state.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PadInput hands its provider to the display's poll on every update
instead of building and comparing a snapshot itself, so with
ANYPS5_PAD_STATUS unset or 0 and no request an update no longer copies
controller names or reads SDL_JoystickCurrentPowerLevel. A press of the
ShowPadStatus key polls at once, so the panel lists the controllers
from its first frame.
PadInput remembers each slot's SDL controller type and name when it
opens the controller, and on every update reads the slot's connection
and SDL_JoystickCurrentPowerLevel through a PadStatusProvider. Only a
changed snapshot is handed to the pad status display, so an idle loop
takes no lock; hot-plug events reach it on the next update. A press of
the ShowPadStatus key in the game window asks the display to show the
panel. PadInput is no longer copyable, as its provider refers to it.
PadKindFromSdl and PadPowerFromSdl turn SDL's game controller type and
joystick power level (SDL_JoystickCurrentPowerLevel: unknown, empty,
low, medium, full, wired) into the pad status types. SDL_JOYSTICK_POWER_MAX
is the enumeration's bound, not a level, and reads as unknown, like any
value outside the enumeration. They are plain functions of the enums,
so tests need neither an SDL subsystem nor a device.
A rebindable keyboard action, F9 by default, that asks for the
controller status panel. F9 is the first free function key: F7, F10,
F11 and F12 are bound by default and no default keyboard-to-pad binding
uses it. Like ToggleFullscreen, TogglePerformanceOverlay and Screenshot
it accepts only keyboard keys, fires once per press (not on key repeat)
and does not press any pad button.
The input mapper's catalogue gets the action, its F9 default and its
keyboard-only restriction, and its existing source-contract tests list
it, since they compare the actions, restrictions and built-in bindings
with the native files.
PC5 (PPSA11018) imports the NID and the library did not export it, so the converted executable stopped at load with error 127. The call validates the handle and index like the other cursor calls and returns 0: no cursor image is drawn, so the magnification has no observable effect. The unmeasured behaviour is recorded under Silent stubs.
APS5_VIDEOOUT_TELEMETRY_DIR, APS5_SAMPLE_THREADS, APS5_SAMPLE_WORKER and
APS5_SAMPLE_COMMITTER were read with getenv and opened with the narrow
fopen/ofstream, so on Windows they worked only for characters in the
ANSI code page, and the tests, which pass UTF-8 path.string() values,
failed whenever %TEMP% was not ASCII.
They are now read with _wgetenv and carried as UTF-8, as the other
diagnostic directories (ANYPS5_SCREENSHOTS, APS5_DUMP_SUBMITS,
APS5_PAD_INPUT_FILE) already are, and the files are opened through
std::filesystem::path. The worker sampler test sets its variables with
_wputenv_s and reads the results through std::filesystem::path.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
When the first button event arrives while a modal dialog captures input, MouseInput
publishes a button reset instead of it and drops every press and release until
the dialog is gone, so a button the title saw pressed before the dialog opened
does not stay pressed when its release is dropped.
MouseInput drops a button press while a modal dialog captures input, so the click
that answers the dialog is not also delivered to the title. Releases still reach
it in this commit.
MouseInput drops relative motion and wheel steps while a modal dialog captures
input, so moving or scrolling to answer the dialog does not also move the title's
cursor. Button events are unchanged by this commit. video_out_mouse_tests links
libSceIme for the dialog tests that follow.
When the first key event arrives while a modal dialog captures input, KeyboardInput
publishes a key reset instead of it and then drops every key press and release
until the dialog is gone, so a key the title saw pressed before the dialog opened
does not stay pressed when its release is dropped.
KeyboardInput no longer publishes a key press to libSceKeyboard while a modal dialog
captures input, so the keys that answer the dialog are not also typed into the
title. Key releases still reach it. keyboard_tests links libSceIme because it
builds KeyboardInput.cpp itself.
While a modal dialog captures input, the controller hand-off that already serves
an IME keyboard publishes slot 0's buttons and left stick to the dialog and
returns the neutral intercepted state to the title, and the button held when the
dialog closes stays hidden until it is released. Key presses, mouse button
presses, wheel steps and motion no longer reach the keyboard-to-pad mapping while
the dialog is shown; releases still do, so no mapped button stays pressed.
DialogInput turns window events into modal dialog inputs: Left, Up, Right, Down,
Tab and Shift+Tab and the mouse wheel move the focus, Enter, the keypad Enter and
Space and a left click confirm, Escape and a right click cancel. Repeats of the
confirming and cancelling keys, other windows' events and other keys are
ignored. The presentation thread feeds it with the events it already polls for
the IME text input.
The presentation thread registers itself as a modal dialog presenter while its
window exists and withdraws on exit, so a dialog opened with no window to show
it is refused and keeps its caller's own answer. Before each flip it reads the
pending dialog and passes it to the driver, or clears it. The IME keyboard keeps
the overlay: while it is shown or captures the keyboard or the pad, the dialog
is not read.
EVO Player and Prospero Win measured RESOURCE_BUSY on ports opened on
bus type 0. The overlay bus is unmeasured, so its on-screen set is
still released as before, which video_out_flip_overlay relies on.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The console answers RESOURCE_BUSY (0x80290009) when the set holding
the buffer on screen is unregistered, and the set stays registered:
EVO Player measured it with a re-registration then failing
SLOT_OCCUPIED, and Prospero Win on firmware 12.02 after its flips went
idle. The set was released and 0 returned instead.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The motor rumble and the trigger rumble of non-DualSense controllers reach SDL with the amplitude a title asked for and no host-side way to reduce or disable it. Build both commands through the rumble intensity helper: at the default of 100 the command is the one built before, and at 0 the host only ever receives a stop. The variable is read when the pad input starts, so an invalid value stops the game there. Vibration that a title plays as audio and that falls back to motor rumble goes through the same path and is scaled with it. DualSense adaptive trigger effects are left untouched.
PS5_Vulkan measured on a base PS5 set to 1080p output that
sceVideoOutIsOutputSupported(15) answers 0, neither 1 nor an error, and
that sceVideoOutConfigureOutput(15) then returns 0x80290019, in a title
declaring high-frame-rate output. A host display below 120 Hz answered
0x80290016 to both instead. Titles that branch on the answer being 1
are unchanged; the undeclared-title answer stays 0x80290016.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PS5_Vulkan measured on a PS5 (firmware 13.40) that
sceVideoOutRegisterBuffers2 refuses a set at buffers 15 to 19 with
0x80290001. The call threw instead. The other out-of-range arguments
keep throwing.
Co-Authored-By: Claude Opus 5.5 <[email protected]>