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 <jamiewalch@chromium.org>
Commit-Queue: Austin Orion <auorion@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#33809}
This commit is contained in:
Austin Orion 2021-04-15 17:10:40 -07:00 committed by Commit Bot
parent 88f4b33196
commit 0fd0d5867b
6 changed files with 61 additions and 11 deletions

View File

@ -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" ]
}
}

View File

@ -11,6 +11,8 @@
#include "modules/desktop_capture/win/wgc_capture_source.h"
#include <windows.graphics.capture.interop.h>
#include <windows.h>
#include <utility>
#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<WGC::IGraphicsCaptureItem> item;
return SUCCEEDED(CreateCaptureItem(&item));
}
bool WgcCaptureSource::FocusOnSource() {
return false;
}
HRESULT WgcCaptureSource::GetCaptureItem(
ComPtr<WGC::IGraphicsCaptureItem>* 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<WGC::IGraphicsCaptureItem> 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<HWND>(GetSourceId())))
return false;
return ::BringWindowToTop(reinterpret_cast<HWND>(GetSourceId())) &&
::SetForegroundWindow(reinterpret_cast<HWND>(GetSourceId()));
}
HRESULT WgcWindowSource::CreateCaptureItem(
ComPtr<WGC::IGraphicsCaptureItem>* result) {
if (!ResolveCoreWinRTDelayload())

View File

@ -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(

View File

@ -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);

View File

@ -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;

View File

@ -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<HWND>(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<HWND>(source_id_));