initial commit
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user