Skip to content

Commit

Permalink
Allow capturing cursor in both DirectX and bitblt capture.
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbound committed Aug 18, 2024
1 parent 2424549 commit 447d286
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 27 deletions.
2 changes: 1 addition & 1 deletion ControlR.Streamer/Services/DisplayManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ private async Task EncodeScreenCaptures(CancellationToken stoppingToken)

_win32Interop.SwitchToInputDesktop();

using var captureResult = _screenCapturer.Capture(_selectedDisplay, captureCursor: false);
using var captureResult = _screenCapturer.Capture(_selectedDisplay);

if (captureResult.HadNoChanges)
{
Expand Down
8 changes: 3 additions & 5 deletions Libraries/ControlR.Libraries.ScreenCapture/Models/DxOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ public DxOutput(
public ID3D11Device Device { get; }
public ID3D11DeviceContext DeviceContext { get; }
public string DeviceName { get; }
public IDXGIOutputDuplication OutputDuplication { get; }
public DXGI_MODE_ROTATION Rotation { get; }

public bool IsDisposed => _isDisposed;

public Rectangle LastCursorArea { get; set; }
public DateTimeOffset LastSuccessfulCapture { get; set; }

public IDXGIOutputDuplication OutputDuplication { get; }
public DXGI_MODE_ROTATION Rotation { get; }
public void Dispose()
{
if (_isDisposed)
Expand Down
72 changes: 51 additions & 21 deletions Libraries/ControlR.Libraries.ScreenCapture/ScreenCapturer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public CaptureResult Capture(
return GetBitBltCapture(display.MonitorArea, captureCursor);
}

var result = GetDirectXCapture(display);
var result = GetDirectXCapture(display, captureCursor);

if (result.HadNoChanges)
{
Expand Down Expand Up @@ -163,22 +163,9 @@ internal CaptureResult GetBitBltCapture(Rectangle captureArea, bool captureCurso
return CaptureResult.Fail("BitBlt function failed.");
}


if (captureCursor)
{
// Get cursor information to draw on the screenshot.
var ci = new CURSORINFO();
ci.cbSize = (uint)Marshal.SizeOf(ci);
PInvoke.GetCursorInfo(ref ci);
if (ci.flags == CURSORINFO_FLAGS.CURSOR_SHOWING)
{
using var icon = Icon.FromHandle(ci.hCursor);
var virtualScreen = GetVirtualScreenBounds();
graphics.DrawIcon(
icon,
ci.ptScreenPos.X - virtualScreen.Left - captureArea.Left,
ci.ptScreenPos.Y - virtualScreen.Top - captureArea.Top);
}
_ = TryDrawCursor(graphics, captureArea);
}

return CaptureResult.Ok(bitmap, false);
Expand All @@ -194,7 +181,7 @@ internal CaptureResult GetBitBltCapture(Rectangle captureArea, bool captureCurso
}
}

internal CaptureResult GetDirectXCapture(DisplayInfo display)
internal CaptureResult GetDirectXCapture(DisplayInfo display, bool captureCursor)
{
var dxOutput = _dxOutputGenerator.GetDxOutput(display.DeviceName);

Expand Down Expand Up @@ -288,6 +275,28 @@ internal CaptureResult GetDirectXCapture(DisplayInfo display)
}

dxOutput.LastSuccessfulCapture = DateTimeOffset.Now;

if (captureCursor)
{
if (!dxOutput.LastCursorArea.IsEmpty)
{
dirtyRects = [..dirtyRects, dxOutput.LastCursorArea];
}

using var graphics = Graphics.FromImage(bitmap);

var iconArea = TryDrawCursor(graphics, display.MonitorArea);
if (!iconArea.IsEmpty)
{
dirtyRects = [..dirtyRects, iconArea];
dxOutput.LastCursorArea = iconArea;
}
else
{
dxOutput.LastCursorArea = Rectangle.Empty;
}
}

return CaptureResult.Ok(bitmap, true, dirtyRects);
}
catch (COMException ex) when (ex.Message.StartsWith("The timeout value has elapsed"))
Expand Down Expand Up @@ -320,11 +329,6 @@ internal CaptureResult GetDirectXCapture(DisplayInfo display)
}
}

private bool IsDxOutputHealthy(DxOutput dxOutput)
{
return _systemTime.Now - dxOutput.LastSuccessfulCapture < TimeSpan.FromSeconds(1.5);
}

private unsafe Rectangle[] GetDirtyRects(IDXGIOutputDuplication outputDuplication)
{
var rectSize = (uint)sizeof(RECT);
Expand Down Expand Up @@ -354,4 +358,30 @@ private unsafe Rectangle[] GetDirtyRects(IDXGIOutputDuplication outputDuplicatio

return dirtyRects;
}

private bool IsDxOutputHealthy(DxOutput dxOutput)
{
return _systemTime.Now - dxOutput.LastSuccessfulCapture < TimeSpan.FromSeconds(1.5);
}

private Rectangle TryDrawCursor(Graphics graphics, Rectangle captureArea)
{
// Get cursor information to draw on the screenshot.
var ci = new CURSORINFO();
ci.cbSize = (uint)Marshal.SizeOf(ci);
PInvoke.GetCursorInfo(ref ci);

if (!ci.flags.HasFlag(CURSORINFO_FLAGS.CURSOR_SHOWING))
{
return Rectangle.Empty;
}

using var icon = Icon.FromHandle(ci.hCursor);
var virtualScreen = GetVirtualScreenBounds();
var x = ci.ptScreenPos.X - virtualScreen.Left - captureArea.Left;
var y = ci.ptScreenPos.Y - virtualScreen.Top - captureArea.Top;
graphics.DrawIcon(icon, x, y);

return new Rectangle(x, y, icon.Width, icon.Height);
}
}

0 comments on commit 447d286

Please sign in to comment.