Skip to content

Game Capture: pin recording to the focused game window - #157

Open
bryan-ovalle2 wants to merge 2 commits into
eklonofficial:mainfrom
bryan-ovalle2:feature/window-capture
Open

Game Capture: pin recording to the focused game window#157
bryan-ovalle2 wants to merge 2 commits into
eklonofficial:mainfrom
bryan-ovalle2:feature/window-capture

Conversation

@bryan-ovalle2

Copy link
Copy Markdown

this is a WIP, wanted to get it up early for visibility/feedback rather than sit on it.

adds a "Game Capture" toggle that crops gpu-screen-recorder to just the game window instead of the whole display.

heads up — there's already an open PR (#136) for window capture. i looked into it before starting this one: it's a few commits behind main right now (not mergeable), and it has a real bug where picking "Focused window" with the default resolution will crash gpu-screen-recorder (-s is required for -w focused and it's never passed unless you also set a manual resolution — _detect_window_resolution() is defined but never called). it also bundles in some unrelated stuff — drops a big chunk of games.json, deletes a bunch of test coverage, removes the follow-my-mouse feature. figured i'd rather note it here than silently duplicate it.

what this does differently:

  • doesn't use GSR's -w focused at all, since that tracks raw input focus — alt-tab to discord or a browser mid-game and it'd start recording that instead of the game. instead there's a background loop that checks the focused window against games.json (same list already used for discord rich presence / clip tagging) and only pins capture once it recognizes an actual game.
  • when the pinned game's window closes, it proactively drops back to full-display capture instead of letting gpu-screen-recorder crash on a dead window and leaning on the watchdog to notice after the fact.
  • window-id pinning is X11/XWayland-only since that's what GSR supports for per-window capture — falls back to full-display on native Wayland compositors (Hyprland/Sway) or before any game has been detected yet.

also threw in Rematch and Gears of War: E-Day Multiplayer Beta to games.json since i had both open while testing this.

testing so far: verified manually against Gears of War: E-Day Multiplayer Beta and Rematch (real Steam/Proton games) — detects and pins within ~1s of the game gaining focus, stays pinned through alt-tabbing to Chrome, and cleanly releases the pin when the game window closes (no more crash-restart cycle in the logs). marking as draft since i haven't tested the wf-recorder/ffmpeg backends or non-X11 sessions yet.

@bryan-ovalle2
bryan-ovalle2 marked this pull request as ready for review August 15, 2026 00:37
@eklonofficial

Copy link
Copy Markdown
Owner

This is the right approach and I want it. Going with this over #136, which I've closed.

Pinning to a window id after a games.json match, rather than using GSR's -w focused, is the call I'd have made. -w focused tracks raw input focus, and for a replay buffer that means tabbing to Discord silently starts recording Discord. Proactively releasing the pin when the window closes instead of letting GSR die on a dead target and waiting for the watchdog is also right.

Two corrections on your read of #136, since I checked before closing it: it doesn't touch games.json and doesn't delete any tests. It's branched off v2.5.0, so diffing its tip against main makes it look that way. The -s bug is real and I confirmed it against the man page, and it would have clobbered follow-my-mouse. Worth being careful with that kind of claim.

Four things before I merge:

  1. Tests. Nothing here is covered. The pieces I'd want locked down: _gsr_capture_args emitting -s from the resolved geometry, falling back to full-display when geometry can't be resolved, and respecting a user's own -w in gsr_args. Plus the loop pinning on a match and releasing when the window is gone.

  2. Debounce the pin. Every pin and release calls _restart_recorder_for_config(), which drops the replay buffer. That's the whole product, so it should be hard to trigger by accident. Follow-my-mouse requires two agreeing samples before it retargets for the same reason. A game that recreates its window on a fullscreen or resolution change will hand you a new window id, and right now that's an immediate restart and a lost buffer.

  3. Slow the poll down. 0.5s with get_active_window plus get_focused_window_id is four-ish subprocess spawns a second, forever, while enabled. Follow-my-mouse runs at 2.0s. With a debounce in place I don't think you lose anything real by matching that.

  4. Say something on the backends that can't do it. _gsr_capture_args is GSR-only, so on wf-recorder and ffmpeg the toggle silently does nothing. Same on native Wayland before a game is detected. Either disable the toggle with a note, the way the follow-my-mouse toggle does when the compositor can't report pointer position, or log it once.

Rebase on main when you get to it, 2.7.0 just went out and touches _build_cmd and the watchdog. Take your time, there's no rush on this.

Adding Rematch and Gears of War: E-Day is fine, keep those in.

@bryan-ovalle2

Copy link
Copy Markdown
Author

Thanks! Sorry about that claim, shoulda realized. I'll let you know when I add your requests. I've honestly been looking for something like this for a while so I'm glad you released this!

@eklonofficial

Copy link
Copy Markdown
Owner

Had another look at this now that 2.7.1 is out, and I merged it locally against current main to check: no conflicts, and the full suite still passes with it applied. The codec work I just landed touches the same function as your capture changes but a different part of it, so you shouldn't have to rebase.

The approach still looks right to me. Pinning to a window id instead of using GSR's -w focused is the correct call and your reasoning for it is sound, and dropping the pin proactively when the window closes rather than letting the watchdog catch a crash is the sort of thing I'd have asked for. Your read on #136 matched mine when I looked at it, for what it's worth.

Three things before I can take it:

  1. Tests. This is the blocker. It's around 240 new lines across main.py, active_window.py and recorder.py with no coverage. _gsr_capture_args is the important one since it's pure and easy to test: pinned window produces -w <id> -s WxH, a manual resolution suppresses the -s, a dead window falls back to full display, and window_capture off changes nothing. _window_capture_loop is worth covering too, particularly that an unrecognized focused window does not move the pin. There's now CI on the repo so these run automatically.

  2. The poll interval. 0.5s means shelling out to xdotool two or three times a second, forever, while someone is gaming. Follow-the-pointer runs at 2.0s and it's tracking something that moves far more. I take your point that a games.json match is a deliberate signal and doesn't need debouncing, and I agree, but that's an argument about debounce rather than frequency. 1.0s or 2.0s would cost you a second on the initial pin and nothing else, since you already check once immediately.

  3. The other backends. window_capture is wired through _gsr_capture_args only, so on wf-recorder or ffmpeg the toggle appears in the UI, does nothing, and says nothing. Either grey it out when the backend isn't GSR or log a warning on apply. I'd take either.

One small style thing: no em-dashes in comments or log strings please, a comma or a full stop instead. My own fault for never writing that down anywhere.

No rush on any of this. Ping me when you've pushed and I'll take another look.

@bryan-ovalle2
bryan-ovalle2 force-pushed the feature/window-capture branch from d410943 to 374c96b Compare August 15, 2026 17:48
@bryan-ovalle2

bryan-ovalle2 commented Aug 15, 2026

Copy link
Copy Markdown
Author

@eklonofficial check these changes out:

  1. Capture mode picker — Header toggle replaced with a Capture pill + submenu (Active Game / Desktop / Window), laid out in one row, centered under the pill. New recording.capture_mode config field drives the existing window_capture bool; old configs migrate automatically. "Window" is a visible, disabled stub for the work done in feat: add per-window capture source selection #136 . Options grey out when the backend isn't gpu-screen-recorder.

  2. Debounce pin swaps/releases — Swapping an active window pin, or releasing one, now needs two agreeing samples (mirrors follow-the-pointer). Fixes a bug where a game recreating its window (fullscreen/resolution change) triggered a recorder restart — and lost the buffer — on every intermediate window id. First pin still lands instantly.

  3. Updated poll interval from 0.5 to 2s

  4. Added tests

I also rebased just to be safe.

@eklonofficial

Copy link
Copy Markdown
Owner

Heads up, there's CI on the repo now and I approved the run on this branch. It came back red, but none of it is yours: four CLI tests assumed the machine has a display, which is true on my desktop and not on a runner. That's fixed on main, so rebase or merge main in and it should go green.

Still the same three things from before on my side: tests for the new window-matching, a slower poll interval, and a guard so this does nothing on the segment backends. No rush.

@bryan-ovalle2
bryan-ovalle2 force-pushed the feature/window-capture branch from 374c96b to c8ec2a7 Compare August 29, 2026 17:49
@bryan-ovalle2

Copy link
Copy Markdown
Author

@eklonofficial Sorry it took a while, been a busy couple of weeks. Here are the highlights from this recent commit:

  • rebased
  • added a guard so the window-capture polling loop never runs on segment backends (wf-recorder/ffmpeg), GSR only.
  • Slowed polling down to 5 sec
  • Update the UI on the game capture button so that it's own sub-navigation happens in place. Before I had a dropdown but that isn't feasible with the current layout.
  • Added tests to the python test suite

I did notice that .home has a max-width of 1180px with no centering. Crazy people like me have 43" monitors so it's really apparent. It's not too bad though, and yea I understand that not many people have displays this big but maybe it's something to consider updating in the future.

@bryan-ovalle2 bryan-ovalle2 changed the title Game Capture: pin recording to the focused game window (WIP) Game Capture: pin recording to the focused game window Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants