Files
linker/cmonitor/server/client/reports/screen/ScreenReport.cs
2023-10-25 16:43:22 +08:00

242 lines
7.8 KiB
C#

using cmonitor.server.service;
using common.libs;
using cmonitor.server.service.messengers.screen;
using MemoryPack;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace cmonitor.server.client.reports.screen
{
public sealed class ScreenReport : IReport
{
public string Name => "Screen";
private readonly ClientSignInState clientSignInState;
private readonly MessengerSender messengerSender;
private readonly Config config;
private ScreenReportInfo report = new ScreenReportInfo();
private uint lastInput;
private readonly DxgiDesktop dxgiDesktop;
private readonly GdiDesktop gdiDesktop;
public ScreenReport(ClientSignInState clientSignInState, MessengerSender messengerSender, Config config)
{
this.clientSignInState = clientSignInState;
this.messengerSender = messengerSender;
this.config = config;
if (config.IsCLient)
{
ScreenCaptureTask();
WinApi.InitLastInputInfo();
dxgiDesktop = new DxgiDesktop(0);
gdiDesktop = new GdiDesktop();
InitSise();
}
}
private void InitSise()
{
if (gdiDesktop.GetSystemScale(out _, out _, out int w, out int h))
{
report.W = w;
report.H = h;
}
}
public object GetReports(ReportType reportType)
{
report.LT = WinApi.GetLastInputInfo();
if (reportType == ReportType.Full || report.LT < lastInput || report.LT - lastInput > 1000)
{
lastInput = report.LT;
return report;
}
return null;
}
private ScreenReportType screenReportType = ScreenReportType.Full;
private ScreenReportFullType screenReportFullType = ScreenReportFullType.Full | ScreenReportFullType.Trim;
private long ticks = 0;
public void Full(ScreenReportFullType screenReportFullType)
{
ticks = DateTime.UtcNow.Ticks;
screenReportType = ScreenReportType.Full;
this.screenReportFullType |= screenReportFullType;
}
public void Clip(ScreenClipInfo screenClipInfo)
{
ticks = DateTime.UtcNow.Ticks;
screenReportType = ScreenReportType.Full;
gdiDesktop.Clip(screenClipInfo);
}
public void Region()
{
ticks = DateTime.UtcNow.Ticks;
screenReportType = ScreenReportType.Region;
}
private void ScreenCaptureTask()
{
if (OperatingSystem.IsWindows() == false)
{
return;
}
Task.Factory.StartNew(async () =>
{
while (true)
{
int delayms = 0;
if (clientSignInState.Connected == true && ((DateTime.UtcNow.Ticks - ticks) / TimeSpan.TicksPerMillisecond < 1000))
{
try
{
long start = DateTime.UtcNow.Ticks;
await ScreenCapture();
delayms = (int)((DateTime.UtcNow.Ticks - start) / TimeSpan.TicksPerMillisecond);
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Error(ex);
}
}
if (delayms < config.ScreenDelay)
{
Thread.Sleep(config.ScreenDelay - delayms);
}
else
{
Thread.Sleep(config.ScreenDelay);
}
}
}, TaskCreationOptions.LongRunning);
}
private Memory<byte> fullImageMemory = Helper.EmptyArray;
private async Task ScreenCapture()
{
DesktopFrame frame = GetFrame();
await SendFrame(frame);
}
private DesktopFrame GetFrame()
{
DesktopFrame frame = null;
long ticks = DateTime.UtcNow.Ticks;
if (gdiDesktop.IsClip())
{
frame = gdiDesktop.GetLatestFrame(config.ScreenScale);
}
else if (screenReportType == ScreenReportType.Full)
{
frame = dxgiDesktop.GetLatestFullFrame(config.ScreenScale);
if (frame.FullImage.Length > 0)
{
fullImageMemory = frame.FullImage;
}
else if ((screenReportFullType & ScreenReportFullType.Full) == ScreenReportFullType.Full)
{
if (fullImageMemory.Length > 0)
{
frame.FullImage = fullImageMemory;
}
RandomCursorPos();
}
screenReportFullType &= ~ScreenReportFullType.Full;
}
else if (screenReportType == ScreenReportType.Region)
{
frame = dxgiDesktop.GetLatestRegionFrame(config.ScreenScale);
}
report.CT = (uint)((DateTime.UtcNow.Ticks - ticks) / TimeSpan.TicksPerMillisecond);
return frame;
}
private async Task SendFrame(DesktopFrame frame)
{
if (frame == null)
{
return;
}
if (frame.FullImage.Length > 0)
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)ScreenMessengerIds.FullReport,
Payload = frame.FullImage,
});
}
else if (frame.RegionImage.Length > 0)
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)ScreenMessengerIds.RegionReport,
Payload = frame.RegionImage,
});
}
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)ScreenMessengerIds.Rectangles,
Payload = MemoryPackSerializer.Serialize(frame.UpdatedRegions),
});
}
private void RandomCursorPos()
{
try
{
if (WinApi.GetCursorPosition(out int x, out int y))
{
x = x <= 0 ? x + 1 : x - 1;
y = y <= 0 ? y + 1 : y - 1;
SetCursorPos(x, y);
}
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Logger.Instance.Error(ex);
}
}
}
[DllImport("user32.dll")]
private static extern bool SetCursorPos(int X, int Y);
}
public sealed class ScreenReportInfo
{
public uint CT { get; set; }
public uint LT { get; set; }
public int W { get; set; }
public int H { get; set; }
}
public enum ScreenReportType : byte
{
Full = 1,
Region = 2
};
public enum ScreenReportFullType : byte
{
Full = 1,
Trim = 2
};
[MemoryPackable]
public sealed partial class ScreenClipInfo
{
public int X { get; set; }
public int Y { get; set; }
public int W { get; set; }
public int H { get; set; }
}
}