From 0fd0d5867bfe0a70e9635a9b801f38eb3e3cac3a Mon Sep 17 00:00:00 2001 From: Austin Orion Date: Thu, 15 Apr 2021 17:10:40 -0700 Subject: [PATCH] Implement FocusOnSelectedSource for WgcCapturerWin. Previously, windows captured by WgcCapturerWin may have been occluded by other windows with no functionality to bring them to the top of the z order. This change implements FocusOnSelectedSource for WgcCapturerWin to afford consumers this functionality, and match the experience offered by current capturers. Bug: webrtc:12664 Change-Id: I8bc067ade90fba0be66a9be57d3429ba54ba1ae0 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/215241 Reviewed-by: Jamie Walch Commit-Queue: Austin Orion Cr-Commit-Position: refs/heads/master@{#33809} --- modules/desktop_capture/BUILD.gn | 5 +++- .../desktop_capture/win/wgc_capture_source.cc | 30 ++++++++++++++----- .../desktop_capture/win/wgc_capture_source.h | 2 ++ .../desktop_capture/win/wgc_capturer_win.cc | 7 +++++ .../desktop_capture/win/wgc_capturer_win.h | 1 + .../win/wgc_capturer_win_unittest.cc | 27 +++++++++++++++-- 6 files changed, 61 insertions(+), 11 deletions(-) diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn index 4281becd68..3108572348 100644 --- a/modules/desktop_capture/BUILD.gn +++ b/modules/desktop_capture/BUILD.gn @@ -147,7 +147,10 @@ if (rtc_include_tests) { if (rtc_enable_win_wgc) { sources += [ "win/wgc_capturer_win_unittest.cc" ] } - deps += [ ":desktop_capture_mock" ] + deps += [ + ":desktop_capture_mock", + "../../system_wrappers:metrics", + ] public_configs = [ ":x11_config" ] } } diff --git a/modules/desktop_capture/win/wgc_capture_source.cc b/modules/desktop_capture/win/wgc_capture_source.cc index f894a1ec3c..33a69fac50 100644 --- a/modules/desktop_capture/win/wgc_capture_source.cc +++ b/modules/desktop_capture/win/wgc_capture_source.cc @@ -11,6 +11,8 @@ #include "modules/desktop_capture/win/wgc_capture_source.h" #include +#include + #include #include "modules/desktop_capture/win/screen_capture_utils.h" @@ -26,6 +28,18 @@ WgcCaptureSource::WgcCaptureSource(DesktopCapturer::SourceId source_id) : source_id_(source_id) {} WgcCaptureSource::~WgcCaptureSource() = default; +bool WgcCaptureSource::IsCapturable() { + // If we can create a capture item, then we can capture it. Unfortunately, + // we can't cache this item because it may be created in a different COM + // apartment than where capture will eventually start from. + ComPtr item; + return SUCCEEDED(CreateCaptureItem(&item)); +} + +bool WgcCaptureSource::FocusOnSource() { + return false; +} + HRESULT WgcCaptureSource::GetCaptureItem( ComPtr* result) { HRESULT hr = S_OK; @@ -36,14 +50,6 @@ HRESULT WgcCaptureSource::GetCaptureItem( return hr; } -bool WgcCaptureSource::IsCapturable() { - // If we can create a capture item, then we can capture it. Unfortunately, - // we can't cache this item because it may be created in a different COM - // apartment than where capture will eventually start from. - ComPtr item; - return SUCCEEDED(CreateCaptureItem(&item)); -} - WgcCaptureSourceFactory::~WgcCaptureSourceFactory() = default; WgcWindowSourceFactory::WgcWindowSourceFactory() = default; @@ -73,6 +79,14 @@ bool WgcWindowSource::IsCapturable() { return WgcCaptureSource::IsCapturable(); } +bool WgcWindowSource::FocusOnSource() { + if (!IsWindowValidAndVisible(reinterpret_cast(GetSourceId()))) + return false; + + return ::BringWindowToTop(reinterpret_cast(GetSourceId())) && + ::SetForegroundWindow(reinterpret_cast(GetSourceId())); +} + HRESULT WgcWindowSource::CreateCaptureItem( ComPtr* result) { if (!ResolveCoreWinRTDelayload()) diff --git a/modules/desktop_capture/win/wgc_capture_source.h b/modules/desktop_capture/win/wgc_capture_source.h index a5599c620d..5dee102281 100644 --- a/modules/desktop_capture/win/wgc_capture_source.h +++ b/modules/desktop_capture/win/wgc_capture_source.h @@ -31,6 +31,7 @@ class WgcCaptureSource { virtual ~WgcCaptureSource(); virtual bool IsCapturable(); + virtual bool FocusOnSource(); HRESULT GetCaptureItem( Microsoft::WRL::ComPtr< ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>* result); @@ -93,6 +94,7 @@ class WgcWindowSource final : public WgcCaptureSource { ~WgcWindowSource() override; bool IsCapturable() override; + bool FocusOnSource() override; private: HRESULT CreateCaptureItem( diff --git a/modules/desktop_capture/win/wgc_capturer_win.cc b/modules/desktop_capture/win/wgc_capturer_win.cc index 0d4848e3e2..83a1e342a3 100644 --- a/modules/desktop_capture/win/wgc_capturer_win.cc +++ b/modules/desktop_capture/win/wgc_capturer_win.cc @@ -77,6 +77,13 @@ bool WgcCapturerWin::SelectSource(DesktopCapturer::SourceId id) { return capture_source_->IsCapturable(); } +bool WgcCapturerWin::FocusOnSelectedSource() { + if (!capture_source_) + return false; + + return capture_source_->FocusOnSource(); +} + void WgcCapturerWin::Start(Callback* callback) { RTC_DCHECK(!callback_); RTC_DCHECK(callback); diff --git a/modules/desktop_capture/win/wgc_capturer_win.h b/modules/desktop_capture/win/wgc_capturer_win.h index 1171d15fad..9d461d38a1 100644 --- a/modules/desktop_capture/win/wgc_capturer_win.h +++ b/modules/desktop_capture/win/wgc_capturer_win.h @@ -94,6 +94,7 @@ class WgcCapturerWin : public DesktopCapturer { // DesktopCapturer interface. bool GetSourceList(SourceList* sources) override; bool SelectSource(SourceId id) override; + bool FocusOnSelectedSource() override; void Start(Callback* callback) override; void CaptureFrame() override; diff --git a/modules/desktop_capture/win/wgc_capturer_win_unittest.cc b/modules/desktop_capture/win/wgc_capturer_win_unittest.cc index 1056c821c3..1700ede6d9 100644 --- a/modules/desktop_capture/win/wgc_capturer_win_unittest.cc +++ b/modules/desktop_capture/win/wgc_capturer_win_unittest.cc @@ -335,10 +335,17 @@ INSTANTIATE_TEST_SUITE_P(SourceAgnostic, CaptureType::kScreenCapture)); // Monitor specific tests. +TEST_F(WgcCapturerWinTest, FocusOnMonitor) { + SetUpForScreenCapture(); + EXPECT_TRUE(capturer_->SelectSource(0)); + + // You can't set focus on a monitor. + EXPECT_FALSE(capturer_->FocusOnSelectedSource()); +} + TEST_F(WgcCapturerWinTest, CaptureAllMonitors) { SetUpForScreenCapture(); - // 0 (or a NULL HMONITOR) leads to WGC capturing all displays. - EXPECT_TRUE(capturer_->SelectSource(0)); + EXPECT_TRUE(capturer_->SelectSource(kFullDesktopScreenId)); capturer_->Start(this); DoCapture(); @@ -347,6 +354,22 @@ TEST_F(WgcCapturerWinTest, CaptureAllMonitors) { } // Window specific tests. +TEST_F(WgcCapturerWinTest, FocusOnWindow) { + capturer_ = WgcCapturerWin::CreateRawWindowCapturer( + DesktopCaptureOptions::CreateDefault()); + window_info_ = CreateTestWindow(kWindowTitle); + source_id_ = GetScreenIdFromSourceList(); + + EXPECT_TRUE(capturer_->SelectSource(source_id_)); + EXPECT_TRUE(capturer_->FocusOnSelectedSource()); + + HWND hwnd = reinterpret_cast(source_id_); + EXPECT_EQ(hwnd, ::GetActiveWindow()); + EXPECT_EQ(hwnd, ::GetForegroundWindow()); + EXPECT_EQ(hwnd, ::GetFocus()); + DestroyTestWindow(window_info_); +} + TEST_F(WgcCapturerWinTest, SelectMinimizedWindow) { SetUpForWindowCapture(); MinimizeTestWindow(reinterpret_cast(source_id_));