diff --git a/Remotely.sln b/Remotely.sln
index c64917ca..75a6ee6f 100644
--- a/Remotely.sln
+++ b/Remotely.sln
@@ -29,11 +29,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Remotely_Server", "Remotely
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Remotely_Library", "Remotely_Library\Remotely_Library.csproj", "{A9E1BA7A-6080-4DAC-9B29-6DC8437150EA}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Remotely_ScreenCast", "Remotely_ScreenCast\Remotely_ScreenCast.csproj", "{2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Remotely_ScreenCast.Win", "Remotely_ScreenCast.Win\Remotely_ScreenCast.Win.csproj", "{2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Remotely_Desktop", "Remotely_Desktop\Remotely_Desktop.csproj", "{486A238C-387B-49C5-A361-B86ACDB2572A}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Remotely_ScreenCast_Linux", "Remotely_ScreenCast_Linux\Remotely_ScreenCast_Linux.csproj", "{9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Remotely_ScreenCast.Linux", "Remotely_ScreenCast.Linux\Remotely_ScreenCast.Linux.csproj", "{E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Remotely_ScreenCast.Core", "Remotely_ScreenCast.Core\Remotely_ScreenCast.Core.csproj", "{B04A1728-2E87-491E-BC7F-F575A1754DEF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -105,18 +107,30 @@ Global
{486A238C-387B-49C5-A361-B86ACDB2572A}.Release|x64.Build.0 = Release|Any CPU
{486A238C-387B-49C5-A361-B86ACDB2572A}.Release|x86.ActiveCfg = Release|Any CPU
{486A238C-387B-49C5-A361-B86ACDB2572A}.Release|x86.Build.0 = Release|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Debug|x64.ActiveCfg = Debug|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Debug|x64.Build.0 = Debug|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Debug|x86.ActiveCfg = Debug|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Debug|x86.Build.0 = Debug|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Release|Any CPU.Build.0 = Release|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Release|x64.ActiveCfg = Release|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Release|x64.Build.0 = Release|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Release|x86.ActiveCfg = Release|Any CPU
- {9DB9F02E-9952-4A61-860A-CE2C6CE2A7E1}.Release|x86.Build.0 = Release|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Debug|x64.Build.0 = Debug|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Debug|x86.Build.0 = Debug|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Release|x64.ActiveCfg = Release|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Release|x64.Build.0 = Release|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Release|x86.ActiveCfg = Release|Any CPU
+ {E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Release|x86.Build.0 = Release|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Debug|x64.Build.0 = Debug|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Debug|x86.Build.0 = Debug|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Release|x64.ActiveCfg = Release|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Release|x64.Build.0 = Release|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Release|x86.ActiveCfg = Release|Any CPU
+ {B04A1728-2E87-491E-BC7F-F575A1754DEF}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Remotely_Agent/Services/DeviceSocket.cs b/Remotely_Agent/Services/DeviceSocket.cs
index a616794d..4e92c529 100644
--- a/Remotely_Agent/Services/DeviceSocket.cs
+++ b/Remotely_Agent/Services/DeviceSocket.cs
@@ -258,13 +258,8 @@ namespace Remotely_Agent.Services
}
try
{
- if (!OSUtils.IsWindows)
- {
- await hubConnection.InvokeAsync("DisplayConsoleMessage", $"Remote control is only supported on Windows at this time.", requesterID);
- return;
- }
-
- if (!File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ScreenCast", OSUtils.ScreenCastExecutableFileName)))
+ var rcBinaryPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ScreenCast", OSUtils.ScreenCastExecutableFileName);
+ if (!File.Exists(rcBinaryPath))
{
await hubConnection.InvokeAsync("DisplayConsoleMessage", "Remote control executable not found on target device.", requesterID);
return;
@@ -278,24 +273,24 @@ namespace Remotely_Agent.Services
if (Program.IsDebug)
{
- Process.Start(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ScreenCast", OSUtils.ScreenCastExecutableFileName), $"-mode Unattended -requester {requesterID} -serviceid {serviceID} -host {Utilities.GetConnectionInfo().Host} -desktop default");
+ Process.Start(rcBinaryPath, $"-mode Unattended -requester {requesterID} -serviceid {serviceID} -host {Utilities.GetConnectionInfo().Host} -desktop default");
}
else
{
- var result = Win32Interop.OpenInteractiveProcess(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ScreenCast", OSUtils.ScreenCastExecutableFileName) + $" -mode Unattended -requester {requesterID} -serviceid {serviceID} -host {Utilities.GetConnectionInfo().Host} -desktop default", "default", true, out _);
+ var result = Win32Interop.OpenInteractiveProcess(rcBinaryPath + $" -mode Unattended -requester {requesterID} -serviceid {serviceID} -host {Utilities.GetConnectionInfo().Host} -desktop default", "default", true, out _);
if (!result)
{
await hubConnection.InvokeAsync("DisplayConsoleMessage", "Remote control failed to start on target device.", requesterID);
}
}
}
- //else if (OSUtils.IsLinux)
- //{
- // var users = OSUtils.StartProcessWithResults("users", "");
- // var username = users?.Split()?.FirstOrDefault()?.Trim();
+ else if (OSUtils.IsLinux)
+ {
+ var users = OSUtils.StartProcessWithResults("users", "");
+ var username = users?.Split()?.FirstOrDefault()?.Trim();
- // Process.Start("sudo", $"-u {username} {rcBinaryPath} -mode Unattended -requester {requesterID} -serviceid {serviceID} -desktop default -hostname {Utilities.GetConnectionInfo().Host.Split("//").Last()}");
- //}
+ Process.Start("sudo", $"-u {username} mono {rcBinaryPath} -mode Unattended -requester {requesterID} -serviceid {serviceID} -host {Utilities.GetConnectionInfo().Host} -desktop default");
+ }
}
catch (Exception ex)
{
@@ -314,17 +309,18 @@ namespace Remotely_Agent.Services
}
try
{
+ var rcBinaryPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ScreenCast", OSUtils.ScreenCastExecutableFileName);
// Start ScreenCast.
if (OSUtils.IsWindows)
{
if (Program.IsDebug)
{
- Process.Start(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ScreenCast", OSUtils.ScreenCastExecutableFileName), $"-mode Unattended -requester {requesterID} -serviceid {serviceID} -host {Utilities.GetConnectionInfo().Host} -relaunch true -desktop default -viewers {String.Join(",", viewerIDs)}");
+ Process.Start(rcBinaryPath, $"-mode Unattended -requester {requesterID} -serviceid {serviceID} -host {Utilities.GetConnectionInfo().Host} -relaunch true -desktop default -viewers {String.Join(",", viewerIDs)}");
}
else
{
- var result = Win32Interop.OpenInteractiveProcess(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ScreenCast", OSUtils.ScreenCastExecutableFileName) + $" -mode Unattended -requester {requesterID} -serviceid {serviceID} -host {Utilities.GetConnectionInfo().Host} -relaunch true -desktop default -viewers {String.Join(",", viewerIDs)}", "default", true, out _);
+ var result = Win32Interop.OpenInteractiveProcess(rcBinaryPath + $" -mode Unattended -requester {requesterID} -serviceid {serviceID} -host {Utilities.GetConnectionInfo().Host} -relaunch true -desktop default -viewers {String.Join(",", viewerIDs)}", "default", true, out _);
if (!result)
{
Logger.Write("Failed to relaunch screen caster.");
@@ -333,13 +329,13 @@ namespace Remotely_Agent.Services
}
}
}
- //else if (OSUtils.IsLinux)
- //{
- // var users = OSUtils.StartProcessWithResults("users", "");
- // var username = users?.Split()?.FirstOrDefault()?.Trim();
+ else if (OSUtils.IsLinux)
+ {
+ var users = OSUtils.StartProcessWithResults("users", "");
+ var username = users?.Split()?.FirstOrDefault()?.Trim();
- // Process.Start("sudo", $"-u {username} {rcBinaryPath} -mode Unattended -requester {requesterID} -serviceid {serviceID} -desktop default -hostname {Utilities.GetConnectionInfo().Host.Split("//").Last()}");
- //}
+ Process.Start("sudo", $"-u {username} mono {rcBinaryPath} -mode Unattended -requester {requesterID} -serviceid {serviceID} -hostname {Utilities.GetConnectionInfo().Host} -desktop default");
+ }
}
catch (Exception ex)
{
diff --git a/Remotely_Desktop/MainWindow.xaml.cs b/Remotely_Desktop/MainWindow.xaml.cs
index def26bf5..804c52dc 100644
--- a/Remotely_Desktop/MainWindow.xaml.cs
+++ b/Remotely_Desktop/MainWindow.xaml.cs
@@ -1,5 +1,5 @@
using Remotely_Desktop.ViewModels;
-using Remotely_ScreenCast.Models;
+using Remotely_ScreenCast.Core.Models;
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/Remotely_Desktop/Remotely_Desktop.csproj b/Remotely_Desktop/Remotely_Desktop.csproj
index 9ad45825..442c6c71 100644
--- a/Remotely_Desktop/Remotely_Desktop.csproj
+++ b/Remotely_Desktop/Remotely_Desktop.csproj
@@ -1,6 +1,6 @@
-
+
@@ -45,8 +45,8 @@
app.manifest
-
- ..\packages\Costura.Fody.3.3.2\lib\net40\Costura.dll
+
+ ..\packages\Costura.Fody.3.3.3\lib\net40\Costura.dll
..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll
@@ -135,20 +135,23 @@
-
+
+ {b04a1728-2e87-491e-bc7f-f575a1754def}
+ Remotely_ScreenCast.Core
+
+
{2dcea1f5-9b64-4edb-9cd0-4d6675d96709}
- Remotely_ScreenCast
+ Remotely_ScreenCast.Win
-
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
+
+
-
+
\ No newline at end of file
diff --git a/Remotely_Desktop/ViewModels/MainWindowViewModel.cs b/Remotely_Desktop/ViewModels/MainWindowViewModel.cs
index a1e0e404..933a3523 100644
--- a/Remotely_Desktop/ViewModels/MainWindowViewModel.cs
+++ b/Remotely_Desktop/ViewModels/MainWindowViewModel.cs
@@ -1,8 +1,11 @@
using Remotely_Desktop.Controls;
using Remotely_Desktop.Services;
-using Remotely_ScreenCast;
-using Remotely_ScreenCast.Capture;
-using Remotely_ScreenCast.Models;
+using Remotely_ScreenCast.Core;
+using Remotely_ScreenCast.Core.Capture;
+using Remotely_ScreenCast.Core.Models;
+using Remotely_ScreenCast.Win;
+using Remotely_ScreenCast.Win.Capture;
+using Remotely_ScreenCast.Win.Input;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -23,16 +26,24 @@ namespace Remotely_Desktop.ViewModels
public MainWindowViewModel()
{
Current = this;
+ Conductor = new Conductor();
+ Conductor.SessionIDChanged += SessionIDChanged;
+ Conductor.ViewerRemoved += ViewerRemoved;
+ Conductor.ViewerAdded += ViewerAdded;
+ Conductor.ScreenCastRequested += ScreenCastRequested;
+ CursorIconWatcher = new CursorIconWatcher(Conductor);
+ CursorIconWatcher.OnChange += CursorIconWatcher_OnChange;
+ }
- Program.SessionIDChanged += SessionIDChanged;
- Program.ViewerRemoved += ViewerRemoved;
- Program.ViewerAdded += ViewerAdded;
- Program.ScreenCastRequested += ScreenCastRequested;
+ private async void CursorIconWatcher_OnChange(object sender, CursorInfo cursor)
+ {
+ await Conductor.OutgoingMessages.SendCursorChange(cursor, Conductor.Viewers.Keys.ToList());
}
public event PropertyChangedEventHandler PropertyChanged;
public static MainWindowViewModel Current { get; private set; }
+ public Conductor Conductor { get; }
public Config Config { get; private set; }
public string ForceHost { get; }
public bool AllowHostChange
@@ -52,6 +63,8 @@ namespace Remotely_Desktop.ViewModels
public string SessionID { get; set; }
public ObservableCollection Viewers { get; } = new ObservableCollection();
+ public CursorIconWatcher CursorIconWatcher { get; }
+
public void FirePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
@@ -75,10 +88,10 @@ namespace Remotely_Desktop.ViewModels
}
- Program.ProcessArgs(new string[] { "-mode", "Normal", "-host", Config.Host });
+ Conductor.ProcessArgs(new string[] { "-mode", "Normal", "-host", Config.Host });
try
{
- await Program.Connect();
+ await Conductor.Connect();
}
catch (Exception ex)
{
@@ -86,24 +99,43 @@ namespace Remotely_Desktop.ViewModels
MessageBox.Show("Failed to connect to server.", "Connection Failed", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
- Program.SetEventHandlers();
-
- await Task.Run(async () =>
- {
- await Program.HandleConnection();
- });
+
+ Conductor.SetMessageHandlers(new WinInput());
+ await Conductor.OutgoingMessages.SendDeviceInfo(Conductor.ServiceID, Environment.MachineName);
+ await Conductor.OutgoingMessages.GetSessionID();
}
- private void ScreenCastRequested(object sender, Tuple args)
+
+
+ private void ScreenCastRequested(object sender, Tuple viewerAndRequester)
{
App.Current.Dispatcher.Invoke(() =>
{
- var result = MessageBox.Show($"You've received a connection request from {args.Item2}. Accept?", "Connection Request", MessageBoxButton.YesNo, MessageBoxImage.Question);
+ var result = MessageBox.Show($"You've received a connection request from {viewerAndRequester.Item2}. Accept?", "Connection Request", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
- Task.Run(() =>
+ Task.Run(async() =>
{
- ScreenCaster.BeginScreenCasting(args.Item1, args.Item2, Program.OutgoingMessages);
+ ICapturer capturer;
+ try
+ {
+ if (Conductor.Viewers.Count == 0)
+ {
+ capturer = new DXCapture();
+ capturer.Init();
+ }
+ else
+ {
+ capturer = new BitBltCapture();
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ capturer = new BitBltCapture();
+ }
+ await Conductor.OutgoingMessages.SendCursorChange(CursorIconWatcher.GetCurrentCursor(), new List() { viewerAndRequester.Item1 });
+ ScreenCaster.BeginScreenCasting(viewerAndRequester.Item1, viewerAndRequester.Item2, Conductor.OutgoingMessages, capturer, Conductor);
});
}
});
@@ -114,7 +146,7 @@ namespace Remotely_Desktop.ViewModels
foreach (Viewer viewer in viewerList)
{
viewer.DisconnectRequested = true;
- await Program.OutgoingMessages.SendViewerRemoved(viewer.ViewerConnectionID);
+ await Conductor.OutgoingMessages.SendViewerRemoved(viewer.ViewerConnectionID);
}
}
diff --git a/Remotely_Desktop/packages.config b/Remotely_Desktop/packages.config
index fd24ce1b..7ba725b0 100644
--- a/Remotely_Desktop/packages.config
+++ b/Remotely_Desktop/packages.config
@@ -1,7 +1,7 @@
-
-
+
+
\ No newline at end of file
diff --git a/Remotely_Library/Services/OSUtils.cs b/Remotely_Library/Services/OSUtils.cs
index 77332db7..9fc8b824 100644
--- a/Remotely_Library/Services/OSUtils.cs
+++ b/Remotely_Library/Services/OSUtils.cs
@@ -47,7 +47,7 @@ namespace Remotely_Library.Services
}
else if (IsLinux)
{
- return "Remotely_ScreenCast";
+ return "Remotely_ScreenCast.Mono.exe";
}
else
{
diff --git a/Remotely_ScreenCast/Capture/ICapturer.cs b/Remotely_ScreenCast.Core/Capture/ICapturer.cs
similarity index 74%
rename from Remotely_ScreenCast/Capture/ICapturer.cs
rename to Remotely_ScreenCast.Core/Capture/ICapturer.cs
index cca22c72..56126725 100644
--- a/Remotely_ScreenCast/Capture/ICapturer.cs
+++ b/Remotely_ScreenCast.Core/Capture/ICapturer.cs
@@ -5,7 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace Remotely_ScreenCast.Capture
+namespace Remotely_ScreenCast.Core.Capture
{
public interface ICapturer : IDisposable
{
@@ -15,6 +15,10 @@ namespace Remotely_ScreenCast.Capture
Bitmap PreviousFrame { get; set; }
EventHandler ScreenChanged { get; set; }
int SelectedScreen { get; set; }
+ int ScreenCount { get; set; }
+ double VirtualScreenHeight { get; set; }
+ double VirtualScreenWidth { get; set; }
+
void Capture();
void Init();
}
diff --git a/Remotely_ScreenCast/Capture/ImageUtils.cs b/Remotely_ScreenCast.Core/Capture/ImageUtils.cs
similarity index 98%
rename from Remotely_ScreenCast/Capture/ImageUtils.cs
rename to Remotely_ScreenCast.Core/Capture/ImageUtils.cs
index ce821c6d..07c8e280 100644
--- a/Remotely_ScreenCast/Capture/ImageUtils.cs
+++ b/Remotely_ScreenCast.Core/Capture/ImageUtils.cs
@@ -1,4 +1,4 @@
-using Remotely_ScreenCast.Models;
+using Remotely_ScreenCast.Core.Models;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -10,7 +10,7 @@ using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
-namespace Remotely_ScreenCast.Capture
+namespace Remotely_ScreenCast.Core.Capture
{
public class ImageUtils
{
diff --git a/Remotely_ScreenCast/Capture/ScreenCaster.cs b/Remotely_ScreenCast.Core/Capture/ScreenCaster.cs
similarity index 78%
rename from Remotely_ScreenCast/Capture/ScreenCaster.cs
rename to Remotely_ScreenCast.Core/Capture/ScreenCaster.cs
index fd13988a..be080ec7 100644
--- a/Remotely_ScreenCast/Capture/ScreenCaster.cs
+++ b/Remotely_ScreenCast.Core/Capture/ScreenCaster.cs
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.SignalR.Client;
-using Remotely_ScreenCast.Models;
-using Remotely_ScreenCast.Sockets;
-using Remotely_ScreenCast.Utilities;
+using Remotely_ScreenCast.Core.Models;
+using Remotely_ScreenCast.Core.Sockets;
+using Remotely_ScreenCast.Core.Utilities;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -9,44 +9,23 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-using System.Windows.Forms;
-namespace Remotely_ScreenCast.Capture
+namespace Remotely_ScreenCast.Core.Capture
{
public class ScreenCaster
{
public static async void BeginScreenCasting(string viewerID,
string requesterName,
- OutgoingMessages outgoingMessages)
+ OutgoingMessages outgoingMessages,
+ ICapturer capturer,
+ Conductor conductor)
{
- ICapturer capturer;
- CaptureMode captureMode;
Viewer viewer;
byte[] encodedImageBytes;
var success = false;
-
- try
- {
- if (Program.Viewers.Count == 0)
- {
- capturer = new DXCapture();
- captureMode = CaptureMode.DirectX;
- capturer.Init();
- }
- else
- {
- capturer = new BitBltCapture();
- captureMode = CaptureMode.BitBtl;
- }
- }
- catch (Exception ex)
- {
- Logger.Write(ex);
- capturer = new BitBltCapture();
- captureMode = CaptureMode.BitBtl;
- }
+
- Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capture Mode: {captureMode.ToString()}. App Mode: {Program.Mode} Desktop: {Program.CurrentDesktopName}");
+ Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}. App Mode: {conductor.Mode} Desktop: {conductor.CurrentDesktopName}");
viewer = new Viewer()
{
@@ -59,17 +38,17 @@ namespace Remotely_ScreenCast.Capture
while (!success)
{
- success = Program.Viewers.TryAdd(viewerID, viewer);
+ success = conductor.Viewers.TryAdd(viewerID, viewer);
}
- if (Program.Mode == Enums.AppMode.Normal)
+ if (conductor.Mode == Enums.AppMode.Normal)
{
- Program.ViewerAdded?.Invoke(null, viewer);
+ conductor.ViewerAdded?.Invoke(null, viewer);
}
await outgoingMessages.SendScreenCount(
capturer.SelectedScreen,
- Screen.AllScreens.Length,
+ capturer.ScreenCount,
viewerID);
await outgoingMessages.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);
@@ -79,8 +58,6 @@ namespace Remotely_ScreenCast.Capture
await outgoingMessages.SendScreenSize(bounds.Width, bounds.Height, viewerID);
};
- await outgoingMessages.SendCursorChange(CursorIconWatcher.Current.GetCurrentCursor(), new List() { viewerID });
-
// TODO: SetThradDesktop causes issues with input after switching.
//var desktopName = Win32Interop.GetCurrentDesktop();
while (!viewer.DisconnectRequested)
@@ -164,13 +141,13 @@ namespace Remotely_ScreenCast.Capture
success = false;
while (!success)
{
- success = Program.Viewers.TryRemove(viewerID, out _);
+ success = conductor.Viewers.TryRemove(viewerID, out _);
}
capturer.Dispose();
// Close if no one is viewing.
- if (Program.Viewers.Count == 0 && Program.Mode == Enums.AppMode.Unattended)
+ if (conductor.Viewers.Count == 0 && conductor.Mode == Enums.AppMode.Unattended)
{
Environment.Exit(0);
}
@@ -180,7 +157,7 @@ namespace Remotely_ScreenCast.Capture
{
var absoluteX = (capturer.CurrentScreenBounds.Width * percentX) + capturer.CurrentScreenBounds.Left;
var absoluteY = (capturer.CurrentScreenBounds.Height * percentY) + capturer.CurrentScreenBounds.Top;
- return new Tuple(absoluteX / SystemInformation.VirtualScreen.Width, absoluteY / SystemInformation.VirtualScreen.Height);
+ return new Tuple(absoluteX / capturer.VirtualScreenWidth, absoluteY / capturer.VirtualScreenHeight);
}
public static Tuple GetAbsolutePointFromRelativePercent(double percentX, double percentY, ICapturer capturer)
{
diff --git a/Remotely_ScreenCast.Core/Conductor.cs b/Remotely_ScreenCast.Core/Conductor.cs
new file mode 100644
index 00000000..f698a7f1
--- /dev/null
+++ b/Remotely_ScreenCast.Core/Conductor.cs
@@ -0,0 +1,98 @@
+using Microsoft.AspNetCore.SignalR.Client;
+using Microsoft.Extensions.DependencyInjection;
+using Remotely_ScreenCast.Core.Enums;
+using Remotely_ScreenCast.Core.Input;
+using Remotely_ScreenCast.Core.Models;
+using Remotely_ScreenCast.Core.Sockets;
+using Remotely_ScreenCast.Core.Utilities;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Remotely_ScreenCast.Core
+{
+ public class Conductor
+ {
+ public AppMode Mode { get; private set; }
+ public string RequesterID { get; private set; }
+ public string ServiceID { get; private set; }
+ public string Host { get; private set; }
+ public HubConnection Connection { get; private set; }
+ public OutgoingMessages OutgoingMessages { get; private set; }
+ public string CurrentDesktopName { get; set; }
+ public ConcurrentDictionary Viewers { get; } = new ConcurrentDictionary();
+ public Dictionary ArgDict { get; set; }
+
+ public void SetMessageHandlers(IKeyboardMouseInput keyboardMouse)
+ {
+ OutgoingMessages = new OutgoingMessages(Connection);
+
+ MessageHandlers.ApplyConnectionHandlers(Connection, this, keyboardMouse);
+ }
+
+ public Task Connect()
+ {
+ Connection = new HubConnectionBuilder()
+ .WithUrl($"{Host}/RCDeviceHub")
+ .AddMessagePackProtocol()
+ .Build();
+
+ return Connection.StartAsync();
+ }
+
+ public void StartWaitForViewerTimer()
+ {
+ var timer = new System.Timers.Timer(10000);
+ timer.AutoReset = false;
+ timer.Elapsed += (sender, arg) =>
+ {
+ // Shut down if no viewers have connected within 10 seconds.
+ if (Viewers.Count == 0)
+ {
+ Logger.Write("No viewers connected after 10 seconds. Shutting down.");
+ Environment.Exit(0);
+ }
+ };
+ timer.Start();
+ }
+
+ public void ProcessArgs(string[] args)
+ {
+ ArgDict = new Dictionary();
+
+ for (var i = 0; i < args.Length; i += 2)
+ {
+ var key = args?[i];
+ if (key != null)
+ {
+ key = key.Trim().Replace("-", "").ToLower();
+ var value = args?[i + 1];
+ if (value != null)
+ {
+ ArgDict[key] = args[i + 1].Trim();
+ }
+ }
+
+ }
+
+ Mode = (AppMode)Enum.Parse(typeof(AppMode), ArgDict["mode"]);
+ Host = ArgDict["host"];
+
+ if (Mode == AppMode.Unattended)
+ {
+ RequesterID = ArgDict["requester"];
+ CurrentDesktopName = ArgDict["desktop"];
+ ServiceID = ArgDict["serviceid"];
+ }
+
+ }
+ public EventHandler SessionIDChanged { get; set; }
+ public EventHandler ViewerRemoved { get; set; }
+ public EventHandler ViewerAdded { get; set; }
+ public EventHandler> ScreenCastRequested { get; set; }
+ public EventHandler> ScreenCastInitiated { get; set; }
+ }
+}
diff --git a/Remotely_ScreenCast/Enums/AppMode.cs b/Remotely_ScreenCast.Core/Enums/AppMode.cs
similarity index 82%
rename from Remotely_ScreenCast/Enums/AppMode.cs
rename to Remotely_ScreenCast.Core/Enums/AppMode.cs
index 13ea2999..849618b5 100644
--- a/Remotely_ScreenCast/Enums/AppMode.cs
+++ b/Remotely_ScreenCast.Core/Enums/AppMode.cs
@@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace Remotely_ScreenCast.Enums
+namespace Remotely_ScreenCast.Core.Enums
{
public enum AppMode
{
diff --git a/Remotely_ScreenCast.Core/Input/IKeyboardMouseInput.cs b/Remotely_ScreenCast.Core/Input/IKeyboardMouseInput.cs
new file mode 100644
index 00000000..f928fd50
--- /dev/null
+++ b/Remotely_ScreenCast.Core/Input/IKeyboardMouseInput.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Remotely_ScreenCast.Core.Input
+{
+ public interface IKeyboardMouseInput
+ {
+ void SendKeyDown(string key);
+ void SendKeyUp(string key);
+ uint SendMouseMove(double percentX, double percentY);
+ uint SendLeftMouseDown(double percentX, double percentY);
+ uint SendLeftMouseUp(double percentX, double percentY);
+ uint SendRightMouseDown(double percentX, double percentY);
+ uint SendRightMouseUp(double percentX, double percentY);
+ uint SendMouseWheel(int deltaY);
+ }
+}
diff --git a/Remotely_ScreenCast/Models/CursorInfo.cs b/Remotely_ScreenCast.Core/Models/CursorInfo.cs
similarity index 92%
rename from Remotely_ScreenCast/Models/CursorInfo.cs
rename to Remotely_ScreenCast.Core/Models/CursorInfo.cs
index c0cb86e6..59b5335d 100644
--- a/Remotely_ScreenCast/Models/CursorInfo.cs
+++ b/Remotely_ScreenCast.Core/Models/CursorInfo.cs
@@ -5,7 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace Remotely_ScreenCast.Models
+namespace Remotely_ScreenCast.Core.Models
{
public class CursorInfo
{
diff --git a/Remotely_ScreenCast/Models/CursorInfo.d.ts b/Remotely_ScreenCast.Core/Models/CursorInfo.d.ts
similarity index 100%
rename from Remotely_ScreenCast/Models/CursorInfo.d.ts
rename to Remotely_ScreenCast.Core/Models/CursorInfo.d.ts
diff --git a/Remotely_ScreenCast/Models/Viewer.cs b/Remotely_ScreenCast.Core/Models/Viewer.cs
similarity index 94%
rename from Remotely_ScreenCast/Models/Viewer.cs
rename to Remotely_ScreenCast.Core/Models/Viewer.cs
index 70baeea0..0a725112 100644
--- a/Remotely_ScreenCast/Models/Viewer.cs
+++ b/Remotely_ScreenCast.Core/Models/Viewer.cs
@@ -1,4 +1,4 @@
-using Remotely_ScreenCast.Capture;
+using Remotely_ScreenCast.Core.Capture;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -6,7 +6,7 @@ using System.Drawing.Imaging;
using System.Linq;
using System.Threading.Tasks;
-namespace Remotely_ScreenCast.Models
+namespace Remotely_ScreenCast.Core.Models
{
public class Viewer
{
diff --git a/Remotely_ScreenCast.Core/Remotely_ScreenCast.Core.csproj b/Remotely_ScreenCast.Core/Remotely_ScreenCast.Core.csproj
new file mode 100644
index 00000000..9a371c88
--- /dev/null
+++ b/Remotely_ScreenCast.Core/Remotely_ScreenCast.Core.csproj
@@ -0,0 +1,26 @@
+
+
+
+ netstandard2.0
+
+
+
+ true
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Remotely_ScreenCast_Linux/Sockets/MessageHandlers.cs b/Remotely_ScreenCast.Core/Sockets/MessageHandlers.cs
similarity index 62%
rename from Remotely_ScreenCast_Linux/Sockets/MessageHandlers.cs
rename to Remotely_ScreenCast.Core/Sockets/MessageHandlers.cs
index efd86c92..5017fbff 100644
--- a/Remotely_ScreenCast_Linux/Sockets/MessageHandlers.cs
+++ b/Remotely_ScreenCast.Core/Sockets/MessageHandlers.cs
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.SignalR.Client;
-using Remotely_ScreenCast_Linux.Capture;
-using Remotely_ScreenCast_Linux.Utilities;
-using Remotely_ScreenCast_Linux;
+using Remotely_ScreenCast.Core.Capture;
+using Remotely_ScreenCast.Core.Utilities;
+using Remotely_ScreenCast.Core;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -10,17 +10,18 @@ using System.Threading.Tasks;
using System.Net;
using System.IO;
using System.Diagnostics;
-using Remotely_ScreenCast_Linux.Models;
+using Remotely_ScreenCast.Core.Models;
+using Remotely_ScreenCast.Core.Input;
-namespace Remotely_ScreenCast_Linux.Sockets
+namespace Remotely_ScreenCast.Core.Sockets
{
public class MessageHandlers
{
- public static void ApplyConnectionHandlers(HubConnection hubConnection, OutgoingMessages outgoingMessages)
+ public static void ApplyConnectionHandlers(HubConnection hubConnection, Conductor conductor, IKeyboardMouseInput keyboardMouse)
{
hubConnection.Closed += (ex) =>
{
- Logger.Write($"Error: {ex.Message}");
+ Logger.Write($"Connection closed. Error: {ex.Message}");
Environment.Exit(1);
return Task.CompletedTask;
};
@@ -29,7 +30,7 @@ namespace Remotely_ScreenCast_Linux.Sockets
{
try
{
- ScreenCaster.BeginScreenCasting(viewerID, requesterName, outgoingMessages);
+ conductor.ScreenCastInitiated?.Invoke(null, new Tuple(viewerID, requesterName));
}
catch (Exception ex)
{
@@ -39,100 +40,97 @@ namespace Remotely_ScreenCast_Linux.Sockets
hubConnection.On("RequestScreenCast", (string viewerID, string requesterName) =>
{
- Program.ScreenCastRequested?.Invoke(null, new Tuple(viewerID, requesterName));
+ conductor.ScreenCastRequested?.Invoke(null, new Tuple(viewerID, requesterName));
});
hubConnection.On("KeyDown", (string key, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
- //var keyCode = Win32Interop.ConvertJavaScriptKeyToVirtualKey(key);
- //Win32Interop.SendKeyDown((User32.VirtualKey)keyCode);
+ keyboardMouse.SendKeyDown(key);
}
});
hubConnection.On("KeyUp", (string key, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
- //var keyCode = Win32Interop.ConvertJavaScriptKeyToVirtualKey(key);
- //Win32Interop.SendKeyUp((User32.VirtualKey)keyCode);
+ keyboardMouse.SendKeyUp(key);
}
});
hubConnection.On("KeyPress", async (string key, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
- //var keyCode = Win32Interop.ConvertJavaScriptKeyToVirtualKey(key);
- //Win32Interop.SendKeyDown((User32.VirtualKey)keyCode);
- //await Task.Delay(1);
- //Win32Interop.SendKeyUp((User32.VirtualKey)keyCode);
+ keyboardMouse.SendKeyDown(key);
+ await Task.Delay(1);
+ keyboardMouse.SendKeyUp(key);
}
});
hubConnection.On("MouseMove", (double percentX, double percentY, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
- var mousePoint = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
- //Win32Interop.SendMouseMove(mousePoint.Item1, mousePoint.Item2);
+ var xyPercents = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
+ keyboardMouse.SendMouseMove(xyPercents.Item1, xyPercents.Item2);
}
});
hubConnection.On("MouseDown", (int button, double percentX, double percentY, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
- var mousePoint = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
+ var xyPercents = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
if (button == 0)
{
- //Win32Interop.SendLeftMouseDown((int)mousePoint.Item1, (int)mousePoint.Item2);
+ keyboardMouse.SendLeftMouseDown(xyPercents.Item1, xyPercents.Item2);
}
else if (button == 2)
{
- //Win32Interop.SendRightMouseDown((int)mousePoint.Item1, (int)mousePoint.Item2);
+ keyboardMouse.SendRightMouseDown(xyPercents.Item1, xyPercents.Item2);
}
}
});
hubConnection.On("MouseUp", (int button, double percentX, double percentY, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
- var mousePoint = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
+ var xyPercents = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
if (button == 0)
{
- //Win32Interop.SendLeftMouseUp((int)mousePoint.Item1, (int)mousePoint.Item2);
+ keyboardMouse.SendLeftMouseUp(xyPercents.Item1, xyPercents.Item2);
}
else if (button == 2)
{
- //Win32Interop.SendRightMouseUp((int)mousePoint.Item1, (int)mousePoint.Item2);
+ keyboardMouse.SendRightMouseUp(xyPercents.Item1, xyPercents.Item2);
}
}
});
hubConnection.On("MouseWheel", (double deltaX, double deltaY, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
- //Win32Interop.SendMouseWheel(-(int)deltaY);
+ keyboardMouse.SendMouseWheel(-(int)deltaY);
}
});
hubConnection.On("ViewerDisconnected", async (string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer))
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer))
{
viewer.DisconnectRequested = true;
}
await hubConnection.InvokeAsync("ViewerDisconnected", viewerID);
- Program.ViewerRemoved?.Invoke(null, viewerID);
+ conductor.ViewerRemoved?.Invoke(null, viewerID);
});
hubConnection.On("LatencyUpdate", (double latency, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer))
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer))
{
viewer.PendingFrames--;
viewer.Latency = latency;
@@ -141,7 +139,7 @@ namespace Remotely_ScreenCast_Linux.Sockets
hubConnection.On("SelectScreen", (int screenIndex, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer))
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer))
{
viewer.Capturer.SelectedScreen = screenIndex;
}
@@ -149,7 +147,7 @@ namespace Remotely_ScreenCast_Linux.Sockets
hubConnection.On("TouchDown", (string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
//User32.GetCursorPos(out var point);
//Win32Interop.SendLeftMouseDown(point.X, point.Y);
@@ -157,7 +155,7 @@ namespace Remotely_ScreenCast_Linux.Sockets
});
hubConnection.On("LongPress", (string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
//User32.GetCursorPos(out var point);
//Win32Interop.SendRightMouseDown(point.X, point.Y);
@@ -166,7 +164,7 @@ namespace Remotely_ScreenCast_Linux.Sockets
});
hubConnection.On("TouchMove", (double moveX, double moveY, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
//User32.GetCursorPos(out var point);
//Win32Interop.SendMouseMove(point.X + moveX, point.Y + moveY);
@@ -174,7 +172,7 @@ namespace Remotely_ScreenCast_Linux.Sockets
});
hubConnection.On("TouchUp", (string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
//User32.GetCursorPos(out var point);
//Win32Interop.SendLeftMouseUp(point.X, point.Y);
@@ -182,17 +180,17 @@ namespace Remotely_ScreenCast_Linux.Sockets
});
hubConnection.On("Tap", (double percentX, double percentY, string viewerID) =>
{
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
{
- var mousePoint = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
- //Win32Interop.SendLeftMouseDown((int)mousePoint.Item1, (int)mousePoint.Item2);
- //Win32Interop.SendLeftMouseUp((int)mousePoint.Item1, (int)mousePoint.Item2);
+ var xyPercents = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
+ keyboardMouse.SendLeftMouseDown(xyPercents.Item1, xyPercents.Item2);
+ keyboardMouse.SendLeftMouseUp(xyPercents.Item1, xyPercents.Item2);
}
});
hubConnection.On("SharedFileIDs", (List fileIDs) => {
fileIDs.ForEach(id =>
{
- var url = $"{Program.Host}/API/FileSharing/{id}";
+ var url = $"{conductor.Host}/API/FileSharing/{id}";
var webRequest = WebRequest.CreateHttp(url);
var response = webRequest.GetResponse();
var contentDisp = response.Headers["Content-Disposition"];
@@ -220,7 +218,7 @@ namespace Remotely_ScreenCast_Linux.Sockets
hubConnection.On("SessionID", (string sessionID) =>
{
- Program.SessionIDChanged?.Invoke(null, sessionID);
+ conductor.SessionIDChanged?.Invoke(null, sessionID);
});
}
}
diff --git a/Remotely_ScreenCast/Sockets/OutgoingMessages.cs b/Remotely_ScreenCast.Core/Sockets/OutgoingMessages.cs
similarity index 80%
rename from Remotely_ScreenCast/Sockets/OutgoingMessages.cs
rename to Remotely_ScreenCast.Core/Sockets/OutgoingMessages.cs
index 33812523..76eb2fdb 100644
--- a/Remotely_ScreenCast/Sockets/OutgoingMessages.cs
+++ b/Remotely_ScreenCast.Core/Sockets/OutgoingMessages.cs
@@ -1,5 +1,5 @@
using Microsoft.AspNetCore.SignalR.Client;
-using Remotely_ScreenCast.Models;
+using Remotely_ScreenCast.Core.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -7,7 +7,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace Remotely_ScreenCast.Sockets
+namespace Remotely_ScreenCast.Core.Sockets
{
public class OutgoingMessages
{
@@ -27,7 +27,7 @@ namespace Remotely_ScreenCast.Sockets
await Connection.SendAsync("SendScreenCapture", captureBytes, viewerID, left, top, width, height, captureTime);
}
- internal async Task SendScreenCount(int primaryScreenIndex, int screenCount, string viewerID)
+ public async Task SendScreenCount(int primaryScreenIndex, int screenCount, string viewerID)
{
await Connection.SendAsync("SendScreenCountToBrowser", primaryScreenIndex, screenCount, viewerID);
}
@@ -42,22 +42,22 @@ namespace Remotely_ScreenCast.Sockets
await Connection.SendAsync("SendCursorChange", cursor, viewerIDs);
}
- internal async Task NotifyViewersRelaunchedScreenCasterReady(string[] viewerIDs)
+ public async Task NotifyViewersRelaunchedScreenCasterReady(string[] viewerIDs)
{
await Connection.SendAsync("NotifyViewersRelaunchedScreenCasterReady", viewerIDs);
}
- internal async Task SendDeviceInfo(string serviceID, string machineName)
+ public async Task SendDeviceInfo(string serviceID, string machineName)
{
await Connection.SendAsync("ReceiveDeviceInfo", serviceID, machineName);
}
- internal async Task SendConnectionFailedToViewers(List viewerIDs)
+ public async Task SendConnectionFailedToViewers(List viewerIDs)
{
await Connection.SendAsync("SendConnectionFailedToViewers", viewerIDs);
}
- internal async Task GetSessionID()
+ public async Task GetSessionID()
{
await Connection.SendAsync("GetSessionID");
}
diff --git a/Remotely_ScreenCast/Utilities/Logger.cs b/Remotely_ScreenCast.Core/Utilities/Logger.cs
similarity index 98%
rename from Remotely_ScreenCast/Utilities/Logger.cs
rename to Remotely_ScreenCast.Core/Utilities/Logger.cs
index 96982575..4be74a50 100644
--- a/Remotely_ScreenCast/Utilities/Logger.cs
+++ b/Remotely_ScreenCast.Core/Utilities/Logger.cs
@@ -6,7 +6,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace Remotely_ScreenCast.Utilities
+namespace Remotely_ScreenCast.Core.Utilities
{
public static class Logger
{
diff --git a/Remotely_ScreenCast.Linux/Capture/X11Capture.cs b/Remotely_ScreenCast.Linux/Capture/X11Capture.cs
new file mode 100644
index 00000000..a9afa12d
--- /dev/null
+++ b/Remotely_ScreenCast.Linux/Capture/X11Capture.cs
@@ -0,0 +1,38 @@
+using Remotely_ScreenCast.Core.Capture;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+
+namespace Remotely_ScreenCast.Linux.Capture
+{
+ public class X11Capture : ICapturer
+ {
+ public bool CaptureFullscreen { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+ public System.Drawing.Bitmap CurrentFrame { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+
+ public Rectangle CurrentScreenBounds => throw new NotImplementedException();
+
+ public System.Drawing.Bitmap PreviousFrame { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+ public EventHandler ScreenChanged { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+ public int SelectedScreen { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+ public int ScreenCount { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+ public double VirtualScreenHeight { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+ public double VirtualScreenWidth { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+
+ public void Capture()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Init()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Remotely_ScreenCast.Linux/Input/X11Input.cs b/Remotely_ScreenCast.Linux/Input/X11Input.cs
new file mode 100644
index 00000000..cb2341c8
--- /dev/null
+++ b/Remotely_ScreenCast.Linux/Input/X11Input.cs
@@ -0,0 +1,50 @@
+using Remotely_ScreenCast.Core.Input;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Remotely_ScreenCast.Linux.Input
+{
+ public class X11Input : IKeyboardMouseInput
+ {
+ public void SendKeyDown(string key)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void SendKeyUp(string key)
+ {
+ throw new NotImplementedException();
+ }
+
+ public uint SendLeftMouseDown(double percentX, double percentY)
+ {
+ throw new NotImplementedException();
+ }
+
+ public uint SendLeftMouseUp(double percentX, double percentY)
+ {
+ throw new NotImplementedException();
+ }
+
+ public uint SendMouseMove(double percentX, double percentY)
+ {
+ throw new NotImplementedException();
+ }
+
+ public uint SendMouseWheel(int deltaY)
+ {
+ throw new NotImplementedException();
+ }
+
+ public uint SendRightMouseDown(double percentX, double percentY)
+ {
+ throw new NotImplementedException();
+ }
+
+ public uint SendRightMouseUp(double percentX, double percentY)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Remotely_ScreenCast.Linux/Program.cs b/Remotely_ScreenCast.Linux/Program.cs
new file mode 100644
index 00000000..9b3d0d3f
--- /dev/null
+++ b/Remotely_ScreenCast.Linux/Program.cs
@@ -0,0 +1,88 @@
+using Remotely_ScreenCast.Core;
+using Remotely_ScreenCast.Core.Capture;
+using Remotely_ScreenCast.Core.Utilities;
+using Remotely_ScreenCast.Linux.Capture;
+using Remotely_ScreenCast.Linux.Input;
+using Remotely_ScreenCast.Linux.X11Interop;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Remotely_ScreenCast.Linux
+{
+ public class Program
+ {
+ public static Conductor Conductor { get; private set; }
+ //public static CursorIconWatcher CursorIconWatcher { get; private set; }
+
+ public static void Main(string[] args)
+ {
+ try
+ {
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ //var display = Xlib.XOpenDisplay(null);
+ //Console.WriteLine($"Display is {display.ToString()}");
+ //var count = Xlib.XScreenCount(display);
+ //Console.WriteLine($"Count is {count}");
+ //using (var bitmap = new System.Drawing.Bitmap(800, 600))
+ //{
+ // using (var graphic = System.Drawing.Graphics.FromImage(bitmap))
+ // {
+ // graphic.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(800, 600));
+ // }
+ // bitmap.Save("Test.jpg");
+ //}
+ //var width = Xlib.XDisplayWidth(display, 0);
+ //var height = Xlib.XDisplayHeight(display, 0);
+ //Console.WriteLine($"Width: {width}, Height: {height}");
+ //Console.ReadLine();
+ Conductor = new Conductor();
+ Conductor.ProcessArgs(args);
+ Conductor.Connect().Wait();
+ Conductor.SetMessageHandlers(new X11Input());
+ Conductor.ScreenCastInitiated += ScreenCastInitiated;
+ //CursorIconWatcher = new CursorIconWatcher(Conductor);
+ //CursorIconWatcher.OnChange += CursorIconWatcher_OnChange;
+ Conductor.OutgoingMessages.SendDeviceInfo(Conductor.ServiceID, Environment.MachineName).Wait();
+ Conductor.StartWaitForViewerTimer();
+ HandleConnection(Conductor).Wait();
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+ }
+
+ private static void ScreenCastInitiated(object sender, Tuple viewerAndRequester)
+ {
+ ICapturer capturer;
+ try
+ {
+ capturer = new X11Capture();
+ //await Conductor.OutgoingMessages.SendCursorChange(CursorIconWatcher.GetCurrentCursor(), new List() { viewerAndRequester.Item1 });
+ ScreenCaster.BeginScreenCasting(viewerAndRequester.Item1, viewerAndRequester.Item2, Conductor.OutgoingMessages, capturer, Conductor);
+ Conductor.OutgoingMessages.SendConnectionFailedToViewers(new List() { viewerAndRequester.Item1 }).Wait();
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+ }
+
+ //public static async void CursorIconWatcher_OnChange(object sender, CursorInfo cursor)
+ //{
+ // await Conductor.OutgoingMessages.SendCursorChange(cursor, Conductor.Viewers.Keys.ToList());
+ //}
+
+ public static async Task HandleConnection(Conductor conductor)
+ {
+ await Task.Delay(100);
+
+ }
+
+ private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ Logger.Write((Exception)e.ExceptionObject);
+ }
+ }
+}
diff --git a/Remotely_ScreenCast_Linux/Remotely_ScreenCast_Linux.csproj b/Remotely_ScreenCast.Linux/Remotely_ScreenCast.Linux.csproj
similarity index 52%
rename from Remotely_ScreenCast_Linux/Remotely_ScreenCast_Linux.csproj
rename to Remotely_ScreenCast.Linux/Remotely_ScreenCast.Linux.csproj
index 6d0d3245..70ca8bd4 100644
--- a/Remotely_ScreenCast_Linux/Remotely_ScreenCast_Linux.csproj
+++ b/Remotely_ScreenCast.Linux/Remotely_ScreenCast.Linux.csproj
@@ -3,7 +3,6 @@
Exe
netcoreapp2.2
- Remotely_ScreenCast
@@ -15,25 +14,12 @@
-
-
-
- CursorInfo.d.ts
- DtsGenerator
-
-
-
-
-
- CursorInfo.cs
- True
- True
-
+
diff --git a/Remotely_ScreenCast.Linux/X11Interop/Xlib.cs b/Remotely_ScreenCast.Linux/X11Interop/Xlib.cs
new file mode 100644
index 00000000..bddd99ba
--- /dev/null
+++ b/Remotely_ScreenCast.Linux/X11Interop/Xlib.cs
@@ -0,0 +1,154 @@
+/*
+
+Copyright 1985, 1986, 1987, 1991, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Security.Permissions;
+using System.Text;
+
+namespace Remotely_ScreenCast.Linux.X11Interop
+{
+ public static unsafe class Xlib
+ {
+
+ #region Structs
+ public struct XImage
+ {
+ public int width;
+ public int height; /* size of image */
+ public int xoffset; /* number of pixels offset in X direction */
+ public int format; /* XYBitmap, XYPixmap, ZPixmap */
+ public char* data; /* pointer to image data */
+ public int byte_order; /* data byte order, LSBFirst, MSBFirst */
+ public int bitmap_unit; /* quant. of scanline 8, 16, 32 */
+ public int bitmap_bit_order; /* LSBFirst, MSBFirst */
+ public int bitmap_pad; /* 8, 16, 32 either XY or ZPixmap */
+ public int depth; /* depth of image */
+ public int bytes_per_line; /* accelerator to next scanline */
+ public int bits_per_pixel; /* bits per pixel (ZPixmap) */
+ public ulong red_mask; /* bits in z arrangement */
+ public ulong green_mask;
+ public ulong blue_mask;
+ public IntPtr obdata; /* hook for the object routines to hang on */
+
+ public XImage create_image()
+ {
+ return new XImage();
+ }
+
+ public int destroy_image()
+ {
+ return 0;
+ }
+
+ public ulong get_pixel()
+ {
+ return 0;
+ }
+ public XImage sub_image()
+ {
+ return new XImage();
+ }
+
+ public int add_pixel()
+ {
+ return 0;
+ }
+ }
+ public struct Screen {
+
+ public IntPtr ext_data; /* hook for extension to hang data */
+ public IntPtr *display;/* back pointer to display structure */ // TODO: XDisplay struct?
+ public IntPtr root; /* Root window id. */
+ public int width;
+ public int height; /* width and height of screen */
+ public int mwidth;
+ public int mheight; /* width and height of in millimeters */
+ public int ndepths; /* number of depths possible */
+ public uint depths; /* list of allowable depths on the screen */ //TODO: Depth[]
+ public int root_depth; /* bits per pixel */
+ public IntPtr root_visual; /* root visual */
+ public IntPtr default_gc; /* GC for the root root visual */
+ public IntPtr cmap; /* default color map */ // TODO: Colormap struct?
+ public ulong white_pixel;
+ public ulong black_pixel; /* White and Black pixel values */
+ public int max_maps, min_maps; /* max and min color maps */
+ public int backing_store; /* Never, WhenMapped, Always */
+ public bool save_unders;
+ public long root_input_mask; /* initial root input mask */
+ }
+ public struct Depth {
+
+ public int depth; /* this depth (Z) of the depth */
+ public int nvisuals; /* number of Visual types at this depth */
+ public Visual[] visuals; /* list of visuals possible at this depth */
+ }
+ public struct Visual {
+
+ public IntPtr ext_data; /* hook for extension to hang data */
+ public int visualid; /* visual id of this visual */
+ public ulong red_mask, green_mask, blue_mask; /* mask values */
+ public int bits_per_rgb; /* log base 2 of distinct color values */
+ public int map_entries; /* color map entries */
+ }
+
+ public class XExtData
+ {
+ public int number; /* number returned by XRegisterExtension */
+ public XExtData next; /* next item on list of data for structure */
+ public IntPtr private_data; /* data private to this extension. */
+ }
+ #endregion Structs
+
+ #region Imports
+ [DllImport("libX11")]
+ public static extern XImage XGetImage(IntPtr display, IntPtr drawable, int x, int y, uint width, uint height, ulong plane_mask, int format);
+ [DllImport("libX11")]
+ public static extern int XScreenCount(IntPtr display);
+ [DllImport("libX11")]
+ public static extern int XDefaultScreen(IntPtr display);
+ [DllImport("libX11")]
+ public static extern IntPtr XOpenDisplay(string display_name);
+ [DllImport("libX11")]
+ public static extern IntPtr XRootWindow(IntPtr display, int screen_number);
+
+ [DllImport("libX11")]
+ public static extern XImage* XGetSubImage(IntPtr display, IntPtr drawable, int x, int y, uint width, uint height, ulong plane_mask, int format, XImage dest_image, int dest_x, int dest_y);
+ [DllImport("libX11")]
+ public static extern IntPtr XScreenOfDisplay(IntPtr display, int screen_number);
+ [DllImport("libX11")]
+ public static extern int XDisplayWidth(IntPtr display, int screen_number);
+ [DllImport("libX11")]
+ public static extern int XDisplayHeight(IntPtr display, int screen_number);
+ [DllImport("libX11")]
+ public static extern int XWidthOfScreen(IntPtr screen);
+ [DllImport("libX11")]
+ public static extern int XHeightOfScreen(IntPtr screen);
+ #endregion Imports
+ }
+}
diff --git a/Remotely_ScreenCast/App.config b/Remotely_ScreenCast.Win/App.config
similarity index 100%
rename from Remotely_ScreenCast/App.config
rename to Remotely_ScreenCast.Win/App.config
diff --git a/Remotely_ScreenCast/Capture/BitBltCapture.cs b/Remotely_ScreenCast.Win/Capture/BitBltCapture.cs
similarity index 88%
rename from Remotely_ScreenCast/Capture/BitBltCapture.cs
rename to Remotely_ScreenCast.Win/Capture/BitBltCapture.cs
index be73e88a..8d64c918 100644
--- a/Remotely_ScreenCast/Capture/BitBltCapture.cs
+++ b/Remotely_ScreenCast.Win/Capture/BitBltCapture.cs
@@ -12,10 +12,11 @@ using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;
-using Remotely_ScreenCast.Utilities;
+using Remotely_ScreenCast.Core.Utilities;
using System.Threading;
+using Remotely_ScreenCast.Core.Capture;
-namespace Remotely_ScreenCast.Capture
+namespace Remotely_ScreenCast.Win.Capture
{
public class BitBltCapture : ICapturer
{
@@ -56,6 +57,10 @@ namespace Remotely_ScreenCast.Capture
}
}
public Rectangle CurrentScreenBounds { get; set; } = Screen.PrimaryScreen.Bounds;
+ public int ScreenCount { get; set; } = Screen.AllScreens.Length;
+ public double VirtualScreenHeight { get; set; } = SystemInformation.VirtualScreen.Width;
+ public double VirtualScreenWidth { get; set; } = SystemInformation.VirtualScreen.Height;
+
private int selectedScreen = Screen.AllScreens.ToList().IndexOf(Screen.PrimaryScreen);
private Graphics graphic;
diff --git a/Remotely_ScreenCast/Capture/CursorIconWatcher.cs b/Remotely_ScreenCast.Win/Capture/CursorIconWatcher.cs
similarity index 94%
rename from Remotely_ScreenCast/Capture/CursorIconWatcher.cs
rename to Remotely_ScreenCast.Win/Capture/CursorIconWatcher.cs
index 2c0fd667..e3a360b8 100644
--- a/Remotely_ScreenCast/Capture/CursorIconWatcher.cs
+++ b/Remotely_ScreenCast.Win/Capture/CursorIconWatcher.cs
@@ -1,4 +1,5 @@
-using Remotely_ScreenCast.Models;
+using Remotely_ScreenCast.Core;
+using Remotely_ScreenCast.Core.Models;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -12,17 +13,22 @@ using System.Timers;
using System.Windows.Forms;
using Win32;
-namespace Remotely_ScreenCast.Capture
+namespace Remotely_ScreenCast.Win.Capture
{
///
/// A class that can be used to watch for cursor icon changes.
///
public class CursorIconWatcher
{
- public static CursorIconWatcher Current { get; } = new CursorIconWatcher();
+ public CursorIconWatcher(Conductor conductor)
+ {
+ Conductor = conductor;
+ }
public event EventHandler OnChange;
private System.Timers.Timer ChangeTimer { get; set; }
private string PreviousCursorHandle { get; set; }
+ public Conductor Conductor { get; }
+
private User32.CursorInfo cursorInfo;
diff --git a/Remotely_ScreenCast/Capture/DXCapture.cs b/Remotely_ScreenCast.Win/Capture/DXCapture.cs
similarity index 94%
rename from Remotely_ScreenCast/Capture/DXCapture.cs
rename to Remotely_ScreenCast.Win/Capture/DXCapture.cs
index ce80ac8e..3d5f3542 100644
--- a/Remotely_ScreenCast/Capture/DXCapture.cs
+++ b/Remotely_ScreenCast.Win/Capture/DXCapture.cs
@@ -1,4 +1,5 @@
-using Remotely_ScreenCast.Utilities;
+using Remotely_ScreenCast.Core.Capture;
+using Remotely_ScreenCast.Core.Utilities;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
@@ -8,9 +9,10 @@ using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading;
+using System.Windows.Forms;
using Win32;
-namespace Remotely_ScreenCast.Capture
+namespace Remotely_ScreenCast.Win.Capture
{
public class DXCapture : ICapturer
{
@@ -63,6 +65,10 @@ namespace Remotely_ScreenCast.Capture
}
}
+ public int ScreenCount { get; set; } = Screen.AllScreens.Length;
+ public double VirtualScreenHeight { get; set; } = SystemInformation.VirtualScreen.Width;
+ public double VirtualScreenWidth { get; set; } = SystemInformation.VirtualScreen.Height;
+
public void Capture()
{
try
diff --git a/Remotely_ScreenCast/FodyWeavers.xml b/Remotely_ScreenCast.Win/FodyWeavers.xml
similarity index 100%
rename from Remotely_ScreenCast/FodyWeavers.xml
rename to Remotely_ScreenCast.Win/FodyWeavers.xml
diff --git a/Remotely_ScreenCast/FodyWeavers.xsd b/Remotely_ScreenCast.Win/FodyWeavers.xsd
similarity index 100%
rename from Remotely_ScreenCast/FodyWeavers.xsd
rename to Remotely_ScreenCast.Win/FodyWeavers.xsd
diff --git a/Remotely_ScreenCast.Win/Input/WinInput.cs b/Remotely_ScreenCast.Win/Input/WinInput.cs
new file mode 100644
index 00000000..4667f71a
--- /dev/null
+++ b/Remotely_ScreenCast.Win/Input/WinInput.cs
@@ -0,0 +1,224 @@
+using Remotely_ScreenCast.Core.Input;
+using System;
+using Win32;
+using static Win32.User32;
+
+namespace Remotely_ScreenCast.Win.Input
+{
+ public class WinInput : IKeyboardMouseInput
+ {
+ public uint SendLeftMouseDown(double percentX, double percentY)
+ {
+ // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
+ var normalizedX = percentX * 65535D;
+ var normalizedY = percentY * 65535D;
+ var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.LEFTDOWN | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+ public uint SendLeftMouseUp(double percentX, double percentY)
+ {
+ // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
+ var normalizedX = percentX * 65535D;
+ var normalizedY = percentY * 65535D;
+ var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.LEFTUP | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+ public uint SendRightMouseDown(double percentX, double percentY)
+ {
+ // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
+ var normalizedX = percentX * 65535D;
+ var normalizedY = percentY * 65535D;
+ var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.RIGHTDOWN | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+ public uint SendRightMouseUp(double percentX, double percentY)
+ {
+ // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
+ var normalizedX = percentX * 65535D;
+ var normalizedY = percentY * 65535D;
+ var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.RIGHTUP | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+ public uint SendMouseMove(double percentX, double percentY)
+ {
+ // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
+ var normalizedX = percentX * 65535D;
+ var normalizedY = percentY * 65535D;
+ var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.MOVE | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+ public uint SendMouseWheel(int deltaY)
+ {
+ if (deltaY < 0)
+ {
+ deltaY = -120;
+ }
+ else if (deltaY > 0)
+ {
+ deltaY = 120;
+ }
+ var union = new User32.InputUnion() { mi = new User32.MOUSEINPUT() { dwFlags = MOUSEEVENTF.WHEEL, dx = 0, dy = 0, time = 0, mouseData = deltaY, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new User32.INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new User32.INPUT[] { input }, INPUT.Size);
+ }
+ public void SendKeyDown(string key)
+ {
+ var keyCode = ConvertJavaScriptKeyToVirtualKey(key);
+ var union = new InputUnion()
+ {
+ ki = new KEYBDINPUT()
+ {
+ wVk = keyCode,
+ wScan = 0,
+ time = 0,
+ dwExtraInfo = GetMessageExtraInfo()
+ }
+ };
+ var input = new INPUT() { type = InputType.KEYBOARD, U = union };
+ SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+ public void SendKeyUp(string key)
+ {
+ var keyCode = ConvertJavaScriptKeyToVirtualKey(key);
+ var union = new InputUnion()
+ {
+ ki = new KEYBDINPUT()
+ {
+ wVk = keyCode,
+ wScan = 0,
+ time = 0,
+ dwFlags = KEYEVENTF.KEYUP,
+ dwExtraInfo = GetMessageExtraInfo()
+ }
+ };
+ var input = new INPUT() { type = InputType.KEYBOARD, U = union };
+ SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+
+ private VirtualKey ConvertJavaScriptKeyToVirtualKey(string key)
+ {
+ VirtualKey keyCode;
+ switch (key)
+ {
+ case "Down":
+ case "ArrowDown":
+ keyCode = VirtualKey.DOWN;
+ break;
+ case "Up":
+ case "ArrowUp":
+ keyCode = VirtualKey.UP;
+ break;
+ case "Left":
+ case "ArrowLeft":
+ keyCode = VirtualKey.LEFT;
+ break;
+ case "Right":
+ case "ArrowRight":
+ keyCode = VirtualKey.RIGHT;
+ break;
+ case "Enter":
+ keyCode = VirtualKey.RETURN;
+ break;
+ case "Esc":
+ case "Escape":
+ keyCode = VirtualKey.ESCAPE;
+ break;
+ case "Alt":
+ keyCode = VirtualKey.MENU;
+ break;
+ case "Control":
+ keyCode = VirtualKey.CONTROL;
+ break;
+ case "Shift":
+ keyCode = VirtualKey.SHIFT;
+ break;
+ case "PAUSE":
+ keyCode = VirtualKey.PAUSE;
+ break;
+ case "BREAK":
+ keyCode = VirtualKey.PAUSE;
+ break;
+ case "Backspace":
+ keyCode = VirtualKey.BACK;
+ break;
+ case "Tab":
+ keyCode = VirtualKey.TAB;
+ break;
+ case "CapsLock":
+ keyCode = VirtualKey.CAPITAL;
+ break;
+ case "Delete":
+ keyCode = VirtualKey.DELETE;
+ break;
+ case "Home":
+ keyCode = VirtualKey.HOME;
+ break;
+ case "End":
+ keyCode = VirtualKey.END;
+ break;
+ case "PageUp":
+ keyCode = VirtualKey.PRIOR;
+ break;
+ case "PageDown":
+ keyCode = VirtualKey.NEXT;
+ break;
+ case "NumLock":
+ keyCode = VirtualKey.NUMLOCK;
+ break;
+ case "Insert":
+ keyCode = VirtualKey.INSERT;
+ break;
+ case "ScrollLock":
+ keyCode = VirtualKey.SCROLL;
+ break;
+ case "F1":
+ keyCode = VirtualKey.F1;
+ break;
+ case "F2":
+ keyCode = VirtualKey.F2;
+ break;
+ case "F3":
+ keyCode = VirtualKey.F3;
+ break;
+ case "F4":
+ keyCode = VirtualKey.F4;
+ break;
+ case "F5":
+ keyCode = VirtualKey.F5;
+ break;
+ case "F6":
+ keyCode = VirtualKey.F6;
+ break;
+ case "F7":
+ keyCode = VirtualKey.F7;
+ break;
+ case "F8":
+ keyCode = VirtualKey.F8;
+ break;
+ case "F9":
+ keyCode = VirtualKey.F9;
+ break;
+ case "F10":
+ keyCode = VirtualKey.F10;
+ break;
+ case "F11":
+ keyCode = VirtualKey.F11;
+ break;
+ case "F12":
+ keyCode = VirtualKey.F12;
+ break;
+ default:
+ keyCode = (VirtualKey)VkKeyScan(Convert.ToChar(key));
+ break;
+ }
+ return keyCode;
+ }
+
+
+ }
+}
diff --git a/Remotely_ScreenCast.Win/Program.cs b/Remotely_ScreenCast.Win/Program.cs
new file mode 100644
index 00000000..72046330
--- /dev/null
+++ b/Remotely_ScreenCast.Win/Program.cs
@@ -0,0 +1,150 @@
+using Microsoft.AspNetCore.SignalR.Client;
+using Microsoft.Extensions.DependencyInjection;
+using Remotely_ScreenCast.Core;
+using Remotely_ScreenCast.Core.Capture;
+using Remotely_ScreenCast.Core.Enums;
+using Remotely_ScreenCast.Core.Models;
+using Remotely_ScreenCast.Core.Sockets;
+using Remotely_ScreenCast.Core.Utilities;
+using Remotely_ScreenCast.Win.Capture;
+using Remotely_ScreenCast.Win.Input;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Win32;
+
+namespace Remotely_ScreenCast.Win
+{
+ public class Program
+ {
+ public static Conductor Conductor { get; private set; }
+ public static CursorIconWatcher CursorIconWatcher { get; private set; }
+
+ public static void Main(string[] args)
+ {
+ try
+ {
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ Conductor = new Conductor();
+ Conductor.ProcessArgs(args);
+ Conductor.Connect().Wait();
+ Conductor.SetMessageHandlers(new WinInput());
+ Conductor.ScreenCastInitiated += ScreenCastInitiated;
+ CursorIconWatcher = new CursorIconWatcher(Conductor);
+ CursorIconWatcher.OnChange += CursorIconWatcher_OnChange;
+ Conductor.OutgoingMessages.SendDeviceInfo(Conductor.ServiceID, Environment.MachineName).Wait();
+ CheckInitialDesktop();
+ CheckForRelaunch();
+ Conductor.StartWaitForViewerTimer();
+ HandleConnection(Conductor).Wait();
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+ }
+
+ private static void CheckForRelaunch()
+ {
+
+ if (Conductor.ArgDict.ContainsKey("relaunch"))
+ {
+ Logger.Write($"Resuming after relaunch in desktop {Conductor.CurrentDesktopName}.");
+ var viewersString = Conductor.ArgDict["viewers"];
+ var viewerIDs = viewersString.Split(",".ToCharArray());
+ Conductor.OutgoingMessages.NotifyViewersRelaunchedScreenCasterReady(viewerIDs).Wait();
+ }
+ else
+ {
+ Conductor.OutgoingMessages.NotifyRequesterUnattendedReady(Conductor.RequesterID).Wait();
+ }
+ }
+
+ private static async void ScreenCastInitiated(object sender, Tuple viewerAndRequester)
+ {
+ ICapturer capturer;
+ try
+ {
+ if (Conductor.Viewers.Count == 0)
+ {
+ capturer = new DXCapture();
+ capturer.Init();
+ }
+ else
+ {
+ capturer = new BitBltCapture();
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ capturer = new BitBltCapture();
+ }
+ await Conductor.OutgoingMessages.SendCursorChange(CursorIconWatcher.GetCurrentCursor(), new List() { viewerAndRequester.Item1 });
+ ScreenCaster.BeginScreenCasting(viewerAndRequester.Item1, viewerAndRequester.Item2, Conductor.OutgoingMessages, capturer, Conductor);
+ }
+
+ public static async void CursorIconWatcher_OnChange(object sender, CursorInfo cursor)
+ {
+ await Conductor.OutgoingMessages.SendCursorChange(cursor, Conductor.Viewers.Keys.ToList());
+ }
+
+ public static async Task HandleConnection(Conductor conductor)
+ {
+ while (true)
+ {
+ var desktopName = Win32Interop.GetCurrentDesktop();
+ if (desktopName.ToLower() != conductor.CurrentDesktopName.ToLower() && conductor.Viewers.Count > 0)
+ {
+ conductor.CurrentDesktopName = desktopName;
+ Logger.Write($"Switching desktops to {desktopName}.");
+ // TODO: SetThradDesktop causes issues with input after switching.
+ //var inputDesktop = Win32Interop.OpenInputDesktop();
+ //User32.SetThreadDesktop(inputDesktop);
+ //User32.CloseDesktop(inputDesktop);
+ conductor.Connection.InvokeAsync("SwitchingDesktops", conductor.Viewers.Keys.ToList()).Wait();
+ var result = Win32Interop.OpenInteractiveProcess(Assembly.GetExecutingAssembly().Location + $" -mode {conductor.Mode.ToString()} -requester {conductor.RequesterID} -serviceid {conductor.ServiceID} -host {conductor.Host} -relaunch true -desktop {desktopName} -viewers {String.Join(",", conductor.Viewers.Keys.ToList())}", desktopName, true, out _);
+ if (!result)
+ {
+ Logger.Write($"Desktop switch to {desktopName} failed.");
+ conductor.OutgoingMessages.SendConnectionFailedToViewers(conductor.Viewers.Keys.ToList()).Wait();
+ }
+ }
+ await Task.Delay(100);
+ }
+ }
+ private static void CheckInitialDesktop()
+ {
+ var desktopName = Win32Interop.GetCurrentDesktop();
+ if (desktopName.ToLower() != Conductor.CurrentDesktopName.ToLower())
+ {
+ Conductor.CurrentDesktopName = desktopName;
+ Logger.Write($"Setting initial desktop to {desktopName}.");
+ Conductor.ArgDict["desktop"] = desktopName;
+ var openProcessString = Assembly.GetExecutingAssembly().Location;
+ foreach (var arg in Conductor.ArgDict)
+ {
+ openProcessString += $" -{arg.Key} {arg.Value}";
+ }
+ var result = Win32Interop.OpenInteractiveProcess(openProcessString, desktopName, true, out _);
+ if (!result)
+ {
+ Logger.Write($"Desktop relaunch to {desktopName} failed.");
+ }
+ Environment.Exit(0);
+ }
+ }
+ private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ Logger.Write((Exception)e.ExceptionObject);
+ }
+ }
+}
diff --git a/Remotely_ScreenCast/Properties/AssemblyInfo.cs b/Remotely_ScreenCast.Win/Properties/AssemblyInfo.cs
similarity index 100%
rename from Remotely_ScreenCast/Properties/AssemblyInfo.cs
rename to Remotely_ScreenCast.Win/Properties/AssemblyInfo.cs
diff --git a/Remotely_ScreenCast.Win/Remotely_ScreenCast.Win.csproj b/Remotely_ScreenCast.Win/Remotely_ScreenCast.Win.csproj
new file mode 100644
index 00000000..56c69c13
--- /dev/null
+++ b/Remotely_ScreenCast.Win/Remotely_ScreenCast.Win.csproj
@@ -0,0 +1,200 @@
+
+
+
+
+
+ Debug
+ AnyCPU
+ {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}
+ Exe
+ Remotely_ScreenCast.Win
+ Remotely_ScreenCast
+ v4.7.2
+ 512
+ true
+ true
+
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+
+
+
+ ..\packages\Costura.Fody.3.3.3\lib\net40\Costura.dll
+
+
+ ..\packages\MessagePack.1.7.3.4\lib\net47\MessagePack.dll
+
+
+ ..\packages\Microsoft.AspNetCore.Connections.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Connections.Abstractions.dll
+
+
+ ..\packages\Microsoft.AspNetCore.Http.Connections.Client.1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Client.dll
+
+
+ ..\packages\Microsoft.AspNetCore.Http.Connections.Common.1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Common.dll
+
+
+ ..\packages\Microsoft.AspNetCore.Http.Features.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll
+
+
+ ..\packages\Microsoft.AspNetCore.SignalR.Client.1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Client.dll
+
+
+ ..\packages\Microsoft.AspNetCore.SignalR.Client.Core.1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Client.Core.dll
+
+
+ ..\packages\Microsoft.AspNetCore.SignalR.Common.1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Common.dll
+
+
+ ..\packages\Microsoft.AspNetCore.SignalR.Protocols.Json.1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.Json.dll
+
+
+ ..\packages\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.dll
+
+
+ ..\packages\Microsoft.Extensions.Configuration.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll
+
+
+ ..\packages\Microsoft.Extensions.Configuration.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll
+
+
+ ..\packages\Microsoft.Extensions.Configuration.Binder.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll
+
+
+ ..\packages\Microsoft.Extensions.DependencyInjection.2.2.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll
+
+
+ ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll
+
+
+ ..\packages\Microsoft.Extensions.Logging.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll
+
+
+ ..\packages\Microsoft.Extensions.Logging.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll
+
+
+ ..\packages\Microsoft.Extensions.Options.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll
+
+
+ ..\packages\Microsoft.Extensions.Primitives.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll
+
+
+ ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll
+
+
+ ..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll
+
+
+ ..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll
+
+
+ ..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll
+
+
+
+ ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll
+
+
+ ..\packages\System.ComponentModel.Annotations.4.5.0\lib\net461\System.ComponentModel.Annotations.dll
+
+
+
+
+
+ ..\packages\System.Drawing.Common.4.5.1\lib\net461\System.Drawing.Common.dll
+
+
+ ..\packages\System.IO.Pipelines.4.5.3\lib\netstandard2.0\System.IO.Pipelines.dll
+
+
+ ..\packages\System.Memory.4.5.2\lib\netstandard2.0\System.Memory.dll
+
+
+
+ ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ ..\packages\System.Threading.Channels.4.5.0\lib\netstandard2.0\System.Threading.Channels.dll
+
+
+ ..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {b04a1728-2e87-491e-bc7f-f575a1754def}
+ Remotely_ScreenCast.Core
+
+
+
+
+
+
+
+
+ if $(ConfigurationName) == Debug (
+ md "$(SolutionDir)Remotely_Agent\bin\Debug\netcoreapp2.2\ScreenCast\"
+ copy /y "$(TargetPath)" "$(SolutionDir)Remotely_Agent\bin\Debug\netcoreapp2.2\ScreenCast\"
+)
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/Remotely_ScreenCast/Win32/ADVAPI32.cs b/Remotely_ScreenCast.Win/Win32/ADVAPI32.cs
similarity index 100%
rename from Remotely_ScreenCast/Win32/ADVAPI32.cs
rename to Remotely_ScreenCast.Win/Win32/ADVAPI32.cs
diff --git a/Remotely_ScreenCast/Win32/GDI32.cs b/Remotely_ScreenCast.Win/Win32/GDI32.cs
similarity index 100%
rename from Remotely_ScreenCast/Win32/GDI32.cs
rename to Remotely_ScreenCast.Win/Win32/GDI32.cs
diff --git a/Remotely_ScreenCast/Win32/Kernel32.cs b/Remotely_ScreenCast.Win/Win32/Kernel32.cs
similarity index 100%
rename from Remotely_ScreenCast/Win32/Kernel32.cs
rename to Remotely_ScreenCast.Win/Win32/Kernel32.cs
diff --git a/Remotely_ScreenCast/Win32/SECUR32.cs b/Remotely_ScreenCast.Win/Win32/SECUR32.cs
similarity index 100%
rename from Remotely_ScreenCast/Win32/SECUR32.cs
rename to Remotely_ScreenCast.Win/Win32/SECUR32.cs
diff --git a/Remotely_ScreenCast/Win32/User32.cs b/Remotely_ScreenCast.Win/Win32/User32.cs
similarity index 100%
rename from Remotely_ScreenCast/Win32/User32.cs
rename to Remotely_ScreenCast.Win/Win32/User32.cs
diff --git a/Remotely_ScreenCast/Win32/WTSAPI32.cs b/Remotely_ScreenCast.Win/Win32/WTSAPI32.cs
similarity index 100%
rename from Remotely_ScreenCast/Win32/WTSAPI32.cs
rename to Remotely_ScreenCast.Win/Win32/WTSAPI32.cs
diff --git a/Remotely_ScreenCast.Win/Win32/Win32Interop.cs b/Remotely_ScreenCast.Win/Win32/Win32Interop.cs
new file mode 100644
index 00000000..e7577d7a
--- /dev/null
+++ b/Remotely_ScreenCast.Win/Win32/Win32Interop.cs
@@ -0,0 +1,140 @@
+using Win32;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using static Win32.ADVAPI32;
+using static Win32.User32;
+using System.Windows.Forms;
+
+namespace Win32
+{
+ public class Win32Interop
+ {
+ public static bool OpenInteractiveProcess(string applicationName, string desktopName, bool hiddenWindow, out PROCESS_INFORMATION procInfo)
+ {
+ uint winlogonPid = 0;
+ IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
+ procInfo = new PROCESS_INFORMATION();
+
+ // Obtain session ID for active session.
+ uint dwSessionId = Kernel32.WTSGetActiveConsoleSessionId();
+
+ // Check for RDP session. If active, use that session ID instead.
+ var rdpSessionID = GetRDPSession();
+ if (rdpSessionID > 0)
+ {
+ dwSessionId = rdpSessionID;
+ }
+
+ // Obtain the process ID of the winlogon process that is running within the currently active session.
+ Process[] processes = Process.GetProcessesByName("winlogon");
+ foreach (Process p in processes)
+ {
+ if ((uint)p.SessionId == dwSessionId)
+ {
+ winlogonPid = (uint)p.Id;
+ }
+ }
+
+ // Obtain a handle to the winlogon process.
+ hProcess = Kernel32.OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
+
+ // Obtain a handle to the access token of the winlogon process.
+ if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
+ {
+ Kernel32.CloseHandle(hProcess);
+ return false;
+ }
+
+ // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser.
+ SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
+ sa.Length = Marshal.SizeOf(sa);
+
+ // Copy the access token of the winlogon process; the newly created token will be a primary token.
+ if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out hUserTokenDup))
+ {
+ Kernel32.CloseHandle(hProcess);
+ Kernel32.CloseHandle(hPToken);
+ return false;
+ }
+
+ // By default, CreateProcessAsUser creates a process on a non-interactive window station, meaning
+ // the window station has a desktop that is invisible and the process is incapable of receiving
+ // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
+ // interaction with the new process.
+ STARTUPINFO si = new STARTUPINFO();
+ si.cb = Marshal.SizeOf(si);
+ si.lpDesktop = @"winsta0\" + desktopName;
+
+ // Flags that specify the priority and creation method of the process.
+ uint dwCreationFlags;
+ if (hiddenWindow)
+ {
+ dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS;
+ }
+ else
+ {
+ dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
+ }
+
+ // Create a new process in the current user's logon session.
+ bool result = CreateProcessAsUser(hUserTokenDup, null, applicationName, ref sa, ref sa, false, dwCreationFlags, IntPtr.Zero, null, ref si, out procInfo);
+
+ // Invalidate the handles.
+ Kernel32.CloseHandle(hProcess);
+ Kernel32.CloseHandle(hPToken);
+ Kernel32.CloseHandle(hUserTokenDup);
+
+ return result;
+ }
+
+ public static uint GetRDPSession()
+ {
+ IntPtr ppSessionInfo = IntPtr.Zero;
+ Int32 count = 0;
+ Int32 retval = WTSAPI32.WTSEnumerateSessions(WTSAPI32.WTS_CURRENT_SERVER_HANDLE, 0, 1, ref ppSessionInfo, ref count);
+ Int32 dataSize = Marshal.SizeOf(typeof(WTSAPI32.WTS_SESSION_INFO));
+ var sessList = new List();
+ Int64 current = (Int64)ppSessionInfo;
+
+ if (retval != 0)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ WTSAPI32.WTS_SESSION_INFO sessInf = (WTSAPI32.WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTSAPI32.WTS_SESSION_INFO));
+ current += dataSize;
+ sessList.Add(sessInf);
+ }
+ }
+ uint retVal = 0;
+ var rdpSession = sessList.Find(ses => ses.pWinStationName.ToLower().Contains("rdp") && ses.State == 0);
+ if (sessList.Exists(ses => ses.pWinStationName.ToLower().Contains("rdp") && ses.State == 0))
+ {
+ retVal = (uint)rdpSession.SessionID;
+ }
+ return retVal;
+ }
+ public static IntPtr OpenInputDesktop()
+ {
+ return User32.OpenInputDesktop(0, false, ACCESS_MASK.GENERIC_ALL);
+ }
+ public static string GetCurrentDesktop()
+ {
+ var inputDesktop = OpenInputDesktop();
+ byte[] deskBytes = new byte[256];
+ uint lenNeeded;
+ var success = GetUserObjectInformationW(inputDesktop, UOI_NAME, deskBytes, 256, out lenNeeded);
+ if (!success)
+ {
+ CloseDesktop(inputDesktop);
+ return "Default";
+ }
+ var desktopName = Encoding.Unicode.GetString(deskBytes.Take((int)lenNeeded).ToArray()).Replace("\0", "");
+ CloseDesktop(inputDesktop);
+ return desktopName;
+ }
+ }
+}
diff --git a/Remotely_ScreenCast/packages.config b/Remotely_ScreenCast.Win/packages.config
similarity index 93%
rename from Remotely_ScreenCast/packages.config
rename to Remotely_ScreenCast.Win/packages.config
index b1d2ab9c..fd5ad1ab 100644
--- a/Remotely_ScreenCast/packages.config
+++ b/Remotely_ScreenCast.Win/packages.config
@@ -1,7 +1,7 @@
-
-
+
+
@@ -27,6 +27,7 @@
+
diff --git a/Remotely_ScreenCast/Capture/CaptureMode.cs b/Remotely_ScreenCast/Capture/CaptureMode.cs
deleted file mode 100644
index d8abc4ef..00000000
--- a/Remotely_ScreenCast/Capture/CaptureMode.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely_ScreenCast.Capture
-{
- public enum CaptureMode
- {
- BitBtl,
- DirectX
- }
-}
diff --git a/Remotely_ScreenCast/Program.cs b/Remotely_ScreenCast/Program.cs
deleted file mode 100644
index 30b7cee9..00000000
--- a/Remotely_ScreenCast/Program.cs
+++ /dev/null
@@ -1,206 +0,0 @@
-using Microsoft.AspNetCore.SignalR.Client;
-using Microsoft.Extensions.DependencyInjection;
-using Remotely_ScreenCast;
-using Remotely_ScreenCast.Capture;
-using Remotely_ScreenCast.Enums;
-using Remotely_ScreenCast.Models;
-using Remotely_ScreenCast.Sockets;
-using Remotely_ScreenCast.Utilities;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Drawing;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using Win32;
-
-namespace Remotely_ScreenCast
-{
- public class Program
- {
- public static AppMode Mode { get; private set; }
- public static string RequesterID { get; private set; }
- public static string ServiceID { get; private set; }
- public static string Host { get; private set; }
- public static HubConnection Connection { get; private set; }
- public static OutgoingMessages OutgoingMessages { get; private set; }
- public static string CurrentDesktopName { get; set; }
- public static ConcurrentDictionary Viewers { get; } = new ConcurrentDictionary();
- public static Dictionary ArgDict { get; set; }
-
- public static void Main(string[] args)
- {
- try
- {
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
- ProcessArgs(args);
- Connect().Wait();
- SetEventHandlers();
- HandleConnection().Wait();
- }
- catch (Exception ex)
- {
- Logger.Write(ex);
- }
- }
-
- public static async Task HandleConnection()
- {
- OutgoingMessages.SendDeviceInfo(ServiceID, Environment.MachineName).Wait();
-
-
- if (Mode == AppMode.Unattended)
- {
- var desktopName = Win32Interop.GetCurrentDesktop();
- if (desktopName.ToLower() != CurrentDesktopName.ToLower())
- {
- CurrentDesktopName = desktopName;
- Logger.Write($"Setting initial desktop to {desktopName}.");
- ArgDict["desktop"] = desktopName;
- var openProcessString = Assembly.GetExecutingAssembly().Location;
- foreach (var arg in ArgDict)
- {
- openProcessString += $" -{arg.Key} {arg.Value}";
- }
- var result = Win32Interop.OpenInteractiveProcess(openProcessString, desktopName, true, out _);
- if (!result)
- {
- Logger.Write($"Desktop relaunch to {desktopName} failed.");
- }
- Environment.Exit(0);
- }
-
- if (ArgDict.ContainsKey("relaunch"))
- {
- Logger.Write($"Resuming after relaunch in desktop {CurrentDesktopName}.");
- var viewersString = ArgDict["viewers"];
- var viewerIDs = viewersString.Split(",".ToCharArray());
- OutgoingMessages.NotifyViewersRelaunchedScreenCasterReady(viewerIDs).Wait();
- }
- else
- {
- OutgoingMessages.NotifyRequesterUnattendedReady(RequesterID).Wait();
- }
-
- StartWaitForViewerTimer();
- }
- else if (Mode == AppMode.Normal)
- {
- OutgoingMessages.GetSessionID().Wait();
- }
-
-
-
- while (true)
- {
- if (Mode == AppMode.Unattended)
- {
- var desktopName = Win32Interop.GetCurrentDesktop();
- if (desktopName.ToLower() != CurrentDesktopName.ToLower() && Viewers.Count > 0)
- {
- CurrentDesktopName = desktopName;
- Logger.Write($"Switching desktops to {desktopName}.");
- // TODO: SetThradDesktop causes issues with input after switching.
- //var inputDesktop = Win32Interop.OpenInputDesktop();
- //User32.SetThreadDesktop(inputDesktop);
- //User32.CloseDesktop(inputDesktop);
- Connection.InvokeAsync("SwitchingDesktops", Viewers.Keys.ToList()).Wait();
- var result = Win32Interop.OpenInteractiveProcess(Assembly.GetExecutingAssembly().Location + $" -mode {Mode.ToString()} -requester {RequesterID} -serviceid {ServiceID} -host {Host} -relaunch true -desktop {desktopName} -viewers {String.Join(",", Viewers.Keys.ToList())}", desktopName, true, out _);
- if (!result)
- {
- Logger.Write($"Desktop switch to {desktopName} failed.");
- OutgoingMessages.SendConnectionFailedToViewers(Viewers.Keys.ToList()).Wait();
- }
- }
- }
- await Task.Delay(100);
- }
- }
-
- public static void SetEventHandlers()
- {
- OutgoingMessages = new OutgoingMessages(Connection);
-
- MessageHandlers.ApplyConnectionHandlers(Connection, OutgoingMessages);
-
- CursorIconWatcher.Current.OnChange += CursorIconWatcher_OnChange;
- }
-
- public static Task Connect()
- {
- Connection = new HubConnectionBuilder()
- .WithUrl($"{Host}/RCDeviceHub")
- .AddMessagePackProtocol()
- .Build();
-
- return Connection.StartAsync();
- }
-
-
- private static async void CursorIconWatcher_OnChange(object sender, CursorInfo cursor)
- {
- await OutgoingMessages.SendCursorChange(cursor, Viewers.Keys.ToList());
- }
-
- private static void StartWaitForViewerTimer()
- {
- var timer = new System.Timers.Timer(10000);
- timer.AutoReset = false;
- timer.Elapsed += (sender, arg) =>
- {
- // Shut down if no viewers have connected within 10 seconds.
- if (Viewers.Count == 0)
- {
- Logger.Write("No viewers connected after 10 seconds. Shutting down.");
- Environment.Exit(0);
- }
- };
- timer.Start();
- }
-
- private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
- {
- Logger.Write((Exception)e.ExceptionObject);
- }
-
- public static void ProcessArgs(string[] args)
- {
- ArgDict = new Dictionary();
-
- for (var i = 0; i < args.Length; i += 2)
- {
- var key = args?[i];
- if (key != null)
- {
- key = key.Trim().Replace("-", "").ToLower();
- var value = args?[i + 1];
- if (value != null)
- {
- ArgDict[key] = args[i + 1].Trim();
- }
- }
-
- }
-
- Mode = (AppMode)Enum.Parse(typeof(AppMode), Program.ArgDict["mode"]);
- Host = Program.ArgDict["host"];
-
- if (Mode == AppMode.Unattended)
- {
- RequesterID = Program.ArgDict["requester"];
- CurrentDesktopName = Program.ArgDict["desktop"];
- ServiceID = Program.ArgDict["serviceid"];
- }
-
- }
- public static EventHandler SessionIDChanged { get; set; }
- public static EventHandler ViewerRemoved { get; set; }
- public static EventHandler ViewerAdded { get; set; }
- public static EventHandler> ScreenCastRequested { get; set; }
- }
-}
diff --git a/Remotely_ScreenCast/Sockets/MessageHandlers.cs b/Remotely_ScreenCast/Sockets/MessageHandlers.cs
deleted file mode 100644
index e0c7e277..00000000
--- a/Remotely_ScreenCast/Sockets/MessageHandlers.cs
+++ /dev/null
@@ -1,229 +0,0 @@
-using Microsoft.AspNetCore.SignalR.Client;
-using Remotely_ScreenCast.Capture;
-using Remotely_ScreenCast.Utilities;
-using Remotely_ScreenCast;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using Win32;
-using System.Net;
-using System.IO;
-using System.Diagnostics;
-using Remotely_ScreenCast.Models;
-
-namespace Remotely_ScreenCast.Sockets
-{
- public class MessageHandlers
- {
- public static void ApplyConnectionHandlers(HubConnection hubConnection, OutgoingMessages outgoingMessages)
- {
- hubConnection.Closed += (ex) =>
- {
- Logger.Write($"Error: {ex.Message}");
- Environment.Exit(1);
- return Task.CompletedTask;
- };
-
- hubConnection.On("GetScreenCast", (string viewerID, string requesterName) =>
- {
- try
- {
- ScreenCaster.BeginScreenCasting(viewerID, requesterName, outgoingMessages);
- }
- catch (Exception ex)
- {
- Logger.Write(ex);
- }
- });
-
- hubConnection.On("RequestScreenCast", (string viewerID, string requesterName) =>
- {
- Program.ScreenCastRequested?.Invoke(null, new Tuple(viewerID, requesterName));
- });
-
- hubConnection.On("KeyDown", (string key, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- var keyCode = Win32Interop.ConvertJavaScriptKeyToVirtualKey(key);
- Win32Interop.SendKeyDown((User32.VirtualKey)keyCode);
- }
- });
-
- hubConnection.On("KeyUp", (string key, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- var keyCode = Win32Interop.ConvertJavaScriptKeyToVirtualKey(key);
- Win32Interop.SendKeyUp((User32.VirtualKey)keyCode);
- }
- });
-
- hubConnection.On("KeyPress", async (string key, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- var keyCode = Win32Interop.ConvertJavaScriptKeyToVirtualKey(key);
- Win32Interop.SendKeyDown((User32.VirtualKey)keyCode);
- await Task.Delay(1);
- Win32Interop.SendKeyUp((User32.VirtualKey)keyCode);
- }
- });
-
- hubConnection.On("MouseMove", (double percentX, double percentY, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- var mousePoint = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
- Win32Interop.SendMouseMove(mousePoint.Item1, mousePoint.Item2);
- }
- });
-
- hubConnection.On("MouseDown", (int button, double percentX, double percentY, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- var mousePoint = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
- if (button == 0)
- {
- Win32Interop.SendLeftMouseDown((int)mousePoint.Item1, (int)mousePoint.Item2);
- }
- else if (button == 2)
- {
- Win32Interop.SendRightMouseDown((int)mousePoint.Item1, (int)mousePoint.Item2);
- }
- }
- });
-
- hubConnection.On("MouseUp", (int button, double percentX, double percentY, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- var mousePoint = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
- if (button == 0)
- {
- Win32Interop.SendLeftMouseUp((int)mousePoint.Item1, (int)mousePoint.Item2);
- }
- else if (button == 2)
- {
- Win32Interop.SendRightMouseUp((int)mousePoint.Item1, (int)mousePoint.Item2);
- }
- }
- });
-
- hubConnection.On("MouseWheel", (double deltaX, double deltaY, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- Win32Interop.SendMouseWheel(-(int)deltaY);
- }
- });
-
- hubConnection.On("ViewerDisconnected", async (string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer))
- {
- viewer.DisconnectRequested = true;
- }
- await hubConnection.InvokeAsync("ViewerDisconnected", viewerID);
- Program.ViewerRemoved?.Invoke(null, viewerID);
-
- });
- hubConnection.On("LatencyUpdate", (double latency, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer))
- {
- viewer.PendingFrames--;
- viewer.Latency = latency;
- }
- });
-
- hubConnection.On("SelectScreen", (int screenIndex, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer))
- {
- viewer.Capturer.SelectedScreen = screenIndex;
- }
- });
-
- hubConnection.On("TouchDown", (string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- User32.GetCursorPos(out var point);
- Win32Interop.SendLeftMouseDown(point.X, point.Y);
- }
- });
- hubConnection.On("LongPress", (string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- User32.GetCursorPos(out var point);
- Win32Interop.SendRightMouseDown(point.X, point.Y);
- Win32Interop.SendRightMouseUp(point.X, point.Y);
- }
- });
- hubConnection.On("TouchMove", (double moveX, double moveY, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- User32.GetCursorPos(out var point);
- Win32Interop.SendMouseMove(point.X + moveX, point.Y + moveY);
- }
- });
- hubConnection.On("TouchUp", (string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- User32.GetCursorPos(out var point);
- Win32Interop.SendLeftMouseUp(point.X, point.Y);
- }
- });
- hubConnection.On("Tap", (double percentX, double percentY, string viewerID) =>
- {
- if (Program.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
- {
- var mousePoint = ScreenCaster.GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
- Win32Interop.SendLeftMouseDown((int)mousePoint.Item1, (int)mousePoint.Item2);
- Win32Interop.SendLeftMouseUp((int)mousePoint.Item1, (int)mousePoint.Item2);
- }
- });
- hubConnection.On("SharedFileIDs", (List fileIDs) => {
- fileIDs.ForEach(id =>
- {
- var url = $"{Program.Host}/API/FileSharing/{id}";
- var webRequest = WebRequest.CreateHttp(url);
- var response = webRequest.GetResponse();
- var contentDisp = response.Headers["Content-Disposition"];
- var fileName = contentDisp
- .Split(";".ToCharArray())
- .FirstOrDefault(x => x.Trim().StartsWith("filename"))
- .Split("=".ToCharArray())[1];
-
- var legalChars = fileName.ToCharArray().Where(x => !Path.GetInvalidFileNameChars().Any(y => x == y));
-
- fileName = new string(legalChars.ToArray());
-
- var dirPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "RemotelySharedFiles")).FullName;
- var filePath = Path.Combine(dirPath, fileName);
- using (var fs = new FileStream(filePath, FileMode.Create))
- {
- using (var rs = response.GetResponseStream())
- {
- rs.CopyTo(fs);
- }
- }
- Process.Start("explorer.exe", dirPath);
- });
- });
-
- hubConnection.On("SessionID", (string sessionID) =>
- {
- Program.SessionIDChanged?.Invoke(null, sessionID);
- });
- }
- }
-}
diff --git a/Remotely_ScreenCast/Win32/Win32Interop.cs b/Remotely_ScreenCast/Win32/Win32Interop.cs
deleted file mode 100644
index ae82e784..00000000
--- a/Remotely_ScreenCast/Win32/Win32Interop.cs
+++ /dev/null
@@ -1,354 +0,0 @@
-using Win32;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using static Win32.ADVAPI32;
-using static Win32.User32;
-using System.Windows.Forms;
-
-namespace Win32
-{
- public class Win32Interop
- {
- public static bool OpenInteractiveProcess(string applicationName, string desktopName, bool hiddenWindow, out PROCESS_INFORMATION procInfo)
- {
- uint winlogonPid = 0;
- IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
- procInfo = new PROCESS_INFORMATION();
-
- // Obtain session ID for active session.
- uint dwSessionId = Kernel32.WTSGetActiveConsoleSessionId();
-
- // Check for RDP session. If active, use that session ID instead.
- var rdpSessionID = GetRDPSession();
- if (rdpSessionID > 0)
- {
- dwSessionId = rdpSessionID;
- }
-
- // Obtain the process ID of the winlogon process that is running within the currently active session.
- Process[] processes = Process.GetProcessesByName("winlogon");
- foreach (Process p in processes)
- {
- if ((uint)p.SessionId == dwSessionId)
- {
- winlogonPid = (uint)p.Id;
- }
- }
-
- // Obtain a handle to the winlogon process.
- hProcess = Kernel32.OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
-
- // Obtain a handle to the access token of the winlogon process.
- if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
- {
- Kernel32.CloseHandle(hProcess);
- return false;
- }
-
- // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser.
- SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
- sa.Length = Marshal.SizeOf(sa);
-
- // Copy the access token of the winlogon process; the newly created token will be a primary token.
- if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out hUserTokenDup))
- {
- Kernel32.CloseHandle(hProcess);
- Kernel32.CloseHandle(hPToken);
- return false;
- }
-
- // By default, CreateProcessAsUser creates a process on a non-interactive window station, meaning
- // the window station has a desktop that is invisible and the process is incapable of receiving
- // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
- // interaction with the new process.
- STARTUPINFO si = new STARTUPINFO();
- si.cb = (int)Marshal.SizeOf(si);
- si.lpDesktop = @"winsta0\" + desktopName;
-
- // Flags that specify the priority and creation method of the process.
- uint dwCreationFlags;
- if (hiddenWindow)
- {
- dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS;
- }
- else
- {
- dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
- }
-
- // Create a new process in the current user's logon session.
- bool result = CreateProcessAsUser(hUserTokenDup, null, applicationName, ref sa, ref sa, false, dwCreationFlags, IntPtr.Zero, null, ref si, out procInfo);
-
- // Invalidate the handles.
- Kernel32.CloseHandle(hProcess);
- Kernel32.CloseHandle(hPToken);
- Kernel32.CloseHandle(hUserTokenDup);
-
- return result;
- }
-
- public static uint GetRDPSession()
- {
- IntPtr ppSessionInfo = IntPtr.Zero;
- Int32 count = 0;
- Int32 retval = WTSAPI32.WTSEnumerateSessions(WTSAPI32.WTS_CURRENT_SERVER_HANDLE, 0, 1, ref ppSessionInfo, ref count);
- Int32 dataSize = Marshal.SizeOf(typeof(WTSAPI32.WTS_SESSION_INFO));
- var sessList = new List();
- Int64 current = (Int64)ppSessionInfo;
-
- if (retval != 0)
- {
- for (int i = 0; i < count; i++)
- {
- WTSAPI32.WTS_SESSION_INFO sessInf = (WTSAPI32.WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTSAPI32.WTS_SESSION_INFO));
- current += dataSize;
- sessList.Add(sessInf);
- }
- }
- uint retVal = 0;
- var rdpSession = sessList.Find(ses => ses.pWinStationName.ToLower().Contains("rdp") && ses.State == 0);
- if (sessList.Exists(ses => ses.pWinStationName.ToLower().Contains("rdp") && ses.State == 0))
- {
- retVal = (uint)rdpSession.SessionID;
- }
- return retVal;
- }
- public static IntPtr OpenInputDesktop()
- {
- return User32.OpenInputDesktop(0, false, ACCESS_MASK.GENERIC_ALL);
- }
- public static uint SendLeftMouseDown(int x, int y)
- {
- // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
- var normalizedX = x * (double)65535;
- var normalizedY = y * (double)65535;
- var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.LEFTDOWN | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = (UIntPtr)GetMessageExtraInfo() } };
- var input = new INPUT() { type = InputType.MOUSE, U = union };
- return SendInput(1, new INPUT[] { input }, INPUT.Size);
- }
- public static uint SendLeftMouseUp(int x, int y)
- {
- // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
- var normalizedX = x * (double)65535;
- var normalizedY = y * (double)65535;
- var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.LEFTUP | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = (UIntPtr)GetMessageExtraInfo() } };
- var input = new INPUT() { type = InputType.MOUSE, U = union };
- return SendInput(1, new INPUT[] { input }, INPUT.Size);
- }
- public static uint SendRightMouseDown(int x, int y)
- {
- // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
- var normalizedX = x * (double)65535;
- var normalizedY = y * (double)65535;
- var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.RIGHTDOWN | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = (UIntPtr)GetMessageExtraInfo() } };
- var input = new INPUT() { type = InputType.MOUSE, U = union };
- return SendInput(1, new INPUT[] { input }, INPUT.Size);
- }
- public static uint SendRightMouseUp(int x, int y)
- {
- // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
- var normalizedX = x * (double)65535;
- var normalizedY = y * (double)65535;
- var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.RIGHTUP | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = (UIntPtr)GetMessageExtraInfo() } };
- var input = new INPUT() { type = InputType.MOUSE, U = union };
- return SendInput(1, new INPUT[] { input }, INPUT.Size);
- }
-
- // Offsets are used in case there's a multi-monitor setup where the left-most or top-most edge of the virtual screen
- // is not 0.
- public static uint SendMouseMove(double x, double y)
- {
- // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
- var normalizedX = x * (double)65535;
- var normalizedY = y * (double)65535;
- var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.MOVE | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = (UIntPtr)GetMessageExtraInfo() } };
- var input = new INPUT() { type = InputType.MOUSE, U = union };
- return SendInput(1, new INPUT[] { input }, INPUT.Size);
- }
-
- public static uint SendMouseWheel(int deltaY)
- {
- if (deltaY < 0)
- {
- deltaY = -120;
- }
- else if (deltaY > 0)
- {
- deltaY = 120;
- }
- var union = new User32.InputUnion() { mi = new User32.MOUSEINPUT() { dwFlags = MOUSEEVENTF.WHEEL, dx = 0, dy = 0, time = 0, mouseData = deltaY, dwExtraInfo = GetMessageExtraInfo() } };
- var input = new User32.INPUT() { type = InputType.MOUSE, U = union };
- return SendInput(1, new User32.INPUT[] { input }, INPUT.Size);
- }
-
- public static void SendKeyDown(VirtualKey key)
- {
- var union = new InputUnion()
- {
- ki = new KEYBDINPUT()
- {
- wVk = key,
- wScan = 0,
- time = 0,
- dwExtraInfo = GetMessageExtraInfo()
- }
- };
- var input = new INPUT() { type = InputType.KEYBOARD, U = union };
- SendInput(1, new INPUT[] { input }, INPUT.Size);
- }
- public static void SendKeyUp(VirtualKey key)
- {
- var union = new InputUnion()
- {
- ki = new KEYBDINPUT()
- {
- wVk = key,
- wScan = 0,
- time = 0,
- dwFlags = KEYEVENTF.KEYUP,
- dwExtraInfo = GetMessageExtraInfo()
- }
- };
- var input = new INPUT() { type = InputType.KEYBOARD, U = union };
- SendInput(1, new INPUT[] { input }, INPUT.Size);
- }
- public static string GetCurrentDesktop()
- {
- var inputDesktop = OpenInputDesktop();
- byte[] deskBytes = new byte[256];
- uint lenNeeded;
- var success = GetUserObjectInformationW(inputDesktop, UOI_NAME, deskBytes, 256, out lenNeeded);
- if (!success)
- {
- CloseDesktop(inputDesktop);
- return "Default";
- }
- var desktopName = Encoding.Unicode.GetString(deskBytes.Take((int)lenNeeded).ToArray()).Replace("\0", "");
- CloseDesktop(inputDesktop);
- return desktopName;
- }
-
- public static short ConvertJavaScriptKeyToVirtualKey(string key)
- {
- short keyCode;
- switch (key)
- {
- case "Down":
- case "ArrowDown":
- keyCode = (short)VirtualKey.DOWN;
- break;
- case "Up":
- case "ArrowUp":
- keyCode = (short)VirtualKey.UP;
- break;
- case "Left":
- case "ArrowLeft":
- keyCode = (short)VirtualKey.LEFT;
- break;
- case "Right":
- case "ArrowRight":
- keyCode = (short)VirtualKey.RIGHT;
- break;
- case "Enter":
- keyCode = (short)VirtualKey.RETURN;
- break;
- case "Esc":
- case "Escape":
- keyCode = (short)VirtualKey.ESCAPE;
- break;
- case "Alt":
- keyCode = (short)VirtualKey.MENU;
- break;
- case "Control":
- keyCode = (short)VirtualKey.CONTROL;
- break;
- case "Shift":
- keyCode = (short)VirtualKey.SHIFT;
- break;
- case "PAUSE":
- keyCode = (short)VirtualKey.PAUSE;
- break;
- case "BREAK":
- keyCode = (short)VirtualKey.PAUSE;
- break;
- case "Backspace":
- keyCode = (short)VirtualKey.BACK;
- break;
- case "Tab":
- keyCode = (short)VirtualKey.TAB;
- break;
- case "CapsLock":
- keyCode = (short)VirtualKey.CAPITAL;
- break;
- case "Delete":
- keyCode = (short)VirtualKey.DELETE;
- break;
- case "Home":
- keyCode = (short)VirtualKey.HOME;
- break;
- case "End":
- keyCode = (short)VirtualKey.END;
- break;
- case "PageUp":
- keyCode = (short)VirtualKey.PRIOR;
- break;
- case "PageDown":
- keyCode = (short)VirtualKey.NEXT;
- break;
- case "NumLock":
- keyCode = (short)VirtualKey.NUMLOCK;
- break;
- case "Insert":
- keyCode = (short)VirtualKey.INSERT;
- break;
- case "ScrollLock":
- keyCode = (short)VirtualKey.SCROLL;
- break;
- case "F1":
- keyCode = (short)VirtualKey.F1;
- break;
- case "F2":
- keyCode = (short)VirtualKey.F2;
- break;
- case "F3":
- keyCode = (short)VirtualKey.F3;
- break;
- case "F4":
- keyCode = (short)VirtualKey.F4;
- break;
- case "F5":
- keyCode = (short)VirtualKey.F5;
- break;
- case "F6":
- keyCode = (short)VirtualKey.F6;
- break;
- case "F7":
- keyCode = (short)VirtualKey.F7;
- break;
- case "F8":
- keyCode = (short)VirtualKey.F8;
- break;
- case "F9":
- keyCode = (short)VirtualKey.F9;
- break;
- case "F10":
- keyCode = (short)VirtualKey.F10;
- break;
- case "F11":
- keyCode = (short)VirtualKey.F11;
- break;
- case "F12":
- keyCode = (short)VirtualKey.F12;
- break;
- default:
- keyCode = User32.VkKeyScan(Convert.ToChar(key));
- break;
- }
- return keyCode;
- }
- }
-}
diff --git a/Remotely_ScreenCast_Linux/Capture/ICapturer.cs b/Remotely_ScreenCast_Linux/Capture/ICapturer.cs
deleted file mode 100644
index 84263084..00000000
--- a/Remotely_ScreenCast_Linux/Capture/ICapturer.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely_ScreenCast_Linux.Capture
-{
- public interface ICapturer : IDisposable
- {
- bool CaptureFullscreen { get; set; }
- Bitmap CurrentFrame { get; set; }
- Rectangle CurrentScreenBounds { get; }
- Bitmap PreviousFrame { get; set; }
- EventHandler ScreenChanged { get; set; }
- int SelectedScreen { get; set; }
- void Capture();
- void Init();
- }
-}
diff --git a/Remotely_ScreenCast_Linux/Capture/ImageUtils.cs b/Remotely_ScreenCast_Linux/Capture/ImageUtils.cs
deleted file mode 100644
index 7f071d63..00000000
--- a/Remotely_ScreenCast_Linux/Capture/ImageUtils.cs
+++ /dev/null
@@ -1,198 +0,0 @@
-using Remotely_ScreenCast_Linux.Models;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Runtime.Serialization.Formatters.Binary;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely_ScreenCast_Linux.Capture
-{
- public class ImageUtils
- {
- public static byte[] EncodeBitmap(Bitmap bitmap)
- {
- using (var ms = new MemoryStream())
- {
- bitmap.Save(ms, ImageFormat.Jpeg);
- return ms.ToArray();
- }
- }
-
- public static Rectangle GetDiffArea(Bitmap currentFrame, Bitmap previousFrame, bool captureFullscreen)
- {
- if (captureFullscreen)
- {
- return new Rectangle(new Point(0, 0), currentFrame.Size);
- }
- if (currentFrame.Height != previousFrame.Height || currentFrame.Width != previousFrame.Width)
- {
- throw new Exception("Bitmaps are not of equal dimensions.");
- }
- if (!Bitmap.IsAlphaPixelFormat(currentFrame.PixelFormat) || !Bitmap.IsAlphaPixelFormat(previousFrame.PixelFormat) ||
- !Bitmap.IsCanonicalPixelFormat(currentFrame.PixelFormat) || !Bitmap.IsCanonicalPixelFormat(previousFrame.PixelFormat))
- {
- throw new Exception("Bitmaps must be 32 bits per pixel and contain alpha channel.");
- }
- var width = currentFrame.Width;
- var height = currentFrame.Height;
- int left = int.MaxValue;
- int top = int.MaxValue;
- int right = int.MinValue;
- int bottom = int.MinValue;
-
- BitmapData bd1 = null;
- BitmapData bd2 = null;
-
- try
- {
- bd1 = previousFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, currentFrame.PixelFormat);
- bd2 = currentFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, previousFrame.PixelFormat);
-
- var bytesPerPixel = Bitmap.GetPixelFormatSize(currentFrame.PixelFormat) / 8;
- var totalSize = bd1.Height * bd1.Width * bytesPerPixel;
-
- unsafe
- {
- byte* scan1 = (byte*)bd1.Scan0.ToPointer();
- byte* scan2 = (byte*)bd2.Scan0.ToPointer();
-
- for (int counter = 0; counter < totalSize - bytesPerPixel; counter += bytesPerPixel)
- {
- byte* data1 = scan1 + counter;
- byte* data2 = scan2 + counter;
-
- if (data1[0] != data2[0] ||
- data1[1] != data2[1] ||
- data1[2] != data2[2] ||
- data1[3] != data2[3])
- {
- // Change was found.
- var pixel = counter / 4;
- var row = (int)Math.Floor((double)pixel / bd1.Width);
- var column = pixel % bd1.Width;
- if (row < top)
- {
- top = row;
- }
- if (row > bottom)
- {
- bottom = row;
- }
- if (column < left)
- {
- left = column;
- }
- if (column > right)
- {
- right = column;
- }
- }
- }
- }
-
- if (left < right && top < bottom)
- {
- // Bounding box is valid.
-
- left = Math.Max(left - 20, 0);
- top = Math.Max(top - 20, 0);
- right = Math.Min(right + 20, width);
- bottom = Math.Min(bottom + 20, height);
-
- return new Rectangle(left, top, right - left, bottom - top);
- }
- else
- {
- return Rectangle.Empty;
- }
- }
- catch
- {
- return Rectangle.Empty;
- }
- finally
- {
- try
- {
- currentFrame.UnlockBits(bd1);
- previousFrame.UnlockBits(bd2);
- bd1 = null;
- bd2 = null;
- }
- catch { }
- }
- }
-
- public static Bitmap GetImageDiff(Bitmap currentFrame, Bitmap previousFrame, bool captureFullscreen)
- {
- if (captureFullscreen)
- {
- return (Bitmap)currentFrame.Clone();
- }
-
- if (currentFrame.Height != previousFrame.Height || currentFrame.Width != previousFrame.Width)
- {
- throw new Exception("Bitmaps are not of equal dimensions.");
- }
- if (!Bitmap.IsAlphaPixelFormat(currentFrame.PixelFormat) || !Bitmap.IsAlphaPixelFormat(previousFrame.PixelFormat) ||
- !Bitmap.IsCanonicalPixelFormat(currentFrame.PixelFormat) || !Bitmap.IsCanonicalPixelFormat(previousFrame.PixelFormat))
- {
- throw new Exception("Bitmaps must be 32 bits per pixel and contain alpha channel.");
- }
- var width = currentFrame.Width;
- var height = currentFrame.Height;
-
- var mergedFrame = new Bitmap(width, height);
-
- var bd1 = previousFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, currentFrame.PixelFormat);
- var bd2 = currentFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, previousFrame.PixelFormat);
- var bd3 = mergedFrame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, currentFrame.PixelFormat);
-
-
- // Get the address of the first line.
- IntPtr ptr1 = bd1.Scan0;
- IntPtr ptr2 = bd2.Scan0;
- IntPtr ptr3 = bd3.Scan0;
-
- // Declare an array to hold the bytes of the bitmap.
- int arraySize = Math.Abs(bd1.Stride) * currentFrame.Height;
- var rgbValues1 = new byte[arraySize];
- var rgbValues2 = new byte[arraySize];
- var rgbValues3 = new byte[arraySize];
-
- // Copy the RGBA values into the array.
- Marshal.Copy(ptr1, rgbValues1, 0, arraySize);
- Marshal.Copy(ptr2, rgbValues2, 0, arraySize);
-
- // Check RGBA value for each pixel.
- for (int counter = 0; counter < rgbValues2.Length - 4; counter += 4)
- {
- if (rgbValues1[counter] != rgbValues2[counter] ||
- rgbValues1[counter + 1] != rgbValues2[counter + 1] ||
- rgbValues1[counter + 2] != rgbValues2[counter + 2] ||
- rgbValues1[counter + 3] != rgbValues2[counter + 3])
- {
- // Change was found.
- rgbValues3[counter] = rgbValues2[counter];
- rgbValues3[counter + 1] = rgbValues2[counter + 1];
- rgbValues3[counter + 2] = rgbValues2[counter + 2];
- rgbValues3[counter + 3] = rgbValues2[counter + 3];
- }
- }
-
- // Copy merged frame to bitmap.
- Marshal.Copy(rgbValues3, 0, ptr3, rgbValues3.Length);
-
- previousFrame.UnlockBits(bd1);
- currentFrame.UnlockBits(bd2);
- mergedFrame.UnlockBits(bd3);
-
- return mergedFrame;
- }
- }
-}
diff --git a/Remotely_ScreenCast_Linux/Capture/ScreenCaster.cs b/Remotely_ScreenCast_Linux/Capture/ScreenCaster.cs
deleted file mode 100644
index 247c5165..00000000
--- a/Remotely_ScreenCast_Linux/Capture/ScreenCaster.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-using Microsoft.AspNetCore.SignalR.Client;
-using Remotely_ScreenCast_Linux;
-using Remotely_ScreenCast_Linux.Capture;
-using Remotely_ScreenCast_Linux.Models;
-using Remotely_ScreenCast_Linux.Sockets;
-using Remotely_ScreenCast_Linux.Utilities;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely_ScreenCast_Linux.Capture
-{
- public class ScreenCaster
- {
- public static async void BeginScreenCasting(string viewerID,
- string requesterName,
- OutgoingMessages outgoingMessages)
- {
- ICapturer capturer;
- capturer = new X11Capture();
- capturer.Init();
- Viewer viewer;
- byte[] encodedImageBytes;
- var success = false;
-
- Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. App Mode: {Program.Mode}");
-
- viewer = new Viewer()
- {
- Capturer = capturer,
- DisconnectRequested = false,
- Name = requesterName,
- ViewerConnectionID = viewerID,
- HasControl = true,
- ImageQuality = 1
- };
-
- while (!success)
- {
- success = Program.Viewers.TryAdd(viewerID, viewer);
- }
-
- if (Program.Mode == Enums.AppMode.Normal)
- {
- Program.ViewerAdded?.Invoke(null, viewer);
- }
-
- await outgoingMessages.SendScreenCount(
- capturer.SelectedScreen,
- //Screen.AllScreens.Length,
- 1,
- viewerID);
-
- await outgoingMessages.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);
-
- capturer.ScreenChanged += async (sender, bounds) =>
- {
- await outgoingMessages.SendScreenSize(bounds.Width, bounds.Height, viewerID);
- };
-
- //await outgoingMessages.SendCursorChange(CursorIconWatcher.Current.GetCurrentCursor(), new List() { viewerID });
-
- while (!viewer.DisconnectRequested)
- {
- try
- {
- while (viewer.PendingFrames > 10)
- {
- await Task.Delay(1);
- }
-
- capturer.Capture();
-
- var diffArea = ImageUtils.GetDiffArea(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen);
-
- if (diffArea.IsEmpty)
- {
- continue;
- }
-
- using (var newImage = capturer.CurrentFrame.Clone(diffArea, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
- {
- if (capturer.CaptureFullscreen)
- {
- capturer.CaptureFullscreen = false;
- }
-
- encodedImageBytes = ImageUtils.EncodeBitmap(newImage);
-
- if (encodedImageBytes?.Length > 0)
- {
- await outgoingMessages.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow);
- viewer.PendingFrames++;
- }
- GC.Collect();
- }
- }
- catch (Exception ex)
- {
- Logger.Write(ex);
- }
- }
- Logger.Write($"Ended screen cast. Requester: {requesterName}. Viewer ID: {viewerID}.");
- success = false;
- while (!success)
- {
- success = Program.Viewers.TryRemove(viewerID, out _);
- }
-
- capturer.Dispose();
-
- // Close if no one is viewing.
- if (Program.Viewers.Count == 0 && Program.Mode == Enums.AppMode.Unattended)
- {
- Environment.Exit(0);
- }
-
- }
- public static Tuple GetAbsolutePercentFromRelativePercent(double percentX, double percentY, ICapturer capturer)
- {
- var absoluteX = (capturer.CurrentScreenBounds.Width * percentX) + capturer.CurrentScreenBounds.Left;
- var absoluteY = (capturer.CurrentScreenBounds.Height * percentY) + capturer.CurrentScreenBounds.Top;
- return new Tuple(800, 600);
- //return new Tuple(absoluteX / SystemInformation.VirtualScreen.Width, absoluteY / SystemInformation.VirtualScreen.Height);
- }
- public static Tuple GetAbsolutePointFromRelativePercent(double percentX, double percentY, ICapturer capturer)
- {
- var absoluteX = (capturer.CurrentScreenBounds.Width * percentX) + capturer.CurrentScreenBounds.Left;
- var absoluteY = (capturer.CurrentScreenBounds.Height * percentY) + capturer.CurrentScreenBounds.Top;
- return new Tuple(absoluteX, absoluteY);
- }
- }
-}
diff --git a/Remotely_ScreenCast_Linux/Capture/X11Capture.cs b/Remotely_ScreenCast_Linux/Capture/X11Capture.cs
deleted file mode 100644
index a3f3a8fc..00000000
--- a/Remotely_ScreenCast_Linux/Capture/X11Capture.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using System;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Windows;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-using System.Drawing.Drawing2D;
-using System.Diagnostics;
-using System.Runtime.Serialization.Formatters.Binary;
-using Remotely_ScreenCast_Linux.Utilities;
-using System.Threading;
-
-namespace Remotely_ScreenCast_Linux.Capture
-{
- public class X11Capture : ICapturer
- {
- public Bitmap CurrentFrame { get; set; }
- public Bitmap PreviousFrame { get; set; }
- public bool IsCapturing { get; set; }
- public bool CaptureFullscreen { get; set; } = true;
- public int PauseForMilliseconds { get; set; }
- public EventHandler ScreenChanged { get; set; }
- private object ScreenLock { get; } = new object();
- public int SelectedScreen
- {
- get
- {
- return selectedScreen;
- }
- set
- {
- if (value == selectedScreen)
- {
- return;
- }
- lock (ScreenLock)
- {
- //if (Screen.AllScreens.Length >= value + 1)
- //{
- // selectedScreen = value;
- //}
- //else
- //{
- // selectedScreen = 0;
- //}
- //CurrentScreenBounds = Screen.AllScreens[selectedScreen].Bounds;
- CaptureFullscreen = true;
- Init();
- ScreenChanged?.Invoke(this, CurrentScreenBounds);
- }
- }
- }
- //public Rectangle CurrentScreenBounds { get; set; } = Screen.PrimaryScreen.Bounds;
- //private int selectedScreen = Screen.AllScreens.ToList().IndexOf(Screen.PrimaryScreen);
- public Rectangle CurrentScreenBounds { get; set; }
- private int selectedScreen;
- private Graphics graphic;
-
-
- public X11Capture()
- {
- Init();
- }
-
- public void Init()
- {
- CurrentFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
- PreviousFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
- graphic = Graphics.FromImage(CurrentFrame);
- }
-
- public void Capture()
- {
- try
- {
- PreviousFrame = (Bitmap)CurrentFrame.Clone();
- graphic.CopyFromScreen(CurrentScreenBounds.Left, CurrentScreenBounds.Top, 0, 0, new Size(CurrentScreenBounds.Width, CurrentScreenBounds.Height));
- }
- catch (Exception ex)
- {
- Logger.Write(ex);
- Init();
- }
- }
-
- public void Dispose()
- {
- graphic.Dispose();
- CurrentFrame.Dispose();
- PreviousFrame.Dispose();
- }
- }
-}
diff --git a/Remotely_ScreenCast_Linux/Enums/AppMode.cs b/Remotely_ScreenCast_Linux/Enums/AppMode.cs
deleted file mode 100644
index 61d3a737..00000000
--- a/Remotely_ScreenCast_Linux/Enums/AppMode.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely_ScreenCast_Linux.Enums
-{
- public enum AppMode
- {
- Unattended,
- Normal
- }
-}
diff --git a/Remotely_ScreenCast_Linux/Models/CursorInfo.cs b/Remotely_ScreenCast_Linux/Models/CursorInfo.cs
deleted file mode 100644
index e16c918c..00000000
--- a/Remotely_ScreenCast_Linux/Models/CursorInfo.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely_ScreenCast_Linux.Models
-{
- public class CursorInfo
- {
- public CursorInfo(byte[] imageBytes, Point hotspot, string cssOverride = null)
- {
- ImageBytes = imageBytes;
- HotSpot = hotspot;
- CssOverride = cssOverride;
- }
-
- public byte[] ImageBytes { get; set; }
- public Point HotSpot { get; set; }
-
- public string CssOverride { get; set; }
- }
-}
diff --git a/Remotely_ScreenCast_Linux/Models/CursorInfo.d.ts b/Remotely_ScreenCast_Linux/Models/CursorInfo.d.ts
deleted file mode 100644
index e7037d9b..00000000
--- a/Remotely_ScreenCast_Linux/Models/CursorInfo.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
- interface CursorInfo {
- ImageBytes: any[];
- HotSpot: any;
- CssOverride: string;
- }
diff --git a/Remotely_ScreenCast_Linux/Models/Viewer.cs b/Remotely_ScreenCast_Linux/Models/Viewer.cs
deleted file mode 100644
index 4785d144..00000000
--- a/Remotely_ScreenCast_Linux/Models/Viewer.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using Remotely_ScreenCast_Linux.Capture;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely_ScreenCast_Linux.Models
-{
- public class Viewer
- {
- public string ViewerConnectionID { get; set; }
- public string Name { get; set; }
- public ICapturer Capturer { get; set; }
- public bool DisconnectRequested { get; set; }
- public bool HasControl { get; set; }
- public double Latency { get; set; } = 1;
- public int PendingFrames { get; set; }
-
- private double imageQuality = 1;
- public double ImageQuality
- {
- get
- {
- return imageQuality;
- }
- set
- {
- if (imageQuality > 1 || imageQuality < 0)
- {
- return;
- }
- imageQuality = value;
- }
- }
- public bool FullScreenRefreshNeeded { get; internal set; }
-
- }
-}
diff --git a/Remotely_ScreenCast_Linux/Program.cs b/Remotely_ScreenCast_Linux/Program.cs
deleted file mode 100644
index 4e8154ad..00000000
--- a/Remotely_ScreenCast_Linux/Program.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-using Microsoft.AspNetCore.SignalR.Client;
-using Microsoft.Extensions.DependencyInjection;
-using Remotely_ScreenCast_Linux;
-using Remotely_ScreenCast_Linux.Capture;
-using Remotely_ScreenCast_Linux.Enums;
-using Remotely_ScreenCast_Linux.Models;
-using Remotely_ScreenCast_Linux.Sockets;
-using Remotely_ScreenCast_Linux.Utilities;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Drawing;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely_ScreenCast_Linux
-{
- public class Program
- {
- public static AppMode Mode { get; private set; }
- public static string RequesterID { get; private set; }
- public static string ServiceID { get; private set; }
- public static string Host { get; private set; }
- public static HubConnection Connection { get; private set; }
- public static OutgoingMessages OutgoingMessages { get; private set; }
- public static ConcurrentDictionary Viewers { get; } = new ConcurrentDictionary();
- public static Dictionary ArgDict { get; set; }
-
- public static void Main(string[] args)
- {
- try
- {
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
- ProcessArgs(args);
- Connect().Wait();
- SetEventHandlers();
- HandleConnection().Wait();
- }
- catch (Exception ex)
- {
- Logger.Write(ex);
- }
- }
-
- public static async Task HandleConnection()
- {
- OutgoingMessages.SendDeviceInfo(ServiceID, Environment.MachineName).Wait();
-
-
- if (Mode == AppMode.Unattended)
- {
- StartWaitForViewerTimer();
- }
- else if (Mode == AppMode.Normal)
- {
- OutgoingMessages.GetSessionID().Wait();
- }
-
-
-
- while (true)
- {
- await Task.Delay(100);
- }
- }
-
- public static void SetEventHandlers()
- {
- OutgoingMessages = new OutgoingMessages(Connection);
-
- MessageHandlers.ApplyConnectionHandlers(Connection, OutgoingMessages);
-
- //CursorIconWatcher.Current.OnChange += CursorIconWatcher_OnChange;
- }
-
- public static Task Connect()
- {
- Connection = new HubConnectionBuilder()
- .WithUrl($"{Host}/RCDeviceHub")
- .AddMessagePackProtocol()
- .Build();
-
- return Connection.StartAsync();
- }
-
-
- private static async void CursorIconWatcher_OnChange(object sender, CursorInfo cursor)
- {
- await OutgoingMessages.SendCursorChange(cursor, Viewers.Keys.ToList());
- }
-
- private static void StartWaitForViewerTimer()
- {
- var timer = new System.Timers.Timer(10000);
- timer.AutoReset = false;
- timer.Elapsed += (sender, arg) =>
- {
- // Shut down if no viewers have connected within 10 seconds.
- if (Viewers.Count == 0)
- {
- Logger.Write("No viewers connected after 10 seconds. Shutting down.");
- Environment.Exit(0);
- }
- };
- timer.Start();
- }
-
- private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
- {
- Logger.Write((Exception)e.ExceptionObject);
- }
-
- public static void ProcessArgs(string[] args)
- {
- ArgDict = new Dictionary();
-
- for (var i = 0; i < args.Length; i += 2)
- {
- var key = args?[i];
- if (key != null)
- {
- key = key.Trim().Replace("-", "").ToLower();
- var value = args?[i + 1];
- if (value != null)
- {
- ArgDict[key] = args[i + 1].Trim();
- }
- }
-
- }
-
- Mode = (AppMode)Enum.Parse(typeof(AppMode), ArgDict["mode"]);
- Host = ArgDict["host"];
-
- if (Mode == AppMode.Unattended)
- {
- RequesterID = ArgDict["requester"];
- ServiceID = ArgDict["serviceid"];
- }
-
- }
- public static EventHandler SessionIDChanged { get; set; }
- public static EventHandler ViewerRemoved { get; set; }
- public static EventHandler ViewerAdded { get; set; }
- public static EventHandler> ScreenCastRequested { get; set; }
- }
-}
diff --git a/Remotely_ScreenCast_Linux/Sockets/OutgoingMessages.cs b/Remotely_ScreenCast_Linux/Sockets/OutgoingMessages.cs
deleted file mode 100644
index 0a15f4c4..00000000
--- a/Remotely_ScreenCast_Linux/Sockets/OutgoingMessages.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using Microsoft.AspNetCore.SignalR.Client;
-using Remotely_ScreenCast_Linux.Models;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely_ScreenCast_Linux.Sockets
-{
- public class OutgoingMessages
- {
- public OutgoingMessages(HubConnection hubConnection)
- {
- Connection = hubConnection;
- }
-
- private HubConnection Connection { get; }
- public async Task SendScreenSize(int width, int height, string viewerID)
- {
- await Connection.SendAsync("SendScreenSize", width, height, viewerID);
- }
-
- public async Task SendScreenCapture(byte[] captureBytes, string viewerID, int left, int top, int width, int height, DateTime captureTime)
- {
- await Connection.SendAsync("SendScreenCapture", captureBytes, viewerID, left, top, width, height, captureTime);
- }
-
- internal async Task SendScreenCount(int primaryScreenIndex, int screenCount, string viewerID)
- {
- await Connection.SendAsync("SendScreenCountToBrowser", primaryScreenIndex, screenCount, viewerID);
- }
-
- public async Task NotifyRequesterUnattendedReady(string requesterID)
- {
- await Connection.SendAsync("NotifyRequesterUnattendedReady", requesterID);
- }
-
- public async Task SendCursorChange(CursorInfo cursor, List viewerIDs)
- {
- await Connection.SendAsync("SendCursorChange", cursor, viewerIDs);
- }
-
- internal async Task NotifyViewersRelaunchedScreenCasterReady(string[] viewerIDs)
- {
- await Connection.SendAsync("NotifyViewersRelaunchedScreenCasterReady", viewerIDs);
- }
-
- internal async Task SendDeviceInfo(string serviceID, string machineName)
- {
- await Connection.SendAsync("ReceiveDeviceInfo", serviceID, machineName);
- }
-
- internal async Task SendConnectionFailedToViewers(List viewerIDs)
- {
- await Connection.SendAsync("SendConnectionFailedToViewers", viewerIDs);
- }
-
- internal async Task GetSessionID()
- {
- await Connection.SendAsync("GetSessionID");
- }
-
- public async Task SendViewerRemoved(string viewerID)
- {
- await Connection.SendAsync("SendViewerRemoved", viewerID);
- }
- }
-}
diff --git a/Remotely_ScreenCast_Linux/Utilities/Logger.cs b/Remotely_ScreenCast_Linux/Utilities/Logger.cs
deleted file mode 100644
index f70956ed..00000000
--- a/Remotely_ScreenCast_Linux/Utilities/Logger.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using Newtonsoft.Json;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely_ScreenCast_Linux.Utilities
-{
- public static class Logger
- {
- public static void Write(string message)
- {
- var path = Path.Combine(Path.GetTempPath(), "Remotely_Logs.txt");
-
- var jsoninfo = new
- {
- Type = "Info",
- Timestamp = DateTime.Now.ToString(),
- Message = message
- };
- if (File.Exists(path))
- {
- var fi = new FileInfo(path);
- while (fi.Length > 1000000)
- {
- var content = File.ReadAllLines(path);
- File.WriteAllLines(path, content.Skip(10));
- fi = new FileInfo(path);
- }
- }
- try
- {
- File.AppendAllText(path, JsonConvert.SerializeObject(jsoninfo) + Environment.NewLine);
- }
- catch
- {
- Task.Delay(1000).ContinueWith((Task task) =>
- {
- Write(message);
- });
- }
- }
-
- public static void Write(Exception ex)
- {
- var exception = ex;
- var path = Path.Combine(Path.GetTempPath(), "Remotely_Logs.txt");
-
- while (exception != null)
- {
- var jsonError = new
- {
- Type = "Error",
- Timestamp = DateTime.Now.ToString(),
- Message = exception?.Message,
- Source = exception?.Source,
- StackTrace = exception?.StackTrace,
- };
- if (File.Exists(path))
- {
- var fi = new FileInfo(path);
- while (fi.Length > 1000000)
- {
- var content = File.ReadAllLines(path);
- File.WriteAllLines(path, content.Skip(10));
- fi = new FileInfo(path);
- }
- }
- File.AppendAllText(path, JsonConvert.SerializeObject(jsonError) + Environment.NewLine);
- exception = exception.InnerException;
- }
- }
- }
-}
diff --git a/Remotely_ScreenCast_Linux/X11/X11Interop.cs b/Remotely_ScreenCast_Linux/X11/X11Interop.cs
deleted file mode 100644
index 7fb87e21..00000000
--- a/Remotely_ScreenCast_Linux/X11/X11Interop.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Remotely_ScreenCast_Linux.X11
-{
- public class X11Interop
- {
- }
-}
diff --git a/Remotely_Server/CurrentVersion.txt b/Remotely_Server/CurrentVersion.txt
index 2ec0c7c6..c7e0c83b 100644
--- a/Remotely_Server/CurrentVersion.txt
+++ b/Remotely_Server/CurrentVersion.txt
@@ -1 +1 @@
-2019.03.25.1255
+2019.03.26.2309
diff --git a/Remotely_Server/Remotely_Server.csproj b/Remotely_Server/Remotely_Server.csproj
index d5368c6e..d479043d 100644
--- a/Remotely_Server/Remotely_Server.csproj
+++ b/Remotely_Server/Remotely_Server.csproj
@@ -57,8 +57,8 @@
-
-
+
+
diff --git a/Remotely_Server/wwwroot/Downloads/Install-Linux-x64.sh b/Remotely_Server/wwwroot/Downloads/Install-Linux-x64.sh
index 2b967555..293b0d7a 100644
--- a/Remotely_Server/wwwroot/Downloads/Install-Linux-x64.sh
+++ b/Remotely_Server/wwwroot/Downloads/Install-Linux-x64.sh
@@ -11,7 +11,8 @@ if [ "$1" = "--uninstall" ]; then
exit
fi
-apt-get install unzip
+apt-get -y install unzip
+apt-get -y install libgdiplus
mkdir -p /usr/local/bin/Remotely/
cd /usr/local/bin/Remotely/
@@ -48,9 +49,11 @@ WorkingDirectory=/usr/local/bin/Remotely/
ExecStart=/usr/local/bin/Remotely/Remotely_Agent
Restart=always
RestartSec=10
+Environment=DISPLAY=:0
+Environment="XAUTHORITY=/home/$USER/.Xauthority"
[Install]
-WantedBy=multi-user.target
+WantedBy=graphical.target
EOL
systemctl enable remotely-agent
diff --git a/Remotely_Server/wwwroot/scripts/RemoteControl/UI.js b/Remotely_Server/wwwroot/scripts/RemoteControl/UI.js
index edefe8e8..ec66a696 100644
--- a/Remotely_Server/wwwroot/scripts/RemoteControl/UI.js
+++ b/Remotely_Server/wwwroot/scripts/RemoteControl/UI.js
@@ -106,10 +106,12 @@ export function ApplyInputHandlers(sockets) {
ConnectionBar.classList.remove("open");
RemoteControl.RCBrowserSockets.SendCtrlAltDel();
});
- document.querySelector("#sessionIDInput, #nameInput").addEventListener("keypress", (ev) => {
- if (ev.key.toLowerCase() == "enter") {
- ConnectToClient();
- }
+ document.querySelectorAll("#sessionIDInput, #nameInput").forEach(x => {
+ x.addEventListener("keypress", (ev) => {
+ if (ev.key.toLowerCase() == "enter") {
+ ConnectToClient();
+ }
+ });
});
document.querySelector("#connectButton").addEventListener("click", (ev) => {
ConnectToClient();
diff --git a/Remotely_Server/wwwroot/scripts/RemoteControl/UI.js.map b/Remotely_Server/wwwroot/scripts/RemoteControl/UI.js.map
index 91f6b4a3..02578180 100644
--- a/Remotely_Server/wwwroot/scripts/RemoteControl/UI.js.map
+++ b/Remotely_Server/wwwroot/scripts/RemoteControl/UI.js.map
@@ -1 +1 @@
-{"version":3,"file":"UI.js","sourceRoot":"","sources":["UI.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"UI.js","sourceRoot":"","sources":["UI.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/Remotely_Server/wwwroot/scripts/RemoteControl/UI.ts b/Remotely_Server/wwwroot/scripts/RemoteControl/UI.ts
index f592b52c..f7433fe4 100644
--- a/Remotely_Server/wwwroot/scripts/RemoteControl/UI.ts
+++ b/Remotely_Server/wwwroot/scripts/RemoteControl/UI.ts
@@ -114,10 +114,12 @@ export function ApplyInputHandlers(sockets: RCBrowserSockets) {
ConnectionBar.classList.remove("open");
RemoteControl.RCBrowserSockets.SendCtrlAltDel();
});
- document.querySelector("#sessionIDInput, #nameInput").addEventListener("keypress", (ev: KeyboardEvent) => {
- if (ev.key.toLowerCase() == "enter") {
- ConnectToClient();
- }
+ document.querySelectorAll("#sessionIDInput, #nameInput").forEach(x => {
+ x.addEventListener("keypress", (ev: KeyboardEvent) => {
+ if (ev.key.toLowerCase() == "enter") {
+ ConnectToClient();
+ }
+ })
});
document.querySelector("#connectButton").addEventListener("click", (ev) => {
ConnectToClient();
diff --git a/Utilities/Publish.ps1 b/Utilities/Publish.ps1
index df444389..81c68766 100644
--- a/Utilities/Publish.ps1
+++ b/Utilities/Publish.ps1
@@ -69,7 +69,7 @@ if ($ArgList.Contains("c")) {
if ((Test-Path -Path ".\Remotely_Agent\bin\Release\netcoreapp2.2\linux-x64\publish") -eq $true) {
Get-ChildItem -Path ".\Remotely_Agent\bin\Release\netcoreapp2.2\linux-x64\publish" | Remove-Item -Force -Recurse
}
-
+
Push-Location -Path ".\Remotely_Agent"
# Publish Core clients.
@@ -81,15 +81,24 @@ if ($ArgList.Contains("c")) {
New-Item -Path ".\Remotely_Agent\bin\Release\netcoreapp2.2\win10-x64\publish\ScreenCast\" -ItemType Directory -Force
New-Item -Path ".\Remotely_Agent\bin\Release\netcoreapp2.2\win10-x86\publish\ScreenCast\" -ItemType Directory -Force
+ New-Item -Path ".\Remotely_Agent\bin\Release\netcoreapp2.2\linux-x64\publish\ScreenCast\" -ItemType Directory -Force
- # Copy .NET Framework ScreenCaster to Agent output.
- if ((Test-Path -Path ".\Remotely_ScreenCast\bin\Release\Remotely_ScreenCast.exe") -eq $true) {
- Copy-Item -Path ".\Remotely_ScreenCast\bin\Release\Remotely_ScreenCast.exe" -Destination ".\Remotely_Agent\bin\Release\netcoreapp2.2\win10-x64\publish\ScreenCast\Remotely_ScreenCast.exe" -Force
- Copy-Item -Path ".\Remotely_ScreenCast\bin\Release\Remotely_ScreenCast.exe" -Destination ".\Remotely_Agent\bin\Release\netcoreapp2.2\win10-x86\publish\ScreenCast\Remotely_ScreenCast.exe" -Force
+ # Copy .NET Framework ScreenCaster to Agent output folder.
+ if ((Test-Path -Path ".\Remotely_ScreenCast.Win\bin\Release\Remotely_ScreenCast.exe") -eq $true) {
+ Copy-Item -Path ".\Remotely_ScreenCast.Win\bin\Release\Remotely_ScreenCast.exe" -Destination ".\Remotely_Agent\bin\Release\netcoreapp2.2\win10-x64\publish\ScreenCast\Remotely_ScreenCast.exe" -Force
+ Copy-Item -Path ".\Remotely_ScreenCast.Win\bin\Release\Remotely_ScreenCast.exe" -Destination ".\Remotely_Agent\bin\Release\netcoreapp2.2\win10-x86\publish\ScreenCast\Remotely_ScreenCast.exe" -Force
}
- elseif ((Test-Path -Path ".\Remotely_ScreenCast\bin\Debug\Remotely_ScreenCast.exe") -eq $true) {
- Copy-Item -Path ".\Remotely_ScreenCast\bin\Debug\Remotely_ScreenCast.exe" -Destination ".\Remotely_Agent\bin\Release\netcoreapp2.2\win10-x64\publish\ScreenCast\Remotely_ScreenCast.exe" -Force
- Copy-Item -Path ".\Remotely_ScreenCast\bin\Debug\Remotely_ScreenCast.exe" -Destination ".\Remotely_Agent\bin\Release\netcoreapp2.2\win10-x86\publish\ScreenCast\Remotely_ScreenCast.exe" -Force
+ elseif ((Test-Path -Path ".\Remotely_ScreenCast.Win\bin\Debug\Remotely_ScreenCast.exe") -eq $true) {
+ Copy-Item -Path ".\Remotely_ScreenCast.Win\bin\Debug\Remotely_ScreenCast.exe" -Destination ".\Remotely_Agent\bin\Release\netcoreapp2.2\win10-x64\publish\ScreenCast\Remotely_ScreenCast.exe" -Force
+ Copy-Item -Path ".\Remotely_ScreenCast.Win\bin\Debug\Remotely_ScreenCast.exe" -Destination ".\Remotely_Agent\bin\Release\netcoreapp2.2\win10-x86\publish\ScreenCast\Remotely_ScreenCast.exe" -Force
+ }
+
+ # Copy Mono ScreenCaster to Agent output folder.
+ if ((Test-Path -Path ".\Remotely_ScreenCast.Mono\bin\Release\Remotely_ScreenCast.Mono.exe") -eq $true) {
+ Copy-Item -Path ".\Remotely_ScreenCast.Mono\bin\Release\Remotely_ScreenCast.Mono.exe" -Destination ".\Remotely_Agent\bin\Release\netcoreapp2.2\linux-x64\publish\ScreenCast\Remotely_ScreenCast.Mono.exe" -Force
+ }
+ elseif ((Test-Path -Path ".\Remotely_ScreenCast.Mono\bin\Debug\Remotely_ScreenCast.Mono.exe") -eq $true) {
+ Copy-Item -Path ".\Remotely_ScreenCast.Mono\bin\Debug\Remotely_ScreenCast.Mono.exe" -Destination ".\Remotely_Agent\bin\Release\netcoreapp2.2\linux-x64\publish\ScreenCast\Remotely_ScreenCast.Mono.exe" -Force
}
# Compress Core clients.