diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs
deleted file mode 100644
index 51be48ec5a..0000000000
--- a/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs
+++ /dev/null
@@ -1,1162 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Diagnostics;
-using System.Drawing;
-using System.Globalization;
-using System.IO;
-using System.IO.Compression;
-using System.Linq;
-using System.Net.Sockets;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-
-using Microsoft.PowerToys.Telemetry;
-
-//
-// Clipboard related routines.
-//
-//
-// 2008 created by Truong Do (ductdo).
-// 2009-... modified by Truong Do (TruongDo).
-// 2023- Included in PowerToys.
-//
-using MouseWithoutBorders.Class;
-using MouseWithoutBorders.Core;
-using MouseWithoutBorders.Exceptions;
-
-using SystemClipboard = System.Windows.Forms.Clipboard;
-using Thread = MouseWithoutBorders.Core.Thread;
-
-namespace MouseWithoutBorders
-{
- internal partial class Common
- {
- internal static readonly char[] Comma = new char[] { ',' };
- internal static readonly char[] Star = new char[] { '*' };
- internal static readonly char[] NullSeparator = new char[] { '\0' };
-
- internal const uint BIG_CLIPBOARD_DATA_TIMEOUT = 30000;
- private const uint MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1024 * 1024; // 1MB
- private const uint MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 100 * 1024 * 1024; // 100MB
- private const int TEXT_HEADER_SIZE = 12;
- private const int DATA_SIZE = 48;
- private const string TEXT_TYPE_SEP = "{4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}";
- private static long lastClipboardEventTime;
- private static string lastMachineWithClipboardData;
- private static string lastDragDropFile;
-#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
- internal static long clipboardCopiedTime;
-#pragma warning restore SA1307
-
- internal static ID LastIDWithClipboardData { get; set; }
-
- internal static string LastDragDropFile
- {
- get => Common.lastDragDropFile;
- set => Common.lastDragDropFile = value;
- }
-
- internal static string LastMachineWithClipboardData
- {
- get => Common.lastMachineWithClipboardData;
- set => Common.lastMachineWithClipboardData = value;
- }
-
- internal static long LastClipboardEventTime
- {
- get => Common.lastClipboardEventTime;
- set => Common.lastClipboardEventTime = value;
- }
-
- internal static IntPtr NextClipboardViewer { get; set; }
-
- internal static bool IsClipboardDataImage { get; private set; }
-
- internal static byte[] LastClipboardData { get; private set; }
-
- private static object lastClipboardObject = string.Empty;
-
- internal static bool HasSwitchedMachineSinceLastCopy { get; set; }
-
- internal static bool CheckClipboardEx(ByteArrayOrString data, bool isFilePath)
- {
- Logger.LogDebug($"{nameof(CheckClipboardEx)}: ShareClipboard = {Setting.Values.ShareClipboard}, TransferFile = {Setting.Values.TransferFile}, data = {data}.");
- Logger.LogDebug($"{nameof(CheckClipboardEx)}: {nameof(Setting.Values.OneWayClipboardMode)} = {Setting.Values.OneWayClipboardMode}.");
-
- if (!Setting.Values.ShareClipboard)
- {
- return false;
- }
-
- if (Common.RunWithNoAdminRight && Setting.Values.OneWayClipboardMode)
- {
- return false;
- }
-
- if (GetTick() - LastClipboardEventTime < 1000)
- {
- Logger.LogDebug("GetTick() - lastClipboardEventTime < 1000");
- LastClipboardEventTime = GetTick();
- return false;
- }
-
- LastClipboardEventTime = GetTick();
-
- try
- {
- IsClipboardDataImage = false;
- LastClipboardData = null;
- LastDragDropFile = null;
- GC.Collect();
-
- string stringData = null;
- byte[] byteData = null;
-
- if (data.IsByteArray)
- {
- byteData = data.GetByteArray();
- }
- else
- {
- stringData = data.GetString();
- }
-
- if (stringData != null)
- {
- if (!HasSwitchedMachineSinceLastCopy)
- {
- if (lastClipboardObject is string lastStringData && lastStringData.Equals(stringData, StringComparison.OrdinalIgnoreCase))
- {
- Logger.LogDebug("CheckClipboardEx: Same string data.");
- return false;
- }
- }
-
- HasSwitchedMachineSinceLastCopy = false;
-
- if (isFilePath)
- {
- Logger.LogDebug("Clipboard contains FileDropList");
-
- if (!Setting.Values.TransferFile)
- {
- Logger.LogDebug("TransferFile option is unchecked.");
- return false;
- }
-
- string filePath = stringData;
-
- _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() =>
- {
- if (File.Exists(filePath) || Directory.Exists(filePath))
- {
- if (File.Exists(filePath) && new FileInfo(filePath).Length <= MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT)
- {
- Logger.LogDebug("Clipboard contains: " + filePath);
- LastDragDropFile = filePath;
- SendClipboardBeat();
- SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_BIG_CLIPBOARD, -1, ICON_BIG_CLIPBOARD, -1 });
- }
- else
- {
- if (Directory.Exists(filePath))
- {
- Logger.LogDebug("Clipboard contains a directory: " + filePath);
- LastDragDropFile = filePath;
- SendClipboardBeat();
- }
- else
- {
- LastDragDropFile = filePath + " - File too big (greater than 100MB), please drag and drop the file instead!";
- SendClipboardBeat();
- Logger.Log("Clipboard: File too big: " + filePath);
- }
-
- SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_ERROR, -1, ICON_ERROR, -1 });
- }
- }
- else
- {
- Logger.Log("CheckClipboardEx: File not found: " + filePath);
- }
- });
- }
- else
- {
- byte[] texts = Common.GetBytesU(stringData);
-
- using MemoryStream ms = new();
- using (DeflateStream s = new(ms, CompressionMode.Compress, true))
- {
- s.Write(texts, 0, texts.Length);
- }
-
- Logger.LogDebug("Plain/Zip = " + texts.Length.ToString(CultureInfo.CurrentCulture) + "/" +
- ms.Length.ToString(CultureInfo.CurrentCulture));
-
- LastClipboardData = ms.GetBuffer();
- }
- }
- else if (byteData != null)
- {
- if (!HasSwitchedMachineSinceLastCopy)
- {
- if (lastClipboardObject is byte[] lastByteData && Enumerable.SequenceEqual(lastByteData, byteData))
- {
- Logger.LogDebug("CheckClipboardEx: Same byte[] data.");
- return false;
- }
- }
-
- HasSwitchedMachineSinceLastCopy = false;
-
- Logger.LogDebug("Clipboard contains image");
- IsClipboardDataImage = true;
- LastClipboardData = byteData;
- }
- else
- {
- Logger.LogDebug("*** Clipboard contains something else!");
- return false;
- }
-
- lastClipboardObject = data;
-
- if (LastClipboardData != null && LastClipboardData.Length > 0)
- {
- if (LastClipboardData.Length > MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP)
- {
- SendClipboardBeat();
- SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_BIG_CLIPBOARD, -1, ICON_BIG_CLIPBOARD, -1 });
- }
- else
- {
- SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_SMALL_CLIPBOARD, -1, -1, -1 });
- SendClipboardDataUsingTCP(LastClipboardData, IsClipboardDataImage);
- }
-
- return true;
- }
- }
- catch (Exception e)
- {
- Logger.Log(e);
- }
-
- return false;
- }
-
- private static void SendClipboardDataUsingTCP(byte[] bytes, bool image)
- {
- if (Sk == null)
- {
- return;
- }
-
- new Task(() =>
- {
- // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again.
- // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892
- using var asyncFlowControl = ExecutionContext.SuppressFlow();
-
- System.Threading.Thread thread = Thread.CurrentThread;
- thread.Name = $"{nameof(SendClipboardDataUsingTCP)}.{thread.ManagedThreadId}";
- Thread.UpdateThreads(thread);
- int l = bytes.Length;
- int index = 0;
- int len;
- DATA package = new();
- byte[] buf = new byte[PACKAGE_SIZE_EX];
- int dataStart = PACKAGE_SIZE_EX - DATA_SIZE;
-
- while (true)
- {
- if ((index + DATA_SIZE) > l)
- {
- len = l - index;
- Array.Clear(buf, 0, PACKAGE_SIZE_EX);
- }
- else
- {
- len = DATA_SIZE;
- }
-
- Array.Copy(bytes, index, buf, dataStart, len);
- package.Bytes = buf;
-
- package.Type = image ? PackageType.ClipboardImage : PackageType.ClipboardText;
- package.Des = ID.ALL;
- SkSend(package, (uint)MachineID, false);
-
- index += DATA_SIZE;
- if (index >= l)
- {
- break;
- }
- }
-
- package.Type = PackageType.ClipboardDataEnd;
- package.Des = ID.ALL;
- SkSend(package, (uint)MachineID, false);
- }).Start();
- }
-
- internal static void ReceiveClipboardDataUsingTCP(DATA data, bool image, TcpSk tcp)
- {
- try
- {
- if (Sk == null || RunOnLogonDesktop || RunOnScrSaverDesktop)
- {
- return;
- }
-
- MemoryStream m = new();
- int dataStart = PACKAGE_SIZE_EX - DATA_SIZE;
- m.Write(data.Bytes, dataStart, DATA_SIZE);
- int unexpectedCount = 0;
-
- bool done = false;
- do
- {
- data = SocketStuff.TcpReceiveData(tcp, out int err);
-
- switch (data.Type)
- {
- case PackageType.ClipboardImage:
- case PackageType.ClipboardText:
- m.Write(data.Bytes, dataStart, DATA_SIZE);
- break;
-
- case PackageType.ClipboardDataEnd:
- done = true;
- break;
-
- default:
- Receiver.ProcessPackage(data, tcp);
- if (++unexpectedCount > 100)
- {
- Logger.Log("ReceiveClipboardDataUsingTCP: unexpectedCount > 100!");
- done = true;
- }
-
- break;
- }
- }
- while (!done);
-
- LastClipboardEventTime = GetTick();
-
- if (image)
- {
- Image im = Image.FromStream(m);
- Clipboard.SetImage(im);
- LastClipboardEventTime = GetTick();
- }
- else
- {
- Common.SetClipboardData(m.GetBuffer());
- LastClipboardEventTime = GetTick();
- }
-
- m.Dispose();
-
- SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_SMALL_CLIPBOARD, -1, ICON_SMALL_CLIPBOARD, -1 });
- }
- catch (Exception e)
- {
- Logger.Log("ReceiveClipboardDataUsingTCP: " + e.Message);
- }
- }
-
- private static readonly Lock ClipboardThreadOldLock = new();
- private static System.Threading.Thread clipboardThreadOld;
-
- internal static void GetRemoteClipboard(string postAction)
- {
- if (!RunOnLogonDesktop && !RunOnScrSaverDesktop)
- {
- if (Common.LastMachineWithClipboardData == null ||
- Common.LastMachineWithClipboardData.Length < 1)
- {
- return;
- }
-
- new Task(() =>
- {
- // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again.
- // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892
- using var asyncFlowControl = ExecutionContext.SuppressFlow();
-
- System.Threading.Thread thread = Thread.CurrentThread;
- thread.Name = $"{nameof(ConnectAndGetData)}.{thread.ManagedThreadId}";
- Thread.UpdateThreads(thread);
- ConnectAndGetData(postAction);
- }).Start();
- }
- }
-
- private static Stream m;
-
- private static void ConnectAndGetData(object postAction)
- {
- if (Sk == null)
- {
- Logger.Log("ConnectAndGetData: Sk == null!");
- return;
- }
-
- string remoteMachine;
- TcpClient clipboardTcpClient = null;
- string postAct = (string)postAction;
-
- Logger.LogDebug("ConnectAndGetData.postAction: " + postAct);
-
- ClipboardPostAction clipboardPostAct = postAct.Contains("mspaint,") ? ClipboardPostAction.Mspaint
- : postAct.Equals("desktop", StringComparison.OrdinalIgnoreCase) ? ClipboardPostAction.Desktop
- : ClipboardPostAction.Other;
-
- try
- {
- remoteMachine = postAct.Contains("mspaint,") ? postAct.Split(Comma)[1] : Common.LastMachineWithClipboardData;
-
- remoteMachine = remoteMachine.Trim();
-
- if (!IsConnectedByAClientSocketTo(remoteMachine))
- {
- Logger.Log($"No potential inbound connection from {MachineName} to {remoteMachine}, ask for a push back instead.");
- ID machineId = MachineStuff.MachinePool.ResolveID(remoteMachine);
-
- if (machineId != ID.NONE)
- {
- SkSend(
- new DATA()
- {
- Type = PackageType.ClipboardAsk,
- Des = machineId,
- MachineName = MachineName,
- PostAction = clipboardPostAct,
- },
- null,
- false);
- }
- else
- {
- Logger.Log($"Unable to resolve {remoteMachine} to its long IP.");
- }
-
- return;
- }
-
- ShowToolTip("Connecting to " + remoteMachine, 2000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
-
- clipboardTcpClient = ConnectToRemoteClipboardSocket(remoteMachine);
- }
- catch (ThreadAbortException)
- {
- Logger.Log("The current thread is being aborted (1).");
- if (clipboardTcpClient != null && clipboardTcpClient.Connected)
- {
- clipboardTcpClient.Client.Close();
- }
-
- return;
- }
- catch (Exception e)
- {
- Logger.Log(e);
- Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
- {
- Common.ICON_BIG_CLIPBOARD,
- -1, Common.ICON_BIG_CLIPBOARD, -1,
- });
- ShowToolTip(e.Message, 1000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
- return;
- }
-
- bool clientPushData = false;
-
- if (!ShakeHand(ref remoteMachine, clipboardTcpClient.Client, out Stream enStream, out Stream deStream, ref clientPushData, ref clipboardPostAct))
- {
- return;
- }
-
- ReceiveAndProcessClipboardData(remoteMachine, clipboardTcpClient.Client, enStream, deStream, postAct);
- }
-
- internal static void ReceiveAndProcessClipboardData(string remoteMachine, Socket s, Stream enStream, Stream deStream, string postAct)
- {
- lock (ClipboardThreadOldLock)
- {
- // Do not enable two connections at the same time.
- if (clipboardThreadOld != null && clipboardThreadOld.ThreadState != System.Threading.ThreadState.AbortRequested
- && clipboardThreadOld.ThreadState != System.Threading.ThreadState.Aborted && clipboardThreadOld.IsAlive
- && clipboardThreadOld.ManagedThreadId != Thread.CurrentThread.ManagedThreadId)
- {
- if (clipboardThreadOld.Join(3000))
- {
- if (m != null)
- {
- m.Flush();
- m.Close();
- m = null;
- }
- }
- }
-
- clipboardThreadOld = Thread.CurrentThread;
- }
-
- try
- {
- byte[] header = new byte[1024];
- byte[] buf = new byte[NETWORK_STREAM_BUF_SIZE];
- string fileName = null;
- string tempFile = "data", savingFolder = string.Empty;
- Common.ToggleIconsIndex = 0;
- int rv;
- long receivedCount = 0;
-
- if ((rv = deStream.ReadEx(header, 0, header.Length)) < header.Length)
- {
- Logger.Log("Reading header failed: " + rv.ToString(CultureInfo.CurrentCulture));
- Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
- {
- Common.ICON_BIG_CLIPBOARD,
- -1, -1, -1,
- });
- return;
- }
-
- fileName = Common.GetStringU(header).Replace("\0", string.Empty);
- Logger.LogDebug("Header: " + fileName);
- string[] headers = fileName.Split(Star);
-
- if (headers.Length < 2 || !long.TryParse(headers[0], out long dataSize))
- {
- Logger.Log(string.Format(
- CultureInfo.CurrentCulture,
- "Reading header failed: {0}:{1}",
- headers.Length,
- fileName));
- Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
- {
- Common.ICON_BIG_CLIPBOARD,
- -1, -1, -1,
- });
- return;
- }
-
- fileName = headers[1];
-
- Logger.LogDebug(string.Format(
- CultureInfo.CurrentCulture,
- "Receiving {0}:{1} from {2}...",
- Path.GetFileName(fileName),
- dataSize,
- remoteMachine));
- ShowToolTip(
- string.Format(
- CultureInfo.CurrentCulture,
- "Receiving {0} from {1}...",
- Path.GetFileName(fileName),
- remoteMachine),
- 5000,
- ToolTipIcon.Info,
- Setting.Values.ShowClipNetStatus);
- if (fileName.StartsWith("image", StringComparison.CurrentCultureIgnoreCase) ||
- fileName.StartsWith("text", StringComparison.CurrentCultureIgnoreCase))
- {
- m = new MemoryStream();
- }
- else
- {
- if (postAct.Equals("desktop", StringComparison.OrdinalIgnoreCase))
- {
- _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() =>
- {
- savingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\MouseWithoutBorders\\";
-
- if (!Directory.Exists(savingFolder))
- {
- _ = Directory.CreateDirectory(savingFolder);
- }
- });
-
- tempFile = savingFolder + Path.GetFileName(fileName);
- m = new FileStream(tempFile, FileMode.Create);
- }
- else if (postAct.Contains("mspaint"))
- {
- tempFile = GetMyStorageDir() + @"ScreenCapture-" +
- remoteMachine + ".png";
- m = new FileStream(tempFile, FileMode.Create);
- }
- else
- {
- tempFile = GetMyStorageDir();
- tempFile += Path.GetFileName(fileName);
- m = new FileStream(tempFile, FileMode.Create);
- }
-
- Logger.Log("==> " + tempFile);
- }
-
- ShowToolTip(
- string.Format(
- CultureInfo.CurrentCulture,
- "Receiving {0} from {1}...",
- Path.GetFileName(fileName),
- remoteMachine),
- 5000,
- ToolTipIcon.Info,
- Setting.Values.ShowClipNetStatus);
-
- do
- {
- rv = deStream.ReadEx(buf, 0, buf.Length);
-
- if (rv > 0)
- {
- receivedCount += rv;
-
- if (receivedCount > dataSize)
- {
- rv -= (int)(receivedCount - dataSize);
- }
-
- m.Write(buf, 0, rv);
- }
-
- if (Common.ToggleIcons == null)
- {
- Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
- {
- Common.ICON_SMALL_CLIPBOARD,
- -1, Common.ICON_SMALL_CLIPBOARD, -1,
- });
- }
-
- string text = string.Format(CultureInfo.CurrentCulture, "{0}KB received: {1}", m.Length / 1024, Path.GetFileName(fileName));
-
- DoSomethingInUIThread(() =>
- {
- MainForm.SetTrayIconText(text);
- });
- }
- while (rv > 0);
-
- if (m != null && fileName != null)
- {
- m.Flush();
- Logger.LogDebug(m.Length.ToString(CultureInfo.CurrentCulture) + " bytes received.");
- Common.LastClipboardEventTime = Common.GetTick();
- string toolTipText = null;
- string sizeText = m.Length >= 1024
- ? (m.Length / 1024).ToString(CultureInfo.CurrentCulture) + "KB"
- : m.Length.ToString(CultureInfo.CurrentCulture) + "Bytes";
-
- PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersClipboardFileTransferEvent());
-
- if (fileName.StartsWith("image", StringComparison.CurrentCultureIgnoreCase))
- {
- Clipboard.SetImage(Image.FromStream(m));
- toolTipText = string.Format(
- CultureInfo.CurrentCulture,
- "{0} {1} from {2} is in Clipboard.",
- sizeText,
- "image",
- remoteMachine);
- }
- else if (fileName.StartsWith("text", StringComparison.CurrentCultureIgnoreCase))
- {
- byte[] data = (m as MemoryStream).GetBuffer();
- toolTipText = string.Format(
- CultureInfo.CurrentCulture,
- "{0} {1} from {2} is in Clipboard.",
- sizeText,
- "text",
- remoteMachine);
- Common.SetClipboardData(data);
- }
- else if (tempFile != null)
- {
- if (postAct.Equals("desktop", StringComparison.OrdinalIgnoreCase))
- {
- toolTipText = string.Format(
- CultureInfo.CurrentCulture,
- "{0} {1} received from {2}!",
- sizeText,
- Path.GetFileName(fileName),
- remoteMachine);
-
- _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() =>
- {
- ProcessStartInfo startInfo = new();
- startInfo.UseShellExecute = true;
- startInfo.WorkingDirectory = savingFolder;
- startInfo.FileName = savingFolder;
- startInfo.Verb = "open";
- _ = Process.Start(startInfo);
- });
- }
- else if (postAct.Contains("mspaint"))
- {
- m.Close();
- m = null;
- OpenImage(tempFile);
- toolTipText = string.Format(
- CultureInfo.CurrentCulture,
- "{0} {1} from {2} is in Mspaint.",
- sizeText,
- Path.GetFileName(tempFile),
- remoteMachine);
- }
- else
- {
- StringCollection filePaths = new()
- {
- tempFile,
- };
- Clipboard.SetFileDropList(filePaths);
- toolTipText = string.Format(
- CultureInfo.CurrentCulture,
- "{0} {1} from {2} is in Clipboard.",
- sizeText,
- Path.GetFileName(fileName),
- remoteMachine);
- }
- }
-
- if (!string.IsNullOrWhiteSpace(toolTipText))
- {
- Common.ShowToolTip(toolTipText, 5000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
- }
-
- DoSomethingInUIThread(() =>
- {
- MainForm.UpdateNotifyIcon();
- });
-
- m?.Close();
- m = null;
- }
- }
- catch (ThreadAbortException)
- {
- Logger.Log("The current thread is being aborted (3).");
- s.Close();
-
- if (m != null)
- {
- m.Close();
- m = null;
- }
-
- return;
- }
- catch (Exception e)
- {
- if (e is IOException)
- {
- string log = $"{nameof(ReceiveAndProcessClipboardData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
- Logger.Log(log);
- }
- else
- {
- Logger.Log(e);
- }
-
- Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
- {
- Common.ICON_BIG_CLIPBOARD,
- -1, Common.ICON_BIG_CLIPBOARD, -1,
- });
- ShowToolTip(e.Message, 1000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
-
- if (m != null)
- {
- m.Close();
- m = null;
- }
-
- return;
- }
-
- s.Close();
- }
-
- internal static bool ShakeHand(ref string remoteName, Socket s, out Stream enStream, out Stream deStream, ref bool clientPushData, ref ClipboardPostAction postAction)
- {
- const int CLIPBOARD_HANDSHAKE_TIMEOUT = 30;
- s.ReceiveTimeout = CLIPBOARD_HANDSHAKE_TIMEOUT * 1000;
- s.NoDelay = true;
- s.SendBufferSize = s.ReceiveBufferSize = 1024000;
-
- bool handShaken = false;
- enStream = deStream = null;
-
- try
- {
- DATA package = new()
- {
- Type = clientPushData ? PackageType.ClipboardPush : PackageType.Clipboard,
- PostAction = postAction,
- Src = MachineID,
- MachineName = MachineName,
- };
-
- byte[] buf = new byte[PACKAGE_SIZE_EX];
-
- NetworkStream ns = new(s);
- enStream = Common.GetEncryptedStream(ns);
- Common.SendOrReceiveARandomDataBlockPerInitialIV(enStream);
- Logger.LogDebug($"{nameof(ShakeHand)}: Writing header package.");
- enStream.Write(package.Bytes, 0, PACKAGE_SIZE_EX);
-
- Logger.LogDebug($"{nameof(ShakeHand)}: Sent: clientPush={clientPushData}, postAction={postAction}.");
-
- deStream = Common.GetDecryptedStream(ns);
- Common.SendOrReceiveARandomDataBlockPerInitialIV(deStream, false);
-
- Logger.LogDebug($"{nameof(ShakeHand)}: Reading header package.");
-
- int bytesReceived = deStream.ReadEx(buf, 0, Common.PACKAGE_SIZE_EX);
- package.Bytes = buf;
-
- string name = "Unknown";
-
- if (bytesReceived == Common.PACKAGE_SIZE_EX)
- {
- if (package.Type is PackageType.Clipboard or PackageType.ClipboardPush)
- {
- name = remoteName = package.MachineName;
-
- Logger.LogDebug($"{nameof(ShakeHand)}: Connection from {name}:{package.Src}");
-
- if (MachineStuff.MachinePool.ResolveID(name) == package.Src && Common.IsConnectedTo(package.Src))
- {
- clientPushData = package.Type == PackageType.ClipboardPush;
- postAction = package.PostAction;
- handShaken = true;
- Logger.LogDebug($"{nameof(ShakeHand)}: Received: clientPush={clientPushData}, postAction={postAction}.");
- }
- else
- {
- Logger.LogDebug($"{nameof(ShakeHand)}: No active connection to the machine: {name}.");
- }
- }
- else
- {
- Logger.LogDebug($"{nameof(ShakeHand)}: Unexpected package type: {package.Type}.");
- }
- }
- else
- {
- Logger.LogDebug($"{nameof(ShakeHand)}: BytesTransferred != PACKAGE_SIZE_EX: {bytesReceived}");
- }
-
- if (!handShaken)
- {
- string msg = $"Clipboard connection rejected: {name}:{remoteName}/{package.Src}\r\n\r\nMake sure you run the same version in all machines.";
- Logger.Log(msg);
- Common.ShowToolTip(msg, 3000, ToolTipIcon.Warning);
- Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE] { Common.ICON_BIG_CLIPBOARD, -1, -1, -1 });
- }
- }
- catch (ThreadAbortException)
- {
- Logger.Log($"{nameof(ShakeHand)}: The current thread is being aborted.");
- s.Close();
- }
- catch (Exception e)
- {
- if (e is IOException)
- {
- string log = $"{nameof(ShakeHand)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
- Logger.Log(log);
- }
- else
- {
- Logger.Log(e);
- }
-
- Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
- {
- Common.ICON_BIG_CLIPBOARD,
- -1, Common.ICON_BIG_CLIPBOARD, -1,
- });
- MainForm.UpdateNotifyIcon();
- ShowToolTip(e.Message + "\r\n\r\nMake sure you run the same version in all machines.", 1000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
-
- if (m != null)
- {
- m.Close();
- m = null;
- }
- }
-
- return handShaken;
- }
-
- internal static TcpClient ConnectToRemoteClipboardSocket(string remoteMachine)
- {
- TcpClient clipboardTcpClient;
- clipboardTcpClient = new TcpClient(AddressFamily.InterNetworkV6);
- clipboardTcpClient.Client.DualMode = true;
-
- SocketStuff sk = Common.Sk;
-
- if (sk != null)
- {
- Common.DoSomethingInUIThread(() => Common.MainForm.ChangeIcon(Common.ICON_SMALL_CLIPBOARD));
-
- System.Net.IPAddress ip = GetConnectedClientSocketIPAddressFor(remoteMachine);
- Logger.LogDebug($"{nameof(ConnectToRemoteClipboardSocket)}Connecting to {remoteMachine}:{ip}:{sk.TcpPort}...");
-
- if (ip != null)
- {
- clipboardTcpClient.Connect(ip, sk.TcpPort);
- }
- else
- {
- clipboardTcpClient.Connect(remoteMachine, sk.TcpPort);
- }
-
- Logger.LogDebug($"Connected from {clipboardTcpClient.Client.LocalEndPoint}. Getting data...");
- return clipboardTcpClient;
- }
- else
- {
- throw new ExpectedSocketException($"{nameof(ConnectToRemoteClipboardSocket)}: No longer connected.");
- }
- }
-
- internal static void SetClipboardData(byte[] data)
- {
- if (data == null || data.Length <= 0)
- {
- Logger.Log("data is null or empty!");
- return;
- }
-
- if (data.Length > 1024000)
- {
- ShowToolTip(
- string.Format(
- CultureInfo.CurrentCulture,
- "Decompressing {0} clipboard data ...",
- (data.Length / 1024).ToString(CultureInfo.CurrentCulture) + "KB"),
- 5000,
- ToolTipIcon.Info,
- Setting.Values.ShowClipNetStatus);
- }
-
- string st = string.Empty;
-
- using (MemoryStream ms = new(data))
- {
- using DeflateStream s = new(ms, CompressionMode.Decompress, true);
- const int BufferSize = 1024000; // Buffer size should be big enough, this is critical to performance!
-
- int rv = 0;
-
- do
- {
- byte[] buffer = new byte[BufferSize];
- rv = s.ReadEx(buffer, 0, BufferSize);
-
- if (rv > 0)
- {
- st += Common.GetStringU(buffer);
- }
- else
- {
- break;
- }
- }
- while (true);
- }
-
- int textTypeCount = 0;
- string[] texts = st.Split(new string[] { TEXT_TYPE_SEP }, StringSplitOptions.RemoveEmptyEntries);
- string tmp;
- DataObject data1 = new();
-
- foreach (string txt in texts)
- {
- if (string.IsNullOrEmpty(txt.Trim(NullSeparator)))
- {
- continue;
- }
-
- tmp = txt[3..];
-
- if (txt.StartsWith("RTF", StringComparison.CurrentCultureIgnoreCase))
- {
- Logger.LogDebug(((double)tmp.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of RTF <-");
- data1.SetData(DataFormats.Rtf, tmp);
- }
- else if (txt.StartsWith("HTM", StringComparison.CurrentCultureIgnoreCase))
- {
- Logger.LogDebug(((double)tmp.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of HTM <-");
- data1.SetData(DataFormats.Html, tmp);
- }
- else if (txt.StartsWith("TXT", StringComparison.CurrentCultureIgnoreCase))
- {
- Logger.LogDebug(((double)tmp.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of TXT <-");
- data1.SetData(DataFormats.UnicodeText, tmp);
- }
- else
- {
- if (textTypeCount == 0)
- {
- Logger.LogDebug(((double)txt.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of UNI <-");
- data1.SetData(DataFormats.UnicodeText, txt);
- }
-
- Logger.Log("Invalid clipboard format received!");
- }
-
- textTypeCount++;
- }
-
- if (textTypeCount > 0)
- {
- Clipboard.SetDataObject(data1);
- }
- }
- }
-
- internal static class Clipboard
- {
- public static void SetFileDropList(StringCollection filePaths)
- {
- Common.DoSomethingInUIThread(() =>
- {
- try
- {
- _ = Common.Retry(
- nameof(SystemClipboard.SetFileDropList),
- () =>
- {
- SystemClipboard.SetFileDropList(filePaths);
- return true;
- },
- (log) => Logger.TelemetryLogTrace(
- log,
- SeverityLevel.Information),
- () => Common.LastClipboardEventTime = Common.GetTick());
- }
- catch (ExternalException e)
- {
- Logger.Log(e);
- }
- catch (ThreadStateException e)
- {
- Logger.Log(e);
- }
- catch (ArgumentNullException e)
- {
- Logger.Log(e);
- }
- catch (ArgumentException e)
- {
- Logger.Log(e);
- }
- });
- }
-
- public static void SetImage(Image image)
- {
- Common.DoSomethingInUIThread(() =>
- {
- try
- {
- _ = Common.Retry(
- nameof(SystemClipboard.SetImage),
- () =>
- {
- SystemClipboard.SetImage(image);
- return true;
- },
- (log) => Logger.TelemetryLogTrace(log, SeverityLevel.Information),
- () => Common.LastClipboardEventTime = Common.GetTick());
- }
- catch (ExternalException e)
- {
- Logger.Log(e);
- }
- catch (ThreadStateException e)
- {
- Logger.Log(e);
- }
- catch (ArgumentNullException e)
- {
- Logger.Log(e);
- }
- });
- }
-
- public static void SetText(string text)
- {
- Common.DoSomethingInUIThread(() =>
- {
- try
- {
- _ = Common.Retry(
- nameof(SystemClipboard.SetText),
- () =>
- {
- SystemClipboard.SetText(text);
- return true;
- },
- (log) => Logger.TelemetryLogTrace(log, SeverityLevel.Information),
- () => Common.LastClipboardEventTime = Common.GetTick());
- }
- catch (ExternalException e)
- {
- Logger.Log(e);
- }
- catch (ThreadStateException e)
- {
- Logger.Log(e);
- }
- catch (ArgumentNullException e)
- {
- Logger.Log(e);
- }
- });
- }
-
- public static void SetDataObject(DataObject dataObject)
- {
- Common.DoSomethingInUIThread(() =>
- {
- try
- {
- SystemClipboard.SetDataObject(dataObject, true, 10, 200);
- }
- catch (ExternalException e)
- {
- string dataFormats = string.Join(",", dataObject.GetFormats());
- Logger.Log($"{e.Message}: {dataFormats}");
- }
- catch (ThreadStateException e)
- {
- Logger.Log(e);
- }
- catch (ArgumentNullException e)
- {
- Logger.Log(e);
- }
- });
- }
- }
-}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.InitAndCleanup.cs b/src/modules/MouseWithoutBorders/App/Class/Common.InitAndCleanup.cs
deleted file mode 100644
index 44861926e9..0000000000
--- a/src/modules/MouseWithoutBorders/App/Class/Common.InitAndCleanup.cs
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Globalization;
-using System.Linq;
-using System.Net.NetworkInformation;
-using System.Security.Cryptography;
-using System.Threading;
-
-//
-// Initialization and clean up.
-//
-//
-// 2008 created by Truong Do (ductdo).
-// 2009-... modified by Truong Do (TruongDo).
-// 2023- Included in PowerToys.
-//
-using Microsoft.Win32;
-using MouseWithoutBorders.Class;
-using MouseWithoutBorders.Core;
-using MouseWithoutBorders.Form;
-using Windows.UI.Input.Preview.Injection;
-
-using Thread = MouseWithoutBorders.Core.Thread;
-
-namespace MouseWithoutBorders
-{
- internal partial class Common
- {
- private static bool initDone;
- internal static int REOPEN_WHEN_WSAECONNRESET = -10054;
- internal static int REOPEN_WHEN_HOTKEY = -10055;
- internal static int PleaseReopenSocket;
- internal static bool ReopenSocketDueToReadError;
-
- internal static DateTime LastResumeSuspendTime { get; set; } = DateTime.UtcNow;
-
- internal static bool InitDone
- {
- get => Common.initDone;
- set => Common.initDone = value;
- }
-
- internal static void UpdateMachineTimeAndID()
- {
- Common.MachineName = Common.MachineName.Trim();
- _ = MachineStuff.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
- }
-
- private static void InitializeMachinePoolFromSettings()
- {
- try
- {
- MachineInf[] info = MachinePoolHelpers.LoadMachineInfoFromMachinePoolStringSetting(Setting.Values.MachinePoolString);
- for (int i = 0; i < info.Length; i++)
- {
- info[i].Name = info[i].Name.Trim();
- }
-
- MachineStuff.MachinePool.Initialize(info);
- MachineStuff.MachinePool.ResetIPAddressesForDeadMachines(true);
- }
- catch (Exception ex)
- {
- Logger.Log(ex);
- MachineStuff.MachinePool.Clear();
- }
- }
-
- internal static void SetupMachineNameAndID()
- {
- try
- {
- GetMachineName();
- DesMachineID = MachineStuff.NewDesMachineID = MachineID;
-
- // MessageBox.Show(machineID.ToString(CultureInfo.CurrentCulture)); // For test
- InitializeMachinePoolFromSettings();
-
- Common.MachineName = Common.MachineName.Trim();
- _ = MachineStuff.MachinePool.LearnMachine(Common.MachineName);
- _ = MachineStuff.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
-
- MachineStuff.UpdateMachinePoolStringSetting();
- }
- catch (Exception e)
- {
- Logger.Log(e);
- }
- }
-
- internal static void Init()
- {
- _ = Helper.GetUserName();
- Common.GeneratedKey = true;
-
- try
- {
- Common.MyKey = Setting.Values.MyKey;
- int tmp = Setting.Values.MyKeyDaysToExpire;
- }
- catch (FormatException e)
- {
- Common.KeyCorrupted = true;
- Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
- Logger.Log(e.Message);
- }
- catch (CryptographicException e)
- {
- Common.KeyCorrupted = true;
- Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
- Logger.Log(e.Message);
- }
-
- try
- {
- InputSimulation.Injector = InputInjector.TryCreate();
- if (InputSimulation.Injector != null)
- {
- InputSimulation.MoveMouseRelative(0, 0);
- NativeMethods.InjectMouseInputAvailable = true;
- }
- }
- catch (EntryPointNotFoundException)
- {
- NativeMethods.InjectMouseInputAvailable = false;
- Logger.Log($"{nameof(NativeMethods.InjectMouseInputAvailable)} = false");
- }
-
- bool dummy = Setting.Values.DrawMouseEx;
- Is64bitOS = IntPtr.Size == 8;
- tcpPort = Setting.Values.TcpPort;
- GetScreenConfig();
- PackageSent = new PackageMonitor(0);
- PackageReceived = new PackageMonitor(0);
- SetupMachineNameAndID();
- InitEncryption();
- CreateHelperThreads();
-
- SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);
- NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
- SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
- PleaseReopenSocket = 9;
- /* TODO: Telemetry for the matrix? */
- }
-
- private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
- {
- Helper.WndProcCounter++;
-
- if (e.Mode is PowerModes.Resume or PowerModes.Suspend)
- {
- Logger.TelemetryLogTrace($"{nameof(SystemEvents_PowerModeChanged)}: {e.Mode}", SeverityLevel.Information);
- LastResumeSuspendTime = DateTime.UtcNow;
- MachineStuff.SwitchToMultipleMode(false, true);
- }
- }
-
- private static void CreateHelperThreads()
- {
- // NOTE(@yuyoyuppe): service crashes while trying to obtain this info, disabling.
- /*
- Thread watchDogThread = new(new ThreadStart(WatchDogThread), nameof(WatchDogThread));
- watchDogThread.Priority = ThreadPriority.Highest;
- watchDogThread.Start();
- */
-
- helper = new Thread(new ThreadStart(Helper.HelperThread), "Helper Thread");
- helper.SetApartmentState(ApartmentState.STA);
- helper.Start();
- }
-
- private static void AskHelperThreadsToExit(int waitTime)
- {
- Helper.signalHelperToExit = true;
- Helper.signalWatchDogToExit = true;
- _ = EvSwitch.Set();
-
- int c = 0;
- if (helper != null && c < waitTime)
- {
- while (Helper.signalHelperToExit)
- {
- Thread.Sleep(1);
- }
-
- helper = null;
- }
- }
-
- internal static void Cleanup()
- {
- try
- {
- SendByeBye();
-
- // UnhookClipboard();
- AskHelperThreadsToExit(500);
- MainForm.NotifyIcon.Visible = false;
- MainForm.NotifyIcon.Dispose();
- CloseAllFormsAndHooks();
-
- DoSomethingInUIThread(() =>
- {
- Sk?.Close(true);
- });
- }
- catch (Exception e)
- {
- Logger.Log(e);
- }
- }
-
- private static long lastReleaseAllKeysCall;
-
- internal static void ReleaseAllKeys()
- {
- if (Math.Abs(GetTick() - lastReleaseAllKeysCall) < 2000)
- {
- return;
- }
-
- lastReleaseAllKeysCall = GetTick();
-
- KEYBDDATA kd;
- kd.dwFlags = (int)LLKHF.UP;
-
- VK[] keys = new VK[]
- {
- VK.LSHIFT, VK.LCONTROL, VK.LMENU, VK.LWIN, VK.RSHIFT,
- VK.RCONTROL, VK.RMENU, VK.RWIN, VK.SHIFT, VK.MENU, VK.CONTROL,
- };
-
- Logger.LogDebug("***** ReleaseAllKeys has been called! *****:");
-
- foreach (VK vk in keys)
- {
- if ((NativeMethods.GetAsyncKeyState((IntPtr)vk) & 0x8000) != 0)
- {
- Logger.LogDebug(vk.ToString() + " is down, release it...");
- Hook?.ResetLastSwitchKeys(); // Sticky key can turn ALL PC mode on (CtrlCtrlCtrl)
- kd.wVk = (int)vk;
- InputSimulation.SendKey(kd);
- Hook?.ResetLastSwitchKeys();
- }
- }
- }
-
- private static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
- {
- Logger.LogDebug("NetworkAvailabilityEventArgs.IsAvailable: " + e.IsAvailable.ToString(CultureInfo.InvariantCulture));
- Helper.WndProcCounter++;
- ScheduleReopenSocketsDueToNetworkChanges(!e.IsAvailable);
- }
-
- private static void ScheduleReopenSocketsDueToNetworkChanges(bool closeSockets = true)
- {
- if (closeSockets)
- {
- // Slept/hibernated machine may still have the sockets' status as Connected:( (unchanged) so it would not re-connect after a timeout when waking up.
- // Closing the sockets when it is going to sleep/hibernate will trigger the reconnection faster when it wakes up.
- DoSomethingInUIThread(
- () =>
- {
- SocketStuff s = Sk;
- Sk = null;
- s?.Close(false);
- },
- true);
- }
-
- if (!Common.IsMyDesktopActive())
- {
- PleaseReopenSocket = 0;
- }
- else if (PleaseReopenSocket != 10)
- {
- PleaseReopenSocket = 10;
- }
- }
- }
-}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs b/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs
index ed56101930..ee2d99398c 100644
--- a/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs
@@ -36,7 +36,7 @@ namespace MouseWithoutBorders
internal static string ActiveDesktop => Common.activeDesktop;
- private static void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
+ internal static void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
GetScreenConfig();
}
@@ -340,7 +340,7 @@ namespace MouseWithoutBorders
Setting.Values.LastX = JUST_GOT_BACK_FROM_SCREEN_SAVER;
if (cleanupIfExit)
{
- Common.Cleanup();
+ InitAndCleanup.Cleanup();
}
Process.GetCurrentProcess().KillProcess();
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.cs b/src/modules/MouseWithoutBorders/App/Class/Common.cs
index 0494a952fd..ba5a1655e0 100644
--- a/src/modules/MouseWithoutBorders/App/Class/Common.cs
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.cs
@@ -33,6 +33,7 @@ using MouseWithoutBorders.Class;
using MouseWithoutBorders.Core;
using MouseWithoutBorders.Exceptions;
+using Clipboard = MouseWithoutBorders.Core.Clipboard;
using Thread = MouseWithoutBorders.Core.Thread;
// Log is enough
@@ -90,8 +91,8 @@ namespace MouseWithoutBorders
private static FrmMatrix matrixForm;
private static FrmInputCallback inputCallbackForm;
private static FrmAbout aboutForm;
- private static Thread helper;
#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
+ internal static Thread helper;
internal static int screenWidth;
internal static int screenHeight;
#pragma warning restore SA1307
@@ -121,7 +122,9 @@ namespace MouseWithoutBorders
internal static int switchCount;
#pragma warning restore SA1307
private static long lastReconnectByHotKeyTime;
- private static int tcpPort;
+#pragma warning disable SA1307 // Accessible fields should begin with upper-case names
+ internal static int tcpPort;
+#pragma warning restore SA1307
private static bool secondOpenSocketTry;
private static string binaryName;
@@ -210,7 +213,7 @@ namespace MouseWithoutBorders
internal static bool Is64bitOS
{
- get; private set;
+ get; set;
// set { Common.is64bitOS = value; }
}
@@ -611,7 +614,7 @@ namespace MouseWithoutBorders
}
* */
- private static void SendByeBye()
+ internal static void SendByeBye()
{
Logger.LogDebug($"{nameof(SendByeBye)}");
SendPackage(ID.ALL, PackageType.ByeBye);
@@ -725,7 +728,7 @@ namespace MouseWithoutBorders
internal static void SendImage(string machine, string file)
{
- LastDragDropFile = file;
+ Clipboard.LastDragDropFile = file;
// Send ClipboardCapture
if (machine.Equals("All", StringComparison.OrdinalIgnoreCase))
@@ -744,7 +747,7 @@ namespace MouseWithoutBorders
internal static void SendImage(ID src, string file)
{
- LastDragDropFile = file;
+ Clipboard.LastDragDropFile = file;
// Send ClipboardCapture
SendPackage(src, PackageType.ClipboardCapture);
@@ -1291,7 +1294,7 @@ namespace MouseWithoutBorders
});
}
- private static string GetMyStorageDir()
+ internal static string GetMyStorageDir()
{
string st = string.Empty;
diff --git a/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs b/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs
index 9a52f69529..62360b4795 100644
--- a/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs
+++ b/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs
@@ -28,6 +28,7 @@ using MouseWithoutBorders.Core;
using SystemClipboard = System.Windows.Forms.Clipboard;
#if !MM_HELPER
+using Clipboard = MouseWithoutBorders.Core.Clipboard;
using Thread = MouseWithoutBorders.Core.Thread;
#endif
@@ -159,7 +160,7 @@ namespace MouseWithoutBorders
public void SendClipboardData(ByteArrayOrString data, bool isFilePath)
{
- _ = Common.CheckClipboardEx(data, isFilePath);
+ _ = Clipboard.CheckClipboardEx(data, isFilePath);
}
}
#endif
diff --git a/src/modules/MouseWithoutBorders/App/Class/InputHook.cs b/src/modules/MouseWithoutBorders/App/Class/InputHook.cs
index 33cbe77e89..d68b1a1584 100644
--- a/src/modules/MouseWithoutBorders/App/Class/InputHook.cs
+++ b/src/modules/MouseWithoutBorders/App/Class/InputHook.cs
@@ -579,7 +579,7 @@ namespace MouseWithoutBorders.Class
{
Common.ShowToolTip("Reconnecting...", 2000);
Common.LastReconnectByHotKeyTime = Common.GetTick();
- Common.PleaseReopenSocket = Common.REOPEN_WHEN_HOTKEY;
+ InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_HOTKEY;
return false;
}
@@ -632,7 +632,7 @@ namespace MouseWithoutBorders.Class
{
// Common.DoSomethingInUIThread(delegate()
{
- Common.ReleaseAllKeys();
+ InitAndCleanup.ReleaseAllKeys();
}
// );
diff --git a/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs b/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs
index a991c7f64f..0bbd8014ae 100644
--- a/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs
+++ b/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs
@@ -407,7 +407,7 @@ namespace MouseWithoutBorders.Class
{
ResetModifiersState(Setting.Values.HotKeyLockMachine);
eatKey = true;
- Common.ReleaseAllKeys();
+ InitAndCleanup.ReleaseAllKeys();
_ = NativeMethods.LockWorkStation();
}
}
@@ -439,7 +439,7 @@ namespace MouseWithoutBorders.Class
{
ctrlDown = altDown = false;
eatKey = true;
- Common.ReleaseAllKeys();
+ InitAndCleanup.ReleaseAllKeys();
}
break;
@@ -449,7 +449,7 @@ namespace MouseWithoutBorders.Class
{
winDown = false;
eatKey = true;
- Common.ReleaseAllKeys();
+ InitAndCleanup.ReleaseAllKeys();
uint rv = NativeMethods.LockWorkStation();
Logger.LogDebug("LockWorkStation returned " + rv.ToString(CultureInfo.CurrentCulture));
}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Program.cs b/src/modules/MouseWithoutBorders/App/Class/Program.cs
index 2fd8357e24..c139da46e9 100644
--- a/src/modules/MouseWithoutBorders/App/Class/Program.cs
+++ b/src/modules/MouseWithoutBorders/App/Class/Program.cs
@@ -235,7 +235,7 @@ namespace MouseWithoutBorders.Class
_ = Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
Application.SetCompatibleTextRenderingDefault(false);
- Common.Init();
+ InitAndCleanup.Init();
Core.Helper.WndProcCounter++;
var formScreen = new FrmScreen();
@@ -314,7 +314,7 @@ namespace MouseWithoutBorders.Class
MachineStuff.UpdateMachinePoolStringSetting();
SocketStuff.InvalidKeyFound = false;
- Common.ReopenSocketDueToReadError = true;
+ InitAndCleanup.ReopenSocketDueToReadError = true;
Common.ReopenSockets(true);
MachineStuff.SendMachineMatrix();
@@ -340,7 +340,7 @@ namespace MouseWithoutBorders.Class
public void Reconnect()
{
SocketStuff.InvalidKeyFound = false;
- Common.ReopenSocketDueToReadError = true;
+ InitAndCleanup.ReopenSocketDueToReadError = true;
Common.ReopenSockets(true);
for (int i = 0; i < 10; i++)
@@ -397,7 +397,7 @@ namespace MouseWithoutBorders.Class
using var asyncFlowControl = ExecutionContext.SuppressFlow();
Common.InputCallbackThreadID = Thread.CurrentThread.ManagedThreadId;
- while (!Common.InitDone)
+ while (!InitAndCleanup.InitDone)
{
Thread.Sleep(100);
}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Setting.cs b/src/modules/MouseWithoutBorders/App/Class/Setting.cs
index 30b99a97d0..c9d81f2049 100644
--- a/src/modules/MouseWithoutBorders/App/Class/Setting.cs
+++ b/src/modules/MouseWithoutBorders/App/Class/Setting.cs
@@ -118,7 +118,7 @@ namespace MouseWithoutBorders.Class
if (shouldReopenSockets)
{
SocketStuff.InvalidKeyFound = false;
- Common.ReopenSocketDueToReadError = true;
+ InitAndCleanup.ReopenSocketDueToReadError = true;
Common.ReopenSockets(true);
}
diff --git a/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs b/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs
index 8796f61dfb..c5241beddf 100644
--- a/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs
+++ b/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs
@@ -29,6 +29,7 @@ using MouseWithoutBorders.Core;
//
using MouseWithoutBorders.Exceptions;
+using Clipboard = MouseWithoutBorders.Core.Clipboard;
using Thread = MouseWithoutBorders.Core.Thread;
[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendData(System.Byte[])", Justification = "Dotnet port with style preservation")]
@@ -281,7 +282,7 @@ namespace MouseWithoutBorders.Class
* */
Common.GetMachineName(); // IPs might have been changed
- Common.UpdateMachineTimeAndID();
+ InitAndCleanup.UpdateMachineTimeAndID();
Logger.LogDebug("Creating sockets...");
@@ -308,7 +309,7 @@ namespace MouseWithoutBorders.Class
{
Logger.TelemetryLogTrace("Restarting the service dues to WSAEADDRINUSE.", SeverityLevel.Warning);
Program.StartService();
- Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
+ InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET;
}
break;
@@ -1248,7 +1249,7 @@ namespace MouseWithoutBorders.Class
// WSAECONNRESET
if (e is ExpectedSocketException se && se.ShouldReconnect)
{
- Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
+ InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET;
Logger.Log($"MainTCPRoutine: {nameof(FlagReopenSocketIfNeeded)}");
}
}
@@ -1306,7 +1307,7 @@ namespace MouseWithoutBorders.Class
}
catch (ObjectDisposedException e)
{
- Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
+ InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET;
UpdateTcpSockets(currentTcp, SocketStatus.ForceClosed);
currentSocket.Close();
Logger.Log($"{nameof(MainTCPRoutine)}: The socket could have been closed/disposed by other threads: {e.Message}");
@@ -1353,10 +1354,10 @@ namespace MouseWithoutBorders.Class
* In this case, we should give ONE try to reconnect.
*/
- if (Common.ReopenSocketDueToReadError)
+ if (InitAndCleanup.ReopenSocketDueToReadError)
{
- Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
- Common.ReopenSocketDueToReadError = false;
+ InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET;
+ InitAndCleanup.ReopenSocketDueToReadError = false;
}
break;
@@ -1641,7 +1642,7 @@ namespace MouseWithoutBorders.Class
bool clientPushData = true;
ClipboardPostAction postAction = ClipboardPostAction.Other;
- bool handShaken = Common.ShakeHand(ref remoteEndPoint, s, out Stream enStream, out Stream deStream, ref clientPushData, ref postAction);
+ bool handShaken = Clipboard.ShakeHand(ref remoteEndPoint, s, out Stream enStream, out Stream deStream, ref clientPushData, ref postAction);
if (!handShaken)
{
@@ -1656,7 +1657,7 @@ namespace MouseWithoutBorders.Class
if (clientPushData)
{
- Common.ReceiveAndProcessClipboardData(remoteEndPoint, s, enStream, deStream, $"{postAction}");
+ Clipboard.ReceiveAndProcessClipboardData(remoteEndPoint, s, enStream, deStream, $"{postAction}");
}
else
{
@@ -1680,23 +1681,23 @@ namespace MouseWithoutBorders.Class
const int CLOSE_TIMEOUT = 10;
byte[] header = new byte[1024];
string headerString = string.Empty;
- if (Common.LastDragDropFile != null)
+ if (Clipboard.LastDragDropFile != null)
{
string fileName = null;
if (!Launch.ImpersonateLoggedOnUserAndDoSomething(() =>
{
- if (!File.Exists(Common.LastDragDropFile))
+ if (!File.Exists(Clipboard.LastDragDropFile))
{
- headerString = Directory.Exists(Common.LastDragDropFile)
- ? $"{0}*{Common.LastDragDropFile} - Folder is not supported, zip it first!"
- : Common.LastDragDropFile.Contains("- File too big")
- ? $"{0}*{Common.LastDragDropFile}"
- : $"{0}*{Common.LastDragDropFile} not found!";
+ headerString = Directory.Exists(Clipboard.LastDragDropFile)
+ ? $"{0}*{Clipboard.LastDragDropFile} - Folder is not supported, zip it first!"
+ : Clipboard.LastDragDropFile.Contains("- File too big")
+ ? $"{0}*{Clipboard.LastDragDropFile}"
+ : $"{0}*{Clipboard.LastDragDropFile} not found!";
}
else
{
- fileName = Common.LastDragDropFile;
+ fileName = Clipboard.LastDragDropFile;
headerString = $"{new FileInfo(fileName).Length}*{fileName}";
}
}))
@@ -1739,11 +1740,11 @@ namespace MouseWithoutBorders.Class
Logger.Log(log);
}
}
- else if (!Common.IsClipboardDataImage && Common.LastClipboardData != null)
+ else if (!Clipboard.IsClipboardDataImage && Clipboard.LastClipboardData != null)
{
try
{
- byte[] data = Common.LastClipboardData;
+ byte[] data = Clipboard.LastClipboardData;
headerString = $"{data.Length}*{"text"}";
Common.GetBytesU(headerString).CopyTo(header, 0);
@@ -1773,9 +1774,9 @@ namespace MouseWithoutBorders.Class
Logger.Log(log);
}
}
- else if (Common.LastClipboardData != null && Common.LastClipboardData.Length > 0)
+ else if (Clipboard.LastClipboardData != null && Clipboard.LastClipboardData.Length > 0)
{
- byte[] data = Common.LastClipboardData;
+ byte[] data = Clipboard.LastClipboardData;
headerString = $"{data.Length}*{"image"}";
Common.GetBytesU(headerString).CopyTo(header, 0);
@@ -1984,8 +1985,8 @@ namespace MouseWithoutBorders.Class
{
tcp = null;
Setting.Values.MachineId = Common.Ran.Next();
- Common.UpdateMachineTimeAndID();
- Common.PleaseReopenSocket = Common.REOPEN_WHEN_HOTKEY;
+ InitAndCleanup.UpdateMachineTimeAndID();
+ InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_HOTKEY;
Logger.TelemetryLogTrace("MachineID conflict.", SeverityLevel.Information);
}
diff --git a/src/modules/MouseWithoutBorders/App/Core/Clipboard.cs b/src/modules/MouseWithoutBorders/App/Core/Clipboard.cs
new file mode 100644
index 0000000000..5840325941
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Core/Clipboard.cs
@@ -0,0 +1,1155 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Net.Sockets;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+using Microsoft.PowerToys.Telemetry;
+using MouseWithoutBorders.Class;
+using MouseWithoutBorders.Exceptions;
+
+using SystemClipboard = System.Windows.Forms.Clipboard;
+
+//
+// Clipboard related routines.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+namespace MouseWithoutBorders.Core;
+
+internal static class Clipboard
+{
+ private static readonly char[] Comma = new char[] { ',' };
+ private static readonly char[] Star = new char[] { '*' };
+ private static readonly char[] NullSeparator = new char[] { '\0' };
+
+ internal const uint BIG_CLIPBOARD_DATA_TIMEOUT = 30000;
+ private const uint MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1024 * 1024; // 1MB
+ private const uint MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 100 * 1024 * 1024; // 100MB
+ private const int TEXT_HEADER_SIZE = 12;
+ private const int DATA_SIZE = 48;
+ private const string TEXT_TYPE_SEP = "{4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}";
+ private static long lastClipboardEventTime;
+ private static string lastMachineWithClipboardData;
+ private static string lastDragDropFile;
+#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
+ internal static long clipboardCopiedTime;
+#pragma warning restore SA1307
+
+ internal static ID LastIDWithClipboardData { get; set; }
+
+ internal static string LastDragDropFile
+ {
+ get => Clipboard.lastDragDropFile;
+ set => Clipboard.lastDragDropFile = value;
+ }
+
+ internal static string LastMachineWithClipboardData
+ {
+ get => Clipboard.lastMachineWithClipboardData;
+ set => Clipboard.lastMachineWithClipboardData = value;
+ }
+
+ private static long LastClipboardEventTime
+ {
+ get => Clipboard.lastClipboardEventTime;
+ set => Clipboard.lastClipboardEventTime = value;
+ }
+
+ private static IntPtr NextClipboardViewer { get; set; }
+
+ internal static bool IsClipboardDataImage { get; private set; }
+
+ internal static byte[] LastClipboardData { get; private set; }
+
+ private static object lastClipboardObject = string.Empty;
+
+ internal static bool HasSwitchedMachineSinceLastCopy { get; set; }
+
+ internal static bool CheckClipboardEx(ByteArrayOrString data, bool isFilePath)
+ {
+ Logger.LogDebug($"{nameof(CheckClipboardEx)}: ShareClipboard = {Setting.Values.ShareClipboard}, TransferFile = {Setting.Values.TransferFile}, data = {data}.");
+ Logger.LogDebug($"{nameof(CheckClipboardEx)}: {nameof(Setting.Values.OneWayClipboardMode)} = {Setting.Values.OneWayClipboardMode}.");
+
+ if (!Setting.Values.ShareClipboard)
+ {
+ return false;
+ }
+
+ if (Common.RunWithNoAdminRight && Setting.Values.OneWayClipboardMode)
+ {
+ return false;
+ }
+
+ if (Common.GetTick() - LastClipboardEventTime < 1000)
+ {
+ Logger.LogDebug("GetTick() - lastClipboardEventTime < 1000");
+ LastClipboardEventTime = Common.GetTick();
+ return false;
+ }
+
+ LastClipboardEventTime = Common.GetTick();
+
+ try
+ {
+ IsClipboardDataImage = false;
+ LastClipboardData = null;
+ LastDragDropFile = null;
+ GC.Collect();
+
+ string stringData = null;
+ byte[] byteData = null;
+
+ if (data.IsByteArray)
+ {
+ byteData = data.GetByteArray();
+ }
+ else
+ {
+ stringData = data.GetString();
+ }
+
+ if (stringData != null)
+ {
+ if (!HasSwitchedMachineSinceLastCopy)
+ {
+ if (lastClipboardObject is string lastStringData && lastStringData.Equals(stringData, StringComparison.OrdinalIgnoreCase))
+ {
+ Logger.LogDebug("CheckClipboardEx: Same string data.");
+ return false;
+ }
+ }
+
+ HasSwitchedMachineSinceLastCopy = false;
+
+ if (isFilePath)
+ {
+ Logger.LogDebug("Clipboard contains FileDropList");
+
+ if (!Setting.Values.TransferFile)
+ {
+ Logger.LogDebug("TransferFile option is unchecked.");
+ return false;
+ }
+
+ string filePath = stringData;
+
+ _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() =>
+ {
+ if (File.Exists(filePath) || Directory.Exists(filePath))
+ {
+ if (File.Exists(filePath) && new FileInfo(filePath).Length <= MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT)
+ {
+ Logger.LogDebug("Clipboard contains: " + filePath);
+ LastDragDropFile = filePath;
+ Common.SendClipboardBeat();
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE] { Common.ICON_BIG_CLIPBOARD, -1, Common.ICON_BIG_CLIPBOARD, -1 });
+ }
+ else
+ {
+ if (Directory.Exists(filePath))
+ {
+ Logger.LogDebug("Clipboard contains a directory: " + filePath);
+ LastDragDropFile = filePath;
+ Common.SendClipboardBeat();
+ }
+ else
+ {
+ LastDragDropFile = filePath + " - File too big (greater than 100MB), please drag and drop the file instead!";
+ Common.SendClipboardBeat();
+ Logger.Log("Clipboard: File too big: " + filePath);
+ }
+
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE] { Common.ICON_ERROR, -1, Common.ICON_ERROR, -1 });
+ }
+ }
+ else
+ {
+ Logger.Log("CheckClipboardEx: File not found: " + filePath);
+ }
+ });
+ }
+ else
+ {
+ byte[] texts = Common.GetBytesU(stringData);
+
+ using MemoryStream ms = new();
+ using (DeflateStream s = new(ms, CompressionMode.Compress, true))
+ {
+ s.Write(texts, 0, texts.Length);
+ }
+
+ Logger.LogDebug("Plain/Zip = " + texts.Length.ToString(CultureInfo.CurrentCulture) + "/" +
+ ms.Length.ToString(CultureInfo.CurrentCulture));
+
+ LastClipboardData = ms.GetBuffer();
+ }
+ }
+ else if (byteData != null)
+ {
+ if (!HasSwitchedMachineSinceLastCopy)
+ {
+ if (lastClipboardObject is byte[] lastByteData && Enumerable.SequenceEqual(lastByteData, byteData))
+ {
+ Logger.LogDebug("CheckClipboardEx: Same byte[] data.");
+ return false;
+ }
+ }
+
+ HasSwitchedMachineSinceLastCopy = false;
+
+ Logger.LogDebug("Clipboard contains image");
+ IsClipboardDataImage = true;
+ LastClipboardData = byteData;
+ }
+ else
+ {
+ Logger.LogDebug("*** Clipboard contains something else!");
+ return false;
+ }
+
+ lastClipboardObject = data;
+
+ if (LastClipboardData != null && LastClipboardData.Length > 0)
+ {
+ if (LastClipboardData.Length > MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP)
+ {
+ Common.SendClipboardBeat();
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE] { Common.ICON_BIG_CLIPBOARD, -1, Common.ICON_BIG_CLIPBOARD, -1 });
+ }
+ else
+ {
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE] { Common.ICON_SMALL_CLIPBOARD, -1, -1, -1 });
+ SendClipboardDataUsingTCP(LastClipboardData, IsClipboardDataImage);
+ }
+
+ return true;
+ }
+ }
+ catch (Exception e)
+ {
+ Logger.Log(e);
+ }
+
+ return false;
+ }
+
+ private static void SendClipboardDataUsingTCP(byte[] bytes, bool image)
+ {
+ if (Common.Sk == null)
+ {
+ return;
+ }
+
+ new Task(() =>
+ {
+ // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again.
+ // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892
+ using var asyncFlowControl = ExecutionContext.SuppressFlow();
+
+ System.Threading.Thread thread = Thread.CurrentThread;
+ thread.Name = $"{nameof(SendClipboardDataUsingTCP)}.{thread.ManagedThreadId}";
+ Thread.UpdateThreads(thread);
+ int l = bytes.Length;
+ int index = 0;
+ int len;
+ DATA package = new();
+ byte[] buf = new byte[Common.PACKAGE_SIZE_EX];
+ int dataStart = Common.PACKAGE_SIZE_EX - DATA_SIZE;
+
+ while (true)
+ {
+ if ((index + DATA_SIZE) > l)
+ {
+ len = l - index;
+ Array.Clear(buf, 0, Common.PACKAGE_SIZE_EX);
+ }
+ else
+ {
+ len = DATA_SIZE;
+ }
+
+ Array.Copy(bytes, index, buf, dataStart, len);
+ package.Bytes = buf;
+
+ package.Type = image ? PackageType.ClipboardImage : PackageType.ClipboardText;
+ package.Des = ID.ALL;
+ Common.SkSend(package, (uint)Common.MachineID, false);
+
+ index += DATA_SIZE;
+ if (index >= l)
+ {
+ break;
+ }
+ }
+
+ package.Type = PackageType.ClipboardDataEnd;
+ package.Des = ID.ALL;
+ Common.SkSend(package, (uint)Common.MachineID, false);
+ }).Start();
+ }
+
+ internal static void ReceiveClipboardDataUsingTCP(DATA data, bool image, TcpSk tcp)
+ {
+ try
+ {
+ if (Common.Sk == null || Common.RunOnLogonDesktop || Common.RunOnScrSaverDesktop)
+ {
+ return;
+ }
+
+ MemoryStream m = new();
+ int dataStart = Common.PACKAGE_SIZE_EX - DATA_SIZE;
+ m.Write(data.Bytes, dataStart, DATA_SIZE);
+ int unexpectedCount = 0;
+
+ bool done = false;
+ do
+ {
+ data = SocketStuff.TcpReceiveData(tcp, out int err);
+
+ switch (data.Type)
+ {
+ case PackageType.ClipboardImage:
+ case PackageType.ClipboardText:
+ m.Write(data.Bytes, dataStart, DATA_SIZE);
+ break;
+
+ case PackageType.ClipboardDataEnd:
+ done = true;
+ break;
+
+ default:
+ Receiver.ProcessPackage(data, tcp);
+ if (++unexpectedCount > 100)
+ {
+ Logger.Log("ReceiveClipboardDataUsingTCP: unexpectedCount > 100!");
+ done = true;
+ }
+
+ break;
+ }
+ }
+ while (!done);
+
+ LastClipboardEventTime = Common.GetTick();
+
+ if (image)
+ {
+ Image im = Image.FromStream(m);
+ Clipboard.SetImage(im);
+ LastClipboardEventTime = Common.GetTick();
+ }
+ else
+ {
+ Clipboard.SetClipboardData(m.GetBuffer());
+ LastClipboardEventTime = Common.GetTick();
+ }
+
+ m.Dispose();
+
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE] { Common.ICON_SMALL_CLIPBOARD, -1, Common.ICON_SMALL_CLIPBOARD, -1 });
+ }
+ catch (Exception e)
+ {
+ Logger.Log("ReceiveClipboardDataUsingTCP: " + e.Message);
+ }
+ }
+
+ private static readonly Lock ClipboardThreadOldLock = new();
+ private static System.Threading.Thread clipboardThreadOld;
+
+ internal static void GetRemoteClipboard(string postAction)
+ {
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ if (Clipboard.LastMachineWithClipboardData == null ||
+ Clipboard.LastMachineWithClipboardData.Length < 1)
+ {
+ return;
+ }
+
+ new Task(() =>
+ {
+ // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again.
+ // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892
+ using var asyncFlowControl = ExecutionContext.SuppressFlow();
+
+ System.Threading.Thread thread = Thread.CurrentThread;
+ thread.Name = $"{nameof(ConnectAndGetData)}.{thread.ManagedThreadId}";
+ Thread.UpdateThreads(thread);
+ ConnectAndGetData(postAction);
+ }).Start();
+ }
+ }
+
+ private static Stream m;
+
+ private static void ConnectAndGetData(object postAction)
+ {
+ if (Common.Sk == null)
+ {
+ Logger.Log("ConnectAndGetData: Sk == null!");
+ return;
+ }
+
+ string remoteMachine;
+ TcpClient clipboardTcpClient = null;
+ string postAct = (string)postAction;
+
+ Logger.LogDebug("ConnectAndGetData.postAction: " + postAct);
+
+ ClipboardPostAction clipboardPostAct = postAct.Contains("mspaint,") ? ClipboardPostAction.Mspaint
+ : postAct.Equals("desktop", StringComparison.OrdinalIgnoreCase) ? ClipboardPostAction.Desktop
+ : ClipboardPostAction.Other;
+
+ try
+ {
+ remoteMachine = postAct.Contains("mspaint,") ? postAct.Split(Comma)[1] : Clipboard.LastMachineWithClipboardData;
+
+ remoteMachine = remoteMachine.Trim();
+
+ if (!Common.IsConnectedByAClientSocketTo(remoteMachine))
+ {
+ Logger.Log($"No potential inbound connection from {Common.MachineName} to {remoteMachine}, ask for a push back instead.");
+ ID machineId = MachineStuff.MachinePool.ResolveID(remoteMachine);
+
+ if (machineId != ID.NONE)
+ {
+ Common.SkSend(
+ new DATA()
+ {
+ Type = PackageType.ClipboardAsk,
+ Des = machineId,
+ MachineName = Common.MachineName,
+ PostAction = clipboardPostAct,
+ },
+ null,
+ false);
+ }
+ else
+ {
+ Logger.Log($"Unable to resolve {remoteMachine} to its long IP.");
+ }
+
+ return;
+ }
+
+ Common.ShowToolTip("Connecting to " + remoteMachine, 2000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
+
+ clipboardTcpClient = ConnectToRemoteClipboardSocket(remoteMachine);
+ }
+ catch (ThreadAbortException)
+ {
+ Logger.Log("The current thread is being aborted (1).");
+ if (clipboardTcpClient != null && clipboardTcpClient.Connected)
+ {
+ clipboardTcpClient.Client.Close();
+ }
+
+ return;
+ }
+ catch (Exception e)
+ {
+ Logger.Log(e);
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_BIG_CLIPBOARD,
+ -1, Common.ICON_BIG_CLIPBOARD, -1,
+ });
+ Common.ShowToolTip(e.Message, 1000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+ return;
+ }
+
+ bool clientPushData = false;
+
+ if (!ShakeHand(ref remoteMachine, clipboardTcpClient.Client, out Stream enStream, out Stream deStream, ref clientPushData, ref clipboardPostAct))
+ {
+ return;
+ }
+
+ ReceiveAndProcessClipboardData(remoteMachine, clipboardTcpClient.Client, enStream, deStream, postAct);
+ }
+
+ internal static void ReceiveAndProcessClipboardData(string remoteMachine, Socket s, Stream enStream, Stream deStream, string postAct)
+ {
+ lock (ClipboardThreadOldLock)
+ {
+ // Do not enable two connections at the same time.
+ if (clipboardThreadOld != null && clipboardThreadOld.ThreadState != System.Threading.ThreadState.AbortRequested
+ && clipboardThreadOld.ThreadState != System.Threading.ThreadState.Aborted && clipboardThreadOld.IsAlive
+ && clipboardThreadOld.ManagedThreadId != Thread.CurrentThread.ManagedThreadId)
+ {
+ if (clipboardThreadOld.Join(3000))
+ {
+ if (m != null)
+ {
+ m.Flush();
+ m.Close();
+ m = null;
+ }
+ }
+ }
+
+ clipboardThreadOld = Thread.CurrentThread;
+ }
+
+ try
+ {
+ byte[] header = new byte[1024];
+ byte[] buf = new byte[Common.NETWORK_STREAM_BUF_SIZE];
+ string fileName = null;
+ string tempFile = "data", savingFolder = string.Empty;
+ Common.ToggleIconsIndex = 0;
+ int rv;
+ long receivedCount = 0;
+
+ if ((rv = deStream.ReadEx(header, 0, header.Length)) < header.Length)
+ {
+ Logger.Log("Reading header failed: " + rv.ToString(CultureInfo.CurrentCulture));
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_BIG_CLIPBOARD,
+ -1, -1, -1,
+ });
+ return;
+ }
+
+ fileName = Common.GetStringU(header).Replace("\0", string.Empty);
+ Logger.LogDebug("Header: " + fileName);
+ string[] headers = fileName.Split(Star);
+
+ if (headers.Length < 2 || !long.TryParse(headers[0], out long dataSize))
+ {
+ Logger.Log(string.Format(
+ CultureInfo.CurrentCulture,
+ "Reading header failed: {0}:{1}",
+ headers.Length,
+ fileName));
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_BIG_CLIPBOARD,
+ -1, -1, -1,
+ });
+ return;
+ }
+
+ fileName = headers[1];
+
+ Logger.LogDebug(string.Format(
+ CultureInfo.CurrentCulture,
+ "Receiving {0}:{1} from {2}...",
+ Path.GetFileName(fileName),
+ dataSize,
+ remoteMachine));
+ Common.ShowToolTip(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ "Receiving {0} from {1}...",
+ Path.GetFileName(fileName),
+ remoteMachine),
+ 5000,
+ ToolTipIcon.Info,
+ Setting.Values.ShowClipNetStatus);
+ if (fileName.StartsWith("image", StringComparison.CurrentCultureIgnoreCase) ||
+ fileName.StartsWith("text", StringComparison.CurrentCultureIgnoreCase))
+ {
+ m = new MemoryStream();
+ }
+ else
+ {
+ if (postAct.Equals("desktop", StringComparison.OrdinalIgnoreCase))
+ {
+ _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() =>
+ {
+ savingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\MouseWithoutBorders\\";
+
+ if (!Directory.Exists(savingFolder))
+ {
+ _ = Directory.CreateDirectory(savingFolder);
+ }
+ });
+
+ tempFile = savingFolder + Path.GetFileName(fileName);
+ m = new FileStream(tempFile, FileMode.Create);
+ }
+ else if (postAct.Contains("mspaint"))
+ {
+ tempFile = Common.GetMyStorageDir() + @"ScreenCapture-" +
+ remoteMachine + ".png";
+ m = new FileStream(tempFile, FileMode.Create);
+ }
+ else
+ {
+ tempFile = Common.GetMyStorageDir();
+ tempFile += Path.GetFileName(fileName);
+ m = new FileStream(tempFile, FileMode.Create);
+ }
+
+ Logger.Log("==> " + tempFile);
+ }
+
+ Common.ShowToolTip(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ "Receiving {0} from {1}...",
+ Path.GetFileName(fileName),
+ remoteMachine),
+ 5000,
+ ToolTipIcon.Info,
+ Setting.Values.ShowClipNetStatus);
+
+ do
+ {
+ rv = deStream.ReadEx(buf, 0, buf.Length);
+
+ if (rv > 0)
+ {
+ receivedCount += rv;
+
+ if (receivedCount > dataSize)
+ {
+ rv -= (int)(receivedCount - dataSize);
+ }
+
+ m.Write(buf, 0, rv);
+ }
+
+ if (Common.ToggleIcons == null)
+ {
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_SMALL_CLIPBOARD,
+ -1, Common.ICON_SMALL_CLIPBOARD, -1,
+ });
+ }
+
+ string text = string.Format(CultureInfo.CurrentCulture, "{0}KB received: {1}", m.Length / 1024, Path.GetFileName(fileName));
+
+ Common.DoSomethingInUIThread(() =>
+ {
+ Common.MainForm.SetTrayIconText(text);
+ });
+ }
+ while (rv > 0);
+
+ if (m != null && fileName != null)
+ {
+ m.Flush();
+ Logger.LogDebug(m.Length.ToString(CultureInfo.CurrentCulture) + " bytes received.");
+ Clipboard.LastClipboardEventTime = Common.GetTick();
+ string toolTipText = null;
+ string sizeText = m.Length >= 1024
+ ? (m.Length / 1024).ToString(CultureInfo.CurrentCulture) + "KB"
+ : m.Length.ToString(CultureInfo.CurrentCulture) + "Bytes";
+
+ PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersClipboardFileTransferEvent());
+
+ if (fileName.StartsWith("image", StringComparison.CurrentCultureIgnoreCase))
+ {
+ Clipboard.SetImage(Image.FromStream(m));
+ toolTipText = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1} from {2} is in Clipboard.",
+ sizeText,
+ "image",
+ remoteMachine);
+ }
+ else if (fileName.StartsWith("text", StringComparison.CurrentCultureIgnoreCase))
+ {
+ byte[] data = (m as MemoryStream).GetBuffer();
+ toolTipText = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1} from {2} is in Clipboard.",
+ sizeText,
+ "text",
+ remoteMachine);
+ Clipboard.SetClipboardData(data);
+ }
+ else if (tempFile != null)
+ {
+ if (postAct.Equals("desktop", StringComparison.OrdinalIgnoreCase))
+ {
+ toolTipText = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1} received from {2}!",
+ sizeText,
+ Path.GetFileName(fileName),
+ remoteMachine);
+
+ _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() =>
+ {
+ ProcessStartInfo startInfo = new();
+ startInfo.UseShellExecute = true;
+ startInfo.WorkingDirectory = savingFolder;
+ startInfo.FileName = savingFolder;
+ startInfo.Verb = "open";
+ _ = Process.Start(startInfo);
+ });
+ }
+ else if (postAct.Contains("mspaint"))
+ {
+ m.Close();
+ m = null;
+ Common.OpenImage(tempFile);
+ toolTipText = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1} from {2} is in Mspaint.",
+ sizeText,
+ Path.GetFileName(tempFile),
+ remoteMachine);
+ }
+ else
+ {
+ StringCollection filePaths = new()
+ {
+ tempFile,
+ };
+ Clipboard.SetFileDropList(filePaths);
+ toolTipText = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1} from {2} is in Clipboard.",
+ sizeText,
+ Path.GetFileName(fileName),
+ remoteMachine);
+ }
+ }
+
+ if (!string.IsNullOrWhiteSpace(toolTipText))
+ {
+ Common.ShowToolTip(toolTipText, 5000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
+ }
+
+ Common.DoSomethingInUIThread(() =>
+ {
+ Common.MainForm.UpdateNotifyIcon();
+ });
+
+ m?.Close();
+ m = null;
+ }
+ }
+ catch (ThreadAbortException)
+ {
+ Logger.Log("The current thread is being aborted (3).");
+ s.Close();
+
+ if (m != null)
+ {
+ m.Close();
+ m = null;
+ }
+
+ return;
+ }
+ catch (Exception e)
+ {
+ if (e is IOException)
+ {
+ string log = $"{nameof(ReceiveAndProcessClipboardData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Logger.Log(log);
+ }
+ else
+ {
+ Logger.Log(e);
+ }
+
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_BIG_CLIPBOARD,
+ -1, Common.ICON_BIG_CLIPBOARD, -1,
+ });
+ Common.ShowToolTip(e.Message, 1000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
+
+ if (m != null)
+ {
+ m.Close();
+ m = null;
+ }
+
+ return;
+ }
+
+ s.Close();
+ }
+
+ internal static bool ShakeHand(ref string remoteName, Socket s, out Stream enStream, out Stream deStream, ref bool clientPushData, ref ClipboardPostAction postAction)
+ {
+ const int CLIPBOARD_HANDSHAKE_TIMEOUT = 30;
+ s.ReceiveTimeout = CLIPBOARD_HANDSHAKE_TIMEOUT * 1000;
+ s.NoDelay = true;
+ s.SendBufferSize = s.ReceiveBufferSize = 1024000;
+
+ bool handShaken = false;
+ enStream = deStream = null;
+
+ try
+ {
+ DATA package = new()
+ {
+ Type = clientPushData ? PackageType.ClipboardPush : PackageType.Clipboard,
+ PostAction = postAction,
+ Src = Common.MachineID,
+ MachineName = Common.MachineName,
+ };
+
+ byte[] buf = new byte[Common.PACKAGE_SIZE_EX];
+
+ NetworkStream ns = new(s);
+ enStream = Common.GetEncryptedStream(ns);
+ Common.SendOrReceiveARandomDataBlockPerInitialIV(enStream);
+ Logger.LogDebug($"{nameof(ShakeHand)}: Writing header package.");
+ enStream.Write(package.Bytes, 0, Common.PACKAGE_SIZE_EX);
+
+ Logger.LogDebug($"{nameof(ShakeHand)}: Sent: clientPush={clientPushData}, postAction={postAction}.");
+
+ deStream = Common.GetDecryptedStream(ns);
+ Common.SendOrReceiveARandomDataBlockPerInitialIV(deStream, false);
+
+ Logger.LogDebug($"{nameof(ShakeHand)}: Reading header package.");
+
+ int bytesReceived = deStream.ReadEx(buf, 0, Common.PACKAGE_SIZE_EX);
+ package.Bytes = buf;
+
+ string name = "Unknown";
+
+ if (bytesReceived == Common.PACKAGE_SIZE_EX)
+ {
+ if (package.Type is PackageType.Clipboard or PackageType.ClipboardPush)
+ {
+ name = remoteName = package.MachineName;
+
+ Logger.LogDebug($"{nameof(ShakeHand)}: Connection from {name}:{package.Src}");
+
+ if (MachineStuff.MachinePool.ResolveID(name) == package.Src && Common.IsConnectedTo(package.Src))
+ {
+ clientPushData = package.Type == PackageType.ClipboardPush;
+ postAction = package.PostAction;
+ handShaken = true;
+ Logger.LogDebug($"{nameof(ShakeHand)}: Received: clientPush={clientPushData}, postAction={postAction}.");
+ }
+ else
+ {
+ Logger.LogDebug($"{nameof(ShakeHand)}: No active connection to the machine: {name}.");
+ }
+ }
+ else
+ {
+ Logger.LogDebug($"{nameof(ShakeHand)}: Unexpected package type: {package.Type}.");
+ }
+ }
+ else
+ {
+ Logger.LogDebug($"{nameof(ShakeHand)}: BytesTransferred != PACKAGE_SIZE_EX: {bytesReceived}");
+ }
+
+ if (!handShaken)
+ {
+ string msg = $"Clipboard connection rejected: {name}:{remoteName}/{package.Src}\r\n\r\nMake sure you run the same version in all machines.";
+ Logger.Log(msg);
+ Common.ShowToolTip(msg, 3000, ToolTipIcon.Warning);
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE] { Common.ICON_BIG_CLIPBOARD, -1, -1, -1 });
+ }
+ }
+ catch (ThreadAbortException)
+ {
+ Logger.Log($"{nameof(ShakeHand)}: The current thread is being aborted.");
+ s.Close();
+ }
+ catch (Exception e)
+ {
+ if (e is IOException)
+ {
+ string log = $"{nameof(ShakeHand)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Logger.Log(log);
+ }
+ else
+ {
+ Logger.Log(e);
+ }
+
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_BIG_CLIPBOARD,
+ -1, Common.ICON_BIG_CLIPBOARD, -1,
+ });
+ Common.MainForm.UpdateNotifyIcon();
+ Common.ShowToolTip(e.Message + "\r\n\r\nMake sure you run the same version in all machines.", 1000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+
+ if (m != null)
+ {
+ m.Close();
+ m = null;
+ }
+ }
+
+ return handShaken;
+ }
+
+ internal static TcpClient ConnectToRemoteClipboardSocket(string remoteMachine)
+ {
+ TcpClient clipboardTcpClient;
+ clipboardTcpClient = new TcpClient(AddressFamily.InterNetworkV6);
+ clipboardTcpClient.Client.DualMode = true;
+
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ Common.DoSomethingInUIThread(() => Common.MainForm.ChangeIcon(Common.ICON_SMALL_CLIPBOARD));
+
+ System.Net.IPAddress ip = Common.GetConnectedClientSocketIPAddressFor(remoteMachine);
+ Logger.LogDebug($"{nameof(ConnectToRemoteClipboardSocket)}Connecting to {remoteMachine}:{ip}:{sk.TcpPort}...");
+
+ if (ip != null)
+ {
+ clipboardTcpClient.Connect(ip, sk.TcpPort);
+ }
+ else
+ {
+ clipboardTcpClient.Connect(remoteMachine, sk.TcpPort);
+ }
+
+ Logger.LogDebug($"Connected from {clipboardTcpClient.Client.LocalEndPoint}. Getting data...");
+ return clipboardTcpClient;
+ }
+ else
+ {
+ throw new ExpectedSocketException($"{nameof(ConnectToRemoteClipboardSocket)}: No longer connected.");
+ }
+ }
+
+ private static void SetClipboardData(byte[] data)
+ {
+ if (data == null || data.Length <= 0)
+ {
+ Logger.Log("data is null or empty!");
+ return;
+ }
+
+ if (data.Length > 1024000)
+ {
+ Common.ShowToolTip(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ "Decompressing {0} clipboard data ...",
+ (data.Length / 1024).ToString(CultureInfo.CurrentCulture) + "KB"),
+ 5000,
+ ToolTipIcon.Info,
+ Setting.Values.ShowClipNetStatus);
+ }
+
+ string st = string.Empty;
+
+ using (MemoryStream ms = new(data))
+ {
+ using DeflateStream s = new(ms, CompressionMode.Decompress, true);
+ const int BufferSize = 1024000; // Buffer size should be big enough, this is critical to performance!
+
+ int rv = 0;
+
+ do
+ {
+ byte[] buffer = new byte[BufferSize];
+ rv = s.ReadEx(buffer, 0, BufferSize);
+
+ if (rv > 0)
+ {
+ st += Common.GetStringU(buffer);
+ }
+ else
+ {
+ break;
+ }
+ }
+ while (true);
+ }
+
+ int textTypeCount = 0;
+ string[] texts = st.Split(new string[] { TEXT_TYPE_SEP }, StringSplitOptions.RemoveEmptyEntries);
+ string tmp;
+ DataObject data1 = new();
+
+ foreach (string txt in texts)
+ {
+ if (string.IsNullOrEmpty(txt.Trim(NullSeparator)))
+ {
+ continue;
+ }
+
+ tmp = txt[3..];
+
+ if (txt.StartsWith("RTF", StringComparison.CurrentCultureIgnoreCase))
+ {
+ Logger.LogDebug(((double)tmp.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of RTF <-");
+ data1.SetData(DataFormats.Rtf, tmp);
+ }
+ else if (txt.StartsWith("HTM", StringComparison.CurrentCultureIgnoreCase))
+ {
+ Logger.LogDebug(((double)tmp.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of HTM <-");
+ data1.SetData(DataFormats.Html, tmp);
+ }
+ else if (txt.StartsWith("TXT", StringComparison.CurrentCultureIgnoreCase))
+ {
+ Logger.LogDebug(((double)tmp.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of TXT <-");
+ data1.SetData(DataFormats.UnicodeText, tmp);
+ }
+ else
+ {
+ if (textTypeCount == 0)
+ {
+ Logger.LogDebug(((double)txt.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of UNI <-");
+ data1.SetData(DataFormats.UnicodeText, txt);
+ }
+
+ Logger.Log("Invalid clipboard format received!");
+ }
+
+ textTypeCount++;
+ }
+
+ if (textTypeCount > 0)
+ {
+ Clipboard.SetDataObject(data1);
+ }
+ }
+
+ private static void SetFileDropList(StringCollection filePaths)
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ try
+ {
+ _ = Common.Retry(
+ nameof(SystemClipboard.SetFileDropList),
+ () =>
+ {
+ SystemClipboard.SetFileDropList(filePaths);
+ return true;
+ },
+ (log) => Logger.TelemetryLogTrace(
+ log,
+ SeverityLevel.Information),
+ () => Clipboard.LastClipboardEventTime = Common.GetTick());
+ }
+ catch (ExternalException e)
+ {
+ Logger.Log(e);
+ }
+ catch (ThreadStateException e)
+ {
+ Logger.Log(e);
+ }
+ catch (ArgumentNullException e)
+ {
+ Logger.Log(e);
+ }
+ catch (ArgumentException e)
+ {
+ Logger.Log(e);
+ }
+ });
+ }
+
+ private static void SetImage(Image image)
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ try
+ {
+ _ = Common.Retry(
+ nameof(SystemClipboard.SetImage),
+ () =>
+ {
+ SystemClipboard.SetImage(image);
+ return true;
+ },
+ (log) => Logger.TelemetryLogTrace(log, SeverityLevel.Information),
+ () => Clipboard.LastClipboardEventTime = Common.GetTick());
+ }
+ catch (ExternalException e)
+ {
+ Logger.Log(e);
+ }
+ catch (ThreadStateException e)
+ {
+ Logger.Log(e);
+ }
+ catch (ArgumentNullException e)
+ {
+ Logger.Log(e);
+ }
+ });
+ }
+
+ internal static void SetText(string text)
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ try
+ {
+ _ = Common.Retry(
+ nameof(SystemClipboard.SetText),
+ () =>
+ {
+ SystemClipboard.SetText(text);
+ return true;
+ },
+ (log) => Logger.TelemetryLogTrace(log, SeverityLevel.Information),
+ () => Clipboard.LastClipboardEventTime = Common.GetTick());
+ }
+ catch (ExternalException e)
+ {
+ Logger.Log(e);
+ }
+ catch (ThreadStateException e)
+ {
+ Logger.Log(e);
+ }
+ catch (ArgumentNullException e)
+ {
+ Logger.Log(e);
+ }
+ });
+ }
+
+ private static void SetDataObject(DataObject dataObject)
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ try
+ {
+ SystemClipboard.SetDataObject(dataObject, true, 10, 200);
+ }
+ catch (ExternalException e)
+ {
+ string dataFormats = string.Join(",", dataObject.GetFormats());
+ Logger.Log($"{e.Message}: {dataFormats}");
+ }
+ catch (ThreadStateException e)
+ {
+ Logger.Log(e);
+ }
+ catch (ArgumentNullException e)
+ {
+ Logger.Log(e);
+ }
+ });
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs b/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs
index 6d13672d3a..2decb83261 100644
--- a/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs
+++ b/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs
@@ -83,7 +83,7 @@ internal static class DragDrop
if (wParam == Common.WM_RBUTTONUP && IsDropping)
{
IsDropping = false;
- Common.LastIDWithClipboardData = ID.NONE;
+ Clipboard.LastIDWithClipboardData = ID.NONE;
}
}
@@ -193,7 +193,7 @@ internal static class DragDrop
{
if (!string.IsNullOrEmpty(dragFileName) && (File.Exists(dragFileName) || Directory.Exists(dragFileName)))
{
- Common.LastDragDropFile = dragFileName;
+ Clipboard.LastDragDropFile = dragFileName;
/*
* possibleDropMachineID is used as desID sent in DragDropStep06();
* */
@@ -270,7 +270,7 @@ internal static class DragDrop
else
{
IsDragging = false;
- Common.LastIDWithClipboardData = ID.NONE;
+ Clipboard.LastIDWithClipboardData = ID.NONE;
}
}
}
@@ -280,7 +280,7 @@ internal static class DragDrop
Logger.LogDebug("DragDropStep10: Hide the form and get data...");
IsDropping = false;
IsDragging = false;
- Common.LastIDWithClipboardData = ID.NONE;
+ Clipboard.LastIDWithClipboardData = ID.NONE;
Common.DoSomethingInUIThread(() =>
{
@@ -288,7 +288,7 @@ internal static class DragDrop
});
PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersDragAndDropEvent());
- Common.GetRemoteClipboard("desktop");
+ Clipboard.GetRemoteClipboard("desktop");
}
internal static void DragDropStep11()
@@ -298,8 +298,8 @@ internal static class DragDrop
IsDropping = false;
IsDragging = false;
DragMachine = (ID)1;
- Common.LastIDWithClipboardData = ID.NONE;
- Common.LastDragDropFile = null;
+ Clipboard.LastIDWithClipboardData = ID.NONE;
+ Clipboard.LastDragDropFile = null;
MouseDown = false;
}
@@ -307,7 +307,7 @@ internal static class DragDrop
{
Logger.LogDebug("DragDropStep12: ClipboardDragDropEnd received");
IsDropping = false;
- Common.LastIDWithClipboardData = ID.NONE;
+ Clipboard.LastIDWithClipboardData = ID.NONE;
Common.DoSomethingInUIThread(() =>
{
diff --git a/src/modules/MouseWithoutBorders/App/Core/Event.cs b/src/modules/MouseWithoutBorders/App/Core/Event.cs
index c30c59e547..1e6ee3e371 100644
--- a/src/modules/MouseWithoutBorders/App/Core/Event.cs
+++ b/src/modules/MouseWithoutBorders/App/Core/Event.cs
@@ -78,7 +78,7 @@ internal static class Event
// if they are, check that there is no application running in fullscreen mode before switching.
if (!p.IsEmpty && Common.IsEasyMouseSwitchAllowed())
{
- Common.HasSwitchedMachineSinceLastCopy = true;
+ Clipboard.HasSwitchedMachineSinceLastCopy = true;
Logger.LogDebug(string.Format(
CultureInfo.CurrentCulture,
@@ -218,10 +218,10 @@ internal static class Event
if (MachineStuff.desMachineID == Common.MachineID)
{
- if (Common.GetTick() - Common.clipboardCopiedTime < Common.BIG_CLIPBOARD_DATA_TIMEOUT)
+ if (Common.GetTick() - Clipboard.clipboardCopiedTime < Clipboard.BIG_CLIPBOARD_DATA_TIMEOUT)
{
- Common.clipboardCopiedTime = 0;
- Common.GetRemoteClipboard("PrepareToSwitchToMachine");
+ Clipboard.clipboardCopiedTime = 0;
+ Clipboard.GetRemoteClipboard("PrepareToSwitchToMachine");
}
}
else
diff --git a/src/modules/MouseWithoutBorders/App/Core/Helper.cs b/src/modules/MouseWithoutBorders/App/Core/Helper.cs
index 4122fbe31b..bd66c9a83f 100644
--- a/src/modules/MouseWithoutBorders/App/Core/Helper.cs
+++ b/src/modules/MouseWithoutBorders/App/Core/Helper.cs
@@ -119,7 +119,7 @@ internal static class Helper
if (MachineStuff.NewDesMachineID == Common.MachineID)
{
- Common.ReleaseAllKeys();
+ InitAndCleanup.ReleaseAllKeys();
}
}
}
@@ -317,7 +317,7 @@ internal static class Helper
Common.GetInputDesktop(),
0);
- Common.HasSwitchedMachineSinceLastCopy = true;
+ Clipboard.HasSwitchedMachineSinceLastCopy = true;
// Common.CreateLowIntegrityProcess("\"" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBordersHelper.exe\"", string.Empty, 0, false, 0);
var processes = Process.GetProcessesByName(HelperProcessName);
diff --git a/src/modules/MouseWithoutBorders/App/Core/InitAndCleanup.cs b/src/modules/MouseWithoutBorders/App/Core/InitAndCleanup.cs
new file mode 100644
index 0000000000..963775cbca
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Core/InitAndCleanup.cs
@@ -0,0 +1,278 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Globalization;
+using System.Net.NetworkInformation;
+using System.Security.Cryptography;
+using System.Threading;
+
+using Microsoft.Win32;
+using MouseWithoutBorders.Class;
+using Windows.UI.Input.Preview.Injection;
+
+//
+// Initialization and clean up.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+namespace MouseWithoutBorders.Core;
+
+internal static class InitAndCleanup
+{
+ private static bool initDone;
+ internal static int REOPEN_WHEN_WSAECONNRESET = -10054;
+ internal static int REOPEN_WHEN_HOTKEY = -10055;
+ internal static int PleaseReopenSocket;
+ internal static bool ReopenSocketDueToReadError;
+
+ private static DateTime LastResumeSuspendTime { get; set; } = DateTime.UtcNow;
+
+ internal static bool InitDone
+ {
+ get => InitAndCleanup.initDone;
+ set => InitAndCleanup.initDone = value;
+ }
+
+ internal static void UpdateMachineTimeAndID()
+ {
+ Common.MachineName = Common.MachineName.Trim();
+ _ = MachineStuff.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
+ }
+
+ private static void InitializeMachinePoolFromSettings()
+ {
+ try
+ {
+ MachineInf[] info = MachinePoolHelpers.LoadMachineInfoFromMachinePoolStringSetting(Setting.Values.MachinePoolString);
+ for (int i = 0; i < info.Length; i++)
+ {
+ info[i].Name = info[i].Name.Trim();
+ }
+
+ MachineStuff.MachinePool.Initialize(info);
+ MachineStuff.MachinePool.ResetIPAddressesForDeadMachines(true);
+ }
+ catch (Exception ex)
+ {
+ Logger.Log(ex);
+ MachineStuff.MachinePool.Clear();
+ }
+ }
+
+ private static void SetupMachineNameAndID()
+ {
+ try
+ {
+ Common.GetMachineName();
+ Common.DesMachineID = MachineStuff.NewDesMachineID = Common.MachineID;
+
+ // MessageBox.Show(machineID.ToString(CultureInfo.CurrentCulture)); // For test
+ InitializeMachinePoolFromSettings();
+
+ Common.MachineName = Common.MachineName.Trim();
+ _ = MachineStuff.MachinePool.LearnMachine(Common.MachineName);
+ _ = MachineStuff.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
+
+ MachineStuff.UpdateMachinePoolStringSetting();
+ }
+ catch (Exception e)
+ {
+ Logger.Log(e);
+ }
+ }
+
+ internal static void Init()
+ {
+ _ = Helper.GetUserName();
+ Common.GeneratedKey = true;
+
+ try
+ {
+ Common.MyKey = Setting.Values.MyKey;
+ int tmp = Setting.Values.MyKeyDaysToExpire;
+ }
+ catch (FormatException e)
+ {
+ Common.KeyCorrupted = true;
+ Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
+ Logger.Log(e.Message);
+ }
+ catch (CryptographicException e)
+ {
+ Common.KeyCorrupted = true;
+ Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
+ Logger.Log(e.Message);
+ }
+
+ try
+ {
+ InputSimulation.Injector = InputInjector.TryCreate();
+ if (InputSimulation.Injector != null)
+ {
+ InputSimulation.MoveMouseRelative(0, 0);
+ NativeMethods.InjectMouseInputAvailable = true;
+ }
+ }
+ catch (EntryPointNotFoundException)
+ {
+ NativeMethods.InjectMouseInputAvailable = false;
+ Logger.Log($"{nameof(NativeMethods.InjectMouseInputAvailable)} = false");
+ }
+
+ bool dummy = Setting.Values.DrawMouseEx;
+ Common.Is64bitOS = IntPtr.Size == 8;
+ Common.tcpPort = Setting.Values.TcpPort;
+ Common.GetScreenConfig();
+ Common.PackageSent = new PackageMonitor(0);
+ Common.PackageReceived = new PackageMonitor(0);
+ SetupMachineNameAndID();
+ Common.InitEncryption();
+ CreateHelperThreads();
+
+ SystemEvents.DisplaySettingsChanged += new EventHandler(Common.SystemEvents_DisplaySettingsChanged);
+ NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
+ SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
+ PleaseReopenSocket = 9;
+ /* TODO: Telemetry for the matrix? */
+ }
+
+ private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
+ {
+ Helper.WndProcCounter++;
+
+ if (e.Mode is PowerModes.Resume or PowerModes.Suspend)
+ {
+ Logger.TelemetryLogTrace($"{nameof(SystemEvents_PowerModeChanged)}: {e.Mode}", SeverityLevel.Information);
+ LastResumeSuspendTime = DateTime.UtcNow;
+ MachineStuff.SwitchToMultipleMode(false, true);
+ }
+ }
+
+ private static void CreateHelperThreads()
+ {
+ // NOTE(@yuyoyuppe): service crashes while trying to obtain this info, disabling.
+ /*
+ Thread watchDogThread = new(new ThreadStart(WatchDogThread), nameof(WatchDogThread));
+ watchDogThread.Priority = ThreadPriority.Highest;
+ watchDogThread.Start();
+ */
+
+ Common.helper = new Thread(new ThreadStart(Helper.HelperThread), "Helper Thread");
+ Common.helper.SetApartmentState(ApartmentState.STA);
+ Common.helper.Start();
+ }
+
+ private static void AskHelperThreadsToExit(int waitTime)
+ {
+ Helper.signalHelperToExit = true;
+ Helper.signalWatchDogToExit = true;
+ _ = Common.EvSwitch.Set();
+
+ int c = 0;
+ if (Common.helper != null && c < waitTime)
+ {
+ while (Helper.signalHelperToExit)
+ {
+ Thread.Sleep(1);
+ }
+
+ Common.helper = null;
+ }
+ }
+
+ internal static void Cleanup()
+ {
+ try
+ {
+ Common.SendByeBye();
+
+ // UnhookClipboard();
+ AskHelperThreadsToExit(500);
+ Common.MainForm.NotifyIcon.Visible = false;
+ Common.MainForm.NotifyIcon.Dispose();
+ Common.CloseAllFormsAndHooks();
+
+ Common.DoSomethingInUIThread(() =>
+ {
+ Common.Sk?.Close(true);
+ });
+ }
+ catch (Exception e)
+ {
+ Logger.Log(e);
+ }
+ }
+
+ private static long lastReleaseAllKeysCall;
+
+ internal static void ReleaseAllKeys()
+ {
+ if (Math.Abs(Common.GetTick() - lastReleaseAllKeysCall) < 2000)
+ {
+ return;
+ }
+
+ lastReleaseAllKeysCall = Common.GetTick();
+
+ KEYBDDATA kd;
+ kd.dwFlags = (int)Common.LLKHF.UP;
+
+ VK[] keys = new VK[]
+ {
+ VK.LSHIFT, VK.LCONTROL, VK.LMENU, VK.LWIN, VK.RSHIFT,
+ VK.RCONTROL, VK.RMENU, VK.RWIN, VK.SHIFT, VK.MENU, VK.CONTROL,
+ };
+
+ Logger.LogDebug("***** ReleaseAllKeys has been called! *****:");
+
+ foreach (VK vk in keys)
+ {
+ if ((NativeMethods.GetAsyncKeyState((IntPtr)vk) & 0x8000) != 0)
+ {
+ Logger.LogDebug(vk.ToString() + " is down, release it...");
+ Common.Hook?.ResetLastSwitchKeys(); // Sticky key can turn ALL PC mode on (CtrlCtrlCtrl)
+ kd.wVk = (int)vk;
+ InputSimulation.SendKey(kd);
+ Common.Hook?.ResetLastSwitchKeys();
+ }
+ }
+ }
+
+ private static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
+ {
+ Logger.LogDebug("NetworkAvailabilityEventArgs.IsAvailable: " + e.IsAvailable.ToString(CultureInfo.InvariantCulture));
+ Helper.WndProcCounter++;
+ ScheduleReopenSocketsDueToNetworkChanges(!e.IsAvailable);
+ }
+
+ private static void ScheduleReopenSocketsDueToNetworkChanges(bool closeSockets = true)
+ {
+ if (closeSockets)
+ {
+ // Slept/hibernated machine may still have the sockets' status as Connected:( (unchanged) so it would not re-connect after a timeout when waking up.
+ // Closing the sockets when it is going to sleep/hibernate will trigger the reconnection faster when it wakes up.
+ Common.DoSomethingInUIThread(
+ () =>
+ {
+ SocketStuff s = Common.Sk;
+ Common.Sk = null;
+ s?.Close(false);
+ },
+ true);
+ }
+
+ if (!Common.IsMyDesktopActive())
+ {
+ PleaseReopenSocket = 0;
+ }
+ else if (PleaseReopenSocket != 10)
+ {
+ PleaseReopenSocket = 10;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Core/Logger.cs b/src/modules/MouseWithoutBorders/App/Core/Logger.cs
index 6635de59f0..86ce7605b5 100644
--- a/src/modules/MouseWithoutBorders/App/Core/Logger.cs
+++ b/src/modules/MouseWithoutBorders/App/Core/Logger.cs
@@ -247,22 +247,24 @@ internal static class Logger
internal static void DumpStaticTypes(StringBuilder sb, int level)
{
- sb.AppendLine($"[{nameof(DragDrop)}]\r\n===============");
- Logger.DumpType(sb, typeof(DragDrop), 0, level);
- sb.AppendLine($"[{nameof(Event)}]\r\n===============");
- Logger.DumpType(sb, typeof(Event), 0, level);
- sb.AppendLine($"[{nameof(Helper)}]\r\n===============");
- Logger.DumpType(sb, typeof(Helper), 0, level);
- sb.AppendLine($"[{nameof(Launch)}]\r\n===============");
- Logger.DumpType(sb, typeof(Launch), 0, level);
- sb.AppendLine($"[{nameof(Logger)}]\r\n===============");
- Logger.DumpType(sb, typeof(Logger), 0, level);
- sb.AppendLine($"[{nameof(MachineStuff)}]\r\n===============");
- Logger.DumpType(sb, typeof(MachineStuff), 0, level);
- sb.AppendLine($"[{nameof(Receiver)}]\r\n===============");
- Logger.DumpType(sb, typeof(Receiver), 0, level);
- sb.AppendLine($"[{nameof(Service)}]\r\n===============");
- Logger.DumpType(sb, typeof(Service), 0, level);
+ var staticTypes = new List
+ {
+ typeof(Clipboard),
+ typeof(DragDrop),
+ typeof(Event),
+ typeof(InitAndCleanup),
+ typeof(Helper),
+ typeof(Launch),
+ typeof(Logger),
+ typeof(MachineStuff),
+ typeof(Receiver),
+ typeof(Service),
+ };
+ foreach (var staticType in staticTypes)
+ {
+ sb.AppendLine(CultureInfo.InvariantCulture, $"[{staticType.Name}]\r\n===============");
+ Logger.DumpType(sb, staticType, 0, level);
+ }
}
internal static bool PrivateDump(StringBuilder sb, object obj, string objName, int level, int maxLevel, bool stop)
diff --git a/src/modules/MouseWithoutBorders/App/Core/MachineStuff.cs b/src/modules/MouseWithoutBorders/App/Core/MachineStuff.cs
index 144102629f..e5263aa788 100644
--- a/src/modules/MouseWithoutBorders/App/Core/MachineStuff.cs
+++ b/src/modules/MouseWithoutBorders/App/Core/MachineStuff.cs
@@ -992,7 +992,7 @@ internal static class MachineStuff
Setting.Values.MatrixOneRow = !((package.Type & PackageType.MatrixTwoRowFlag) == PackageType.MatrixTwoRowFlag);
MachineMatrix = MachineMatrix; // Save
- Common.ReopenSocketDueToReadError = true;
+ InitAndCleanup.ReopenSocketDueToReadError = true;
UpdateClientSockets("UpdateMachineMatrix");
@@ -1044,7 +1044,7 @@ internal static class MachineStuff
Common.MoveMouseToCenter();
}
- Common.ReleaseAllKeys();
+ InitAndCleanup.ReleaseAllKeys();
Common.UpdateMultipleModeIconAndMenu();
}
diff --git a/src/modules/MouseWithoutBorders/App/Core/Receiver.cs b/src/modules/MouseWithoutBorders/App/Core/Receiver.cs
index 303bec4ff0..1b1e0730b0 100644
--- a/src/modules/MouseWithoutBorders/App/Core/Receiver.cs
+++ b/src/modules/MouseWithoutBorders/App/Core/Receiver.cs
@@ -157,7 +157,7 @@ internal static class Receiver
if (!p.IsEmpty)
{
- Common.HasSwitchedMachineSinceLastCopy = true;
+ Clipboard.HasSwitchedMachineSinceLastCopy = true;
Logger.LogDebug(string.Format(
CultureInfo.CurrentCulture,
@@ -274,7 +274,7 @@ internal static class Receiver
Common.PackageReceived.Clipboard++;
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
{
- Common.clipboardCopiedTime = Common.GetTick();
+ Clipboard.clipboardCopiedTime = Common.GetTick();
GetNameOfMachineWithClipboardData(package);
SignalBigClipboardData();
}
@@ -282,10 +282,10 @@ internal static class Receiver
break;
case PackageType.MachineSwitched:
- if (Common.GetTick() - Common.clipboardCopiedTime < Common.BIG_CLIPBOARD_DATA_TIMEOUT && (package.Des == Common.MachineID))
+ if (Common.GetTick() - Clipboard.clipboardCopiedTime < Clipboard.BIG_CLIPBOARD_DATA_TIMEOUT && (package.Des == Common.MachineID))
{
- Common.clipboardCopiedTime = 0;
- Common.GetRemoteClipboard("PackageType.MachineSwitched");
+ Clipboard.clipboardCopiedTime = 0;
+ Clipboard.GetRemoteClipboard("PackageType.MachineSwitched");
}
break;
@@ -297,7 +297,7 @@ internal static class Receiver
if (package.Des == Common.MachineID || package.Des == ID.ALL)
{
GetNameOfMachineWithClipboardData(package);
- Common.GetRemoteClipboard("mspaint," + Common.LastMachineWithClipboardData);
+ Clipboard.GetRemoteClipboard("mspaint," + Clipboard.LastMachineWithClipboardData);
}
}
@@ -326,10 +326,10 @@ internal static class Receiver
Thread.UpdateThreads(thread);
string remoteMachine = package.MachineName;
- System.Net.Sockets.TcpClient client = Common.ConnectToRemoteClipboardSocket(remoteMachine);
+ System.Net.Sockets.TcpClient client = Clipboard.ConnectToRemoteClipboardSocket(remoteMachine);
bool clientPushData = true;
- if (Common.ShakeHand(ref remoteMachine, client.Client, out Stream enStream, out Stream deStream, ref clientPushData, ref package.PostAction))
+ if (Clipboard.ShakeHand(ref remoteMachine, client.Client, out Stream enStream, out Stream deStream, ref clientPushData, ref package.PostAction))
{
SocketStuff.SendClipboardData(client.Client, enStream);
}
@@ -360,7 +360,7 @@ internal static class Receiver
case PackageType.ClipboardText:
case PackageType.ClipboardImage:
- Common.clipboardCopiedTime = 0;
+ Clipboard.clipboardCopiedTime = 0;
if (package.Type == PackageType.ClipboardImage)
{
Common.PackageReceived.ClipboardImage++;
@@ -372,7 +372,7 @@ internal static class Receiver
if (tcp != null)
{
- Common.ReceiveClipboardDataUsingTCP(
+ Clipboard.ReceiveClipboardDataUsingTCP(
package,
package.Type == PackageType.ClipboardImage,
tcp);
@@ -381,10 +381,10 @@ internal static class Receiver
break;
case PackageType.HideMouse:
- Common.HasSwitchedMachineSinceLastCopy = true;
+ Clipboard.HasSwitchedMachineSinceLastCopy = true;
Common.HideMouseCursor(true);
Helper.MainFormDotEx(false);
- Common.ReleaseAllKeys();
+ InitAndCleanup.ReleaseAllKeys();
break;
default:
@@ -405,11 +405,11 @@ internal static class Receiver
internal static void GetNameOfMachineWithClipboardData(DATA package)
{
- Common.LastIDWithClipboardData = package.Src;
- List matchingMachines = MachineStuff.MachinePool.TryFindMachineByID(Common.LastIDWithClipboardData);
+ Clipboard.LastIDWithClipboardData = package.Src;
+ List matchingMachines = MachineStuff.MachinePool.TryFindMachineByID(Clipboard.LastIDWithClipboardData);
if (matchingMachines.Count >= 1)
{
- Common.LastMachineWithClipboardData = matchingMachines[0].Name.Trim();
+ Clipboard.LastMachineWithClipboardData = matchingMachines[0].Name.Trim();
}
/*
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.cs
index 84d464d33d..97884d4821 100644
--- a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.cs
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.cs
@@ -84,7 +84,7 @@ namespace MouseWithoutBorders
if ((connectedClientSocket = Common.GetConnectedClientSocket()) != null)
{
ShowStatus($"Connected from local IP Address: {connectedClientSocket.Address}.");
- Common.UpdateMachineTimeAndID();
+ InitAndCleanup.UpdateMachineTimeAndID();
Common.MMSleep(1);
connected = true;
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs b/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs
index ca095d8140..66301c52cb 100644
--- a/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs
+++ b/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs
@@ -22,6 +22,8 @@ using Microsoft.PowerToys.Telemetry;
//
using MouseWithoutBorders.Class;
using MouseWithoutBorders.Core;
+
+using Clipboard = MouseWithoutBorders.Core.Clipboard;
using Timer = System.Windows.Forms.Timer;
[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#buttonOK_Click(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
@@ -110,7 +112,7 @@ namespace MouseWithoutBorders
{
SocketStuff.InvalidKeyFound = false;
showInvalidKeyMessage = false;
- Common.ReopenSocketDueToReadError = true;
+ InitAndCleanup.ReopenSocketDueToReadError = true;
Common.ReopenSockets(true);
for (int i = 0; i < 10; i++)
@@ -780,7 +782,7 @@ namespace MouseWithoutBorders
ShowUpdateMessage();
- Common.HasSwitchedMachineSinceLastCopy = true;
+ Clipboard.HasSwitchedMachineSinceLastCopy = true;
}
private void CheckBoxDisableCAD_CheckedChanged(object sender, EventArgs e)
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs b/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs
index b01a653f60..1ab0ce8cc7 100644
--- a/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs
+++ b/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs
@@ -139,13 +139,13 @@ namespace MouseWithoutBorders
{
if (cleanup)
{
- Common.Cleanup();
+ InitAndCleanup.Cleanup();
}
Helper.WndProcCounter++;
if (!Common.RunOnScrSaverDesktop)
{
- Common.ReleaseAllKeys();
+ InitAndCleanup.ReleaseAllKeys();
}
Helper.RunDDHelper(true);
@@ -412,7 +412,7 @@ namespace MouseWithoutBorders
count = 0;
- Common.InitDone = true;
+ InitAndCleanup.InitDone = true;
#if SHOW_ON_WINLOGON
if (Common.RunOnLogonDesktop)
{
@@ -423,39 +423,39 @@ namespace MouseWithoutBorders
if ((count % 2) == 0)
{
- if (Common.PleaseReopenSocket == 10 || (Common.PleaseReopenSocket > 0 && count > 0 && count % 300 == 0))
+ if (InitAndCleanup.PleaseReopenSocket == 10 || (InitAndCleanup.PleaseReopenSocket > 0 && count > 0 && count % 300 == 0))
{
- if (!Common.AtLeastOneSocketEstablished() || Common.PleaseReopenSocket == 10)
+ if (!Common.AtLeastOneSocketEstablished() || InitAndCleanup.PleaseReopenSocket == 10)
{
Thread.Sleep(1000);
- if (Common.PleaseReopenSocket > 0)
+ if (InitAndCleanup.PleaseReopenSocket > 0)
{
- Common.PleaseReopenSocket--;
+ InitAndCleanup.PleaseReopenSocket--;
}
// Double check.
if (!Common.AtLeastOneSocketEstablished())
{
Common.GetMachineName();
- Logger.LogDebug("Common.pleaseReopenSocket: " + Common.PleaseReopenSocket.ToString(CultureInfo.InvariantCulture));
+ Logger.LogDebug("Common.pleaseReopenSocket: " + InitAndCleanup.PleaseReopenSocket.ToString(CultureInfo.InvariantCulture));
Common.ReopenSockets(false);
MachineStuff.NewDesMachineID = Common.DesMachineID = Common.MachineID;
}
}
else
{
- Common.PleaseReopenSocket = 0;
+ InitAndCleanup.PleaseReopenSocket = 0;
}
}
- if (Common.PleaseReopenSocket == Common.REOPEN_WHEN_HOTKEY)
+ if (InitAndCleanup.PleaseReopenSocket == InitAndCleanup.REOPEN_WHEN_HOTKEY)
{
- Common.PleaseReopenSocket = 0;
+ InitAndCleanup.PleaseReopenSocket = 0;
Common.ReopenSockets(true);
}
- else if (Common.PleaseReopenSocket == Common.REOPEN_WHEN_WSAECONNRESET)
+ else if (InitAndCleanup.PleaseReopenSocket == InitAndCleanup.REOPEN_WHEN_WSAECONNRESET)
{
- Common.PleaseReopenSocket = 0;
+ InitAndCleanup.PleaseReopenSocket = 0;
Thread.Sleep(1000);
MachineStuff.UpdateClientSockets("REOPEN_WHEN_WSAECONNRESET");
}
diff --git a/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/Logger.PrivateDump.expected.txt b/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/Logger.PrivateDump.expected.txt
index 3c933bfff1..1bbd8ba49c 100644
--- a/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/Logger.PrivateDump.expected.txt
+++ b/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/Logger.PrivateDump.expected.txt
@@ -4,28 +4,6 @@
[Other Logs]
===============
= MouseWithoutBorders.Common
-Comma = System.Char[]
---System.Char[] = System.Char[]: N/A
-Star = System.Char[]
---System.Char[] = System.Char[]: N/A
-NullSeparator = System.Char[]
---System.Char[] = System.Char[]: N/A
-lastClipboardEventTime = 0
-clipboardCopiedTime = 0
-k__BackingField = NONE
-k__BackingField = 0
-k__BackingField = False
-lastClipboardObject =
-k__BackingField = False
-ClipboardThreadOldLock = Lock
---_owningThreadId = 0
---_state = 0
---_recursionCount = 0
---_spinCount = 22
---_waiterStartTimeMs = 0
---s_contentionCount = 0
---s_maxSpinCount = 22
---s_minSpinCountForAdaptiveSpin = -100
screenWidth = 0
screenHeight = 0
lastX = 0
@@ -99,17 +77,6 @@ LegalKeyDictionary = Concurrent.ConcurrentDictionary`2[System.String,System.Byte
--_budget = ????????????
--_growLockArray = True
--_comparerIsDefaultForClasses = False
-initDone = False
-REOPEN_WHEN_WSAECONNRESET = -10054
-REOPEN_WHEN_HOTKEY = -10055
-PleaseReopenSocket = 0
-ReopenSocketDueToReadError = False
-k__BackingField = ????????????
---_dateData = ????????????
---MinValue = 01/01/0001 00:00:00
---MaxValue = 31/12/9999 23:59:59
---UnixEpoch = 01/01/1970 00:00:00
-lastReleaseAllKeysCall = 0
PackageSent = MouseWithoutBorders.PackageMonitor
--Keyboard = 0
--Mouse = 0
@@ -153,12 +120,6 @@ p = {X=0,Y=0}
--y = 0
--Empty = {X=0,Y=0}
k__BackingField = False
-BIG_CLIPBOARD_DATA_TIMEOUT = 30000
-MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1048576
-MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 104857600
-TEXT_HEADER_SIZE = 12
-DATA_SIZE = 48
-TEXT_TYPE_SEP = {4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}
TOGGLE_ICONS_SIZE = 4
ICON_ONE = 0
ICON_ALL = 1
@@ -195,6 +156,36 @@ WM_KEYDOWN = 256
WM_KEYUP = 257
WM_SYSKEYDOWN = 260
WM_SYSKEYUP = 261
+[Clipboard]
+===============
+Comma = System.Char[]
+--System.Char[] = System.Char[]: N/A
+Star = System.Char[]
+--System.Char[] = System.Char[]: N/A
+NullSeparator = System.Char[]
+--System.Char[] = System.Char[]: N/A
+lastClipboardEventTime = 0
+clipboardCopiedTime = 0
+k__BackingField = NONE
+k__BackingField = 0
+k__BackingField = False
+lastClipboardObject =
+k__BackingField = False
+ClipboardThreadOldLock = Lock
+--_owningThreadId = 0
+--_state = 0
+--_recursionCount = 0
+--_spinCount = 22
+--_waiterStartTimeMs = 0
+--s_contentionCount = 0
+--s_maxSpinCount = 22
+--s_minSpinCountForAdaptiveSpin = -100
+BIG_CLIPBOARD_DATA_TIMEOUT = 30000
+MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1048576
+MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 104857600
+TEXT_HEADER_SIZE = 12
+DATA_SIZE = 48
+TEXT_TYPE_SEP = {4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}
[DragDrop]
===============
isDragging = False
@@ -249,6 +240,19 @@ actualLastPos = {X=0,Y=0}
--Empty = {X=0,Y=0}
myLastX = 0
myLastY = 0
+[InitAndCleanup]
+===============
+initDone = False
+REOPEN_WHEN_WSAECONNRESET = -10054
+REOPEN_WHEN_HOTKEY = -10055
+PleaseReopenSocket = 0
+ReopenSocketDueToReadError = False
+k__BackingField = ????????????
+--_dateData = ????????????
+--MinValue = 01/01/0001 00:00:00
+--MaxValue = 31/12/9999 23:59:59
+--UnixEpoch = 01/01/1970 00:00:00
+lastReleaseAllKeysCall = 0
[Helper]
===============
signalHelperToExit = False