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.