mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Refactor BitBlt and DirectX capturer into one service.
This commit is contained in:
parent
0970b2e27d
commit
7cc2820086
@ -6,12 +6,10 @@ using Remotely.Desktop.Linux.Controls;
|
||||
using Remotely.Desktop.Linux.Services;
|
||||
using Remotely.Desktop.Linux.Views;
|
||||
using Remotely.ScreenCast.Core;
|
||||
using Remotely.ScreenCast.Core.Capture;
|
||||
using Remotely.ScreenCast.Core.Interfaces;
|
||||
using Remotely.ScreenCast.Core.Models;
|
||||
using Remotely.ScreenCast.Core.Services;
|
||||
using Remotely.ScreenCast.Core.Communication;
|
||||
using Remotely.ScreenCast.Linux.Capture;
|
||||
using Remotely.ScreenCast.Linux.Services;
|
||||
using Remotely.Shared.Models;
|
||||
using Remotely.Shared.Services;
|
||||
@ -225,14 +223,14 @@ namespace Remotely.Desktop.Linux.ViewModels
|
||||
builder.AddConsole().AddEventLog();
|
||||
});
|
||||
|
||||
serviceCollection.AddSingleton<IScreenCaster, LinuxScreenCaster>();
|
||||
serviceCollection.AddSingleton<IScreenCaster, ScreenCasterLinux>();
|
||||
serviceCollection.AddSingleton<IKeyboardMouseInput, X11Input>();
|
||||
serviceCollection.AddSingleton<IClipboardService, LinuxClipboardService>();
|
||||
serviceCollection.AddSingleton<IAudioCapturer, LinuxAudioCapturer>();
|
||||
serviceCollection.AddSingleton<IClipboardService, ClipboardServiceLinux>();
|
||||
serviceCollection.AddSingleton<IAudioCapturer, AudioCapturerLinux>();
|
||||
serviceCollection.AddSingleton<CasterSocket>();
|
||||
serviceCollection.AddSingleton<IdleTimer>();
|
||||
serviceCollection.AddSingleton<Conductor>();
|
||||
serviceCollection.AddTransient<ICapturer, X11Capture>();
|
||||
serviceCollection.AddTransient<IScreenCapturer, X11Capture>();
|
||||
|
||||
|
||||
ServiceContainer.Instance = serviceCollection.BuildServiceProvider();
|
||||
|
||||
@ -2,10 +2,8 @@
|
||||
using Remotely.Desktop.Win.Services;
|
||||
using Remotely.Shared.Models;
|
||||
using Remotely.ScreenCast.Core;
|
||||
using Remotely.ScreenCast.Core.Capture;
|
||||
using Remotely.ScreenCast.Core.Models;
|
||||
using Remotely.ScreenCast.Core.Services;
|
||||
using Remotely.ScreenCast.Win.Capture;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@ -255,34 +253,14 @@ namespace Remotely.Desktop.Win.ViewModels
|
||||
});
|
||||
|
||||
serviceCollection.AddSingleton<CursorIconWatcher>();
|
||||
serviceCollection.AddSingleton<IScreenCaster, WinScreenCaster>();
|
||||
serviceCollection.AddSingleton<IKeyboardMouseInput, WinInput>();
|
||||
serviceCollection.AddSingleton<IClipboardService, WinClipboardService>();
|
||||
serviceCollection.AddSingleton<IAudioCapturer, WinAudioCapturer>();
|
||||
serviceCollection.AddSingleton<IScreenCaster, ScreenCasterWin>();
|
||||
serviceCollection.AddSingleton<IKeyboardMouseInput, KeyboardMouseInputWin>();
|
||||
serviceCollection.AddSingleton<IClipboardService, ClipboardServiceWin>();
|
||||
serviceCollection.AddSingleton<IAudioCapturer, AudioCapturerWin>();
|
||||
serviceCollection.AddSingleton<CasterSocket>();
|
||||
serviceCollection.AddSingleton<IdleTimer>();
|
||||
serviceCollection.AddSingleton<Conductor>();
|
||||
serviceCollection.AddTransient<ICapturer>(provider =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var dxCapture = new DXCapture();
|
||||
if (dxCapture.GetScreenCount() == Screen.AllScreens.Length)
|
||||
{
|
||||
return dxCapture;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Write("DX screen count doesn't match. Using CPU capturer instead.");
|
||||
dxCapture.Dispose();
|
||||
return new BitBltCapture();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new BitBltCapture();
|
||||
}
|
||||
});
|
||||
serviceCollection.AddTransient<IScreenCapturer, ScreenCapturerWin>();
|
||||
|
||||
|
||||
ServiceContainer.Instance = serviceCollection.BuildServiceProvider();
|
||||
|
||||
@ -7,7 +7,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Remotely.ScreenCast.Core.Capture;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
@ -129,9 +128,9 @@ namespace Remotely.ScreenCast.Core.Communication
|
||||
await Connection.SendAsync("SendScreenCapture", captureBytes, viewerID, left, top, width, height, captureTime);
|
||||
}
|
||||
|
||||
public async Task SendScreenCount(int primaryScreenIndex, int screenCount, string viewerID)
|
||||
public async Task SendScreenData(string selectedScreen, string[] displayNames, string viewerID)
|
||||
{
|
||||
await Connection.SendAsync("SendScreenCountToBrowser", primaryScreenIndex, screenCount, viewerID);
|
||||
await Connection.SendAsync("SendScreenDataToBrowser", selectedScreen, displayNames, viewerID);
|
||||
}
|
||||
|
||||
public async Task SendScreenSize(int width, int height, string viewerID)
|
||||
@ -332,11 +331,11 @@ namespace Remotely.ScreenCast.Core.Communication
|
||||
}
|
||||
});
|
||||
|
||||
Connection.On("SelectScreen", (int screenIndex, string viewerID) =>
|
||||
Connection.On("SelectScreen", (string displayName, string viewerID) =>
|
||||
{
|
||||
if (conductor.Viewers.TryGetValue(viewerID, out var viewer))
|
||||
{
|
||||
viewer.Capturer.SetSelectedScreen(screenIndex);
|
||||
viewer.Capturer.SetSelectedScreen(displayName);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -7,19 +7,27 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.ScreenCast.Core.Interfaces
|
||||
{
|
||||
public interface ICapturer : IDisposable
|
||||
public interface IScreenCapturer : IDisposable
|
||||
{
|
||||
event EventHandler<Rectangle> ScreenChanged;
|
||||
|
||||
bool CaptureFullscreen { get; set; }
|
||||
Bitmap CurrentFrame { get; set; }
|
||||
Rectangle CurrentScreenBounds { get; }
|
||||
Bitmap PreviousFrame { get; set; }
|
||||
event EventHandler<Rectangle> ScreenChanged;
|
||||
int SelectedScreen { get; }
|
||||
void SetSelectedScreen(int screenNumber);
|
||||
int GetScreenCount();
|
||||
Rectangle GetVirtualScreenBounds();
|
||||
string SelectedScreen { get; }
|
||||
|
||||
IEnumerable<string> GetDisplayNames();
|
||||
|
||||
void GetNextFrame();
|
||||
|
||||
int GetScreenCount();
|
||||
|
||||
int GetSelectedScreenIndex();
|
||||
Rectangle GetVirtualScreenBounds();
|
||||
|
||||
void Init();
|
||||
|
||||
void SetSelectedScreen(string displayName);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
using Remotely.ScreenCast.Core.Capture;
|
||||
using Remotely.ScreenCast.Core.Communication;
|
||||
using Remotely.ScreenCast.Core.Communication;
|
||||
using Remotely.ScreenCast.Core.Interfaces;
|
||||
using Remotely.ScreenCast.Core.Services;
|
||||
using System;
|
||||
@ -20,7 +19,7 @@ namespace Remotely.ScreenCast.Core.Models
|
||||
ImageQuality = 75;
|
||||
}
|
||||
public bool AutoAdjustQuality { get; internal set; } = true;
|
||||
public ICapturer Capturer { get; set; }
|
||||
public IScreenCapturer Capturer { get; set; }
|
||||
public bool DisconnectRequested { get; set; }
|
||||
public EncoderParameters EncoderParams { get; private set; }
|
||||
public bool FullScreenRefreshNeeded { get; internal set; }
|
||||
|
||||
@ -17,14 +17,15 @@ using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Drawing.Imaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Remotely.ScreenCast.Core.Utilities;
|
||||
|
||||
namespace Remotely.ScreenCast.Core.Capture
|
||||
namespace Remotely.ScreenCast.Core.Services
|
||||
{
|
||||
public class ScreenCasterBase
|
||||
{
|
||||
public async Task BeginScreenCasting(string viewerID,
|
||||
string requesterName,
|
||||
ICapturer capturer)
|
||||
IScreenCapturer capturer)
|
||||
{
|
||||
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
|
||||
var viewers = conductor.Viewers;
|
||||
@ -59,9 +60,9 @@ namespace Remotely.ScreenCast.Core.Capture
|
||||
|
||||
await casterSocket.SendMachineName(Environment.MachineName, viewerID);
|
||||
|
||||
await casterSocket.SendScreenCount(
|
||||
await casterSocket.SendScreenData(
|
||||
capturer.SelectedScreen,
|
||||
capturer.GetScreenCount(),
|
||||
capturer.GetDisplayNames().ToArray(),
|
||||
viewerID);
|
||||
|
||||
await casterSocket.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);
|
||||
@ -10,7 +10,7 @@ using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.ScreenCast.Core.Capture
|
||||
namespace Remotely.ScreenCast.Core.Utilities
|
||||
{
|
||||
public class ImageUtils
|
||||
{
|
||||
@ -3,7 +3,6 @@ using Remotely.ScreenCast.Core.Services;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Remotely.ScreenCast.Linux.Services;
|
||||
using Remotely.ScreenCast.Linux.Capture;
|
||||
using Remotely.ScreenCast.Core.Communication;
|
||||
using Remotely.ScreenCast.Core.Interfaces;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@ -60,15 +59,15 @@ namespace Remotely.ScreenCast.Linux
|
||||
builder.AddConsole().AddEventLog();
|
||||
});
|
||||
|
||||
serviceCollection.AddSingleton<IScreenCaster, LinuxScreenCaster>();
|
||||
serviceCollection.AddSingleton<IScreenCaster, ScreenCasterLinux>();
|
||||
serviceCollection.AddSingleton<IKeyboardMouseInput, X11Input>();
|
||||
serviceCollection.AddSingleton<IClipboardService, LinuxClipboardService>();
|
||||
serviceCollection.AddSingleton<IAudioCapturer, LinuxAudioCapturer>();
|
||||
serviceCollection.AddSingleton<IClipboardService, ClipboardServiceLinux>();
|
||||
serviceCollection.AddSingleton<IAudioCapturer, AudioCapturerLinux>();
|
||||
serviceCollection.AddSingleton<CasterSocket>();
|
||||
serviceCollection.AddSingleton<IdleTimer>();
|
||||
serviceCollection.AddSingleton<Conductor>();
|
||||
serviceCollection.AddSingleton<ChatHostService>();
|
||||
serviceCollection.AddTransient<ICapturer, X11Capture>();
|
||||
serviceCollection.AddTransient<IScreenCapturer, X11Capture>();
|
||||
|
||||
ServiceContainer.Instance = serviceCollection.BuildServiceProvider();
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ using System.Text;
|
||||
|
||||
namespace Remotely.ScreenCast.Linux.Services
|
||||
{
|
||||
public class LinuxAudioCapturer : IAudioCapturer
|
||||
public class AudioCapturerLinux : IAudioCapturer
|
||||
{
|
||||
public void ToggleAudio(bool toggleOn)
|
||||
{
|
||||
@ -8,7 +8,7 @@ using System.Text;
|
||||
|
||||
namespace Remotely.ScreenCast.Linux.Services
|
||||
{
|
||||
public class LinuxClipboardService : IClipboardService
|
||||
public class ClipboardServiceLinux : IClipboardService
|
||||
{
|
||||
public event EventHandler<string> ClipboardTextChanged;
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Remotely.ScreenCast.Core;
|
||||
using Remotely.ScreenCast.Core.Capture;
|
||||
using Remotely.ScreenCast.Core.Interfaces;
|
||||
using Remotely.ScreenCast.Core.Services;
|
||||
using Remotely.ScreenCast.Linux.Capture;
|
||||
using Remotely.Shared.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -13,7 +11,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.ScreenCast.Linux.Services
|
||||
{
|
||||
public class LinuxScreenCaster : ScreenCasterBase, IScreenCaster
|
||||
public class ScreenCasterLinux : ScreenCasterBase, IScreenCaster
|
||||
{
|
||||
public async Task BeginScreenCasting(ScreenCastRequest screenCastRequest)
|
||||
{
|
||||
@ -21,7 +19,7 @@ namespace Remotely.ScreenCast.Linux.Services
|
||||
{
|
||||
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
|
||||
await conductor.CasterSocket.SendCursorChange(new CursorInfo(null, Point.Empty, "default"), new List<string>() { screenCastRequest.ViewerID });
|
||||
_ = BeginScreenCasting(screenCastRequest.ViewerID, screenCastRequest.RequesterName, ServiceContainer.Instance.GetRequiredService<ICapturer>());
|
||||
_ = BeginScreenCasting(screenCastRequest.ViewerID, screenCastRequest.RequesterName, ServiceContainer.Instance.GetRequiredService<IScreenCapturer>());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -1,31 +1,42 @@
|
||||
using Remotely.ScreenCast.Core.Capture;
|
||||
using Remotely.ScreenCast.Core.Interfaces;
|
||||
using Remotely.ScreenCast.Core.Interfaces;
|
||||
using Remotely.ScreenCast.Core.Services;
|
||||
using Remotely.ScreenCast.Linux.X11Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Remotely.ScreenCast.Linux.Capture
|
||||
namespace Remotely.ScreenCast.Linux.Services
|
||||
{
|
||||
public class X11Capture : ICapturer
|
||||
public class X11Capture : IScreenCapturer
|
||||
{
|
||||
private readonly Dictionary<string, int> x11Screens = new Dictionary<string, int>();
|
||||
public X11Capture()
|
||||
{
|
||||
Display = LibX11.XOpenDisplay(null);
|
||||
Init();
|
||||
}
|
||||
|
||||
public event EventHandler<Rectangle> ScreenChanged;
|
||||
|
||||
public bool CaptureFullscreen { get; set; }
|
||||
public Bitmap CurrentFrame { get; set; }
|
||||
public Rectangle CurrentScreenBounds { get; private set; }
|
||||
public IntPtr Display { get; private set; }
|
||||
public Bitmap PreviousFrame { get; set; }
|
||||
public event EventHandler<Rectangle> ScreenChanged;
|
||||
public int SelectedScreen { get; private set; } = -1;
|
||||
public string SelectedScreen { get; private set; } = "0";
|
||||
public void Dispose()
|
||||
{
|
||||
//Graphic.Dispose();
|
||||
CurrentFrame.Dispose();
|
||||
PreviousFrame.Dispose();
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetDisplayNames() => x11Screens.Keys;
|
||||
|
||||
public void GetNextFrame()
|
||||
{
|
||||
try
|
||||
@ -40,19 +51,13 @@ namespace Remotely.ScreenCast.Linux.Capture
|
||||
Init();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
//Graphic.Dispose();
|
||||
CurrentFrame.Dispose();
|
||||
PreviousFrame.Dispose();
|
||||
}
|
||||
|
||||
public int GetScreenCount()
|
||||
{
|
||||
return LibX11.XScreenCount(Display);
|
||||
}
|
||||
|
||||
public int GetSelectedScreenIndex() => x11Screens[SelectedScreen];
|
||||
|
||||
public Rectangle GetVirtualScreenBounds()
|
||||
{
|
||||
int width = 0;
|
||||
@ -72,8 +77,14 @@ namespace Remotely.ScreenCast.Linux.Capture
|
||||
{
|
||||
try
|
||||
{
|
||||
x11Screens.Clear();
|
||||
|
||||
for (var i = 0; i < GetScreenCount(); i++)
|
||||
{
|
||||
x11Screens.Add(i.ToString(), i);
|
||||
}
|
||||
var defaultScreen = LibX11.XDefaultScreen(Display);
|
||||
SetSelectedScreen(defaultScreen);
|
||||
SetSelectedScreen(defaultScreen.ToString());
|
||||
CurrentFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
|
||||
PreviousFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
@ -82,25 +93,24 @@ namespace Remotely.ScreenCast.Linux.Capture
|
||||
Logger.Write(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSelectedScreen(int screenNumber)
|
||||
public void SetSelectedScreen(string displayName)
|
||||
{
|
||||
if (screenNumber == SelectedScreen)
|
||||
if (displayName == SelectedScreen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (GetScreenCount() >= screenNumber + 1)
|
||||
if (x11Screens.ContainsKey(displayName))
|
||||
{
|
||||
SelectedScreen = screenNumber;
|
||||
SelectedScreen = displayName;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedScreen = 0;
|
||||
SelectedScreen = x11Screens.Keys.First();
|
||||
}
|
||||
var width = LibX11.XDisplayWidth(Display, SelectedScreen);
|
||||
var height = LibX11.XDisplayHeight(Display, SelectedScreen);
|
||||
var width = LibX11.XDisplayWidth(Display, x11Screens[SelectedScreen]);
|
||||
var height = LibX11.XDisplayHeight(Display, x11Screens[SelectedScreen]);
|
||||
CurrentScreenBounds = new Rectangle(0, 0, width, height);
|
||||
CaptureFullscreen = true;
|
||||
Init();
|
||||
@ -115,7 +125,7 @@ namespace Remotely.ScreenCast.Linux.Capture
|
||||
|
||||
private void RefreshCurrentFrame()
|
||||
{
|
||||
var window = LibX11.XRootWindow(Display, SelectedScreen);
|
||||
var window = LibX11.XRootWindow(Display, x11Screens[SelectedScreen]);
|
||||
|
||||
var imagePointer = LibX11.XGetImage(Display, window, 0, 0, CurrentScreenBounds.Width, CurrentScreenBounds.Height, ~0, 2);
|
||||
var image = Marshal.PtrToStructure<LibX11.XImage>(imagePointer);
|
||||
@ -6,7 +6,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using Remotely.ScreenCast.Linux.Capture;
|
||||
using Remotely.ScreenCast.Core.Models;
|
||||
|
||||
namespace Remotely.ScreenCast.Linux.Services
|
||||
@ -98,7 +97,7 @@ namespace Remotely.ScreenCast.Linux.Services
|
||||
try
|
||||
{
|
||||
LibXtst.XTestFakeMotionEvent(Display,
|
||||
viewer.Capturer.SelectedScreen,
|
||||
viewer.Capturer.GetSelectedScreenIndex(),
|
||||
(int)(viewer.Capturer.CurrentScreenBounds.Width * percentX),
|
||||
(int)(viewer.Capturer.CurrentScreenBounds.Height * percentY),
|
||||
0);
|
||||
|
||||
@ -1,99 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using Remotely.ScreenCast.Core.Services;
|
||||
using System.Threading;
|
||||
using Remotely.ScreenCast.Core.Interfaces;
|
||||
using Remotely.Shared.Win32;
|
||||
|
||||
namespace Remotely.ScreenCast.Win.Capture
|
||||
{
|
||||
public class BitBltCapture : ICapturer
|
||||
{
|
||||
public BitBltCapture()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
public event EventHandler<Rectangle> ScreenChanged;
|
||||
|
||||
public bool CaptureFullscreen { get; set; } = true;
|
||||
public Bitmap CurrentFrame { get; set; }
|
||||
public Rectangle CurrentScreenBounds { get; set; } = Screen.PrimaryScreen.Bounds;
|
||||
public Bitmap PreviousFrame { get; set; }
|
||||
public int SelectedScreen { get; private set; } = Screen.AllScreens.ToList().IndexOf(Screen.PrimaryScreen);
|
||||
private Graphics Graphic { get; set; }
|
||||
public void Dispose()
|
||||
{
|
||||
Graphic.Dispose();
|
||||
CurrentFrame.Dispose();
|
||||
PreviousFrame.Dispose();
|
||||
}
|
||||
|
||||
public void GetNextFrame()
|
||||
{
|
||||
try
|
||||
{
|
||||
Win32Interop.SwitchToInputDesktop();
|
||||
PreviousFrame.Dispose();
|
||||
PreviousFrame = (Bitmap)CurrentFrame.Clone();
|
||||
Graphic.CopyFromScreen(CurrentScreenBounds.Left, CurrentScreenBounds.Top, 0, 0, new Size(CurrentScreenBounds.Width, CurrentScreenBounds.Height));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
Logger.Write("Capturer error. Trying to switch desktops in BitBltCapture.");
|
||||
if (Win32Interop.SwitchToInputDesktop())
|
||||
{
|
||||
Win32Interop.GetCurrentDesktop(out var desktopName);
|
||||
Logger.Write($"Switch to desktop {desktopName} after capture error in BitBltCapture.");
|
||||
}
|
||||
Init();
|
||||
}
|
||||
}
|
||||
public int GetScreenCount()
|
||||
{
|
||||
return Screen.AllScreens.Length;
|
||||
}
|
||||
|
||||
public Rectangle GetVirtualScreenBounds()
|
||||
{
|
||||
return SystemInformation.VirtualScreen;
|
||||
}
|
||||
|
||||
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 SetSelectedScreen(int screenNumber)
|
||||
{
|
||||
if (screenNumber == SelectedScreen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetScreenCount() >= screenNumber + 1)
|
||||
{
|
||||
SelectedScreen = screenNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedScreen = 0;
|
||||
}
|
||||
CurrentScreenBounds = Screen.AllScreens[SelectedScreen].Bounds;
|
||||
CaptureFullscreen = true;
|
||||
Init();
|
||||
ScreenChanged?.Invoke(this, CurrentScreenBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,6 @@ using Remotely.Shared.Win32;
|
||||
using System.Threading;
|
||||
using Remotely.ScreenCast.Win.Services;
|
||||
using Remotely.ScreenCast.Core.Interfaces;
|
||||
using Remotely.ScreenCast.Win.Capture;
|
||||
using Remotely.ScreenCast.Core.Communication;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@ -70,36 +69,15 @@ namespace Remotely.ScreenCast.Win
|
||||
});
|
||||
|
||||
serviceCollection.AddSingleton<CursorIconWatcher>();
|
||||
serviceCollection.AddSingleton<IScreenCaster, WinScreenCaster>();
|
||||
serviceCollection.AddSingleton<IKeyboardMouseInput, WinInput>();
|
||||
serviceCollection.AddSingleton<IClipboardService, WinClipboardService>();
|
||||
serviceCollection.AddSingleton<IAudioCapturer, WinAudioCapturer>();
|
||||
serviceCollection.AddSingleton<IScreenCaster, ScreenCasterWin>();
|
||||
serviceCollection.AddSingleton<IKeyboardMouseInput, KeyboardMouseInputWin>();
|
||||
serviceCollection.AddSingleton<IClipboardService, ClipboardServiceWin>();
|
||||
serviceCollection.AddSingleton<IAudioCapturer, AudioCapturerWin>();
|
||||
serviceCollection.AddSingleton<CasterSocket>();
|
||||
serviceCollection.AddSingleton<IdleTimer>();
|
||||
serviceCollection.AddSingleton<Conductor>();
|
||||
serviceCollection.AddSingleton<ChatHostService>();
|
||||
serviceCollection.AddTransient<ICapturer>(provider =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var dxCapture = new DXCapture();
|
||||
if (dxCapture.GetScreenCount() == Screen.AllScreens.Length)
|
||||
{
|
||||
return dxCapture;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Write("DX screen count doesn't match. Using CPU capturer instead.");
|
||||
dxCapture.Dispose();
|
||||
return new BitBltCapture();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
return new BitBltCapture();
|
||||
}
|
||||
});
|
||||
serviceCollection.AddTransient<IScreenCapturer, ScreenCapturerWin>();
|
||||
|
||||
ServiceContainer.Instance = serviceCollection.BuildServiceProvider();
|
||||
}
|
||||
|
||||
@ -36,6 +36,10 @@
|
||||
<ProjectReference Include="..\Shared\Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="if $(ConfigurationName) == Debug (
 if $(PlatformName) == Any CPU (
 md "$(SolutionDir)Agent\bin\Debug\netcoreapp3.1\ScreenCast\"
 xcopy "$(TargetDir)*" "$(SolutionDir)Agent\bin\Debug\netcoreapp3.1\ScreenCast\" /y /e /i
 )
 if $(PlatformName) == x64 (
 md "$(SolutionDir)Agent\bin\x64\Debug\netcoreapp3.1\ScreenCast\"
 xcopy "$(TargetDir)*" "$(SolutionDir)Agent\bin\x64\Debug\netcoreapp3.1\ScreenCast\" /y /e /i
 )
 if $(PlatformName) == x86 (
 md "$(SolutionDir)Agent\bin\x86\Debug\netcoreapp3.1\ScreenCast\"
 xcopy "$(TargetDir)*" "$(SolutionDir)Agent\bin\x86\Debug\netcoreapp3.1\ScreenCast\" /y /e /i
 )
)" />
|
||||
|
||||
@ -13,7 +13,7 @@ using Remotely.ScreenCast.Core.Interfaces;
|
||||
|
||||
namespace Remotely.ScreenCast.Win.Services
|
||||
{
|
||||
public class WinAudioCapturer : IAudioCapturer
|
||||
public class AudioCapturerWin : IAudioCapturer
|
||||
{
|
||||
private WasapiLoopbackCapture Capturer { get; set; }
|
||||
private Stopwatch SendTimer { get; set; }
|
||||
@ -12,7 +12,7 @@ using System.Windows.Forms;
|
||||
|
||||
namespace Remotely.ScreenCast.Win.Services
|
||||
{
|
||||
public class WinClipboardService : IClipboardService
|
||||
public class ClipboardServiceWin : IClipboardService
|
||||
{
|
||||
public event EventHandler<string> ClipboardTextChanged;
|
||||
|
||||
@ -12,9 +12,9 @@ using Remotely.ScreenCast.Core;
|
||||
|
||||
namespace Remotely.ScreenCast.Win.Services
|
||||
{
|
||||
public class WinInput : IKeyboardMouseInput
|
||||
public class KeyboardMouseInputWin : IKeyboardMouseInput
|
||||
{
|
||||
public WinInput()
|
||||
public KeyboardMouseInputWin()
|
||||
{
|
||||
StartInputActionThread();
|
||||
Application.ApplicationExit += Application_ApplicationExit;
|
||||
@ -30,14 +30,14 @@ namespace Remotely.ScreenCast.Win.Services
|
||||
|
||||
private bool ShutdownStarted { get; set; }
|
||||
|
||||
public Tuple<double, double> GetAbsolutePercentFromRelativePercent(double percentX, double percentY, ICapturer capturer)
|
||||
public Tuple<double, double> GetAbsolutePercentFromRelativePercent(double percentX, double percentY, IScreenCapturer capturer)
|
||||
{
|
||||
var absoluteX = (capturer.CurrentScreenBounds.Width * percentX) + capturer.CurrentScreenBounds.Left - capturer.GetVirtualScreenBounds().Left;
|
||||
var absoluteY = (capturer.CurrentScreenBounds.Height * percentY) + capturer.CurrentScreenBounds.Top - capturer.GetVirtualScreenBounds().Top;
|
||||
return new Tuple<double, double>(absoluteX / capturer.GetVirtualScreenBounds().Width, absoluteY / capturer.GetVirtualScreenBounds().Height);
|
||||
}
|
||||
|
||||
public Tuple<double, double> GetAbsolutePointFromRelativePercent(double percentX, double percentY, ICapturer capturer)
|
||||
public Tuple<double, double> GetAbsolutePointFromRelativePercent(double percentX, double percentY, IScreenCapturer capturer)
|
||||
{
|
||||
var absoluteX = (capturer.CurrentScreenBounds.Width * percentX) + capturer.CurrentScreenBounds.Left;
|
||||
var absoluteY = (capturer.CurrentScreenBounds.Height * percentY) + capturer.CurrentScreenBounds.Top;
|
||||
@ -1,4 +1,5 @@
|
||||
// Much of this class was taken from the SharpDX samples.
|
||||
// The DirectX capture code is based off examples from the
|
||||
// SharpDX Samples at https://github.com/sharpdx/SharpDX.
|
||||
|
||||
// Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
|
||||
//
|
||||
@ -29,6 +30,7 @@ using SharpDX.Direct3D11;
|
||||
using SharpDX.DXGI;
|
||||
using SharpDX.Mathematics.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
@ -36,13 +38,14 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Remotely.ScreenCast.Win.Capture
|
||||
namespace Remotely.ScreenCast.Win.Services
|
||||
{
|
||||
public class DXCapture : ICapturer
|
||||
public class ScreenCapturerWin : IScreenCapturer
|
||||
{
|
||||
private readonly Dictionary<string, int> bitBltScreens = new Dictionary<string, int>();
|
||||
private readonly Dictionary<string, OutputDuplication> directxScreens = new Dictionary<string, OutputDuplication>();
|
||||
private Adapter1 adapter;
|
||||
private SharpDX.Direct3D11.Device device;
|
||||
private OutputDuplication duplicatedOutput;
|
||||
private Factory1 factory;
|
||||
private FeatureLevel[] featureLevels = new FeatureLevel[]
|
||||
{
|
||||
@ -57,24 +60,39 @@ namespace Remotely.ScreenCast.Win.Capture
|
||||
FeatureLevel.Level_12_1
|
||||
};
|
||||
private int height;
|
||||
private Output output;
|
||||
private Output1 output1;
|
||||
private Texture2D screenTexture;
|
||||
private Texture2DDescription textureDesc;
|
||||
private int width;
|
||||
public bool CaptureFullscreen { get; set; } = true;
|
||||
public Bitmap CurrentFrame { get; set; }
|
||||
public Rectangle CurrentScreenBounds { get; private set; }
|
||||
public bool NeedsInit { get; set; } = true;
|
||||
public Bitmap PreviousFrame { get; set; }
|
||||
public event EventHandler<Rectangle> ScreenChanged;
|
||||
public int SelectedScreen { get; private set; } = 0;
|
||||
|
||||
public DXCapture()
|
||||
public ScreenCapturerWin()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
public event EventHandler<Rectangle> ScreenChanged;
|
||||
|
||||
public bool CaptureFullscreen { get; set; } = true;
|
||||
public Bitmap CurrentFrame { get; set; }
|
||||
public Rectangle CurrentScreenBounds { get; private set; } = Screen.PrimaryScreen.Bounds;
|
||||
public bool NeedsInit { get; set; } = true;
|
||||
public Bitmap PreviousFrame { get; set; }
|
||||
public string SelectedScreen { get; private set; } = Screen.PrimaryScreen.DeviceName;
|
||||
private Graphics Graphic { get; set; }
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var output in directxScreens.Values)
|
||||
{
|
||||
output.Dispose();
|
||||
}
|
||||
directxScreens.Clear();
|
||||
device?.Dispose();
|
||||
adapter?.Dispose();
|
||||
factory?.Dispose();
|
||||
CurrentFrame?.Dispose();
|
||||
PreviousFrame?.Dispose();
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetDisplayNames() => Screen.AllScreens.Select(x => x.DeviceName);
|
||||
|
||||
public void GetNextFrame()
|
||||
{
|
||||
try
|
||||
@ -90,12 +108,96 @@ namespace Remotely.ScreenCast.Win.Capture
|
||||
Init();
|
||||
}
|
||||
|
||||
Win32Interop.SwitchToInputDesktop();
|
||||
|
||||
PreviousFrame.Dispose();
|
||||
PreviousFrame = (Bitmap)CurrentFrame.Clone();
|
||||
|
||||
if (directxScreens.ContainsKey(SelectedScreen))
|
||||
{
|
||||
try
|
||||
{
|
||||
GetDirectXFrame();
|
||||
}
|
||||
catch
|
||||
{
|
||||
GetBitBltFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Write(e);
|
||||
NeedsInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetScreenCount() => Screen.AllScreens.Length;
|
||||
|
||||
public int GetSelectedScreenIndex() => bitBltScreens[SelectedScreen];
|
||||
|
||||
public Rectangle GetVirtualScreenBounds() => SystemInformation.VirtualScreen;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
CurrentFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
|
||||
PreviousFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
|
||||
|
||||
InitBitBlt();
|
||||
InitDirectX();
|
||||
}
|
||||
public void SetSelectedScreen(string displayName)
|
||||
{
|
||||
if (displayName == SelectedScreen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (bitBltScreens.ContainsKey(displayName))
|
||||
{
|
||||
SelectedScreen = displayName;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedScreen = bitBltScreens.Keys.First();
|
||||
}
|
||||
CurrentScreenBounds = Screen.AllScreens[bitBltScreens[SelectedScreen]].Bounds;
|
||||
CaptureFullscreen = true;
|
||||
NeedsInit = true;
|
||||
ScreenChanged?.Invoke(this, CurrentScreenBounds);
|
||||
}
|
||||
|
||||
private void GetBitBltFrame()
|
||||
{
|
||||
try
|
||||
{
|
||||
Win32Interop.SwitchToInputDesktop();
|
||||
PreviousFrame.Dispose();
|
||||
PreviousFrame = (Bitmap)CurrentFrame.Clone();
|
||||
Graphic.CopyFromScreen(CurrentScreenBounds.Left, CurrentScreenBounds.Top, 0, 0, new Size(CurrentScreenBounds.Width, CurrentScreenBounds.Height));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
Logger.Write("Capturer error. Trying to switch desktops in BitBltCapture.");
|
||||
if (Win32Interop.SwitchToInputDesktop())
|
||||
{
|
||||
Win32Interop.GetCurrentDesktop(out var desktopName);
|
||||
Logger.Write($"Switch to desktop {desktopName} after capture error in BitBltCapture.");
|
||||
}
|
||||
NeedsInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void GetDirectXFrame()
|
||||
{
|
||||
try
|
||||
{
|
||||
SharpDX.DXGI.Resource screenResource;
|
||||
OutputDuplicateFrameInformation duplicateFrameInformation;
|
||||
|
||||
var duplicatedOutput = directxScreens[SelectedScreen];
|
||||
|
||||
// Try to get duplicated frame within given time is ms
|
||||
var result = duplicatedOutput.TryAcquireNextFrame(100, out duplicateFrameInformation, out screenResource);
|
||||
|
||||
@ -121,16 +223,16 @@ namespace Remotely.ScreenCast.Win.Capture
|
||||
//RawRectangle[] dirtyRectsBuffer = new RawRectangle[duplicateFrameInformation.TotalMetadataBufferSize];
|
||||
//duplicatedOutput.GetFrameDirtyRects(duplicateFrameInformation.TotalMetadataBufferSize, dirtyRectsBuffer, out var dirtyRectsSizeRequired);
|
||||
|
||||
|
||||
|
||||
// copy resource into memory that can be accessed by the CPU
|
||||
using (var screenTexture2D = screenResource.QueryInterface<Texture2D>())
|
||||
{
|
||||
device.ImmediateContext.CopyResource(screenTexture2D, screenTexture);
|
||||
}
|
||||
|
||||
|
||||
// Get the desktop capture texture
|
||||
var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None);
|
||||
|
||||
|
||||
var boundsRect = new Rectangle(0, 0, width, height);
|
||||
|
||||
// Copy pixels from screen capture Texture to GDI bitmap
|
||||
@ -162,36 +264,17 @@ namespace Remotely.ScreenCast.Win.Capture
|
||||
NeedsInit = true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
}
|
||||
|
||||
private void InitBitBlt()
|
||||
{
|
||||
Graphic = Graphics.FromImage(CurrentFrame);
|
||||
for (var i = 0; i < Screen.AllScreens.Length; i++)
|
||||
{
|
||||
Logger.Write(e);
|
||||
NeedsInit = true;
|
||||
bitBltScreens.Add(Screen.AllScreens[i].DeviceName, i);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
duplicatedOutput?.Dispose();
|
||||
output1?.Dispose();
|
||||
output?.Dispose();
|
||||
device?.Dispose();
|
||||
adapter?.Dispose();
|
||||
factory?.Dispose();
|
||||
CurrentFrame?.Dispose();
|
||||
PreviousFrame?.Dispose();
|
||||
}
|
||||
|
||||
public int GetScreenCount()
|
||||
{
|
||||
return adapter.GetOutputCount();
|
||||
}
|
||||
|
||||
public Rectangle GetVirtualScreenBounds()
|
||||
{
|
||||
return SystemInformation.VirtualScreen;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
private void InitDirectX()
|
||||
{
|
||||
Dispose();
|
||||
|
||||
@ -201,72 +284,47 @@ namespace Remotely.ScreenCast.Win.Capture
|
||||
adapter = factory.Adapters1.FirstOrDefault(x => x.Outputs.Length > 0);
|
||||
//Get device from adapter
|
||||
device = new SharpDX.Direct3D11.Device(adapter);
|
||||
//Get front buffer of the adapter
|
||||
if (adapter.GetOutputCount() < SelectedScreen + 1)
|
||||
|
||||
for (var i = 0; i < adapter.GetOutputCount(); i++)
|
||||
{
|
||||
SelectedScreen = 0;
|
||||
using (var output = adapter.GetOutput(i))
|
||||
using (var output1 = output.QueryInterface<Output1>())
|
||||
{
|
||||
// Width/Height of desktop to capture
|
||||
var bounds = output1.Description.DesktopBounds;
|
||||
var newWidth = bounds.Right - bounds.Left;
|
||||
var newHeight = bounds.Bottom - bounds.Top;
|
||||
CurrentScreenBounds = new Rectangle(bounds.Left, bounds.Top, newWidth, newHeight);
|
||||
if (newWidth != width || newHeight != height)
|
||||
{
|
||||
ScreenChanged?.Invoke(this, CurrentScreenBounds);
|
||||
}
|
||||
width = newWidth;
|
||||
height = newHeight;
|
||||
|
||||
CurrentFrame = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
||||
PreviousFrame = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
||||
|
||||
// Create Staging texture CPU-accessible
|
||||
textureDesc = new Texture2DDescription
|
||||
{
|
||||
CpuAccessFlags = CpuAccessFlags.Read,
|
||||
BindFlags = BindFlags.None,
|
||||
Format = Format.B8G8R8A8_UNorm,
|
||||
Width = width,
|
||||
Height = height,
|
||||
OptionFlags = ResourceOptionFlags.None,
|
||||
MipLevels = 1,
|
||||
ArraySize = 1,
|
||||
SampleDescription = { Count = 1, Quality = 0 },
|
||||
Usage = ResourceUsage.Staging
|
||||
};
|
||||
screenTexture = new Texture2D(device, textureDesc);
|
||||
directxScreens.Add(output1.Description.DeviceName, output1.DuplicateOutput(device));
|
||||
}
|
||||
}
|
||||
output = adapter.GetOutput(SelectedScreen);
|
||||
output1 = output.QueryInterface<Output1>();
|
||||
|
||||
// Width/Height of desktop to capture
|
||||
var bounds = output1.Description.DesktopBounds;
|
||||
var newWidth = bounds.Right - bounds.Left;
|
||||
var newHeight = bounds.Bottom - bounds.Top;
|
||||
CurrentScreenBounds = new Rectangle(bounds.Left, bounds.Top, newWidth, newHeight);
|
||||
if (newWidth != width || newHeight != height)
|
||||
{
|
||||
ScreenChanged?.Invoke(this, CurrentScreenBounds);
|
||||
}
|
||||
width = newWidth;
|
||||
height = newHeight;
|
||||
|
||||
CurrentFrame = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
||||
PreviousFrame = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
||||
|
||||
// Create Staging texture CPU-accessible
|
||||
textureDesc = new Texture2DDescription
|
||||
{
|
||||
CpuAccessFlags = CpuAccessFlags.Read,
|
||||
BindFlags = BindFlags.None,
|
||||
Format = Format.B8G8R8A8_UNorm,
|
||||
Width = width,
|
||||
Height = height,
|
||||
OptionFlags = ResourceOptionFlags.None,
|
||||
MipLevels = 1,
|
||||
ArraySize = 1,
|
||||
SampleDescription = { Count = 1, Quality = 0 },
|
||||
Usage = ResourceUsage.Staging
|
||||
};
|
||||
screenTexture = new Texture2D(device, textureDesc);
|
||||
duplicatedOutput = output1.DuplicateOutput(device);
|
||||
|
||||
NeedsInit = false;
|
||||
}
|
||||
|
||||
public void SetSelectedScreen(int screenNumber)
|
||||
{
|
||||
if (screenNumber == SelectedScreen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (adapter == null)
|
||||
{
|
||||
SelectedScreen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (adapter.Outputs.Length >= screenNumber + 1)
|
||||
{
|
||||
SelectedScreen = screenNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedScreen = 0;
|
||||
}
|
||||
}
|
||||
CaptureFullscreen = true;
|
||||
NeedsInit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,20 +6,18 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Remotely.ScreenCast.Core.Enums;
|
||||
using Remotely.ScreenCast.Core.Services;
|
||||
using Remotely.ScreenCast.Core.Capture;
|
||||
using Remotely.ScreenCast.Core;
|
||||
using Remotely.ScreenCast.Core.Models;
|
||||
using Remotely.Shared.Models;
|
||||
using Remotely.ScreenCast.Win.Capture;
|
||||
using Remotely.Shared.Win32;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Threading;
|
||||
|
||||
namespace Remotely.ScreenCast.Win.Services
|
||||
{
|
||||
public class WinScreenCaster : ScreenCasterBase, IScreenCaster
|
||||
public class ScreenCasterWin : ScreenCasterBase, IScreenCaster
|
||||
{
|
||||
public WinScreenCaster(CursorIconWatcher cursorIconWatcher)
|
||||
public ScreenCasterWin(CursorIconWatcher cursorIconWatcher)
|
||||
{
|
||||
CursorIconWatcher = cursorIconWatcher;
|
||||
}
|
||||
@ -40,7 +38,7 @@ namespace Remotely.ScreenCast.Win.Services
|
||||
|
||||
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
|
||||
await conductor.CasterSocket.SendCursorChange(CursorIconWatcher.GetCurrentCursor(), new List<string>() { screenCastRequest.ViewerID });
|
||||
_ = BeginScreenCasting(screenCastRequest.ViewerID, screenCastRequest.RequesterName, ServiceContainer.Instance.GetRequiredService<ICapturer>());
|
||||
_ = BeginScreenCasting(screenCastRequest.ViewerID, screenCastRequest.RequesterName, ServiceContainer.Instance.GetRequiredService<IScreenCapturer>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -135,6 +135,10 @@ namespace Remotely.Server.Services
|
||||
public Task RemoteControl(string deviceID)
|
||||
{
|
||||
var targetDevice = DeviceSocketHub.ServiceConnections.FirstOrDefault(x => x.Value.ID == deviceID);
|
||||
if (targetDevice.Value is null)
|
||||
{
|
||||
return Clients.Caller.SendAsync("DisplayMessage", $"The selected device is not online.", "Device is not online."); ;
|
||||
}
|
||||
if (DataService.DoesUserHaveAccessToDevice(deviceID, RemotelyUser))
|
||||
{
|
||||
var currentUsers = RCDeviceSocketHub.SessionInfoList.Count(x => x.Value.OrganizationID == RemotelyUser.OrganizationID);
|
||||
|
||||
@ -132,9 +132,9 @@ namespace Remotely.Server.Services
|
||||
return base.OnDisconnectedAsync(exception);
|
||||
}
|
||||
|
||||
public Task SelectScreen(int screenIndex)
|
||||
public Task SelectScreen(string displayName)
|
||||
{
|
||||
return RCDeviceHub.Clients.Client(ScreenCasterID).SendAsync("SelectScreen", screenIndex, Context.ConnectionId);
|
||||
return RCDeviceHub.Clients.Client(ScreenCasterID).SendAsync("SelectScreen", displayName, Context.ConnectionId);
|
||||
}
|
||||
|
||||
public Task SendClipboardTransfer(string transferText, bool typeText)
|
||||
|
||||
@ -210,13 +210,13 @@ namespace Remotely.Server.Services
|
||||
return RCBrowserHub.Clients.Client(rcBrowserHubConnectionID).SendAsync("ScreenCapture", captureBytes, left, top, width, height, captureTime);
|
||||
}
|
||||
|
||||
public Task SendScreenCountToBrowser(int primaryScreenIndex, int screenCount, string rcBrowserHubConnectionID)
|
||||
public Task SendScreenDataToBrowser(string selectedDisplay, string[] displayNames, string browserHubConnectionId)
|
||||
{
|
||||
lock (ViewerList)
|
||||
{
|
||||
ViewerList.Add(rcBrowserHubConnectionID);
|
||||
ViewerList.Add(browserHubConnectionId);
|
||||
}
|
||||
return RCBrowserHub.Clients.Client(rcBrowserHubConnectionID).SendAsync("ScreenCount", primaryScreenIndex, screenCount);
|
||||
return RCBrowserHub.Clients.Client(browserHubConnectionId).SendAsync("ScreenData", selectedDisplay, displayNames);
|
||||
}
|
||||
|
||||
public Task SendScreenSize(int width, int height, string rcBrowserHubConnectionID)
|
||||
|
||||
@ -54,8 +54,8 @@ export class RCBrowserSockets {
|
||||
SendLatencyUpdate(sentTime, bytesReceived) {
|
||||
this.Connection.invoke("SendLatencyUpdate", sentTime, bytesReceived);
|
||||
}
|
||||
SendSelectScreen(index) {
|
||||
this.Connection.invoke("SelectScreen", index);
|
||||
SendSelectScreen(displayName) {
|
||||
this.Connection.invoke("SelectScreen", displayName);
|
||||
}
|
||||
SendMouseMove(percentX, percentY) {
|
||||
this.Connection.invoke("MouseMove", percentX, percentY);
|
||||
@ -120,18 +120,18 @@ export class RCBrowserSockets {
|
||||
Remotely.ClipboardWatcher.SetClipboardText(clipboardText);
|
||||
PopupMessage("Clipboard updated.");
|
||||
});
|
||||
hubConnection.on("ScreenCount", (primaryScreenIndex, screenCount) => {
|
||||
hubConnection.on("ScreenData", (selectedDisplay, displayNames) => {
|
||||
document.querySelector("#screenSelectBar").innerHTML = "";
|
||||
for (let i = 0; i < screenCount; i++) {
|
||||
for (let i = 0; i < displayNames.length; i++) {
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = `Monitor ${i}`;
|
||||
button.classList.add("horizontal-bar-button");
|
||||
if (i == primaryScreenIndex) {
|
||||
if (displayNames[i] == selectedDisplay) {
|
||||
button.classList.add("toggled");
|
||||
}
|
||||
document.querySelector("#screenSelectBar").appendChild(button);
|
||||
button.onclick = (ev) => {
|
||||
this.SendSelectScreen(i);
|
||||
this.SendSelectScreen(displayNames[i]);
|
||||
document.querySelectorAll("#screenSelectBar .horizontal-bar-button").forEach(button => {
|
||||
button.classList.remove("toggled");
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -68,8 +68,8 @@ export class RCBrowserSockets {
|
||||
SendLatencyUpdate(sentTime: Date, bytesReceived: number) {
|
||||
this.Connection.invoke("SendLatencyUpdate", sentTime, bytesReceived);
|
||||
}
|
||||
SendSelectScreen(index: number) {
|
||||
this.Connection.invoke("SelectScreen", index);
|
||||
SendSelectScreen(displayName: string) {
|
||||
this.Connection.invoke("SelectScreen", displayName);
|
||||
}
|
||||
SendMouseMove(percentX: number, percentY: number): any {
|
||||
this.Connection.invoke("MouseMove", percentX, percentY);
|
||||
@ -134,18 +134,18 @@ export class RCBrowserSockets {
|
||||
Remotely.ClipboardWatcher.SetClipboardText(clipboardText);
|
||||
PopupMessage("Clipboard updated.");
|
||||
});
|
||||
hubConnection.on("ScreenCount", (primaryScreenIndex: number, screenCount: number) => {
|
||||
hubConnection.on("ScreenData", (selectedDisplay: string, displayNames: string[]) => {
|
||||
document.querySelector("#screenSelectBar").innerHTML = "";
|
||||
for (let i = 0; i < screenCount; i++) {
|
||||
for (let i = 0; i < displayNames.length; i++) {
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = `Monitor ${i}`;
|
||||
button.classList.add("horizontal-bar-button");
|
||||
if (i == primaryScreenIndex) {
|
||||
if (displayNames[i] == selectedDisplay) {
|
||||
button.classList.add("toggled");
|
||||
}
|
||||
document.querySelector("#screenSelectBar").appendChild(button);
|
||||
button.onclick = (ev: MouseEvent) => {
|
||||
this.SendSelectScreen(i);
|
||||
this.SendSelectScreen(displayNames[i]);
|
||||
document.querySelectorAll("#screenSelectBar .horizontal-bar-button").forEach(button => {
|
||||
button.classList.remove("toggled");
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user