Refactor IScreenCapturer.

This commit is contained in:
Jared Goodwin 2020-08-06 20:27:55 -07:00
parent dd3b9083bd
commit b2c9536e23
25 changed files with 542 additions and 502 deletions

View File

@ -9,14 +9,12 @@ namespace Remotely.Desktop.Core.Interfaces
event EventHandler<Rectangle> ScreenChanged;
bool CaptureFullscreen { get; set; }
Bitmap CurrentFrame { get; set; }
Rectangle CurrentScreenBounds { get; }
Bitmap PreviousFrame { get; set; }
string SelectedScreen { get; }
IEnumerable<string> GetDisplayNames();
void GetNextFrame();
Bitmap GetNextFrame();
int GetScreenCount();

View File

@ -209,13 +209,13 @@ namespace Remotely.Desktop.Core.Services
});
Connection.On("ReceiveRtcAnswer", (string sdp, string viewerID) =>
Connection.On("ReceiveRtcAnswer", async (string sdp, string viewerID) =>
{
try
{
if (conductor.Viewers.TryGetValue(viewerID, out var viewer))
{
viewer.RtcSession.SetRemoteDescription("answer", sdp);
await viewer.RtcSession.SetRemoteDescription("answer", sdp);
}
}
catch (Exception ex)

View File

@ -13,6 +13,7 @@ using System.Collections.Concurrent;
using Remotely.Desktop.Core.Enums;
using Remotely.Shared.Models;
using Remotely.Shared.Win32;
using System.Drawing;
namespace Remotely.Desktop.Core.Services
{
@ -35,6 +36,8 @@ namespace Remotely.Desktop.Core.Services
try
{
Bitmap currentFrame = null;
Bitmap previousFrame = null;
byte[] encodedImageBytes;
var fpsQueue = new Queue<DateTimeOffset>();
mode = Conductor.Mode;
@ -76,12 +79,17 @@ namespace Remotely.Desktop.Core.Services
await viewer.SendScreenSize(bounds.Width, bounds.Height);
};
await viewer.SendScreenCapture(
ImageUtils.EncodeBitmap(viewer.Capturer.CurrentFrame, viewer.EncoderParams),
viewer.Capturer.CurrentScreenBounds.Left,
viewer.Capturer.CurrentScreenBounds.Top,
viewer.Capturer.CurrentScreenBounds.Width,
viewer.Capturer.CurrentScreenBounds.Height);
using (var initialFrame = viewer.Capturer.GetNextFrame())
{
await viewer.SendScreenCapture(
ImageUtils.EncodeBitmap(initialFrame, viewer.EncoderParams),
viewer.Capturer.CurrentScreenBounds.Left,
viewer.Capturer.CurrentScreenBounds.Top,
viewer.Capturer.CurrentScreenBounds.Width,
viewer.Capturer.CurrentScreenBounds.Height);
}
while (!viewer.DisconnectRequested && viewer.IsConnected)
{
@ -105,16 +113,19 @@ namespace Remotely.Desktop.Core.Services
viewer.ThrottleIfNeeded();
viewer.Capturer.GetNextFrame();
previousFrame?.Dispose();
previousFrame = (Bitmap)currentFrame?.Clone();
currentFrame?.Dispose();
currentFrame = viewer.Capturer.GetNextFrame();
var diffArea = ImageUtils.GetDiffArea(viewer.Capturer.CurrentFrame, viewer.Capturer.PreviousFrame, viewer.Capturer.CaptureFullscreen);
var diffArea = ImageUtils.GetDiffArea(currentFrame, previousFrame, viewer.Capturer.CaptureFullscreen);
if (diffArea.IsEmpty)
{
continue;
}
using (var newImage = viewer.Capturer.CurrentFrame.Clone(diffArea, PixelFormat.Format32bppArgb))
using (var newImage = currentFrame.Clone(diffArea, PixelFormat.Format32bppArgb))
{
if (viewer.Capturer.CaptureFullscreen)
{

View File

@ -8,47 +8,51 @@ using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
namespace Remotely.Desktop.Linux.Services
{
public class ScreenCapturerLinux : IScreenCapturer
{
private readonly SemaphoreSlim screenCaptureLock = new SemaphoreSlim(1);
private readonly Dictionary<string, int> x11Screens = new Dictionary<string, int>();
public ScreenCapturerLinux()
{
Display = LibX11.XOpenDisplay(null);
Init();
GetNextFrame();
}
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 string SelectedScreen { get; private set; }
public void Dispose()
{
CurrentFrame.Dispose();
PreviousFrame.Dispose();
LibX11.XCloseDisplay(Display);
}
public IEnumerable<string> GetDisplayNames() => x11Screens.Keys;
public void GetNextFrame()
public Bitmap GetNextFrame()
{
try
{
PreviousFrame?.Dispose();
PreviousFrame = (Bitmap)CurrentFrame.Clone();
RefreshCurrentFrame();
screenCaptureLock.Wait();
return GetX11Screen();
}
catch (Exception ex)
{
Logger.Write(ex);
Init();
return null;
}
finally
{
screenCaptureLock.Release();
}
}
public int GetScreenCount()
@ -84,8 +88,6 @@ namespace Remotely.Desktop.Linux.Services
x11Screens.Add(i.ToString(), i);
}
SetSelectedScreen(x11Screens.Keys.First());
CurrentFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
PreviousFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
}
catch (Exception ex)
{
@ -121,19 +123,21 @@ namespace Remotely.Desktop.Linux.Services
}
}
private void RefreshCurrentFrame()
private Bitmap GetX11Screen()
{
var currentFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
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);
var bd = CurrentFrame.LockBits(new Rectangle(0, 0, CurrentFrame.Width, CurrentFrame.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
var bd = currentFrame.LockBits(new Rectangle(0, 0, CurrentScreenBounds.Width, CurrentScreenBounds.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
byte* scan1 = (byte*)bd.Scan0.ToPointer();
byte* scan2 = (byte*)image.data.ToPointer();
var bytesPerPixel = Bitmap.GetPixelFormatSize(CurrentFrame.PixelFormat) / 8;
var bytesPerPixel = Bitmap.GetPixelFormatSize(currentFrame.PixelFormat) / 8;
var totalSize = bd.Height * bd.Width * bytesPerPixel;
for (int counter = 0; counter < totalSize - bytesPerPixel; counter++)
{
@ -141,8 +145,10 @@ namespace Remotely.Desktop.Linux.Services
}
}
CurrentFrame.UnlockBits(bd);
currentFrame.UnlockBits(bd);
LibX11.XDestroyImage(imagePointer);
return currentFrame;
}
}
}

View File

@ -35,6 +35,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
namespace Remotely.Desktop.Win.Services
@ -43,37 +44,33 @@ namespace Remotely.Desktop.Win.Services
{
private readonly Dictionary<string, int> bitBltScreens = new Dictionary<string, int>();
private readonly Dictionary<string, DirectXOutput> directxScreens = new Dictionary<string, DirectXOutput>();
private readonly SemaphoreSlim screenCaptureLock = new SemaphoreSlim(1);
public ScreenCapturerWin()
{
Init();
GetBitBltFrame();
SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
}
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()
{
SystemEvents.DisplaySettingsChanged -= SystemEvents_DisplaySettingsChanged;
ClearDirectXOutputs();
CurrentFrame?.Dispose();
PreviousFrame?.Dispose();
}
public IEnumerable<string> GetDisplayNames() => Screen.AllScreens.Select(x => x.DeviceName);
public void GetNextFrame()
public Bitmap GetNextFrame()
{
try
{
screenCaptureLock.Wait();
Win32Interop.SwitchToInputDesktop();
if (NeedsInit)
@ -82,25 +79,33 @@ namespace Remotely.Desktop.Win.Services
Init();
}
PreviousFrame?.Dispose();
PreviousFrame = (Bitmap)CurrentFrame.Clone();
// Sometimes DX will result in a timeout, even when there are changes
// on the screen. I've observed this when a laptop lid is closed, or
// on some machines that aren't connected to a monitor. This will
// have it fall back to BitBlt in those cases.
if (!directxScreens.ContainsKey(SelectedScreen) ||
GetDirectXFrame() == GetDirectXFrameResult.Timeout)
if (directxScreens.ContainsKey(SelectedScreen))
{
GetBitBltFrame();
var directXResult = GetDirectXFrame();
if (directXResult.result == GetDirectXFrameResult.Success)
{
return directXResult.frame;
}
}
return GetBitBltFrame();
}
catch (Exception e)
{
Logger.Write(e);
NeedsInit = true;
}
finally
{
screenCaptureLock.Release();
}
return null;
}
public int GetScreenCount() => Screen.AllScreens.Length;
@ -111,9 +116,6 @@ namespace Remotely.Desktop.Win.Services
public void Init()
{
CurrentFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
PreviousFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
InitBitBlt();
InitDirectX();
@ -147,14 +149,17 @@ namespace Remotely.Desktop.Win.Services
directxScreens.Clear();
}
private void GetBitBltFrame()
private Bitmap GetBitBltFrame()
{
try
{
Win32Interop.SwitchToInputDesktop();
PreviousFrame.Dispose();
PreviousFrame = (Bitmap)CurrentFrame.Clone();
Graphic.CopyFromScreen(CurrentScreenBounds.Left, CurrentScreenBounds.Top, 0, 0, new Size(CurrentScreenBounds.Width, CurrentScreenBounds.Height));
var currentFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
using (var graphic = Graphics.FromImage(currentFrame))
{
graphic.CopyFromScreen(CurrentScreenBounds.Left, CurrentScreenBounds.Top, 0, 0, new Size(CurrentScreenBounds.Width, CurrentScreenBounds.Height));
}
return currentFrame;
}
catch (Exception ex)
{
@ -167,6 +172,8 @@ namespace Remotely.Desktop.Win.Services
}
NeedsInit = true;
}
return null;
}
private enum GetDirectXFrameResult
@ -176,7 +183,7 @@ namespace Remotely.Desktop.Win.Services
Timeout,
}
private GetDirectXFrameResult GetDirectXFrame()
private (GetDirectXFrameResult result, Bitmap frame) GetDirectXFrame()
{
try
{
@ -193,13 +200,13 @@ namespace Remotely.Desktop.Win.Services
{
if (result.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Code)
{
return GetDirectXFrameResult.Timeout;
return (GetDirectXFrameResult.Timeout, null);
}
else
{
Logger.Write($"TryAcquireFrame error. Code: {result.Code}");
NeedsInit = true;
return GetDirectXFrameResult.Failure;
return (GetDirectXFrameResult.Failure, null);
}
}
@ -210,9 +217,11 @@ namespace Remotely.Desktop.Win.Services
duplicatedOutput.ReleaseFrame();
}
catch { }
return GetDirectXFrameResult.Failure;
return (GetDirectXFrameResult.Failure, null);
}
var currentFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
// Copy resource into memory that can be accessed by the CPU
using (var screenTexture2D = screenResource.QueryInterface<Texture2D>())
{
@ -225,7 +234,7 @@ namespace Remotely.Desktop.Win.Services
var boundsRect = new Rectangle(0, 0, texture2D.Description.Width, texture2D.Description.Height);
// Copy pixels from screen capture Texture to GDI bitmap
var mapDest = CurrentFrame.LockBits(boundsRect, ImageLockMode.WriteOnly, CurrentFrame.PixelFormat);
var mapDest = currentFrame.LockBits(boundsRect, ImageLockMode.WriteOnly, currentFrame.PixelFormat);
var sourcePtr = mapSource.DataPointer;
var destPtr = mapDest.Scan0;
for (int y = 0; y < texture2D.Description.Height; y++)
@ -239,13 +248,13 @@ namespace Remotely.Desktop.Win.Services
}
// Release source and dest locks
CurrentFrame.UnlockBits(mapDest);
currentFrame.UnlockBits(mapDest);
device.ImmediateContext.UnmapSubresource(texture2D, 0);
screenResource.Dispose();
duplicatedOutput.ReleaseFrame();
return GetDirectXFrameResult.Success;
return (GetDirectXFrameResult.Success, currentFrame);
}
catch (SharpDXException e)
{
@ -253,16 +262,15 @@ namespace Remotely.Desktop.Win.Services
{
Logger.Write(e);
NeedsInit = true;
return GetDirectXFrameResult.Failure;
return (GetDirectXFrameResult.Failure, null);
}
return GetDirectXFrameResult.Timeout;
return (GetDirectXFrameResult.Timeout, null);
}
}
private void InitBitBlt()
{
bitBltScreens.Clear();
Graphic = Graphics.FromImage(CurrentFrame);
for (var i = 0; i < Screen.AllScreens.Length; i++)
{
bitBltScreens.Add(Screen.AllScreens[i].DeviceName, i);

View File

@ -191,6 +191,7 @@
<div id="screenViewerWrapper" class="center-aligned">
<canvas id="screenViewer" hidden="hidden"></canvas>
<video id="videoScreenViewer" hidden="hidden"></video>
<input id="fileTransferInput" hidden="hidden" type="file" multiple />
<textarea id="touchKeyboardTextArea" value=" #"> #</textarea>
</div>

View File

@ -121,7 +121,8 @@ button {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
}
#screenViewer {
#screenViewer, #videoScreenViewer {
max-width: 99vw;
max-height: 99vh;
z-index: 1;

View File

@ -1,4 +1,4 @@
import { AudioButton, ChangeScreenButton, HorizontalBars, ScreenSelectBar, ClipboardTransferButton, ClipboardTransferBar, TypeClipboardButton, ShowMessage, ConnectButton, CtrlAltDelButton, DisconnectButton, FileTransferButton, FileTransferInput, FitToScreenButton, ScreenViewer, BlockInputButton, InviteButton, KeyboardButton, TouchKeyboardTextArea, MenuFrame, MenuButton, QualityButton, QualityBar, QualitySlider, AutoQualityAdjustCheckBox, ScreenViewerWrapper, WindowsSessionSelect, RecordSessionButton, DownloadRecordingButton } from "./UI.js";
import { AudioButton, ChangeScreenButton, HorizontalBars, ScreenSelectBar, ClipboardTransferButton, ClipboardTransferBar, TypeClipboardButton, ShowMessage, ConnectButton, CtrlAltDelButton, DisconnectButton, FileTransferButton, FileTransferInput, FitToScreenButton, ScreenViewer, BlockInputButton, InviteButton, KeyboardButton, TouchKeyboardTextArea, MenuFrame, MenuButton, QualityButton, QualityBar, QualitySlider, AutoQualityAdjustCheckBox, ScreenViewerWrapper, WindowsSessionSelect, RecordSessionButton, DownloadRecordingButton, VideoScreenViewer } from "./UI.js";
import { Sound } from "../Sound.js";
import { MainRc } from "./Main.js";
import { UploadFiles } from "./FileUploader.js";
@ -84,10 +84,14 @@ export function ApplyInputHandlers() {
if (FitToScreenButton.classList.contains("toggled")) {
ScreenViewer.style.removeProperty("max-width");
ScreenViewer.style.removeProperty("max-height");
VideoScreenViewer.style.removeProperty("max-width");
VideoScreenViewer.style.removeProperty("max-height");
}
else {
ScreenViewer.style.maxWidth = "unset";
ScreenViewer.style.maxHeight = "unset";
VideoScreenViewer.style.maxWidth = "unset";
VideoScreenViewer.style.maxHeight = "unset";
}
});
BlockInputButton.addEventListener("click", (ev) => {
@ -149,175 +153,177 @@ export function ApplyInputHandlers() {
AutoQualityAdjustCheckBox.addEventListener("change", ev => {
MainRc.MessageSender.SendAutoQualityAdjust(AutoQualityAdjustCheckBox.checked);
});
ScreenViewer.addEventListener("pointermove", function (e) {
currentPointerDevice = e.pointerType;
});
ScreenViewer.addEventListener("pointerdown", function (e) {
currentPointerDevice = e.pointerType;
});
ScreenViewer.addEventListener("pointerenter", function (e) {
currentPointerDevice = e.pointerType;
});
ScreenViewer.addEventListener("mousemove", function (e) {
e.preventDefault();
if (Date.now() - lastPointerMove < 25) {
return;
}
lastPointerMove = Date.now();
var percentX = e.offsetX / ScreenViewer.clientWidth;
var percentY = e.offsetY / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseMove(percentX, percentY);
});
ScreenViewer.addEventListener("mousedown", function (e) {
if (currentPointerDevice == "touch") {
return;
}
if (e.button != 0 && e.button != 2) {
return;
}
e.preventDefault();
var percentX = e.offsetX / ScreenViewer.clientWidth;
var percentY = e.offsetY / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseDown(e.button, percentX, percentY);
});
ScreenViewer.addEventListener("mouseup", function (e) {
if (currentPointerDevice == "touch") {
return;
}
if (e.button != 0 && e.button != 2) {
return;
}
e.preventDefault();
var percentX = e.offsetX / ScreenViewer.clientWidth;
var percentY = e.offsetY / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseUp(e.button, percentX, percentY);
});
ScreenViewer.addEventListener("click", function (e) {
if (cancelNextViewerClick) {
cancelNextViewerClick = false;
return;
}
if (currentPointerDevice == "mouse") {
[ScreenViewer, VideoScreenViewer].forEach(viewer => {
viewer.addEventListener("pointermove", function (e) {
currentPointerDevice = e.pointerType;
});
viewer.addEventListener("pointerdown", function (e) {
currentPointerDevice = e.pointerType;
});
viewer.addEventListener("pointerenter", function (e) {
currentPointerDevice = e.pointerType;
});
viewer.addEventListener("mousemove", function (e) {
e.preventDefault();
e.stopPropagation();
}
else if (currentPointerDevice == "touch" && currentTouchCount == 0) {
var percentX = e.offsetX / ScreenViewer.clientWidth;
var percentY = e.offsetY / ScreenViewer.clientHeight;
MainRc.MessageSender.SendTap(percentX, percentY);
}
});
ScreenViewer.addEventListener("touchstart", function (e) {
currentTouchCount = e.touches.length;
if (currentTouchCount == 1) {
startLongPressTimeout = window.setTimeout(() => {
var percentX = e.touches[0].pageX / ScreenViewer.clientWidth;
var percentY = e.touches[0].pageY / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseDown(2, percentX, percentY);
MainRc.MessageSender.SendMouseUp(2, percentX, percentY);
}, 1000);
}
if (currentTouchCount > 1) {
cancelNextViewerClick = true;
}
if (currentTouchCount == 2) {
startPinchPoint1 = { X: e.touches[0].pageX, Y: e.touches[0].pageY, IsEmpty: false };
startPinchPoint2 = { X: e.touches[1].pageX, Y: e.touches[1].pageY, IsEmpty: false };
lastPinchDistance = GetDistanceBetween(startPinchPoint1.X, startPinchPoint1.Y, startPinchPoint2.X, startPinchPoint2.Y);
lastPinchCenterX = (startPinchPoint1.X + startPinchPoint2.X) / 2;
lastPinchCenterY = (startPinchPoint1.Y + startPinchPoint2.Y) / 2;
}
isDragging = false;
KeyboardButton.removeAttribute("hidden");
var focusedInput = document.querySelector("input:focus");
if (focusedInput) {
focusedInput.blur();
}
});
ScreenViewer.addEventListener("touchmove", function (e) {
currentTouchCount = e.touches.length;
clearTimeout(startLongPressTimeout);
if (e.touches.length == 2) {
var pinchPoint1 = {
X: e.touches[0].pageX,
Y: e.touches[0].pageY,
IsEmpty: false
};
var pinchPoint2 = {
X: e.touches[1].pageX,
Y: e.touches[1].pageY,
IsEmpty: false
};
var pinchDistance = GetDistanceBetween(pinchPoint1.X, pinchPoint1.Y, pinchPoint2.X, pinchPoint2.Y);
var pinchCenterX = (pinchPoint1.X + pinchPoint2.X) / 2;
var pinchCenterY = (pinchPoint1.Y + pinchPoint2.Y) / 2;
ScreenViewerWrapper.scrollBy(lastPinchCenterX - pinchCenterX, lastPinchCenterY - pinchCenterY);
lastPinchCenterX = pinchCenterX;
lastPinchCenterY = pinchCenterY;
if (Math.abs(pinchDistance - lastPinchDistance) > 5) {
isPinchZooming = true;
if (FitToScreenButton.classList.contains("toggled")) {
FitToScreenButton.click();
}
var currentWidth = ScreenViewer.clientWidth;
var currentHeight = ScreenViewer.clientHeight;
var clientAdjustedScrollLeftPercent = (ScreenViewerWrapper.scrollLeft + (ScreenViewerWrapper.clientWidth * .5)) / ScreenViewerWrapper.scrollWidth;
var clientAdjustedScrollTopPercent = (ScreenViewerWrapper.scrollTop + (ScreenViewerWrapper.clientHeight * .5)) / ScreenViewerWrapper.scrollHeight;
var currentWidthPercent = Number(ScreenViewer.style.width.slice(0, -1));
var newWidthPercent = Math.max(100, (currentWidthPercent + (pinchDistance - lastPinchDistance) * (currentWidthPercent / 100)));
newWidthPercent = Math.min(5000, newWidthPercent);
ScreenViewer.style.width = String(newWidthPercent) + "%";
var heightChange = ScreenViewer.clientHeight - currentHeight;
var widthChange = ScreenViewer.clientWidth - currentWidth;
var pinchAdjustX = pinchCenterX / window.innerWidth - .5;
var pinchAdjustY = pinchCenterY / window.innerHeight - .5;
var scrollByX = widthChange * (clientAdjustedScrollLeftPercent + (pinchAdjustX * ScreenViewerWrapper.clientWidth / ScreenViewerWrapper.scrollWidth));
var scrollByY = heightChange * (clientAdjustedScrollTopPercent + (pinchAdjustY * ScreenViewerWrapper.clientHeight / ScreenViewerWrapper.scrollHeight));
ScreenViewerWrapper.scrollBy(scrollByX, scrollByY);
lastPinchDistance = pinchDistance;
if (Date.now() - lastPointerMove < 25) {
return;
}
return;
}
else if (isDragging) {
e.preventDefault();
e.stopPropagation();
var screenViewerLeft = ScreenViewer.getBoundingClientRect().left;
var screenViewerTop = ScreenViewer.getBoundingClientRect().top;
var pagePercentX = (e.touches[0].pageX - screenViewerLeft) / ScreenViewer.clientWidth;
var pagePercentY = (e.touches[0].pageY - screenViewerTop) / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseMove(pagePercentX, pagePercentY);
}
});
ScreenViewer.addEventListener("touchend", function (e) {
currentTouchCount = e.touches.length;
clearTimeout(startLongPressTimeout);
if (e.touches.length == 1 && !isPinchZooming) {
isDragging = true;
var percentX = (e.touches[0].pageX - ScreenViewer.getBoundingClientRect().left) / ScreenViewer.clientWidth;
var percentY = (e.touches[0].pageY - ScreenViewer.getBoundingClientRect().top) / ScreenViewer.clientHeight;
lastPointerMove = Date.now();
var percentX = e.offsetX / viewer.clientWidth;
var percentY = e.offsetY / viewer.clientHeight;
MainRc.MessageSender.SendMouseMove(percentX, percentY);
MainRc.MessageSender.SendMouseDown(0, percentX, percentY);
return;
}
if (currentTouchCount == 0) {
cancelNextViewerClick = false;
isPinchZooming = false;
startPinchPoint1 = null;
startPinchPoint2 = null;
}
if (isDragging) {
var percentX = (e.changedTouches[0].pageX - ScreenViewer.getBoundingClientRect().left) / ScreenViewer.clientWidth;
var percentY = (e.changedTouches[0].pageY - ScreenViewer.getBoundingClientRect().top) / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseUp(0, percentX, percentY);
}
isDragging = false;
});
ScreenViewer.addEventListener("contextmenu", (ev) => {
ev.preventDefault();
});
ScreenViewer.addEventListener("wheel", function (e) {
e.preventDefault();
MainRc.MessageSender.SendMouseWheel(e.deltaX, e.deltaY);
});
viewer.addEventListener("mousedown", function (e) {
if (currentPointerDevice == "touch") {
return;
}
if (e.button != 0 && e.button != 2) {
return;
}
e.preventDefault();
var percentX = e.offsetX / viewer.clientWidth;
var percentY = e.offsetY / viewer.clientHeight;
MainRc.MessageSender.SendMouseDown(e.button, percentX, percentY);
});
viewer.addEventListener("mouseup", function (e) {
if (currentPointerDevice == "touch") {
return;
}
if (e.button != 0 && e.button != 2) {
return;
}
e.preventDefault();
var percentX = e.offsetX / viewer.clientWidth;
var percentY = e.offsetY / viewer.clientHeight;
MainRc.MessageSender.SendMouseUp(e.button, percentX, percentY);
});
viewer.addEventListener("click", function (e) {
if (cancelNextViewerClick) {
cancelNextViewerClick = false;
return;
}
if (currentPointerDevice == "mouse") {
e.preventDefault();
e.stopPropagation();
}
else if (currentPointerDevice == "touch" && currentTouchCount == 0) {
var percentX = e.offsetX / viewer.clientWidth;
var percentY = e.offsetY / viewer.clientHeight;
MainRc.MessageSender.SendTap(percentX, percentY);
}
});
viewer.addEventListener("touchstart", function (e) {
currentTouchCount = e.touches.length;
if (currentTouchCount == 1) {
startLongPressTimeout = window.setTimeout(() => {
var percentX = e.touches[0].pageX / viewer.clientWidth;
var percentY = e.touches[0].pageY / viewer.clientHeight;
MainRc.MessageSender.SendMouseDown(2, percentX, percentY);
MainRc.MessageSender.SendMouseUp(2, percentX, percentY);
}, 1000);
}
if (currentTouchCount > 1) {
cancelNextViewerClick = true;
}
if (currentTouchCount == 2) {
startPinchPoint1 = { X: e.touches[0].pageX, Y: e.touches[0].pageY, IsEmpty: false };
startPinchPoint2 = { X: e.touches[1].pageX, Y: e.touches[1].pageY, IsEmpty: false };
lastPinchDistance = GetDistanceBetween(startPinchPoint1.X, startPinchPoint1.Y, startPinchPoint2.X, startPinchPoint2.Y);
lastPinchCenterX = (startPinchPoint1.X + startPinchPoint2.X) / 2;
lastPinchCenterY = (startPinchPoint1.Y + startPinchPoint2.Y) / 2;
}
isDragging = false;
KeyboardButton.removeAttribute("hidden");
var focusedInput = document.querySelector("input:focus");
if (focusedInput) {
focusedInput.blur();
}
});
viewer.addEventListener("touchmove", function (e) {
currentTouchCount = e.touches.length;
clearTimeout(startLongPressTimeout);
if (e.touches.length == 2) {
var pinchPoint1 = {
X: e.touches[0].pageX,
Y: e.touches[0].pageY,
IsEmpty: false
};
var pinchPoint2 = {
X: e.touches[1].pageX,
Y: e.touches[1].pageY,
IsEmpty: false
};
var pinchDistance = GetDistanceBetween(pinchPoint1.X, pinchPoint1.Y, pinchPoint2.X, pinchPoint2.Y);
var pinchCenterX = (pinchPoint1.X + pinchPoint2.X) / 2;
var pinchCenterY = (pinchPoint1.Y + pinchPoint2.Y) / 2;
ScreenViewerWrapper.scrollBy(lastPinchCenterX - pinchCenterX, lastPinchCenterY - pinchCenterY);
lastPinchCenterX = pinchCenterX;
lastPinchCenterY = pinchCenterY;
if (Math.abs(pinchDistance - lastPinchDistance) > 5) {
isPinchZooming = true;
if (FitToScreenButton.classList.contains("toggled")) {
FitToScreenButton.click();
}
var currentWidth = viewer.clientWidth;
var currentHeight = viewer.clientHeight;
var clientAdjustedScrollLeftPercent = (ScreenViewerWrapper.scrollLeft + (ScreenViewerWrapper.clientWidth * .5)) / ScreenViewerWrapper.scrollWidth;
var clientAdjustedScrollTopPercent = (ScreenViewerWrapper.scrollTop + (ScreenViewerWrapper.clientHeight * .5)) / ScreenViewerWrapper.scrollHeight;
var currentWidthPercent = Number(viewer.style.width.slice(0, -1));
var newWidthPercent = Math.max(100, (currentWidthPercent + (pinchDistance - lastPinchDistance) * (currentWidthPercent / 100)));
newWidthPercent = Math.min(5000, newWidthPercent);
viewer.style.width = String(newWidthPercent) + "%";
var heightChange = viewer.clientHeight - currentHeight;
var widthChange = viewer.clientWidth - currentWidth;
var pinchAdjustX = pinchCenterX / window.innerWidth - .5;
var pinchAdjustY = pinchCenterY / window.innerHeight - .5;
var scrollByX = widthChange * (clientAdjustedScrollLeftPercent + (pinchAdjustX * ScreenViewerWrapper.clientWidth / ScreenViewerWrapper.scrollWidth));
var scrollByY = heightChange * (clientAdjustedScrollTopPercent + (pinchAdjustY * ScreenViewerWrapper.clientHeight / ScreenViewerWrapper.scrollHeight));
ScreenViewerWrapper.scrollBy(scrollByX, scrollByY);
lastPinchDistance = pinchDistance;
}
return;
}
else if (isDragging) {
e.preventDefault();
e.stopPropagation();
var screenViewerLeft = viewer.getBoundingClientRect().left;
var screenViewerTop = viewer.getBoundingClientRect().top;
var pagePercentX = (e.touches[0].pageX - screenViewerLeft) / viewer.clientWidth;
var pagePercentY = (e.touches[0].pageY - screenViewerTop) / viewer.clientHeight;
MainRc.MessageSender.SendMouseMove(pagePercentX, pagePercentY);
}
});
viewer.addEventListener("touchend", function (e) {
currentTouchCount = e.touches.length;
clearTimeout(startLongPressTimeout);
if (e.touches.length == 1 && !isPinchZooming) {
isDragging = true;
var percentX = (e.touches[0].pageX - viewer.getBoundingClientRect().left) / viewer.clientWidth;
var percentY = (e.touches[0].pageY - viewer.getBoundingClientRect().top) / viewer.clientHeight;
MainRc.MessageSender.SendMouseMove(percentX, percentY);
MainRc.MessageSender.SendMouseDown(0, percentX, percentY);
return;
}
if (currentTouchCount == 0) {
cancelNextViewerClick = false;
isPinchZooming = false;
startPinchPoint1 = null;
startPinchPoint2 = null;
}
if (isDragging) {
var percentX = (e.changedTouches[0].pageX - viewer.getBoundingClientRect().left) / viewer.clientWidth;
var percentY = (e.changedTouches[0].pageY - viewer.getBoundingClientRect().top) / viewer.clientHeight;
MainRc.MessageSender.SendMouseUp(0, percentX, percentY);
}
isDragging = false;
});
viewer.addEventListener("contextmenu", (ev) => {
ev.preventDefault();
});
viewer.addEventListener("wheel", function (e) {
e.preventDefault();
MainRc.MessageSender.SendMouseWheel(e.deltaX, e.deltaY);
});
});
TouchKeyboardTextArea.addEventListener("input", (ev) => {
if (TouchKeyboardTextArea.value.length == 1) {

File diff suppressed because one or more lines are too long

View File

@ -27,7 +27,8 @@
ScreenViewerWrapper,
WindowsSessionSelect,
RecordSessionButton,
DownloadRecordingButton
DownloadRecordingButton,
VideoScreenViewer
} from "./UI.js";
import { Sound } from "../Sound.js";
import { MainRc } from "./Main.js";
@ -118,10 +119,14 @@ export function ApplyInputHandlers() {
if (FitToScreenButton.classList.contains("toggled")) {
ScreenViewer.style.removeProperty("max-width");
ScreenViewer.style.removeProperty("max-height");
VideoScreenViewer.style.removeProperty("max-width");
VideoScreenViewer.style.removeProperty("max-height");
}
else {
ScreenViewer.style.maxWidth = "unset";
ScreenViewer.style.maxHeight = "unset";
VideoScreenViewer.style.maxWidth = "unset";
VideoScreenViewer.style.maxHeight = "unset";
}
});
BlockInputButton.addEventListener("click", (ev) => {
@ -183,208 +188,226 @@ export function ApplyInputHandlers() {
AutoQualityAdjustCheckBox.addEventListener("change", ev => {
MainRc.MessageSender.SendAutoQualityAdjust(AutoQualityAdjustCheckBox.checked);
});
ScreenViewer.addEventListener("pointermove", function (e) {
currentPointerDevice = e.pointerType;
});
ScreenViewer.addEventListener("pointerdown", function (e) {
currentPointerDevice = e.pointerType;
});
ScreenViewer.addEventListener("pointerenter", function (e) {
currentPointerDevice = e.pointerType;
});
ScreenViewer.addEventListener("mousemove", function (e) {
e.preventDefault();
if (Date.now() - lastPointerMove < 25) {
return;
}
lastPointerMove = Date.now();
var percentX = e.offsetX / ScreenViewer.clientWidth;
var percentY = e.offsetY / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseMove(percentX, percentY);
});
ScreenViewer.addEventListener("mousedown", function (e) {
if (currentPointerDevice == "touch") {
return;
}
if (e.button != 0 && e.button != 2) {
return;
}
e.preventDefault();
var percentX = e.offsetX / ScreenViewer.clientWidth;
var percentY = e.offsetY / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseDown(e.button, percentX, percentY);
});
ScreenViewer.addEventListener("mouseup", function (e) {
if (currentPointerDevice == "touch") {
return;
}
if (e.button != 0 && e.button != 2) {
return;
}
e.preventDefault();
var percentX = e.offsetX / ScreenViewer.clientWidth;
var percentY = e.offsetY / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseUp(e.button, percentX, percentY);
});
ScreenViewer.addEventListener("click", function (e) {
if (cancelNextViewerClick) {
cancelNextViewerClick = false;
return;
}
if (currentPointerDevice == "mouse") {
[ ScreenViewer, VideoScreenViewer ].forEach(viewer => {
viewer.addEventListener("pointermove", function (e: PointerEvent) {
currentPointerDevice = e.pointerType;
});
viewer.addEventListener("pointerdown", function (e: PointerEvent) {
currentPointerDevice = e.pointerType;
});
viewer.addEventListener("pointerenter", function (e: PointerEvent) {
currentPointerDevice = e.pointerType;
});
viewer.addEventListener("mousemove", function (e: MouseEvent) {
e.preventDefault();
e.stopPropagation();
}
else if (currentPointerDevice == "touch" && currentTouchCount == 0) {
var percentX = e.offsetX / ScreenViewer.clientWidth;
var percentY = e.offsetY / ScreenViewer.clientHeight;
MainRc.MessageSender.SendTap(percentX, percentY);
}
});
ScreenViewer.addEventListener("touchstart", function (e) {
currentTouchCount = e.touches.length;
if (currentTouchCount == 1) {
startLongPressTimeout = window.setTimeout(() => {
var percentX = e.touches[0].pageX / ScreenViewer.clientWidth;
var percentY = e.touches[0].pageY / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseDown(2, percentX, percentY);
MainRc.MessageSender.SendMouseUp(2, percentX, percentY);
}, 1000);
}
if (currentTouchCount > 1) {
cancelNextViewerClick = true;
}
if (currentTouchCount == 2) {
startPinchPoint1 = { X: e.touches[0].pageX, Y: e.touches[0].pageY, IsEmpty: false };
startPinchPoint2 = { X: e.touches[1].pageX, Y: e.touches[1].pageY, IsEmpty: false };
lastPinchDistance = GetDistanceBetween(startPinchPoint1.X,
startPinchPoint1.Y,
startPinchPoint2.X,
startPinchPoint2.Y);
lastPinchCenterX = (startPinchPoint1.X + startPinchPoint2.X) / 2;
lastPinchCenterY = (startPinchPoint1.Y + startPinchPoint2.Y) / 2;
}
isDragging = false;
KeyboardButton.removeAttribute("hidden");
var focusedInput = document.querySelector("input:focus") as HTMLInputElement;
if (focusedInput) {
focusedInput.blur();
}
});
ScreenViewer.addEventListener("touchmove", function (e) {
currentTouchCount = e.touches.length;
clearTimeout(startLongPressTimeout);
if (e.touches.length == 2) {
var pinchPoint1 = {
X: e.touches[0].pageX,
Y: e.touches[0].pageY,
IsEmpty: false
};
var pinchPoint2 = {
X: e.touches[1].pageX,
Y: e.touches[1].pageY,
IsEmpty: false
};
var pinchDistance = GetDistanceBetween(pinchPoint1.X,
pinchPoint1.Y,
pinchPoint2.X,
pinchPoint2.Y);
var pinchCenterX = (pinchPoint1.X + pinchPoint2.X) / 2;
var pinchCenterY = (pinchPoint1.Y + pinchPoint2.Y) / 2;
ScreenViewerWrapper.scrollBy(lastPinchCenterX - pinchCenterX,
lastPinchCenterY - pinchCenterY);
lastPinchCenterX = pinchCenterX;
lastPinchCenterY = pinchCenterY;
if (Math.abs(pinchDistance - lastPinchDistance) > 5) {
isPinchZooming = true;
if (FitToScreenButton.classList.contains("toggled")) {
FitToScreenButton.click();
}
var currentWidth = ScreenViewer.clientWidth;
var currentHeight = ScreenViewer.clientHeight;
var clientAdjustedScrollLeftPercent = (ScreenViewerWrapper.scrollLeft + (ScreenViewerWrapper.clientWidth * .5)) / ScreenViewerWrapper.scrollWidth;
var clientAdjustedScrollTopPercent = (ScreenViewerWrapper.scrollTop + (ScreenViewerWrapper.clientHeight * .5)) / ScreenViewerWrapper.scrollHeight;
var currentWidthPercent = Number(ScreenViewer.style.width.slice(0, -1));
var newWidthPercent = Math.max(100, (currentWidthPercent + (pinchDistance - lastPinchDistance) * (currentWidthPercent / 100)));
newWidthPercent = Math.min(5000, newWidthPercent);
ScreenViewer.style.width = String(newWidthPercent) + "%";
var heightChange = ScreenViewer.clientHeight - currentHeight;
var widthChange = ScreenViewer.clientWidth - currentWidth;
var pinchAdjustX = pinchCenterX / window.innerWidth - .5;
var pinchAdjustY = pinchCenterY / window.innerHeight - .5;
var scrollByX = widthChange * (clientAdjustedScrollLeftPercent + (pinchAdjustX * ScreenViewerWrapper.clientWidth / ScreenViewerWrapper.scrollWidth));
var scrollByY = heightChange * (clientAdjustedScrollTopPercent + (pinchAdjustY * ScreenViewerWrapper.clientHeight / ScreenViewerWrapper.scrollHeight));
ScreenViewerWrapper.scrollBy(scrollByX, scrollByY);
lastPinchDistance = pinchDistance;
if (Date.now() - lastPointerMove < 25) {
return;
}
return;
}
else if (isDragging) {
e.preventDefault();
e.stopPropagation();
var screenViewerLeft = ScreenViewer.getBoundingClientRect().left;
var screenViewerTop = ScreenViewer.getBoundingClientRect().top;
var pagePercentX = (e.touches[0].pageX - screenViewerLeft) / ScreenViewer.clientWidth;
var pagePercentY = (e.touches[0].pageY - screenViewerTop) / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseMove(pagePercentX, pagePercentY);
}
});
ScreenViewer.addEventListener("touchend", function (e) {
currentTouchCount = e.touches.length;
clearTimeout(startLongPressTimeout);
if (e.touches.length == 1 && !isPinchZooming) {
isDragging = true;
var percentX = (e.touches[0].pageX - ScreenViewer.getBoundingClientRect().left) / ScreenViewer.clientWidth;
var percentY = (e.touches[0].pageY - ScreenViewer.getBoundingClientRect().top) / ScreenViewer.clientHeight;
lastPointerMove = Date.now();
var percentX = e.offsetX / viewer.clientWidth;
var percentY = e.offsetY / viewer.clientHeight;
MainRc.MessageSender.SendMouseMove(percentX, percentY);
MainRc.MessageSender.SendMouseDown(0, percentX, percentY);
return;
}
});
if (currentTouchCount == 0) {
cancelNextViewerClick = false;
isPinchZooming = false;
startPinchPoint1 = null;
startPinchPoint2 = null;
}
if (isDragging) {
var percentX = (e.changedTouches[0].pageX - ScreenViewer.getBoundingClientRect().left) / ScreenViewer.clientWidth;
var percentY = (e.changedTouches[0].pageY - ScreenViewer.getBoundingClientRect().top) / ScreenViewer.clientHeight;
MainRc.MessageSender.SendMouseUp(0, percentX, percentY);
}
viewer.addEventListener("mousedown", function (e: MouseEvent) {
if (currentPointerDevice == "touch") {
return;
}
if (e.button != 0 && e.button != 2) {
return;
}
e.preventDefault();
var percentX = e.offsetX / viewer.clientWidth;
var percentY = e.offsetY / viewer.clientHeight;
MainRc.MessageSender.SendMouseDown(e.button, percentX, percentY);
});
viewer.addEventListener("mouseup", function (e: MouseEvent) {
if (currentPointerDevice == "touch") {
return;
}
if (e.button != 0 && e.button != 2) {
return;
}
e.preventDefault();
var percentX = e.offsetX / viewer.clientWidth;
var percentY = e.offsetY / viewer.clientHeight;
MainRc.MessageSender.SendMouseUp(e.button, percentX, percentY);
});
viewer.addEventListener("click", function (e: MouseEvent) {
if (cancelNextViewerClick) {
cancelNextViewerClick = false;
return;
}
if (currentPointerDevice == "mouse") {
e.preventDefault();
e.stopPropagation();
}
else if (currentPointerDevice == "touch" && currentTouchCount == 0) {
var percentX = e.offsetX / viewer.clientWidth;
var percentY = e.offsetY / viewer.clientHeight;
MainRc.MessageSender.SendTap(percentX, percentY);
}
});
viewer.addEventListener("touchstart", function (e: TouchEvent) {
currentTouchCount = e.touches.length;
if (currentTouchCount == 1) {
startLongPressTimeout = window.setTimeout(() => {
var percentX = e.touches[0].pageX / viewer.clientWidth;
var percentY = e.touches[0].pageY / viewer.clientHeight;
MainRc.MessageSender.SendMouseDown(2, percentX, percentY);
MainRc.MessageSender.SendMouseUp(2, percentX, percentY);
}, 1000);
}
if (currentTouchCount > 1) {
cancelNextViewerClick = true;
}
if (currentTouchCount == 2) {
startPinchPoint1 = { X: e.touches[0].pageX, Y: e.touches[0].pageY, IsEmpty: false };
startPinchPoint2 = { X: e.touches[1].pageX, Y: e.touches[1].pageY, IsEmpty: false };
lastPinchDistance = GetDistanceBetween(startPinchPoint1.X,
startPinchPoint1.Y,
startPinchPoint2.X,
startPinchPoint2.Y);
lastPinchCenterX = (startPinchPoint1.X + startPinchPoint2.X) / 2;
lastPinchCenterY = (startPinchPoint1.Y + startPinchPoint2.Y) / 2;
}
isDragging = false;
KeyboardButton.removeAttribute("hidden");
var focusedInput = document.querySelector("input:focus") as HTMLInputElement;
if (focusedInput) {
focusedInput.blur();
}
});
viewer.addEventListener("touchmove", function (e: TouchEvent) {
currentTouchCount = e.touches.length;
clearTimeout(startLongPressTimeout);
if (e.touches.length == 2) {
var pinchPoint1 = {
X: e.touches[0].pageX,
Y: e.touches[0].pageY,
IsEmpty: false
};
var pinchPoint2 = {
X: e.touches[1].pageX,
Y: e.touches[1].pageY,
IsEmpty: false
};
var pinchDistance = GetDistanceBetween(pinchPoint1.X,
pinchPoint1.Y,
pinchPoint2.X,
pinchPoint2.Y);
var pinchCenterX = (pinchPoint1.X + pinchPoint2.X) / 2;
var pinchCenterY = (pinchPoint1.Y + pinchPoint2.Y) / 2;
ScreenViewerWrapper.scrollBy(lastPinchCenterX - pinchCenterX,
lastPinchCenterY - pinchCenterY);
lastPinchCenterX = pinchCenterX;
lastPinchCenterY = pinchCenterY;
if (Math.abs(pinchDistance - lastPinchDistance) > 5) {
isPinchZooming = true;
if (FitToScreenButton.classList.contains("toggled")) {
FitToScreenButton.click();
}
var currentWidth = viewer.clientWidth;
var currentHeight = viewer.clientHeight;
var clientAdjustedScrollLeftPercent = (ScreenViewerWrapper.scrollLeft + (ScreenViewerWrapper.clientWidth * .5)) / ScreenViewerWrapper.scrollWidth;
var clientAdjustedScrollTopPercent = (ScreenViewerWrapper.scrollTop + (ScreenViewerWrapper.clientHeight * .5)) / ScreenViewerWrapper.scrollHeight;
var currentWidthPercent = Number(viewer.style.width.slice(0, -1));
var newWidthPercent = Math.max(100, (currentWidthPercent + (pinchDistance - lastPinchDistance) * (currentWidthPercent / 100)));
newWidthPercent = Math.min(5000, newWidthPercent);
viewer.style.width = String(newWidthPercent) + "%";
var heightChange = viewer.clientHeight - currentHeight;
var widthChange = viewer.clientWidth - currentWidth;
var pinchAdjustX = pinchCenterX / window.innerWidth - .5;
var pinchAdjustY = pinchCenterY / window.innerHeight - .5;
var scrollByX = widthChange * (clientAdjustedScrollLeftPercent + (pinchAdjustX * ScreenViewerWrapper.clientWidth / ScreenViewerWrapper.scrollWidth));
var scrollByY = heightChange * (clientAdjustedScrollTopPercent + (pinchAdjustY * ScreenViewerWrapper.clientHeight / ScreenViewerWrapper.scrollHeight));
ScreenViewerWrapper.scrollBy(scrollByX, scrollByY);
lastPinchDistance = pinchDistance;
}
return;
}
else if (isDragging) {
e.preventDefault();
e.stopPropagation();
var screenViewerLeft = viewer.getBoundingClientRect().left;
var screenViewerTop = viewer.getBoundingClientRect().top;
var pagePercentX = (e.touches[0].pageX - screenViewerLeft) / viewer.clientWidth;
var pagePercentY = (e.touches[0].pageY - screenViewerTop) / viewer.clientHeight;
MainRc.MessageSender.SendMouseMove(pagePercentX, pagePercentY);
}
});
viewer.addEventListener("touchend", function (e: TouchEvent) {
currentTouchCount = e.touches.length;
clearTimeout(startLongPressTimeout);
if (e.touches.length == 1 && !isPinchZooming) {
isDragging = true;
var percentX = (e.touches[0].pageX - viewer.getBoundingClientRect().left) / viewer.clientWidth;
var percentY = (e.touches[0].pageY - viewer.getBoundingClientRect().top) / viewer.clientHeight;
MainRc.MessageSender.SendMouseMove(percentX, percentY);
MainRc.MessageSender.SendMouseDown(0, percentX, percentY);
return;
}
if (currentTouchCount == 0) {
cancelNextViewerClick = false;
isPinchZooming = false;
startPinchPoint1 = null;
startPinchPoint2 = null;
}
if (isDragging) {
var percentX = (e.changedTouches[0].pageX - viewer.getBoundingClientRect().left) / viewer.clientWidth;
var percentY = (e.changedTouches[0].pageY - viewer.getBoundingClientRect().top) / viewer.clientHeight;
MainRc.MessageSender.SendMouseUp(0, percentX, percentY);
}
isDragging = false;
});
viewer.addEventListener("contextmenu", (ev) => {
ev.preventDefault();
});
viewer.addEventListener("wheel", function (e: WheelEvent) {
e.preventDefault();
MainRc.MessageSender.SendMouseWheel(e.deltaX, e.deltaY);
});
isDragging = false;
});
ScreenViewer.addEventListener("contextmenu", (ev) => {
ev.preventDefault();
});
ScreenViewer.addEventListener("wheel", function (e) {
e.preventDefault();
MainRc.MessageSender.SendMouseWheel(e.deltaX, e.deltaY);
});
TouchKeyboardTextArea.addEventListener("input", (ev) => {
if (TouchKeyboardTextArea.value.length == 1) {
MainRc.MessageSender.SendKeyPress("Backspace");

File diff suppressed because one or more lines are too long

View File

@ -24,7 +24,6 @@ import { FileTransferProgress } from "./UI.js";
import { BinaryDtoType } from "../Enums/BinaryDtoType.js";
export class MessageSender {
GetWindowsSessions() {
this.SendToAgent(() => MainRc.RtcSession.SendDto(new WindowsSessionsDto()),
() => MainRc.RCHubConnection.GetWindowsSessions());

View File

@ -27,11 +27,13 @@ export class RCHubConnection {
UI.StatusMessage.innerHTML = `Connection error: ${err.message}`;
UI.Screen2DContext.clearRect(0, 0, UI.ScreenViewer.width, UI.ScreenViewer.height);
UI.ScreenViewer.setAttribute("hidden", "hidden");
UI.VideoScreenViewer.setAttribute("hidden", "hidden");
UI.ConnectBox.style.removeProperty("display");
});
this.Connection.closedCallbacks.push((ev) => {
UI.Screen2DContext.clearRect(0, 0, UI.ScreenViewer.width, UI.ScreenViewer.height);
UI.ScreenViewer.setAttribute("hidden", "hidden");
UI.VideoScreenViewer.setAttribute("hidden", "hidden");
UI.ConnectBox.style.removeProperty("display");
});
MainRc.ClipboardWatcher.WatchClipboard();

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@ import { Sound } from "../Sound.js";
import { ShowMessage } from "../UI.js";
import { IceServerModel } from "../Models/IceServerModel.js";
import { RemoteControlMode } from "../Enums/RemoteControlMode.js";
import { WindowsSessionsDto, WindowsSession } from "./RtcDtos.js";
import { WindowsSession } from "./RtcDtos.js";
var signalR = window["signalR"];
@ -41,11 +41,13 @@ export class RCHubConnection {
UI.StatusMessage.innerHTML = `Connection error: ${err.message}`;
UI.Screen2DContext.clearRect(0, 0, UI.ScreenViewer.width, UI.ScreenViewer.height);
UI.ScreenViewer.setAttribute("hidden", "hidden");
UI.VideoScreenViewer.setAttribute("hidden", "hidden");
UI.ConnectBox.style.removeProperty("display");
});
this.Connection.closedCallbacks.push((ev) => {
UI.Screen2DContext.clearRect(0, 0, UI.ScreenViewer.width, UI.ScreenViewer.height);
UI.ScreenViewer.setAttribute("hidden", "hidden");
UI.VideoScreenViewer.setAttribute("hidden", "hidden");
UI.ConnectBox.style.removeProperty("display");
});

View File

@ -48,6 +48,14 @@ export class RtcSession {
this.PeerConnection.onicecandidate = async (ev) => {
await MainRc.RCHubConnection.SendIceCandidate(ev.candidate);
};
UI.VideoScreenViewer.onloadedmetadata = (ev) => {
UI.VideoScreenViewer.play();
};
this.PeerConnection.ontrack = (event) => {
UI.VideoScreenViewer.srcObject = new MediaStream([event.track]);
UI.VideoScreenViewer.removeAttribute("hidden");
UI.ScreenViewer.setAttribute("hidden", "hidden");
};
}
Disconnect() {
this.PeerConnection.close();

View File

@ -1 +1 @@
{"version":3,"file":"RtcSession.js","sourceRoot":"","sources":["RtcSession.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"RtcSession.js","sourceRoot":"","sources":["RtcSession.ts"],"names":[],"mappings":"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"}

View File

@ -8,7 +8,7 @@ export class RtcSession {
DataChannel: RTCDataChannel;
MessagePack: any = window['MessagePack'];
Init(iceServers: IceServerModel[]) {
this.PeerConnection = new RTCPeerConnection({
iceServers: iceServers.map(x => {
return {
@ -55,6 +55,15 @@ export class RtcSession {
this.PeerConnection.onicecandidate = async (ev) => {
await MainRc.RCHubConnection.SendIceCandidate(ev.candidate);
};
UI.VideoScreenViewer.onloadedmetadata = (ev) => {
UI.VideoScreenViewer.play();
}
this.PeerConnection.ontrack = (event) => {
UI.VideoScreenViewer.srcObject = new MediaStream([event.track]);
UI.VideoScreenViewer.removeAttribute("hidden");
UI.ScreenViewer.setAttribute("hidden", "hidden");
};
}
Disconnect() {

View File

@ -1,10 +1,10 @@
import { ScreenViewer } from "./UI.js";
import { GetCurrentViewer } from "./UI.js";
export class SessionRecorder {
constructor() {
this.RecordedData = [];
}
Start() {
if (!window["MediaRecorder"] || !ScreenViewer.captureStream) {
if (!window["MediaRecorder"] || !GetCurrentViewer().captureStream) {
alert("Session recording isn't supported on this browser.");
return;
}
@ -12,7 +12,7 @@ export class SessionRecorder {
this.Recorder.stop();
}
this.RecordedData = [];
this.Stream = ScreenViewer.captureStream(10);
this.Stream = GetCurrentViewer().captureStream(10);
var options = { mimeType: 'video/webm' };
this.Recorder = new window["MediaRecorder"](this.Stream, options);
this.Recorder.ondataavailable = (event) => {

View File

@ -1 +1 @@
{"version":3,"file":"SessionRecorder.js","sourceRoot":"","sources":["SessionRecorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,OAAO,eAAe;IAA5B;QAGY,iBAAY,GAAe,EAAE,CAAC;IA+D1C,CAAC;IA7DG,KAAK;QACD,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAE,YAAoB,CAAC,aAAa,EAAE;YAClE,KAAK,CAAC,oDAAoD,CAAC,CAAC;YAC5D,OAAO;SACV;QAED,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,UAAU,EAAE;YACpD,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;SACxB;QAED,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,MAAM,GAAI,YAAoB,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,IAAI,OAAO,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;QACzC,IAAI,CAAC,QAAQ,GAAG,IAAI,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClE,IAAI,CAAC,QAAQ,CAAC,eAAe,GAAG,CAAC,KAAK,EAAE,EAAE;YACtC,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE;gBACnC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;aACtC;QACL,CAAC,CAAA;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI;QACA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAChB,OAAO;SACV;QAED,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;IAED,aAAa;QACT,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,IAAI,CAAC,EAAE;YACrD,KAAK,CAAC,oBAAoB,CAAC,CAAC;YAC5B,OAAO;SACV;QAED,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,UAAU,EAAE;YACpD,KAAK,CAAC,kDAAkD,CAAC,CAAC;YAC1D,OAAO;SACV;QACD,IAAI,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,IAAI,UAAU,GAAG,GAAG,WAAW,CAAC,WAAW,EAAE,GAAG;YAC5C,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG;YAC9D,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG;YACvD,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG;YACxD,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG;YAC1D,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QAE9D,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QAC/D,IAAI,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAChB,IAAI,CAAC,QAAQ,GAAG,kBAAkB,UAAU,OAAO,CAAC;QACpD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,UAAU,CAAC,GAAG,EAAE;YACZ,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC,EAAE,GAAG,CAAC,CAAC;IACZ,CAAC;CACJ"}
{"version":3,"file":"SessionRecorder.js","sourceRoot":"","sources":["SessionRecorder.ts"],"names":[],"mappings":"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"}

View File

@ -1,4 +1,4 @@
import { ScreenViewer } from "./UI.js";
import { GetCurrentViewer } from "./UI.js";
export class SessionRecorder {
private Recorder: any;
@ -6,7 +6,7 @@ export class SessionRecorder {
private RecordedData: Array<any> = [];
Start() {
if (!window["MediaRecorder"] || !(ScreenViewer as any).captureStream) {
if (!window["MediaRecorder"] || !(GetCurrentViewer() as any).captureStream) {
alert("Session recording isn't supported on this browser.");
return;
}
@ -16,7 +16,7 @@ export class SessionRecorder {
}
this.RecordedData = [];
this.Stream = (ScreenViewer as any).captureStream(10);
this.Stream = (GetCurrentViewer() as any).captureStream(10);
var options = { mimeType: 'video/webm' };
this.Recorder = new window["MediaRecorder"](this.Stream, options);
this.Recorder.ondataavailable = (event) => {

View File

@ -9,6 +9,7 @@ export var ConnectButton = document.getElementById("connectButton");
export var RequesterNameInput = document.getElementById("nameInput");
export var StatusMessage = document.getElementById("statusMessage");
export var ScreenViewer = document.getElementById("screenViewer");
export var VideoScreenViewer = document.getElementById("videoScreenViewer");
export var ScreenViewerWrapper = document.getElementById("screenViewerWrapper");
export var Screen2DContext = ScreenViewer.getContext("2d");
export var HorizontalBars = document.querySelectorAll(".horizontal-button-bar");
@ -41,6 +42,12 @@ export var ToastsWrapper = document.getElementById("toastsWrapper");
export var WindowsSessionSelect = document.getElementById("windowsSessionSelect");
export var RecordSessionButton = document.getElementById("recordSessionButton");
export var DownloadRecordingButton = document.getElementById("downloadRecordingButton");
export function GetCurrentViewer() {
if (ScreenViewer.hasAttribute("hidden")) {
return VideoScreenViewer;
}
return ScreenViewer;
}
export function Prompt(promptMessage) {
return new Promise((resolve, reject) => {
var modalDiv = document.createElement("div");
@ -73,6 +80,8 @@ export function Prompt(promptMessage) {
export function SetScreenSize(width, height) {
ScreenViewer.width = width;
ScreenViewer.height = height;
VideoScreenViewer.width = width;
VideoScreenViewer.height = height;
Screen2DContext.clearRect(0, 0, width, height);
}
export function ShowMessage(message) {
@ -85,15 +94,16 @@ export function ShowMessage(message) {
}, 5000);
}
export function UpdateCursor(imageBytes, hotSpotX, hotSpotY, cssOverride) {
var targetElement = GetCurrentViewer();
if (cssOverride) {
ScreenViewer.style.cursor = cssOverride;
targetElement.style.cursor = cssOverride;
}
else if (imageBytes.byteLength == 0) {
ScreenViewer.style.cursor = "default";
targetElement.style.cursor = "default";
}
else {
var base64 = ConvertUInt8ArrayToBase64(imageBytes);
ScreenViewer.style.cursor = `url('data:image/png;base64,${base64}') ${hotSpotX} ${hotSpotY}, default`;
targetElement.style.cursor = `url('data:image/png;base64,${base64}') ${hotSpotX} ${hotSpotY}, default`;
}
}
export function UpdateDisplays(selectedDisplay, displayNames) {

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,5 @@
import { MainRc } from "./Main.js";
import { RemoteControlMode } from "../Enums/RemoteControlMode.js";
import { Point } from "../Models/Point.js";
import { GetDistanceBetween, ConvertUInt8ArrayToBase64 } from "../Utilities.js";
import { UploadFiles } from "./FileUploader.js";
import { Sound } from "../Sound.js";
import { ConvertUInt8ArrayToBase64 } from "../Utilities.js";
import { WindowsSession, SessionType } from "./RtcDtos.js";
export var AudioButton = document.getElementById("audioButton") as HTMLButtonElement;
@ -14,6 +10,7 @@ export var ConnectButton = document.getElementById("connectButton") as HTMLButto
export var RequesterNameInput = document.getElementById("nameInput") as HTMLInputElement;
export var StatusMessage = document.getElementById("statusMessage") as HTMLDivElement;
export var ScreenViewer = document.getElementById("screenViewer") as HTMLCanvasElement;
export var VideoScreenViewer = document.getElementById("videoScreenViewer") as HTMLVideoElement;
export var ScreenViewerWrapper = document.getElementById("screenViewerWrapper") as HTMLDivElement;
export var Screen2DContext = ScreenViewer.getContext("2d");
export var HorizontalBars = document.querySelectorAll(".horizontal-button-bar");
@ -47,6 +44,13 @@ export var WindowsSessionSelect = document.getElementById("windowsSessionSelect"
export var RecordSessionButton = document.getElementById("recordSessionButton") as HTMLButtonElement;
export var DownloadRecordingButton = document.getElementById("downloadRecordingButton") as HTMLButtonElement;
export function GetCurrentViewer(): HTMLElement {
if (ScreenViewer.hasAttribute("hidden")) {
return VideoScreenViewer;
}
return ScreenViewer;
}
export function Prompt(promptMessage: string): Promise<string> {
return new Promise((resolve, reject) => {
var modalDiv = document.createElement("div");
@ -89,6 +93,8 @@ export function Prompt(promptMessage: string): Promise<string> {
export function SetScreenSize(width: number, height: number) {
ScreenViewer.width = width;
ScreenViewer.height = height;
VideoScreenViewer.width = width;
VideoScreenViewer.height = height;
Screen2DContext.clearRect(0, 0, width, height);
}
@ -103,15 +109,17 @@ export function ShowMessage(message: string) {
}
export function UpdateCursor(imageBytes: Uint8Array, hotSpotX: number, hotSpotY: number, cssOverride: string) {
var targetElement = GetCurrentViewer();
if (cssOverride) {
ScreenViewer.style.cursor = cssOverride;
targetElement.style.cursor = cssOverride;
}
else if (imageBytes.byteLength == 0) {
ScreenViewer.style.cursor = "default";
targetElement.style.cursor = "default";
}
else {
var base64 = ConvertUInt8ArrayToBase64(imageBytes);
ScreenViewer.style.cursor = `url('data:image/png;base64,${base64}') ${hotSpotX} ${hotSpotY}, default`;
targetElement.style.cursor = `url('data:image/png;base64,${base64}') ${hotSpotX} ${hotSpotY}, default`;
}
}

View File

@ -1,52 +0,0 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Remotely.Desktop.Core.Utilities;
using Remotely.Desktop.Win.Services;
using System;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
namespace Remotely.Tests
{
[TestClass]
public class CaptureTests
{
[TestMethod]
[Ignore("Debug only.")]
public async Task Capture()
{
var capturer = new ScreenCapturerWin();
capturer.GetNextFrame();
Process.Start("msg", "* test");
await Task.Delay(500);
capturer.GetNextFrame();
var diffArea = ImageUtils.GetDiffArea(capturer.CurrentFrame, capturer.PreviousFrame, false);
if (diffArea.IsEmpty)
{
return;
}
using (var newImage = capturer.CurrentFrame.Clone(diffArea, PixelFormat.Format32bppArgb))
{
if (capturer.CaptureFullscreen)
{
capturer.CaptureFullscreen = false;
}
newImage.Save(Path.Combine(Path.GetTempPath(), "!ImageDiff.jpg"), ImageFormat.Jpeg);
capturer.CurrentFrame.Save(Path.Combine(Path.GetTempPath(), "!Current.jpg"), ImageFormat.Jpeg);
capturer.PreviousFrame.Save(Path.Combine(Path.GetTempPath(), "!Previous.jpg"), ImageFormat.Jpeg);
}
}
private double MeasureCommand(Action command)
{
var stopwatch = Stopwatch.StartNew();
command.Invoke();
stopwatch.Stop();
Console.WriteLine($"Command time: {stopwatch.Elapsed.TotalMilliseconds}");
return stopwatch.Elapsed.TotalMilliseconds;
}
}
}