Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Fix Cap Windows window target discovery returning [] from cap targets windows --json

オープン
#2,164 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
68/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
rust
領域
cli, desktop

調査の方向性

crates/scap-targets/src/platform/win.rs から始め、WindowImpl::list() と get_topmost_at_cursor_fallback() を比較し、その後 crates/recording/src/sources/screen_capture/mod.rs と apps/cli/src/targets.rs を通じて結果を追跡します。Windows で表示されている対象ウィンドウを用いて cap targets windows --json を再現し、既存のフィルターを維持したまま、使用可能な数値 ID が返され、クロップの挙動が分離されていることを確認します。

索引モデルが issue の本文から書いたものです。

説明

Summary

I am documenting a reproducible Windows limitation in the Cap CLI and intend to implement the resolution in a new pull request against the Cap repository after validating the fix locally. My production consumer is the Robotic Video Sales Letter agent in run.py, where I need Cap to record the Camoufox browser window rather than the entire desktop.

Environment

  • Windows edition: Windows 11 Home Single Language
  • Version: 24H2
  • Installed: 4/6/2025
  • OS build: 26100.4652
  • Experience: Windows Feature Experience Pack 1000.26100.128.0

Exact observed problem

On Windows, the Cap CLI can be invoked successfully, but cap targets windows --json returns an empty JSON array ([]) even while a visible Camoufox top-level application window is open. Because no target is exposed, the result cannot be passed to cap record start --window <id> through the normal CLI workflow.

The CLI entrypoint is apps/cli/src/targets.rs. Its windows() function calls cap_recording::screen_capture::list_windows(), then serializes each returned window into the JSON target shape. An empty result at this boundary therefore becomes []; this is not a JSON formatting problem in the CLI.

The recording target abstraction is defined in crates/recording/src/sources/screen_capture/mod.rs. ScreenCaptureTarget::Window { id } expects a WindowId, resolves the target with Window::from_id(id), obtains the display and window bounds, and derives crop information from those bounds.

The Windows target implementation is crates/scap-targets/src/platform/win.rs. WindowImpl::list() defines an enumeration callback for windows, but currently invokes EnumChildWindows(Some(GetDesktopWindow()), ...). This is the suspicious failure boundary: EnumChildWindows enumerates child windows beneath a parent, whereas the application windows required by cap targets windows are top-level windows and are discoverable through EnumWindows.

The same win.rs file already uses EnumWindows in get_topmost_at_cursor_fallback(). This makes the list path internally inconsistent: the general window-list path begins with desktop-child enumeration, while another Windows path enumerates top-level windows directly.

Evidence from my repository

My consumer-side implementation is run.py. _find_camoufox_hwnd() uses win32gui.EnumWindows() to enumerate visible top-level windows, filters titles and process information, and returns the Camoufox window handle when it finds a match. This independently finds a valid HWND while Cap target discovery returns [].

The same run.py passes the discovered value to the Cap recording command when a window ID is available and retains a screen-recording fallback when it is not. The workaround is intentionally explicit because Cap target discovery is currently unavailable on my Windows setup.

The workaround is documented in README.md, which records that the Cap Windows target command returns an empty list and that pywin32 top-level enumeration is used as a consumer-side fallback. pywin32 is not doing the recording; it is only discovering an HWND and allowing my runner to identify the browser window.

The browser and cursor implementation in camoufox_capability.py is separate from this failure. It drives Camoufox and harvests browser events; it does not provide Cap target enumeration and is not the source of the empty Windows target array.

HWND and Cap identifier relationship

The Windows implementation in crates/scap-targets/src/platform/win.rs wraps the native HWND in WindowImpl and converts the handle value to WindowIdImpl with the underlying numeric value cast to u64. Therefore, a live numeric HWND returned by win32gui.EnumWindows() is conceptually the same native identifier that Cap uses for a Windows WindowId, provided the window is still valid when recording begins.

My current understanding is therefore:

  1. win32gui.EnumWindows() discovers valid top-level HWNDs on Windows.
  2. Cap'''s WindowImpl::list() uses EnumChildWindows from the desktop window, which enumerates children of the desktop rather than top-level application windows.
  3. The fix should switch WindowImpl::list() to use EnumWindows directly, matching the pattern already present in get_topmost_at_cursor_fallback().

Scope of this issue

The primary scope is Windows target discovery for the Cap CLI, specifically the path from apps/cli/src/targets.rs through crates/recording/src/sources/screen_capture/mod.rs into crates/scap-targets/src/platform/win.rs.

This is distinct from a second possible limitation: a discovered window ID may still produce display-region cropping rather than true isolated window-content capture. The Windows capture implementation in crates/recording/src/sources/screen_capture/windows.rs configures Direct3D capture and applies crop_bounds, while the shared crop calculation is in crates/recording/src/sources/screen_capture/mod.rs. Fixing enumeration should restore target discoverability, but it must not be presented as automatically fixing capture semantics or crop correctness.

macOS caveat and platform-agnostic contract:
The macOS implementation is separate in crates/scap-targets/src/platform/macos.rs, where native Core Graphics window identifiers are used instead of Windows HWNDs. The macOS capture source is crates/recording/src/sources/screen_capture/macos.rs. The platform-specific discovery code must remain platform-appropriate.

However, the shared contract is the same across platforms: a listed window target must resolve to the native window, its ID must be passed unchanged through the CLI and recording layers, and --window should represent the window content rather than merely a rectangle on a display. Existing macOS reports such as Cap issue #1754 indicate that target discovery and window-content capture are separate concerns. I will keep the Windows discovery fix focused while adding or proposing cross-platform regression coverage at the shared target boundary where appropriate.

Intended resolution in a new PR

I intend to fork or branch the Cap repository, reproduce the failure on the Windows environment listed above, and submit a new PR that:

  • Corrects the Windows window-list enumeration path in crates/scap-targets/src/platform/win.rs so visible top-level application windows can be discovered by the CLI.
  • Preserves and verifies the existing validity filters, including visibility, child-window exclusion, tool-window exclusion, ignored executables, and exclusion of Cap-owned windows where those filters are intentional.
  • Verifies that a returned native HWND becomes the expected WindowId and survives serialization through apps/cli/src/targets.rs.
  • Adds a regression test or the strongest available platform test proving that a visible top-level Windows test window appears in cap targets windows --json with a usable ID.
  • Verifies the ID handoff into cap record start --window without claiming that target discovery alone resolves all window-cropping behavior.
  • Keeps macOS and other platform implementations unchanged unless shared tests expose a genuine contract problem; platform-specific native enumeration should not be replaced with a Windows-specific assumption.

Acceptance criteria

  • On Windows, with a visible eligible application window open, cap targets windows --json returns at least one target instead of [].
  • The returned target contains a numeric ID that corresponds to the native Windows window handle representation used by crates/scap-targets/src/platform/win.rs.
  • The ID can be supplied to cap record start --window <id> without requiring pywin32 in the consuming application.
  • Invalid, hidden, child, tool, ignored, and Cap-owned windows remain filtered according to the intended behavior of the existing implementation.
  • The existing screen fallback in run.py remains valid for consumers while the new PR is developed.
  • Window-content isolation and crop behavior are tested or explicitly tracked separately from the empty-target discovery bug.

I am opening this issue before implementing the new PR so the failure boundary, consumer workaround, Windows-specific evidence, cross-platform caveat, and intended acceptance criteria are explicit.

主要言語
Rust
スター
22.5k
フォーク
1.9k
平均マージ
6時間 33分
マージ済み PR(30日)
77

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

CapSoftware/Cap のほかの issue

CapSoftware/Cap の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。