WingMan – Diff between revs 10 and 14

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