-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathClipboardMonitor.cs
More file actions
136 lines (121 loc) · 4.63 KB
/
Copy pathClipboardMonitor.cs
File metadata and controls
136 lines (121 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace OneNoteHyperlinkRemover
{
/// <summary>
/// Monitors clipboard changes by polling GetClipboardSequenceNumber.
/// This is the only approach that works in OneNote COM add-ins because
/// OneNote's message loop does not pump messages for windows/hooks
/// created by add-ins (AddClipboardFormatListener and SetWinEventHook
/// both require a message pump to deliver callbacks).
/// </summary>
internal sealed class ClipboardMonitor : IDisposable
{
private const string ZeroWidthSpace = "";
[DllImport("user32.dll")]
private static extern uint GetClipboardSequenceNumber();
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
private readonly Thread _thread;
private readonly ManualResetEvent _stop = new(false);
private readonly int _interval;
private uint _lastSeq;
private string _lastText = "";
private bool _disposed;
public ClipboardMonitor(int intervalMs = 300)
{
_interval = Math.Max(100, intervalMs);
_lastSeq = GetClipboardSequenceNumber();
_thread = new Thread(MonitorLoop)
{
IsBackground = true,
Name = "ClipboardMonitor"
};
_thread.Start();
Log("ClipboardMonitor started (polling " + _interval + "ms)");
}
private void MonitorLoop()
{
while (!_stop.WaitOne(_interval))
{
try
{
uint seq = GetClipboardSequenceNumber();
if (seq == _lastSeq) continue;
_lastSeq = seq;
string text = null;
var readThread = new Thread(() =>
{
try
{
if (Clipboard.ContainsText())
text = Clipboard.GetText();
}
catch { }
});
readThread.SetApartmentState(ApartmentState.STA);
readThread.Start();
readThread.Join(500);
if (string.IsNullOrEmpty(text) || text == _lastText) continue;
_lastText = text;
if (!text.Contains(ZeroWidthSpace)) continue;
if (!IsOneNoteForeground()) continue;
string cleaned = text.Replace(ZeroWidthSpace, "");
if (cleaned == text) continue;
var writeThread = new Thread(() =>
{
try { Clipboard.SetText(cleaned); }
catch { }
});
writeThread.SetApartmentState(ApartmentState.STA);
writeThread.Start();
writeThread.Join(500);
_lastText = cleaned;
Log("CLEANED: " + cleaned.Substring(0, Math.Min(80, cleaned.Length)));
}
catch { }
}
}
private static bool IsOneNoteForeground()
{
try
{
IntPtr hwnd = GetForegroundWindow();
if (hwnd == IntPtr.Zero) return false;
GetWindowThreadProcessId(hwnd, out uint pid);
var proc = Process.GetProcessById((int)pid);
return proc.ProcessName.Equals("ONENOTE", StringComparison.OrdinalIgnoreCase);
}
catch { return false; }
}
[Conditional("DEBUG")]
private static void Log(string msg)
{
try
{
var path = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"OneNoteHyperlinkRemover", "addin.log");
System.IO.File.AppendAllText(path,
$"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] [Clipboard] {msg}{Environment.NewLine}");
}
catch { }
}
public void Dispose()
{
if (!_disposed)
{
_disposed = true;
_stop.Set();
_thread.Join(1000);
_stop.Dispose();
Log("ClipboardMonitor stopped");
}
}
}
}