Skip to content

Commit 813d7e6

Browse files
committed
multiple fixes again
1. implement IDisposable 2. workaround the `selected entries are pinned to top` issue 3. use SetDataObject instead of SetText (support non-plain-text clip format) 4. use `Search` instead of `SecondToEndSearch` due to behavior change of plugin api
1 parent ed326cd commit 813d7e6

File tree

2 files changed

+51
-17
lines changed

2 files changed

+51
-17
lines changed

ClipboardMonitor.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ public static IDataObject GetDataObject() {
4848
return LoopCall(() => System.Windows.Forms.Clipboard.GetDataObject());
4949
}
5050

51+
public static bool SetDataObject(object data) {
52+
return LoopCall(() => {
53+
System.Windows.Forms.Clipboard.SetDataObject(data);
54+
return true;
55+
});
56+
}
57+
5158
public static bool SetText(string text) {
5259
return LoopCall(() => {
5360
System.Windows.Forms.Clipboard.SetText(text);
@@ -60,6 +67,7 @@ class ClipboardWatcher : Form
6067
{
6168
// static instance of this form
6269
private static ClipboardWatcher mInstance;
70+
private static Thread mThread;
6371

6472
// needed to dispose this form
6573
static IntPtr nextClipboardViewer;
@@ -74,27 +82,31 @@ public static void Start()
7482
if (mInstance != null)
7583
return;
7684

77-
Thread t = new Thread(new ParameterizedThreadStart(x =>
85+
mThread = new Thread(new ParameterizedThreadStart(x =>
7886
{
7987
Application.Run(new ClipboardWatcher());
8088
}));
81-
t.SetApartmentState(ApartmentState.STA); // give the [STAThread] attribute
82-
t.IsBackground = true;
83-
t.Start();
89+
mThread.SetApartmentState(ApartmentState.STA); // give the [STAThread] attribute
90+
mThread.IsBackground = true;
91+
mThread.Start();
8492
}
8593

8694
// stop listening (dispose form)
8795
public static void Stop()
8896
{
97+
if (mInstance == null)
98+
return;
99+
89100
mInstance.Invoke(new MethodInvoker(() =>
90101
{
91102
ChangeClipboardChain(mInstance.Handle, nextClipboardViewer);
92103
}));
93104
mInstance.Invoke(new MethodInvoker(mInstance.Close));
94-
95105
mInstance.Dispose();
96-
97106
mInstance = null;
107+
108+
mThread.Join();
109+
mThread = null;
98110
}
99111

100112
// on load: (hide this window)

Main.cs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,47 @@
88

99
namespace Flow.Launcher.Plugin.ClipboardHistory
1010
{
11-
public class ClipboardHistory : IPlugin
11+
public class ClipboardHistory : IPlugin, IDisposable
1212
{
13-
private const int MaxDataCount = 5000;
14-
//private readonly KeyboardSimulator keyboardSimulator = new KeyboardSimulator(new InputSimulator());
13+
private const int MaxDataCount = 1000;
1514
private readonly InputSimulator inputSimulator = new InputSimulator();
1615
private PluginInitContext context;
17-
LinkedList<string> dataList = new LinkedList<string>();
16+
private int currentScore = 1;
17+
LinkedList<ClipboardData> dataList = new LinkedList<ClipboardData>();
1818

19+
public struct ClipboardData : IEquatable<ClipboardData> {
20+
public object data;
21+
public string text;
22+
public string displayText;
23+
public int score;
24+
25+
public override bool Equals(object obj) => obj is ClipboardData && Equals((ClipboardData)obj);
26+
public bool Equals(ClipboardData other) => text.Equals(other.text);
27+
public override int GetHashCode() => text.GetHashCode();
28+
}
29+
1930
public List<Result> Query(Query query)
2031
{
2132
var results = new List<Result>();
22-
IEnumerable<string> displayData;
33+
IEnumerable<ClipboardData> displayData;
2334

24-
if (query.Terms.Length == 0)
35+
if (query.Search.Trim().Length == 0)
2536
{
2637
displayData = dataList;
2738
}
2839
else
2940
{
30-
displayData = dataList.Where(i => i.ToLower().Contains(query.SecondToEndSearch.ToLower()));
41+
displayData = dataList.Where(i => i.text.ToLower().Contains(query.Search.ToLower()));
3142
}
3243

3344
results.AddRange(displayData.Select(o => new Result
3445
{
35-
Title = o.Trim().Replace("\r\n", " ").Replace('\n', ' '),
46+
Title = o.displayText,
3647
IcoPath = "Images\\clipboard.png",
48+
Score = o.score,
3749
Action = c =>
3850
{
39-
if (!ClipboardMonitor.ClipboardWrapper.SetText(o))
51+
if (!ClipboardMonitor.ClipboardWrapper.SetDataObject(o.data))
4052
return false;
4153

4254
Task.Delay(50).ContinueWith(t => inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.CONTROL, VirtualKeyCode.VK_V));
@@ -62,12 +74,18 @@ void ClipboardMonitor_OnClipboardChange(ClipboardFormat format, object data)
6274
{
6375
if (data != null && !string.IsNullOrEmpty(data.ToString().Trim()))
6476
{
65-
LinkedListNode<string> node = dataList.Find(data.ToString());
77+
ClipboardData obj = new ClipboardData { };
78+
obj.data = data;
79+
obj.text = data.ToString();
80+
obj.displayText = obj.text.Trim().Replace("\r\n", " ").Replace('\n', ' ');
81+
obj.score = currentScore++ * 1000;
82+
83+
LinkedListNode<ClipboardData> node = dataList.Find(obj);
6684
if (node != null)
6785
{
6886
dataList.Remove(node);
6987
}
70-
dataList.AddFirst(data.ToString());
88+
dataList.AddFirst(obj);
7189

7290
if (dataList.Count > MaxDataCount)
7391
{
@@ -76,5 +94,9 @@ void ClipboardMonitor_OnClipboardChange(ClipboardFormat format, object data)
7694
}
7795
}
7896
}
97+
98+
public void Dispose() {
99+
ClipboardMonitor.Stop();
100+
}
79101
}
80102
}

0 commit comments

Comments
 (0)