206 lines
7.5 KiB
C#
206 lines
7.5 KiB
C#
using Quasar.Client.Helper;
|
|
using Quasar.Common.Enums;
|
|
using Quasar.Common.Messages;
|
|
using Quasar.Common.Networking;
|
|
using Quasar.Common.Video;
|
|
using Quasar.Common.Video.Codecs;
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.IO;
|
|
using System.Windows.Forms;
|
|
|
|
namespace Quasar.Client.Messages
|
|
{
|
|
public class RemoteDesktopHandler : NotificationMessageProcessor, IDisposable
|
|
{
|
|
private UnsafeStreamCodec _streamCodec;
|
|
|
|
public override bool CanExecute(IMessage message) => message is GetDesktop ||
|
|
message is DoMouseEvent ||
|
|
message is DoKeyboardEvent ||
|
|
message is GetMonitors;
|
|
|
|
public override bool CanExecuteFrom(ISender sender) => true;
|
|
|
|
public override void Execute(ISender sender, IMessage message)
|
|
{
|
|
switch (message)
|
|
{
|
|
case GetDesktop msg:
|
|
Execute(sender, msg);
|
|
break;
|
|
case DoMouseEvent msg:
|
|
Execute(sender, msg);
|
|
break;
|
|
case DoKeyboardEvent msg:
|
|
Execute(sender, msg);
|
|
break;
|
|
case GetMonitors msg:
|
|
Execute(sender, msg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void Execute(ISender client, GetDesktop message)
|
|
{
|
|
// TODO: Switch to streaming mode without request-response once switched from windows forms
|
|
// TODO: Capture mouse in frames: https://stackoverflow.com/questions/6750056/how-to-capture-the-screen-and-mouse-pointer-using-windows-apis
|
|
var monitorBounds = ScreenHelper.GetBounds((message.DisplayIndex));
|
|
var resolution = new Resolution { Height = monitorBounds.Height, Width = monitorBounds.Width };
|
|
|
|
if (_streamCodec == null)
|
|
_streamCodec = new UnsafeStreamCodec(message.Quality, message.DisplayIndex, resolution);
|
|
|
|
if (message.CreateNew)
|
|
{
|
|
_streamCodec?.Dispose();
|
|
_streamCodec = new UnsafeStreamCodec(message.Quality, message.DisplayIndex, resolution);
|
|
OnReport("Remote desktop session started");
|
|
}
|
|
|
|
if (_streamCodec.ImageQuality != message.Quality || _streamCodec.Monitor != message.DisplayIndex || _streamCodec.Resolution != resolution)
|
|
{
|
|
_streamCodec?.Dispose();
|
|
|
|
_streamCodec = new UnsafeStreamCodec(message.Quality, message.DisplayIndex, resolution);
|
|
}
|
|
|
|
BitmapData desktopData = null;
|
|
Bitmap desktop = null;
|
|
try
|
|
{
|
|
desktop = ScreenHelper.CaptureScreen(message.DisplayIndex);
|
|
desktopData = desktop.LockBits(new Rectangle(0, 0, desktop.Width, desktop.Height),
|
|
ImageLockMode.ReadWrite, desktop.PixelFormat);
|
|
|
|
using (MemoryStream stream = new MemoryStream())
|
|
{
|
|
if (_streamCodec == null) throw new Exception("StreamCodec can not be null.");
|
|
_streamCodec.CodeImage(desktopData.Scan0,
|
|
new Rectangle(0, 0, desktop.Width, desktop.Height),
|
|
new Size(desktop.Width, desktop.Height),
|
|
desktop.PixelFormat, stream);
|
|
client.Send(new GetDesktopResponse
|
|
{
|
|
Image = stream.ToArray(),
|
|
Quality = _streamCodec.ImageQuality,
|
|
Monitor = _streamCodec.Monitor,
|
|
Resolution = _streamCodec.Resolution
|
|
});
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
if (_streamCodec != null)
|
|
{
|
|
client.Send(new GetDesktopResponse
|
|
{
|
|
Image = null,
|
|
Quality = _streamCodec.ImageQuality,
|
|
Monitor = _streamCodec.Monitor,
|
|
Resolution = _streamCodec.Resolution
|
|
});
|
|
}
|
|
|
|
_streamCodec = null;
|
|
}
|
|
finally
|
|
{
|
|
if (desktop != null)
|
|
{
|
|
if (desktopData != null)
|
|
{
|
|
try
|
|
{
|
|
desktop.UnlockBits(desktopData);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
desktop.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Execute(ISender sender, DoMouseEvent message)
|
|
{
|
|
try
|
|
{
|
|
Screen[] allScreens = Screen.AllScreens;
|
|
int offsetX = allScreens[message.MonitorIndex].Bounds.X;
|
|
int offsetY = allScreens[message.MonitorIndex].Bounds.Y;
|
|
Point p = new Point(message.X + offsetX, message.Y + offsetY);
|
|
|
|
// Disable screensaver if active before input
|
|
switch (message.Action)
|
|
{
|
|
case MouseAction.LeftDown:
|
|
case MouseAction.LeftUp:
|
|
case MouseAction.RightDown:
|
|
case MouseAction.RightUp:
|
|
case MouseAction.MoveCursor:
|
|
if (NativeMethodsHelper.IsScreensaverActive())
|
|
NativeMethodsHelper.DisableScreensaver();
|
|
break;
|
|
}
|
|
|
|
switch (message.Action)
|
|
{
|
|
case MouseAction.LeftDown:
|
|
case MouseAction.LeftUp:
|
|
NativeMethodsHelper.DoMouseLeftClick(p, message.IsMouseDown);
|
|
break;
|
|
case MouseAction.RightDown:
|
|
case MouseAction.RightUp:
|
|
NativeMethodsHelper.DoMouseRightClick(p, message.IsMouseDown);
|
|
break;
|
|
case MouseAction.MoveCursor:
|
|
NativeMethodsHelper.DoMouseMove(p);
|
|
break;
|
|
case MouseAction.ScrollDown:
|
|
NativeMethodsHelper.DoMouseScroll(p, true);
|
|
break;
|
|
case MouseAction.ScrollUp:
|
|
NativeMethodsHelper.DoMouseScroll(p, false);
|
|
break;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
private void Execute(ISender sender, DoKeyboardEvent message)
|
|
{
|
|
if (NativeMethodsHelper.IsScreensaverActive())
|
|
NativeMethodsHelper.DisableScreensaver();
|
|
|
|
NativeMethodsHelper.DoKeyPress(message.Key, message.KeyDown);
|
|
}
|
|
|
|
private void Execute(ISender client, GetMonitors message)
|
|
{
|
|
client.Send(new GetMonitorsResponse {Number = Screen.AllScreens.Length});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disposes all managed and unmanaged resources associated with this message processor.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
_streamCodec?.Dispose();
|
|
}
|
|
}
|
|
}
|
|
}
|