Add F10 back-buffer screenshot (PNG, focus-independent)

Capture the rendered back buffer to a timestamped PNG next to the exe via
WIC, triggered by F10 (delivered even when unfocused). The capture runs in
render_frame just before Present so it includes the ImGui overlay, and reads
off the GPU so it works regardless of window focus, z-order, or occlusion. A
brief toast confirms the save (drawn the next frame, so it's never in the shot).
F10 chosen to avoid Steam's F12; its WM_SYSKEYDOWN is swallowed so Windows
doesn't enter menu mode. Documented in the Help menu + README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 00:58:38 +02:00
parent 31db2d82c6
commit f72da74f78
5 changed files with 203 additions and 5 deletions

View File

@@ -8,6 +8,7 @@
#include <wrl/client.h>
#include <functional>
#include <string>
namespace coop
{
@@ -36,6 +37,16 @@ public:
// flip to the game's published frames instead of the monitor).
void render_frame(const RenderCallback& render, UINT sync_interval = 1);
// Request a PNG screenshot of the next rendered frame, saved to `path`. The capture
// happens inside render_frame just before Present, so it includes the ImGui overlay,
// and reads the back buffer off the GPU -- independent of window focus, z-order, or
// occlusion (works even when the window is fully covered). One-shot.
void request_screenshot(std::wstring path);
// If render_frame saved a screenshot since the last call, returns its path and clears
// the result (so a confirmation shows once); otherwise returns an empty string.
[[nodiscard]] std::wstring take_screenshot_result();
[[nodiscard]] HWND hwnd() const
{
return hwnd_;
@@ -56,8 +67,11 @@ private:
void create_render_target();
void release_render_target();
void handle_resize(UINT width, UINT height);
bool save_backbuffer_png(const std::wstring& path);
HWND hwnd_ = nullptr;
std::wstring pending_screenshot_; // set by request_screenshot, consumed in render_frame
std::wstring saved_screenshot_; // last successfully written shot, for a UI confirmation
bool resize_pending_ = false;
UINT resize_width_ = 0;
UINT resize_height_ = 0;