libobs-winrt: win-capture: HDC cursor capture for WGC
Starting with Windows 10 2004, we can disable WGC cursor capture, and provide a user toggle. We swap out WGC support for our own though because ours does not break hardware cursor support.master
parent
87f5bd6e9f
commit
cb4954c279
|
@ -12,12 +12,24 @@ struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
|
|||
void **object) = 0;
|
||||
};
|
||||
|
||||
extern "C" EXPORT bool winrt_capture_supported()
|
||||
extern "C" EXPORT BOOL winrt_capture_supported()
|
||||
{
|
||||
/* no contract for IGraphicsCaptureItemInterop, verify 10.0.18362.0 */
|
||||
return winrt::Windows::Foundation::Metadata::ApiInformation::IsTypePresent(
|
||||
L"Windows.Graphics.Capture.GraphicsCaptureSession") &&
|
||||
winrt::Windows::Graphics::Capture::GraphicsCaptureSession::
|
||||
IsSupported();
|
||||
}
|
||||
|
||||
extern "C" EXPORT BOOL winrt_capture_cursor_toggle_supported()
|
||||
{
|
||||
#ifdef NTDDI_WIN10_VB
|
||||
return winrt::Windows::Foundation::Metadata::ApiInformation::
|
||||
IsApiContractPresent(L"Windows.Foundation.UniversalApiContract",
|
||||
8);
|
||||
IsPropertyPresent(
|
||||
L"Windows.Graphics.Capture.GraphicsCaptureSession",
|
||||
L"IsCursorCaptureEnabled");
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -78,10 +90,12 @@ static bool get_client_box(HWND window, uint32_t width, uint32_t height,
|
|||
}
|
||||
|
||||
struct winrt_capture {
|
||||
bool capture_cursor;
|
||||
HWND window;
|
||||
bool client_area;
|
||||
|
||||
bool capture_cursor;
|
||||
bool cursor_visible;
|
||||
|
||||
gs_texture_t *texture;
|
||||
bool texture_written;
|
||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item{nullptr};
|
||||
|
@ -104,6 +118,58 @@ struct winrt_capture {
|
|||
bool thread_changed;
|
||||
struct winrt_capture *next;
|
||||
|
||||
void draw_cursor()
|
||||
{
|
||||
CURSORINFO ci{};
|
||||
ci.cbSize = sizeof(CURSORINFO);
|
||||
if (!GetCursorInfo(&ci))
|
||||
return;
|
||||
|
||||
if (!ci.flags & CURSOR_SHOWING)
|
||||
return;
|
||||
|
||||
HICON icon = CopyIcon(ci.hCursor);
|
||||
if (!icon)
|
||||
return;
|
||||
|
||||
ICONINFO ii;
|
||||
if (GetIconInfo(icon, &ii)) {
|
||||
POINT win_pos{};
|
||||
if (window) {
|
||||
if (client_area) {
|
||||
ClientToScreen(window, &win_pos);
|
||||
} else {
|
||||
RECT window_rect;
|
||||
if (DwmGetWindowAttribute(
|
||||
window,
|
||||
DWMWA_EXTENDED_FRAME_BOUNDS,
|
||||
&window_rect,
|
||||
sizeof(window_rect)) ==
|
||||
S_OK) {
|
||||
win_pos.x = window_rect.left;
|
||||
win_pos.y = window_rect.top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
POINT pos;
|
||||
pos.x = ci.ptScreenPos.x - (int)ii.xHotspot - win_pos.x;
|
||||
pos.y = ci.ptScreenPos.y - (int)ii.yHotspot - win_pos.y;
|
||||
|
||||
HDC hdc = (HDC)gs_texture_get_dc(texture);
|
||||
|
||||
DrawIconEx(hdc, pos.x, pos.y, icon, 0, 0, 0, NULL,
|
||||
DI_NORMAL);
|
||||
|
||||
gs_texture_release_dc(texture);
|
||||
|
||||
DeleteObject(ii.hbmColor);
|
||||
DeleteObject(ii.hbmMask);
|
||||
}
|
||||
|
||||
DestroyIcon(icon);
|
||||
}
|
||||
|
||||
void on_frame_arrived(winrt::Windows::Graphics::Capture::
|
||||
Direct3D11CaptureFramePool const &sender,
|
||||
winrt::Windows::Foundation::IInspectable const &)
|
||||
|
@ -146,9 +212,8 @@ struct winrt_capture {
|
|||
}
|
||||
|
||||
if (!texture) {
|
||||
texture = gs_texture_create(texture_width,
|
||||
texture_height, GS_BGRA, 1,
|
||||
nullptr, 0);
|
||||
texture = gs_texture_create_gdi(texture_width,
|
||||
texture_height);
|
||||
}
|
||||
|
||||
if (client_box_available) {
|
||||
|
@ -163,6 +228,10 @@ struct winrt_capture {
|
|||
frame_surface.get());
|
||||
}
|
||||
|
||||
if (capture_cursor && cursor_visible) {
|
||||
draw_cursor();
|
||||
}
|
||||
|
||||
texture_written = true;
|
||||
|
||||
if (frame_content_size.Width != last_size.Width ||
|
||||
|
@ -222,6 +291,12 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data)
|
|||
const winrt::Windows::Graphics::Capture::GraphicsCaptureSession session =
|
||||
frame_pool.CreateCaptureSession(capture->item);
|
||||
|
||||
/* disable cursor capture if possible since ours performs better */
|
||||
#ifdef NTDDI_WIN10_VB
|
||||
if (winrt_capture_cursor_toggle_supported())
|
||||
session.IsCursorCaptureEnabled(false);
|
||||
#endif
|
||||
|
||||
capture->device = device;
|
||||
d3d_device->GetImmediateContext(&capture->context);
|
||||
capture->frame_pool = frame_pool;
|
||||
|
@ -236,7 +311,7 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data)
|
|||
thread_local bool initialized_tls;
|
||||
|
||||
extern "C" EXPORT struct winrt_capture *
|
||||
winrt_capture_init(bool cursor, HWND window, bool client_area)
|
||||
winrt_capture_init(BOOL cursor, HWND window, BOOL client_area)
|
||||
{
|
||||
ID3D11Device *const d3d_device = (ID3D11Device *)gs_get_device_obj();
|
||||
ComPtr<IDXGIDevice> dxgi_device;
|
||||
|
@ -287,13 +362,21 @@ winrt_capture_init(bool cursor, HWND window, bool client_area)
|
|||
const winrt::Windows::Graphics::Capture::GraphicsCaptureSession session =
|
||||
frame_pool.CreateCaptureSession(item);
|
||||
|
||||
/* disable cursor capture if possible since ours performs better */
|
||||
const BOOL cursor_toggle_supported =
|
||||
winrt_capture_cursor_toggle_supported();
|
||||
#ifdef NTDDI_WIN10_VB
|
||||
if (cursor_toggle_supported)
|
||||
session.IsCursorCaptureEnabled(false);
|
||||
#endif
|
||||
|
||||
if (capture_list == nullptr)
|
||||
initialized_tls = true;
|
||||
|
||||
struct winrt_capture *capture = new winrt_capture{};
|
||||
capture->capture_cursor = cursor;
|
||||
capture->window = window;
|
||||
capture->client_area = client_area;
|
||||
capture->capture_cursor = cursor && cursor_toggle_supported;
|
||||
capture->item = item;
|
||||
capture->device = device;
|
||||
d3d_device->GetImmediateContext(&capture->context);
|
||||
|
@ -366,6 +449,12 @@ static void draw_texture(struct winrt_capture *capture, gs_effect_t *effect)
|
|||
gs_technique_end(tech);
|
||||
}
|
||||
|
||||
extern "C" EXPORT void winrt_capture_show_cursor(struct winrt_capture *capture,
|
||||
BOOL visible)
|
||||
{
|
||||
capture->cursor_visible = visible;
|
||||
}
|
||||
|
||||
extern "C" EXPORT void winrt_capture_render(struct winrt_capture *capture,
|
||||
gs_effect_t *effect)
|
||||
{
|
||||
|
|
|
@ -9,11 +9,14 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
EXPORT bool winrt_capture_supported();
|
||||
EXPORT struct winrt_capture *winrt_capture_init(bool cursor, HWND window,
|
||||
bool client_area);
|
||||
EXPORT BOOL winrt_capture_supported();
|
||||
EXPORT BOOL winrt_capture_cursor_toggle_supported();
|
||||
EXPORT struct winrt_capture *winrt_capture_init(BOOL cursor, HWND window,
|
||||
BOOL client_area);
|
||||
EXPORT void winrt_capture_free(struct winrt_capture *capture);
|
||||
|
||||
EXPORT void winrt_capture_show_cursor(struct winrt_capture *capture,
|
||||
BOOL visible);
|
||||
EXPORT void winrt_capture_render(struct winrt_capture *capture,
|
||||
gs_effect_t *effect);
|
||||
EXPORT uint32_t winrt_capture_width(const struct winrt_capture *capture);
|
||||
|
|
|
@ -26,10 +26,13 @@
|
|||
#define WC_CHECK_TIMER 1.0f
|
||||
|
||||
struct winrt_exports {
|
||||
bool *(*winrt_capture_supported)();
|
||||
struct winrt_capture *(*winrt_capture_init)(bool cursor, HWND window,
|
||||
bool client_area);
|
||||
BOOL *(*winrt_capture_supported)();
|
||||
BOOL *(*winrt_capture_cursor_toggle_supported)();
|
||||
struct winrt_capture *(*winrt_capture_init)(BOOL cursor, HWND window,
|
||||
BOOL client_area);
|
||||
void (*winrt_capture_free)(struct winrt_capture *capture);
|
||||
void (*winrt_capture_show_cursor)(struct winrt_capture *capture,
|
||||
BOOL visible);
|
||||
void (*winrt_capture_render)(struct winrt_capture *capture,
|
||||
gs_effect_t *effect);
|
||||
uint32_t (*winrt_capture_width)(const struct winrt_capture *capture);
|
||||
|
@ -171,8 +174,10 @@ static bool load_winrt_imports(struct winrt_exports *exports, void *module,
|
|||
bool success = true;
|
||||
|
||||
WINRT_IMPORT(winrt_capture_supported);
|
||||
WINRT_IMPORT(winrt_capture_cursor_toggle_supported);
|
||||
WINRT_IMPORT(winrt_capture_init);
|
||||
WINRT_IMPORT(winrt_capture_free);
|
||||
WINRT_IMPORT(winrt_capture_show_cursor);
|
||||
WINRT_IMPORT(winrt_capture_render);
|
||||
WINRT_IMPORT(winrt_capture_width);
|
||||
WINRT_IMPORT(winrt_capture_height);
|
||||
|
@ -260,13 +265,18 @@ static void wc_defaults(obs_data_t *defaults)
|
|||
}
|
||||
|
||||
static void update_settings_visibility(obs_properties_t *props,
|
||||
enum window_capture_method method)
|
||||
struct window_capture *wc)
|
||||
{
|
||||
const enum window_capture_method method = wc->method;
|
||||
const bool bitblt_options = method == METHOD_BITBLT;
|
||||
const bool wgc_options = method == METHOD_WGC;
|
||||
|
||||
const bool wgc_cursor_toggle =
|
||||
wgc_options &&
|
||||
wc->exports.winrt_capture_cursor_toggle_supported();
|
||||
|
||||
obs_property_t *p = obs_properties_get(props, "cursor");
|
||||
obs_property_set_visible(p, bitblt_options);
|
||||
obs_property_set_visible(p, bitblt_options || wgc_cursor_toggle);
|
||||
|
||||
p = obs_properties_get(props, "compatibility");
|
||||
obs_property_set_visible(p, bitblt_options);
|
||||
|
@ -281,7 +291,7 @@ static bool wc_capture_method_changed(obs_properties_t *props,
|
|||
struct window_capture *wc = obs_properties_get_param(props);
|
||||
update_settings(wc, settings);
|
||||
|
||||
update_settings_visibility(props, wc->method);
|
||||
update_settings_visibility(props, wc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -297,7 +307,7 @@ static bool wc_window_changed(obs_properties_t *props, obs_property_t *p,
|
|||
struct window_capture *wc = obs_properties_get_param(props);
|
||||
update_settings(wc, settings);
|
||||
|
||||
update_settings_visibility(props, wc->method);
|
||||
update_settings_visibility(props, wc);
|
||||
|
||||
check_window_property_setting(props, p, settings, "window", 0);
|
||||
return true;
|
||||
|
@ -417,8 +427,12 @@ static void wc_tick(void *data, float seconds)
|
|||
if (!GetWindowThreadProcessId(wc->window, &target_pid))
|
||||
target_pid = 0;
|
||||
|
||||
wc->capture.cursor_hidden = foreground_pid && target_pid &&
|
||||
foreground_pid != target_pid;
|
||||
const bool cursor_hidden = foreground_pid && target_pid &&
|
||||
foreground_pid != target_pid;
|
||||
wc->capture.cursor_hidden = cursor_hidden;
|
||||
if (wc->capture_winrt)
|
||||
wc->exports.winrt_capture_show_cursor(wc->capture_winrt,
|
||||
!cursor_hidden);
|
||||
|
||||
wc->cursor_check_time = 0.0f;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue