macOS 15 では、ズームでウィンドウを隠すことはできません
現代のmacOSでは、ウィンドウをスクリーンキャプチャから隠すことは信頼性を持たないため、他のアプリからも、自分のアプリからもできません。これは、CGSSetWindowCaptureExcludedが削除されたこと、SLSSetWindowSharingStateがクロスプロセスで静黙的に無視されたこと、およびNSWindow.sharingType = .noneがZoomやQuickTimeに対してソフトな提案であるということについてのエンジニアリングの物語です。
短いエンジニアリングのポストマーティム:「プライベートウィンドウ」アプリを構築したが、うまくいかない話。
アイデア
多くの人が、会議中にClaudeのデスクトップウィンドウを開いている。多くの人が、Zoomでスクリーンを共有するとき、そのウィンドウが全員に見えることに対しては望ましくない。それは何らかの機密情報ではない。ただ、それはプライベートな作業状態だから。
1PasswordやHand Mirrorのようなアプリが、自らのウィンドウをスクリーン記録から隠すことができるのを知っていた。私は、小さなメニューバーのユーティリティを構築して、任意のアプリ(Claude、Notesなど)を選択し、そのウィンドウを記録から非表示にできるようにすることができるだろうと考えた。 任意の アプリ — Claude、Notes、何でも — およびそのウィンドウを記録から非表示に切り替える。
週末プロジェクト。2時間以内。
それ以上かかりました。そして結論は次の通りです。 現代のmacOSでは、これはできません。他のアプリに対して、そして、実際には、自分のアプリに対しても信頼性がありません。
これがなぜであるかのエンジニアリングの物語です。
試行1:別のアプリのウィンドウを隠す
macOSのウィンドウをスクリーン記録から非表示にするための古典的な方法は NSWindow.sharingType = .noneです。しかし、これはウィンドウごとのフラグであり、そのウィンドウを所有する プロセスのみが自らのウィンドウに設定できる。AppKitは、別のアプリのウィンドウリストにアクセスできない。 owning
よく知られたワークアラウンドは、Hand Mirrorやさまざまなスクリーンブランクツールが長年使用してきたプライベートSkyLight関数です。
OSStatus CGSSetWindowCaptureExcluded(CGSConnectionID cid, CGWindowID wid, bool excluded);
ウィンドウを CGWindowListCopyWindowInfoで列挙し、ターゲットアプリのPIDにフィルタをかけ、各ウィンドウIDに対してこの関数を呼び出します。この呼び出しはWindowServer(所有プロセスではなく)を通るので、どのウィンドウも記録から除外されます。
私はこれを dlsym お /System/Library/PrivateFrameworks/SkyLight.framework/...で構築し、macOS 15.3.1で実行して、次の結果を得ました。
[InvisibleApp] symbol not found: CGSSetWindowCaptureExcluded
[InvisibleApp] symbol not found: SLSSetWindowCaptureExcluded
この関数は 消えました。Appleがそれを削除しました。私は、リネームされたバージョン(SLSSetWindowExcludedFromCapture, CGSSetWindowSharingState、すべての明らかなバリエーション)を探しました。ほとんどが存在しませんが、2つは見つけました。
SLSSetWindowSharingState(CGSConnectionID, CGWindowID, int sharingState)— 内部で使用される基本的な呼び出し。状態をNSWindow.sharingType = .none共有0はNSWindowSharingNone.SLSGetWindowOwner— ウィンドウの所有プロセスの接続IDを提供します。
したがって、私は橋を再構築し、ターゲットウィンドウに対して SLSSetWindowSharingState を呼び出しました。私のメイン接続とウィンドウの所有接続の両方を試しました。
ビルド、実行、トグルをオン、ログは返答を noErrと表示しました。スクリーンショットを取ったが、Claudeはまだスクリーンショットに含まれている。Zoomを試したが、Claudeはまだ共有中に含まれている。
SLSSetWindowSharingState クロスプロセスで呼び出された場合に成功するが、WindowServerはそれを静かに無視する。 macOS 15では、所有プロセスのみが自らのウィンドウの共有状態を変更できる。
また、明らかに開けているエスケープハッチも閉じられていることを確認しました: DYLD_INSERT_LIBRARIES Claudeのプロセスへのインジェクションはブロッキングされている。Claude(および多くの現代アプリ)はハードウェアランタイムを有効にし、 disable-library-validation entitlementを持たないため。
したがって、これで解決しました: macOS 15では、第三者アプリが別のアプリのウィンドウを記録から非表示にすることはできません。 結論はAppleが望むものと一致しています:ウィンドウレベルの記録状態は、所有アプリの権利であり、終わりです。
試行2:自分のウィンドウを隠す
プランB:製品を変更します。Claudeを隠すツールではなく、私の自らの小さなチャットウィンドウを構築します。同じ仕事、違う形。私のウィンドウ、私の sharingType = .none。これは、すべての記録隠しツールが使用するよく知られたメカニズムであり、1行のコードで実現できます。
window.sharingType = .none
Anthropic Messages API(またはローカル claude CLIによるサブスクリプション認証)にストリーミングチャットを接続し、チャットウィンドウに sharingType = .none を設定し、それを配布します。これは明確で、サポートされ、公開されているAPIです。
それを構築しました。実行時の実際の共有タイプ値をログに記録し、macOSがそれを受け入れたことを確認しました:
[InvisibleApp] window 151526 sharingType=0
スクリーンショットを取ったが、チャットウィンドウが正しく非表示でした。✅
QuickTimeによるスクリーン録画を実行したが、チャットウィンドウが録画中に表示された。❌
Zoomでスクリーンを共有したが、チャットウィンドウが相手側に表示された。❌
これは予期外でした。全体の ポイント の NSWindowSharingNone は、それらのフローからそれを除外することです。したがって、私はアプリ内にスクリーンキャプチャを実行するための自己テストを構築しました。ScreenCaptureKit(現代の公開キャプチャAPI)を使用し、QuickTimeが内部で使用するフレームワークを用いました。単一ショットキャプチャ(SCScreenshotManager.captureImage)と連続キャプチャ(SCStream)の両方を試しました — どちらも、チャットウィンドウが正しく除外されたPNGを生成しました。
したがって:
| キャプチャ方法 | 自ウィンドウを隠すか? |
|---|---|
| Cmd-Shift-3/4/5(システムスクリーンショット) | ✅ |
| アプリのSCK単一ショットキャプチャ | ✅ |
| アプリのSCK連続SCStream | ✅ |
| QuickTime「新しいスクリーン録画」 | ❌ |
| Zoom「スクリーン共有 → デスクトップ」 | ❌ |
同じOS、同じマシン、同じウィンドウ、同じ sharingType = .none。変化するのは、誰がキャプチャしているかだけです。
特別権限キャプチャパス
エンジニアがほとんど気づかない部分は次の通りです: macOS 15では、スクリーンキャプチャは1つのAPIではなく、少なくとも2つあります — 公開APIと、追加の権限を持つプライベートAPIです。
QuickTime Playerの権限をダンプしました:
codesign -d --entitlements - /System/Applications/QuickTime\ Player.app
com.apple.private.screencapturekit.noprompt = true
com.apple.private.tcc.allow = [
kTCCServiceMicrophone,
kTCCServiceCamera,
kTCCServiceScreenCapture,
]
これらの com.apple.private.* キーは、Appleが自社の第一パーティーバイナリにのみ提供できる。あなたや私はそれらを要求できません。認証が拒否され、App Storeも拒否します。
そして、それらが提供するのは、キャプチャ許可プロンプトをスキップするだけでなく、WindowServerが共有タイプフィルタを適用する前にディスプレイ画像をキャプチャできるという能力です。 before the WindowServer applies sharing-type filtering。ウィンドウはフレームバッファに含まれており、Appleのツールはすべてを確認します。
Zoomは類似の特別権限パスを使用しています。それはキーノード拡張、システム拡張、または長年許可された会議アプリから取得されたプライベートAPIである可能性があります — 私は深く掘り下げていないため、どれかを特定できません。しかし、行動は同じです:標準的な公開除外メカニズムは適用されません。
これは意味します。
あなたが第三者開発者であり、目標が「このウィンドウは、どのMacでもスクリーン記録に現れないべきだ」という場合、 macOS 15では、それは保証できません。 あなたのウィンドウは、あなたが自ら書いたすべてのキャプチャパスから隠されています。Google Meet(ブラウザ → getDisplayMedia → SCK)、Microsoft Teams(SCK)、OBS(SCK)、すべてのコンフォーマントな第三者キャプチャツールから隠されています。しかし、AppleのQuickTimeやAppleが許可した会議アプリはまだそれを見られます。
1Password / Hand Mirrorの「スクリーン記録保護」機能も同じ制限があります。人々はQuickTimeで1Passwordのフォールドをスクリーン記録するのをあまりしないので、漏れは気づかれません。
Appleに対して誠実に述べたい結論は次の通りです: 公開権限を com.apple.private.screencapturekit.nopromptに等しく発表する、または NSWindow.sharingType = .none が、すべてのキャプチャパスに対してハードな保証であることを明確にすること。 すべて キャプチャパスに対して。 macOS 15.3.1では、それはどちらでもなく、ほとんどのパスに対してハードな保証であり、特別なツールがバイパスできるというソフトな提案です。現状は、ユーザーがキャプチャ中にウィンドウが非表示であると信じているが、実際にはそうではないというセキュリティポジションを作り出しており、何も保護がないよりも悪化しています。 対処法(悪影響の順) 私の使用ケース — Zoomの共有中にチャットウィンドウを隠すために — これらはすべて機能し、すべてが素晴らしいわけではありません:
Zoomで単一ウィンドウを共有する。
共有スクリーンダイアログには「ウィンドウ」タブがあります。Zoomはそのウィンドウのピクセルだけをキャプチャし、それ以外は一切取り出さないため、私のチャットとスクリーン上のすべての内容が自動的に非表示になります。これは最も信頼できる解決策であり、コードを必要としません。ただし、視聴者はスクリーン全体のコンテキストを見ることができません。
- MeetまたはTeamsに代わりにZoomを使う。 どちらも
- を尊重しています。あなたが会議ツールをコントロールしている場合は素晴らしいが、そうでない場合は非常に悪い。 別のスペースにチャットを置く。
sharingType = .noneMission Controlは複数のデスクトップを提供します。スペース1を共有し、チャットをスペース2に保ちます。スワイプで相互作用します。遅いが、流れを破るため、しかし機能します。 - 2つのデバイスを使う。 ラップトップの横に並んだ携帯電話またはiPadは、理論的にどのキャプチャツールも無効にできます。
- 私はオプション1とすでに構築したチャットアプリを組み合わせました。チャットは約95%のキャプチャパスから非表示であり、Zoomのデスクトップ共有の場合には、Zoomのデスクトップ共有を使わないようにしています。 次に望むこと
公開権限
が、認証されたアプリが「私のウィンドウはすべてのキャプチャから除外されるべきだ」と宣言できるようにする。
- 今日、それは不可能です。 誠実な すべて ドキュメント。
- ドキュメントは、ハードな保証のように見えますが、実際にはそうではありません。少なくともドキュメントに、特別なAppleツールやプライベート権限を持つアプリがキャプチャできるという点を明記すべきです。今日、それはありません。
NSWindow.sharingTypeシステムにインストールされているアプリが特別なキャプチャアクセスを持っているかどうかを確認できる方法 — Privacy & Securityの「ファイルとフォルダ」に類似するもの。今日、ユーザーが誰がプライバシーをバイパスしているかを確認するための表面はありません。 - それらのいずれかが実装されるまで、実用的なアドバイスは次の通りです:あなたのスクリーン上のすべてのウィンドウが、OSおよび主要な会議アプリによってキャプチャ可能であると仮定してください。排除APIは現実に存在し、多くの世界で機能しますが、最も重要な世界に対して信頼できるセキュリティ境界ではありません。 You Cannot Hide a Window From Zoom on macOS 15 2
You Cannot Hide a Window From Zoom on macOS 15 1 sharingType あなたが設定したものです。除外APIは現実のもので、世界の大部分に対して機能していますが、最も重要な地域に対して信頼できるセキュリティ境界とは言えません。
恵 スコアボードが到着しました!
スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!
