Repository navigation
Merge Purun controls and prepare Android packaging for games without overlays - #42
Merged
Merged
Conversation
…mall calls - GameProfile::system_language and confirm_button: what sceUtilityGetSystemParamInt and the new sceImposeGetLanguageMode report. The defaults stay a Japanese console (Japanese, circle), as before. - sceRtcGetAccumulativeTime, sceCtrlSetIdleCancelThreshold and scePowerSetClockFrequency, with their NIDs from the SDK's stubs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Under TRACE_KERNEL, "[sysparam]" lines show what sceUtilityGetSystemParamInt answers and what the game then hands sceImposeSetLanguageMode, so which confirm button a game ends up with is read, not guessed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The pad mapping assumed a Japanese console: "confirm on the south button" meant south presses circle. A game on a console where cross confirms (any non-Japanese release, once its profile says so) then went back on south and confirmed on east, the other way round from its own prompts. - The south and east buttons now press the game's confirm and back buttons, taken from GameProfile::confirm_button, so input.confirm names the physical button that confirms whatever the console. - input.confirm defaults to south where cross confirms and east where circle does; a value in settings.ini or PAD_FACE still wins. - AUTO_CONFIRM presses the console's confirm button. - The menu's confirm setting, the ○ and × key bindings' labels and the "[pad] ... connected" line say which button confirms on this console. A Japanese profile (confirm_button 0) behaves exactly as before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A game played by tilting (LocoRoco tilts with L and R) can now be tilted with the motion sensors of a gamepad or of the phone itself. It is off by default and only for a game whose profile says how it tilts. - GameProfile::tilt names the buttons that tilt left and right, and whether the game eases its tilt towards the held side; then a small roll presses the button for part of the frames and tilts part way. - input/tilt: the roll from the accelerometer, fused with the gyroscope's rate; the dead zone with hysteresis, re-centring, inversion; three modes: Angle, Angle + level horizon, and Rate, where turning the device tilts and the tilt stays when the turning stops. Unit tested with synthetic readings (portablekit_tilt_tests). - input/motion: the sensors through SDL, a gamepad's first, else the device's own turned with the screen. The log says which were found, and why none were: Steam Input's virtual pad hides a Steam Deck's. - A tilt button the player presses takes over from the sensors, so a tilt never becomes both buttons at once. R3 alone re-centres, and so do the start and closing the menu. - Angle + level horizon turns the finished game picture against the device's roll and zooms it just enough to cover its rectangle at that angle (1:1 when level), capped at 10 degrees by default. The overlay and the interface are drawn after it and stay upright. - Controls > Tilt controls in the menu, settings.ini keys input.tilt*, and <prefix>_TILT, _TILT_MODE, _TILT_FULL, _TILT_DEAD_ZONE. - The input script's virtual pad gets a gyroscope and an accelerometer when a script uses the new tilt and gyro steps, so all of it can be driven without hardware. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A game started from Steam on a Steam Deck gets the Deck's controls through
Steam Input: SDL is told to ignore the real controller (28de:1205) and sees
only Steam's virtual pad, which has no motion sensors, and tilt controls
did nothing even with Steam Input turned off for the game, because the
Deck's built-in controls stay under Steam Input.
input/steam_deck_imu reads the controller's state reports from its hidraw
node beside Steam, on Linux, when the pad in use has no sensors of its own.
Only the motion fields are used; buttons and sticks keep coming through
Steam's pad, so nothing is pressed twice.
Measured on a Deck (SteamOS, Game Mode):
- The controller's vendor interface (report descriptor starting with usage
page 0xFFFF) sends 64-byte reports 01 00 09 40 at 250 a second; the
accelerometer is int16 X, Y, Z at 24, the gyroscope at 30.
- While a game whose Steam layout leaves the gyroscope unused is running,
every motion field is zero: Steam has the motion unit off. In Steam's
own interface it is on.
- Setting 48 (the motion unit's mode) to 0x18 through feature message
0x87 turns it on and data arrive at once; 0 turns it off again.
- At rest on a table the accelerometer read (0.4, 9.78, -1.1) m/s² in
SDL's gamepad axes, +Y up out of the face, as SDL's own Deck driver
gives them.
So when the motion fields stay empty for 0.3 s the mode is set, again
once a second if Steam turns it back off (logged), and set back off when
tilt controls are turned off or the game exits, if it was set here.
<prefix>_TILT_DECK=0 leaves the controller alone. The gyroscope is
averaged over the reports of each frame.
The log names the source ("[tilt] Steam Deck controller /dev/hidrawN:
reading its gyroscope and accelerometer beside Steam Input"), the menu
shows "Steam Deck: gyroscope and accelerometer", and the advice to turn
Steam Input off is given only for pads other than a Deck's own.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Deck's controller was read on the main thread, from the frame's pad sampling: non-blocking reads until the queue was empty, and the feature report that switches the motion unit on sent from there too. The kernel sends a feature report as a USB control transfer and waits for it, so a controller slow to answer could have held up a frame. Now a thread owns the device: it waits in poll() with a 100 ms timeout, reads at most 256 reports per wake, and sends the motion unit's setting itself. The main thread only takes the latest accelerometer reading and the mean gyroscope rate under a mutex. Turning tilt controls off parks the thread (after switching the unit back off if it switched it on) without waiting for it; at exit it is stopped and joined. Measured on a Deck with a probe calling open, read and describe once a frame: the slowest call took 234 us (the first, which scans sysfs and starts the thread); closing took 6 us. Switching on after 0.3 s of empty motion fields, switching off when closed, and on again when reopened all worked. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…uild Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Angle + level horizon turned the picture against the device's roll, so the game's horizon stayed level with the real one. What the player wants from a tilting game is the opposite: the ground fixed to the screen, so the device held tilted is the tilted world and the character rolls. How LocoRoco 2 turns its world, traced with <prefix>_TRACE_CAMERA and a temporary dump of each frame's matrices while R, then L, was held: the view and world matrices stay unturned; the projection of its transformed draws turns, as scale x turn. At rest its first two rows are (1/120, 0) and (0, 1/68); held R eased over about half a second to (7.2253e-3, 4.1715e-3) and (-7.3615e-3, 1.2750e-2), that is exactly -30 degrees with the scales unchanged, and held L to +30. It eases back to 0 on release. - The renderer takes the turn of the projection of each frame's biggest transformed draw (projection_roll: each row divided by its length, so the aspect drops out) and hands it to input::motion::set_game_roll. - level_degrees() turns the picture back by that much, within the level limit, while tilt controls are on in Angle + level horizon. The zoom that keeps the corners filled is unchanged. - The level limit may now go to 30 degrees, LocoRoco's full tilt; below it the ground turns on the screen again past the limit. - <prefix>_TILT_LEVEL_FROM=device turns the picture against the device's roll as before. - <prefix>_TRACE_TILT prints the game's roll and the level turn. Not yet seen on a screen: the turn is derived from traced matrices only. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…dev build Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… off the menu LocoRoco jumps with L and R together. With tilt controls on: - L and R pressed together reach the game as both, as before: a tilt button the player presses takes over from the motion, so the motion is not added at all while either is held. A single shoulder tilts that way alone, over the motion. - A jump button presses both tilt buttons while held, whatever the device's roll (input.jump_button: off, l3, south, east, west, north). The default is L3: the PSP has no stick click, so it takes nothing from the game, while every face button is read by LocoRoco 2 somewhere (circle next to L and R in its play code, cross as its confirm button, triangle and square with START and SELECT). A face button chosen instead no longer presses its own button. - The keyboard gets a Jump action (Keyboard and mouse), unbound by default, listed only for a game that tilts. Angle + level horizon did not play well on a Steam Deck and is no longer offered in the menu. It is still honoured from settings.ini or <prefix>_TILT_MODE (level, or horizon), shown by name, and leaves for Angle or Rate from the menu; its limit row only shows while it is in use. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…k-dev build Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A Steam Deck build hung twice a minute or two into play: the log stopped, the main thread slept in a loop, and the process could not be attached to (ptrace_scope 1, no root). The stall watchdog is how such a stall can be read afterwards. When the game has flipped no framebuffer for five seconds outside the paused menu: - the scheduler's idle loop, where the main thread waits when every guest thread is blocked, writes Kernel::dump_state to stderr and flushes it: the clock, vblanks, idle vblanks, the current thread, interrupts, the pacing and fast loading, and every thread with its state, priority, pc, ra, sp, what it waits for, its deadline, and the semaphore, event flag, mutex or mailbox it waits on. Once, and again every 30 seconds while the stall lasts; - a thread of its own, for a stall anywhere else, says how long since the last frame and when the scheduler last went idle; - both add the last 16 changes of the pad word handed to the game, with their age. <prefix>_STALL_WATCHDOG=0 turns it off; =N waits N seconds. Tried on macOS without a window with a limit of a millisecond: the dump lists LocoRoco 2's threads (LocoRocoMain waiting on a delay, its sound threads on their semaphores). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SDL turns SIGTERM into a quit event, and the window's events are only read when the game flips its framebuffer; a game that stopped flipping ignored both, which is why the stalled Steam Deck build needed SIGKILL. While the stall watchdog sees a stall from the scheduler's idle loop it now reads the window's events ten times a second and stops the game when the window is closed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A game played otherwise than the framework's defaults suppose (W A S D to move, the mouse for a camera) can now give its own keyboard and mouse defaults: GameProfile::keyboard_defaults gets the framework's bindings and mouse setting and changes what it needs. defaults_for() applies it before a phone's own changes, so "Restore control defaults" returns to it too. A player's own bindings stay: only actions settings.ini does not name take the defaults, and those lose any key or button a saved action already has (input::keep_saved), so a default added later, such as Jump on Space where an older file put Space on cross, cannot press two controls at once. <prefix>_TRACE_PAD prints the keyboard as loaded, marking the defaults. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> # Conflicts: # host/settings/settings.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merge the current framework with the Purun development controls and stall fixes, preserving the newer HLE implementations. Android packaging now accepts games with no overlay libraries and carries the framework, game and compiled third-party license texts.
Validation: the full framework build and all 21 CTest tests passed on macOS Apple Silicon. SDL 3.4.16 and bundled FFmpeg built for Android arm64/API 29. The full 193-unit Purun Android AOT APK build passed, including Java/resources, signing, Android 10 native imports, ZIP alignment, 16 KiB ELF segment alignment and the exported SDL_main entry point. The APK contains four arm64 libraries and a fallback font, with no game files; this also exercises the no-overlay packaging path. No Android device is connected; startup, sensors and gameplay have not been verified.