WingMan – Diff between revs 32 and 36

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 32 Rev 36
1 using System; 1 using System;
2 using System.Collections.Specialized; 2 using System.Collections.Specialized;
3 using System.IO; 3 using System.IO;
4 using System.Linq; 4 using System.Linq;
5 using System.Threading; 5 using System.Threading;
6 using System.Threading.Tasks; 6 using System.Threading.Tasks;
7 using System.Threading.Tasks.Dataflow; 7 using System.Threading.Tasks.Dataflow;
8 using System.Windows.Forms; 8 using System.Windows.Forms;
9 using Gma.System.MouseKeyHook; 9 using Gma.System.MouseKeyHook;
-   10 using ProtoBuf;
10 using WingMan.Communication; 11 using WingMan.Communication;
11 using WingMan.Utilities; 12 using WingMan.Utilities;
12   13  
13 namespace WingMan.Bindings 14 namespace WingMan.Bindings
14 { 15 {
15 public class KeyInterceptor : IDisposable 16 public class KeyInterceptor : IDisposable
16 { 17 {
17 public delegate void MouseKeyBindingMatched(object sender, KeyBindingMatchedEventArgs args); 18 public delegate void MouseKeyBindingMatched(object sender, KeyBindingMatchedEventArgs args);
18   19  
19 private volatile bool ProcessPipe; 20 private volatile bool _processPipe;
20   21  
21 public KeyInterceptor(RemoteKeyBindings remoteKeyBindings, MqttCommunication mqttCommunication, 22 public KeyInterceptor(RemoteKeyBindings remoteKeyBindings, MqttCommunication mqttCommunication,
22 TaskScheduler taskScheduler, CancellationToken cancellationToken) 23 TaskScheduler taskScheduler, CancellationToken cancellationToken)
23 { 24 {
24 DataFlowSemaphoreSlim = new SemaphoreSlim(1, 1); 25 DataFlowSemaphoreSlim = new SemaphoreSlim(1, 1);
25   26  
26 RemoteKeyBindings = remoteKeyBindings; 27 RemoteKeyBindings = remoteKeyBindings;
27 RemoteKeyBindings.Bindings.CollectionChanged += OnRemoteKeyBindingsChanged; 28 RemoteKeyBindings.Bindings.CollectionChanged += OnRemoteKeyBindingsChanged;
28   29  
29 MqttCommunication = mqttCommunication; 30 MqttCommunication = mqttCommunication;
30 TaskScheduler = taskScheduler; 31 TaskScheduler = taskScheduler;
31 CancellationToken = cancellationToken; 32 CancellationToken = cancellationToken;
32   33  
33 MouseKeyGloalHook = Hook.GlobalEvents(); 34 MouseKeyGloalHook = Hook.GlobalEvents();
34 MouseKeyGloalHook.KeyUp += MouseKeyGloalHookOnKeyUp; 35 MouseKeyGloalHook.KeyUp += MouseKeyGloalHookOnKeyUp;
35 MouseKeyGloalHook.KeyDown += MouseKeyGloalHookOnKeyDown; 36 MouseKeyGloalHook.KeyDown += MouseKeyGloalHookOnKeyDown;
36 } 37 }
37   38  
38 private BatchBlock<string> KeyComboBatchBlock { get; set; } 39 private BatchBlock<string> KeyComboBatchBlock { get; set; }
39 private ActionBlock<string[]> KeyComboActionBlock { get; set; } 40 private ActionBlock<string[]> KeyComboActionBlock { get; set; }
40 private IDisposable KeyComboDataFlowLink { get; set; } 41 private IDisposable KeyComboDataFlowLink { get; set; }
41 private SemaphoreSlim DataFlowSemaphoreSlim { get; } 42 private SemaphoreSlim DataFlowSemaphoreSlim { get; }
42 private RemoteKeyBindings RemoteKeyBindings { get; } 43 private RemoteKeyBindings RemoteKeyBindings { get; }
43 private MqttCommunication MqttCommunication { get; } 44 private MqttCommunication MqttCommunication { get; }
44 private TaskScheduler TaskScheduler { get; } 45 private TaskScheduler TaskScheduler { get; }
45 private CancellationToken CancellationToken { get; } 46 private CancellationToken CancellationToken { get; }
46 private IKeyboardMouseEvents MouseKeyGloalHook { get; set; } 47 private IKeyboardMouseEvents MouseKeyGloalHook { get; set; }
47   48  
48 public void Dispose() 49 public void Dispose()
49 { 50 {
50 MouseKeyGloalHook.KeyUp -= MouseKeyGloalHookOnKeyUp; 51 MouseKeyGloalHook.KeyUp -= MouseKeyGloalHookOnKeyUp;
51 MouseKeyGloalHook.KeyDown -= MouseKeyGloalHookOnKeyDown; 52 MouseKeyGloalHook.KeyDown -= MouseKeyGloalHookOnKeyDown;
52 RemoteKeyBindings.Bindings.CollectionChanged -= OnRemoteKeyBindingsChanged; 53 RemoteKeyBindings.Bindings.CollectionChanged -= OnRemoteKeyBindingsChanged;
53   54  
54 KeyComboDataFlowLink?.Dispose(); 55 KeyComboDataFlowLink?.Dispose();
55 KeyComboDataFlowLink = null; 56 KeyComboDataFlowLink = null;
56   57  
57 MouseKeyGloalHook?.Dispose(); 58 MouseKeyGloalHook?.Dispose();
58 MouseKeyGloalHook = null; 59 MouseKeyGloalHook = null;
59 } 60 }
60   61  
61 private async void OnRemoteKeyBindingsChanged(object sender, NotifyCollectionChangedEventArgs e) 62 private async void OnRemoteKeyBindingsChanged(object sender, NotifyCollectionChangedEventArgs e)
62 { 63 {
63 await DataFlowSemaphoreSlim.WaitAsync(CancellationToken); 64 await DataFlowSemaphoreSlim.WaitAsync(CancellationToken);
64   65  
65 try 66 try
66 { 67 {
67 // Break the link and dispose it. 68 // Break the link and dispose it.
68 KeyComboDataFlowLink?.Dispose(); 69 KeyComboDataFlowLink?.Dispose();
69 KeyComboDataFlowLink = null; 70 KeyComboDataFlowLink = null;
70   71  
71 // Create a sliding window of size equal to the longest key combination. 72 // Create a sliding window of size equal to the longest key combination.
72 if (!RemoteKeyBindings.Bindings.Any()) 73 if (!RemoteKeyBindings.Bindings.Any())
73 return; 74 return;
74   75  
75 var remoteKeyBindings = RemoteKeyBindings.Bindings.Where(binding => binding.Keys.Any()).ToList(); 76 var remoteKeyBindings = RemoteKeyBindings.Bindings.Where(binding => binding.Keys.Any()).ToList();
76 if (!remoteKeyBindings.Any()) 77 if (!remoteKeyBindings.Any())
77 return; 78 return;
78   79  
79 var maxKeyComboLength = remoteKeyBindings.Max(binding => binding.Keys.Count); 80 var maxKeyComboLength = remoteKeyBindings.Max(binding => binding.Keys.Count);
80 if (maxKeyComboLength <= 0) 81 if (maxKeyComboLength <= 0)
81 return; 82 return;
82   83  
83 KeyComboBatchBlock = 84 KeyComboBatchBlock =
84 new BatchBlock<string>(maxKeyComboLength); 85 new BatchBlock<string>(maxKeyComboLength);
85 KeyComboActionBlock = new ActionBlock<string[]>(ProcessKeyCombos, 86 KeyComboActionBlock = new ActionBlock<string[]>(ProcessKeyCombos,
86 new ExecutionDataflowBlockOptions {CancellationToken = CancellationToken}); 87 new ExecutionDataflowBlockOptions {CancellationToken = CancellationToken});
87 KeyComboDataFlowLink = KeyComboBatchBlock.LinkTo(KeyComboActionBlock); 88 KeyComboDataFlowLink = KeyComboBatchBlock.LinkTo(KeyComboActionBlock);
88 } 89 }
89 finally 90 finally
90 { 91 {
91 DataFlowSemaphoreSlim.Release(); 92 DataFlowSemaphoreSlim.Release();
92 } 93 }
93 } 94 }
94   95  
95 private async Task ProcessKeyCombos(string[] keys) 96 private async Task ProcessKeyCombos(string[] keys)
96 { 97 {
97 await DataFlowSemaphoreSlim.WaitAsync(CancellationToken); 98 await DataFlowSemaphoreSlim.WaitAsync(CancellationToken);
98   99  
99 try 100 try
100 { 101 {
101 if (!ProcessPipe) 102 if (!_processPipe)
102 return; 103 return;
103   104  
104 foreach (var binding in RemoteKeyBindings.Bindings) 105 foreach (var binding in RemoteKeyBindings.Bindings)
105 { 106 {
106 if (!keys.SubsetEquals(binding.Keys)) 107 if (!keys.SubsetEquals(binding.Keys))
107 continue; 108 continue;
108   109  
109 // Raise the match event. 110 // Raise the match event.
110 await Task.Delay(0, CancellationToken) 111 await Task.Delay(0, CancellationToken)
111 .ContinueWith( 112 .ContinueWith(
112 _ => OnMouseKeyBindingMatched?.Invoke(this, 113 _ => OnMouseKeyBindingMatched?.Invoke(this,
113 new KeyBindingMatchedEventArgs(binding.Nick, binding.Name, binding.Keys)), 114 new KeyBindingMatchedEventArgs(binding.Nick, binding.Name, binding.Keys)),
114 CancellationToken, 115 CancellationToken,
115 TaskContinuationOptions.None, TaskScheduler); 116 TaskContinuationOptions.None, TaskScheduler);
116   117  
117 using (var memoryStream = new MemoryStream()) 118 using (var memoryStream = new MemoryStream())
118 { 119 {
119 ExecuteKeyBinding.XmlSerializer.Serialize(memoryStream, 120 Serializer.Serialize(memoryStream,
120 new ExecuteKeyBinding(binding.Nick, binding.Name)); 121 new ExecuteKeyBinding(binding.Nick, binding.Name));
121   122  
122 memoryStream.Position = 0L; 123 memoryStream.Position = 0L;
123   124  
124 await MqttCommunication.Broadcast("execute", memoryStream.ToArray()); 125 await MqttCommunication.Broadcast("execute", memoryStream.ToArray());
125 } 126 }
126 } 127 }
127 } 128 }
128 finally 129 finally
129 { 130 {
130 DataFlowSemaphoreSlim.Release(); 131 DataFlowSemaphoreSlim.Release();
131 } 132 }
132 } 133 }
133   134  
134 public event MouseKeyBindingMatched OnMouseKeyBindingMatched; 135 public event MouseKeyBindingMatched OnMouseKeyBindingMatched;
135   136  
136 private async void MouseKeyGloalHookOnKeyDown(object sender, KeyEventArgs e) 137 private async void MouseKeyGloalHookOnKeyDown(object sender, KeyEventArgs e)
137 { 138 {
138 ProcessPipe = true; 139 _processPipe = true;
139   140  
140 if (!KeyConversion.KeysToString.TryGetValue((byte) e.KeyCode, out var key)) 141 if (!KeyConversion.KeysToString.TryGetValue((byte) e.KeyCode, out var key))
141 return; 142 return;
142   143  
143 await DataFlowSemaphoreSlim.WaitAsync(CancellationToken); 144 await DataFlowSemaphoreSlim.WaitAsync(CancellationToken);
144 try 145 try
145 { 146 {
146 if (KeyComboBatchBlock != null) 147 if (KeyComboBatchBlock != null)
147 await KeyComboBatchBlock.SendAsync(key, CancellationToken); 148 await KeyComboBatchBlock.SendAsync(key, CancellationToken);
148 } 149 }
149 finally 150 finally
150 { 151 {
151 DataFlowSemaphoreSlim.Release(); 152 DataFlowSemaphoreSlim.Release();
152 } 153 }
153 } 154 }
154   155  
155 private void MouseKeyGloalHookOnKeyUp(object sender, KeyEventArgs e) 156 private void MouseKeyGloalHookOnKeyUp(object sender, KeyEventArgs e)
156 { 157 {
157 ProcessPipe = false; 158 _processPipe = false;
158 } 159 }
159 } 160 }
160 } -  
161   161 }
-   162  
162
Generated by GNU Enscript 1.6.5.90.
-  
163   -  
164   -  
165   -