using System; using System.Collections.Generic; using System.Globalization; using System.Threading.Tasks; using Windows.Graphics.Capture; namespace ytLive.Services; /// /// Turns a capture key ("monitor:<n>", "window:<hwnd>", "picker:<...>") /// into a live , and hosts the OS /// GraphicsCapturePicker used by "Change Capture…". Picker picks are transient: /// the picked GraphicsCaptureItem has no HWND/monitor identity, so a /// "picker:" key resolves only within the current session and re-detection /// takes over after a reload (documented v1 limit). /// public sealed class ScreenCaptureSourceFactory { private readonly Func _ownerHwndProvider; private readonly Dictionary _picked = new(); private readonly object _gate = new(); public ScreenCaptureSourceFactory(Func ownerHwndProvider) { _ownerHwndProvider = ownerHwndProvider; } /// Creates the source for a persisted key, or null when it can't be resolved. public IScreenCaptureSource? Resolve(string key) { if (key.StartsWith("monitor:", StringComparison.OrdinalIgnoreCase)) { var indexText = key.AsSpan("monitor:".Length); if (int.TryParse(indexText, NumberStyles.Integer, CultureInfo.InvariantCulture, out var index)) return ScreenCaptureFrameSource.CreateForMonitor(index); return null; } if (key.StartsWith("window:", StringComparison.OrdinalIgnoreCase)) { var hexText = key.AsSpan("window:".Length); if (long.TryParse(hexText, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var hwnd)) return ScreenCaptureFrameSource.CreateForWindow(new IntPtr(hwnd)); return null; } if (key.StartsWith("picker:", StringComparison.OrdinalIgnoreCase)) { lock (_gate) return _picked.TryGetValue(key, out var item) ? ScreenCaptureFrameSource.CreateForPicker(key, item) : null; } return null; } /// /// Shows the OS capture picker (must run on the UI thread, owner window set /// via IInitializeWithWindow). Returns the session key, or null if cancelled. /// public async Task PickAsync() { var picker = new GraphicsCapturePicker(); CaptureInterop.SetWindowOwner(picker, _ownerHwndProvider()); var item = await picker.PickSingleItemAsync(); if (item == null) return null; var key = $"picker:{item.DisplayName}"; lock (_gate) _picked[key] = item; return key; } }