WingMan – Diff between revs 32 and 33

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 32 Rev 33
1 using System; 1 using System;
2 using System.Collections.Generic; 2 using System.Collections.Generic;
3 using System.Collections.ObjectModel; 3 using System.Collections.ObjectModel;
4 using System.ComponentModel; 4 using System.ComponentModel;
5 using System.Drawing; 5 using System.Drawing;
6 using System.IO; 6 using System.IO;
7 using System.Linq; 7 using System.Linq;
8 using System.Net; 8 using System.Net;
9 using System.Threading; 9 using System.Threading;
10 using System.Threading.Tasks; 10 using System.Threading.Tasks;
11 using System.Windows.Forms; 11 using System.Windows.Forms;
12 using Gma.System.MouseKeyHook; 12 using Gma.System.MouseKeyHook;
13 using MQTTnet.Extensions.ManagedClient; 13 using MQTTnet.Extensions.ManagedClient;
14 using MQTTnet.Server; 14 using MQTTnet.Server;
15 using WingMan.AutoCompletion; 15 using WingMan.AutoCompletion;
16 using WingMan.Bindings; 16 using WingMan.Bindings;
17 using WingMan.Communication; 17 using WingMan.Communication;
18 using WingMan.Discovery; 18 using WingMan.Discovery;
19 using WingMan.Lobby; 19 using WingMan.Lobby;
20 using WingMan.Properties; 20 using WingMan.Properties;
21 using WingMan.Utilities; 21 using WingMan.Utilities;
22   22  
23 namespace WingMan 23 namespace WingMan
24 { 24 {
25 public partial class WingManForm : Form 25 public partial class WingManForm : Form
26 { 26 {
-   27 private const int tabControlDetachPixelOffset = 20;
-   28  
27 public WingManForm() 29 public WingManForm()
28 { 30 {
29 InitializeComponent(); 31 InitializeComponent();
30   32  
31 FormTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 33 FormTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
32 FormCancellationTokenSource = new CancellationTokenSource(); 34 FormCancellationTokenSource = new CancellationTokenSource();
33   35  
34 // Set up discovery. 36 // Set up discovery.
35 Discovery = new Discovery.Discovery(FormCancellationTokenSource, FormTaskScheduler); 37 Discovery = new Discovery.Discovery(FormCancellationTokenSource, FormTaskScheduler);
36 Discovery.OnPortMapFailed += OnDiscoveryPortMapFailed; 38 Discovery.OnPortMapFailed += OnDiscoveryPortMapFailed;
37   39  
38 // Set up autocompletion. 40 // Set up autocompletion.
39 AutoCompletion = new AutoCompletion.AutoCompletion(FormTaskScheduler, FormCancellationTokenSource.Token); 41 AutoCompletion = new AutoCompletion.AutoCompletion(FormTaskScheduler, FormCancellationTokenSource.Token);
40 AutoCompletion.OnSaveFailed += AutoCompletionOnSaveFailed; 42 AutoCompletion.OnSaveFailed += AutoCompletionOnSaveFailed;
41 AutoCompletion.OnLoadFailed += AutoCompletionOnLoadFailed; 43 AutoCompletion.OnLoadFailed += AutoCompletionOnLoadFailed;
42   44  
43 Task.Run(() => AutoCompletion.Load(Address.Name, Address.AutoCompleteCustomSource)); 45 Task.Run(() => AutoCompletion.Load(Address.Name, Address.AutoCompleteCustomSource));
44 Task.Run(() => AutoCompletion.Load(Port.Name, Address.AutoCompleteCustomSource)); 46 Task.Run(() => AutoCompletion.Load(Port.Name, Address.AutoCompleteCustomSource));
45 Task.Run(() => AutoCompletion.Load(Nick.Name, Nick.AutoCompleteCustomSource)); 47 Task.Run(() => AutoCompletion.Load(Nick.Name, Nick.AutoCompleteCustomSource));
46   48  
47 MqttCommunication = new MqttCommunication(FormTaskScheduler, FormCancellationTokenSource.Token); 49 MqttCommunication = new MqttCommunication(FormTaskScheduler, FormCancellationTokenSource.Token);
48 MqttCommunication.OnClientAuthenticationFailed += OnMqttClientAuthenticationFailed; 50 MqttCommunication.OnClientAuthenticationFailed += OnMqttClientAuthenticationFailed;
49 MqttCommunication.OnClientConnectionFailed += OnMqttClientConnectionFailed; 51 MqttCommunication.OnClientConnectionFailed += OnMqttClientConnectionFailed;
50 MqttCommunication.OnClientDisconnected += OnMqttClientDisconnected; 52 MqttCommunication.OnClientDisconnected += OnMqttClientDisconnected;
51 MqttCommunication.OnClientConnected += OnMqttClientConnected; 53 MqttCommunication.OnClientConnected += OnMqttClientConnected;
52 MqttCommunication.OnServerAuthenticationFailed += OnMqttServerAuthenticationFailed; 54 MqttCommunication.OnServerAuthenticationFailed += OnMqttServerAuthenticationFailed;
53 MqttCommunication.OnServerStopped += OnMqttServerStopped; 55 MqttCommunication.OnServerStopped += OnMqttServerStopped;
54 MqttCommunication.OnServerStarted += OnMqttServerStarted; 56 MqttCommunication.OnServerStarted += OnMqttServerStarted;
55 MqttCommunication.OnServerClientConnected += OnMqttServerClientConnected; 57 MqttCommunication.OnServerClientConnected += OnMqttServerClientConnected;
56 MqttCommunication.OnServerClientDisconnected += OnMqttServerClientDisconnected; 58 MqttCommunication.OnServerClientDisconnected += OnMqttServerClientDisconnected;
57   59  
58 LocalKeyBindings = new LocalKeyBindings(new List<KeyBinding>()); 60 LocalKeyBindings = new LocalKeyBindings(new List<KeyBinding>());
59 RemoteKeyBindings = new RemoteKeyBindings(new ObservableCollection<RemoteKeyBinding>()); 61 RemoteKeyBindings = new RemoteKeyBindings(new ObservableCollection<RemoteKeyBinding>());
60   62  
61 LocalCheckedListBoxBindingSource = new BindingSource 63 LocalCheckedListBoxBindingSource = new BindingSource
62 { 64 {
63 DataSource = LocalKeyBindings.Bindings 65 DataSource = LocalKeyBindings.Bindings
64 }; 66 };
65 LocalCheckedListBoxBindingSource.ListChanged += LocalCheckedListBoxBindingSourceOnListChanged; 67 LocalCheckedListBoxBindingSource.ListChanged += LocalCheckedListBoxBindingSourceOnListChanged;
66 LocalBindingsCheckedListBox.DisplayMember = "DisplayName"; 68 LocalBindingsCheckedListBox.DisplayMember = "DisplayName";
67 LocalBindingsCheckedListBox.ValueMember = "Keys"; 69 LocalBindingsCheckedListBox.ValueMember = "Keys";
68 LocalBindingsCheckedListBox.DataSource = LocalCheckedListBoxBindingSource; 70 LocalBindingsCheckedListBox.DataSource = LocalCheckedListBoxBindingSource;
69   71  
70 KeyBindingsExchange = new KeyBindingsExchange 72 KeyBindingsExchange = new KeyBindingsExchange
71 { 73 {
72 ExchangeBindings = new List<KeyBindingExchange>() 74 ExchangeBindings = new List<KeyBindingExchange>()
73 }; 75 };
74   76  
75 RemoteBindingsComboBoxSource = new BindingSource 77 RemoteBindingsComboBoxSource = new BindingSource
76 { 78 {
77 DataSource = KeyBindingsExchange.ExchangeBindings 79 DataSource = KeyBindingsExchange.ExchangeBindings
78 }; 80 };
79 RemoteBindingsComboBox.DisplayMember = "Nick"; 81 RemoteBindingsComboBox.DisplayMember = "Nick";
80 RemoteBindingsComboBox.ValueMember = "KeyBindings"; 82 RemoteBindingsComboBox.ValueMember = "KeyBindings";
81 RemoteBindingsComboBox.DataSource = RemoteBindingsComboBoxSource; 83 RemoteBindingsComboBox.DataSource = RemoteBindingsComboBoxSource;
82   84  
83 // Start lobby message synchronizer. 85 // Start lobby message synchronizer.
84 LobbyMessageSynchronizer = new LobbyMessageSynchronizer(MqttCommunication, FormTaskScheduler, 86 LobbyMessageSynchronizer = new LobbyMessageSynchronizer(MqttCommunication, FormTaskScheduler,
85 FormCancellationTokenSource.Token); 87 FormCancellationTokenSource.Token);
86 LobbyMessageSynchronizer.OnLobbyMessageReceived += OnLobbyMessageReceived; 88 LobbyMessageSynchronizer.OnLobbyMessageReceived += OnLobbyMessageReceived;
87   89  
88 // Start mouse key bindings synchronizer. 90 // Start mouse key bindings synchronizer.
89 KeyBindingsSynchronizer = new KeyBindingsSynchronizer(LocalKeyBindings, MqttCommunication, 91 KeyBindingsSynchronizer = new KeyBindingsSynchronizer(LocalKeyBindings, MqttCommunication,
90 FormTaskScheduler, FormCancellationTokenSource.Token); 92 FormTaskScheduler, FormCancellationTokenSource.Token);
91 KeyBindingsSynchronizer.OnMouseKeyBindingsSynchronized += OnMouseKeyBindingsSynchronized; 93 KeyBindingsSynchronizer.OnMouseKeyBindingsSynchronized += OnMouseKeyBindingsSynchronized;
92   94  
93 // Start mouse key interceptor. 95 // Start mouse key interceptor.
94 KeyInterceptor = new KeyInterceptor(RemoteKeyBindings, MqttCommunication, FormTaskScheduler, 96 KeyInterceptor = new KeyInterceptor(RemoteKeyBindings, MqttCommunication, FormTaskScheduler,
95 FormCancellationTokenSource.Token); 97 FormCancellationTokenSource.Token);
96 KeyInterceptor.OnMouseKeyBindingMatched += OnMouseKeyBindingMatched; 98 KeyInterceptor.OnMouseKeyBindingMatched += OnMouseKeyBindingMatched;
97   99  
98 // Start mouse key simulator. 100 // Start mouse key simulator.
99 KeySimulator = new KeySimulator(LocalKeyBindings, MqttCommunication, FormTaskScheduler, 101 KeySimulator = new KeySimulator(LocalKeyBindings, MqttCommunication, FormTaskScheduler,
100 FormCancellationTokenSource.Token); 102 FormCancellationTokenSource.Token);
101 KeySimulator.OnMouseKeyBindingExecuting += OnMouseKeyBindingExecuting; 103 KeySimulator.OnMouseKeyBindingExecuting += OnMouseKeyBindingExecuting;
102 } 104 }
103   105  
104 private static Discovery.Discovery Discovery { get; set; } 106 private static Discovery.Discovery Discovery { get; set; }
105 private static AutoCompletion.AutoCompletion AutoCompletion { get; set; } 107 private static AutoCompletion.AutoCompletion AutoCompletion { get; set; }
106 private static CancellationTokenSource FormCancellationTokenSource { get; set; } 108 private static CancellationTokenSource FormCancellationTokenSource { get; set; }
107   109  
108 private static TaskScheduler FormTaskScheduler { get; set; } 110 private static TaskScheduler FormTaskScheduler { get; set; }
109   111  
110 private static IKeyboardMouseEvents MouseKeyApplicationHook { get; set; } 112 private static IKeyboardMouseEvents MouseKeyApplicationHook { get; set; }
111   113  
112 private List<string> MouseKeyCombo { get; set; } 114 private List<string> MouseKeyCombo { get; set; }
113   115  
114 private LocalKeyBindings LocalKeyBindings { get; } 116 private LocalKeyBindings LocalKeyBindings { get; }
115   117  
116 private RemoteKeyBindings RemoteKeyBindings { get; } 118 private RemoteKeyBindings RemoteKeyBindings { get; }
117   119  
118 private BindingSource LocalCheckedListBoxBindingSource { get; } 120 private BindingSource LocalCheckedListBoxBindingSource { get; }
119   121  
120 private BindingSource RemoteBindingsComboBoxSource { get; } 122 private BindingSource RemoteBindingsComboBoxSource { get; }
121   123  
122 private KeyBindingsExchange KeyBindingsExchange { get; } 124 private KeyBindingsExchange KeyBindingsExchange { get; }
123   125  
124 public MqttCommunication MqttCommunication { get; set; } 126 public MqttCommunication MqttCommunication { get; set; }
125   127  
126 public LobbyMessageSynchronizer LobbyMessageSynchronizer { get; set; } 128 public LobbyMessageSynchronizer LobbyMessageSynchronizer { get; set; }
127   129  
128 public KeyBindingsSynchronizer KeyBindingsSynchronizer { get; set; } 130 public KeyBindingsSynchronizer KeyBindingsSynchronizer { get; set; }
129   131  
130 public KeyInterceptor KeyInterceptor { get; set; } 132 public KeyInterceptor KeyInterceptor { get; set; }
131   133  
132 public KeySimulator KeySimulator { get; set; } 134 public KeySimulator KeySimulator { get; set; }
-   135  
-   136 private static Point tabControlClickStartPosition { get; set; }
-   137 private static TabControl DetachedTabControl { get; set; }
-   138 private static Form DetachedForm { get; set; }
133   139  
134 public void OnDiscoveryPortMapFailed(object sender, DiscoveryFailedEventArgs args) 140 public void OnDiscoveryPortMapFailed(object sender, DiscoveryFailedEventArgs args)
135 { 141 {
136 switch (args.Type) 142 switch (args.Type)
137 { 143 {
138 case DiscoveryType.UPnP: 144 case DiscoveryType.UPnP:
139 ActivityTextBox.AppendText( 145 ActivityTextBox.AppendText(
140 $"{Strings.Failed_to_create_UPnP_port_mapping}{Environment.NewLine}"); 146 $"{Strings.Failed_to_create_UPnP_port_mapping}{Environment.NewLine}");
141 break; 147 break;
142 case DiscoveryType.PMP: 148 case DiscoveryType.PMP:
143 ActivityTextBox.AppendText( 149 ActivityTextBox.AppendText(
144 $"{Strings.Failed_to_create_PMP_port_mapping}{Environment.NewLine}"); 150 $"{Strings.Failed_to_create_PMP_port_mapping}{Environment.NewLine}");
145 break; 151 break;
146 } 152 }
147 } 153 }
148   154  
149 private void LocalCheckedListBoxBindingSourceOnListChanged(object sender, ListChangedEventArgs e) 155 private void LocalCheckedListBoxBindingSourceOnListChanged(object sender, ListChangedEventArgs e)
150 { 156 {
151 // Check items 157 // Check items
152 LocalBindingsCheckedListBox.ItemCheck -= LocalBindingsCheckedListBoxItemCheck; 158 LocalBindingsCheckedListBox.ItemCheck -= LocalBindingsCheckedListBoxItemCheck;
153   159  
154 for (var i = 0; i < LocalKeyBindings.Bindings.Count; ++i) 160 for (var i = 0; i < LocalKeyBindings.Bindings.Count; ++i)
155 switch (LocalKeyBindings.Bindings[i].Enabled) 161 switch (LocalKeyBindings.Bindings[i].Enabled)
156 { 162 {
157 case true: 163 case true:
158 LocalBindingsCheckedListBox.SetItemCheckState(i, CheckState.Checked); 164 LocalBindingsCheckedListBox.SetItemCheckState(i, CheckState.Checked);
159 break; 165 break;
160 default: 166 default:
161 LocalBindingsCheckedListBox.SetItemCheckState(i, CheckState.Unchecked); 167 LocalBindingsCheckedListBox.SetItemCheckState(i, CheckState.Unchecked);
162 break; 168 break;
163 } 169 }
164   170  
165 LocalBindingsCheckedListBox.ItemCheck += LocalBindingsCheckedListBoxItemCheck; 171 LocalBindingsCheckedListBox.ItemCheck += LocalBindingsCheckedListBoxItemCheck;
166 } 172 }
167   173  
168 private void AutoCompletionOnLoadFailed(object sender, AutoCompletionFailedEventArgs args) 174 private void AutoCompletionOnLoadFailed(object sender, AutoCompletionFailedEventArgs args)
169 { 175 {
170 ActivityTextBox.AppendText( 176 ActivityTextBox.AppendText(
171 $"{Strings.Failed_loading_autocomplete_source} : {args.Name} : {args.Exception.Message}{Environment.NewLine}"); 177 $"{Strings.Failed_loading_autocomplete_source} : {args.Name} : {args.Exception.Message}{Environment.NewLine}");
172 } 178 }
173   179  
174 private void AutoCompletionOnSaveFailed(object sender, AutoCompletionFailedEventArgs args) 180 private void AutoCompletionOnSaveFailed(object sender, AutoCompletionFailedEventArgs args)
175 { 181 {
176 ActivityTextBox.AppendText( 182 ActivityTextBox.AppendText(
177 $"{Strings.Failed_saving_autocomplete_source} : {args.Name} : {args.Exception.Message}{Environment.NewLine}"); 183 $"{Strings.Failed_saving_autocomplete_source} : {args.Name} : {args.Exception.Message}{Environment.NewLine}");
178 } 184 }
179   185  
180 /// <inheritdoc /> 186 /// <inheritdoc />
181 /// <summary> 187 /// <summary>
182 /// Clean up any resources being used. 188 /// Clean up any resources being used.
183 /// </summary> 189 /// </summary>
184 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 190 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
185 protected override void Dispose(bool disposing) 191 protected override void Dispose(bool disposing)
186 { 192 {
187 FormCancellationTokenSource?.Dispose(); 193 FormCancellationTokenSource?.Dispose();
188 FormCancellationTokenSource = null; 194 FormCancellationTokenSource = null;
189   195  
190 if (disposing && components != null) 196 if (disposing && components != null)
191 { 197 {
192 components.Dispose(); 198 components.Dispose();
193 components = null; 199 components = null;
194 } 200 }
195   201  
196 base.Dispose(disposing); 202 base.Dispose(disposing);
197 } 203 }
198   204  
199 private void OnMouseKeyBindingExecuting(object sender, KeyBindingExecutingEventArgs args) 205 private void OnMouseKeyBindingExecuting(object sender, KeyBindingExecutingEventArgs args)
200 { 206 {
201 ActivityTextBox.AppendText( 207 ActivityTextBox.AppendText(
202 $"{Strings.Executing_binding_from_remote_client} : {args.Nick} : {args.Name}{Environment.NewLine}"); 208 $"{Strings.Executing_binding_from_remote_client} : {args.Nick} : {args.Name}{Environment.NewLine}");
203 } 209 }
204   210  
205 private void OnMouseKeyBindingMatched(object sender, KeyBindingMatchedEventArgs args) 211 private void OnMouseKeyBindingMatched(object sender, KeyBindingMatchedEventArgs args)
206 { 212 {
207 ActivityTextBox.AppendText( 213 ActivityTextBox.AppendText(
208 $"{Strings.Matched_remote_key_binding} : {args.Nick} : {args.Name} : {string.Join(" + ", args.KeyCombo)}{Environment.NewLine}"); 214 $"{Strings.Matched_remote_key_binding} : {args.Nick} : {args.Name} : {string.Join(" + ", args.KeyCombo)}{Environment.NewLine}");
209 } 215 }
210   216  
211 private void OnMqttServerClientDisconnected(object sender, MqttClientDisconnectedEventArgs e) 217 private void OnMqttServerClientDisconnected(object sender, MqttClientDisconnectedEventArgs e)
212 { 218 {
213 ActivityTextBox.AppendText( 219 ActivityTextBox.AppendText(
214 $"{Strings.Client_disconnected}{Environment.NewLine}"); 220 $"{Strings.Client_disconnected}{Environment.NewLine}");
215 } 221 }
216   222  
217 private void OnMqttServerClientConnected(object sender, MqttClientConnectedEventArgs e) 223 private void OnMqttServerClientConnected(object sender, MqttClientConnectedEventArgs e)
218 { 224 {
219 ActivityTextBox.AppendText( 225 ActivityTextBox.AppendText(
220 $"{Strings.Client_connected}{Environment.NewLine}"); 226 $"{Strings.Client_connected}{Environment.NewLine}");
221 } 227 }
222   228  
223 private void OnMqttServerStarted(object sender, EventArgs e) 229 private void OnMqttServerStarted(object sender, EventArgs e)
224 { 230 {
225 ActivityTextBox.AppendText( 231 ActivityTextBox.AppendText(
226 $"{Strings.Server_started}{Environment.NewLine}"); 232 $"{Strings.Server_started}{Environment.NewLine}");
227 } 233 }
228   234  
229 private void OnMqttServerStopped(object sender, EventArgs e) 235 private void OnMqttServerStopped(object sender, EventArgs e)
230 { 236 {
231 ActivityTextBox.AppendText( 237 ActivityTextBox.AppendText(
232 $"{Strings.Server_stopped}{Environment.NewLine}"); 238 $"{Strings.Server_stopped}{Environment.NewLine}");
233 } 239 }
234   240  
235 private void OnMqttClientConnected(object sender, MQTTnet.Client.MqttClientConnectedEventArgs e) 241 private void OnMqttClientConnected(object sender, MQTTnet.Client.MqttClientConnectedEventArgs e)
236 { 242 {
237 ActivityTextBox.AppendText( 243 ActivityTextBox.AppendText(
238 $"{Strings.Client_connected}{Environment.NewLine}"); 244 $"{Strings.Client_connected}{Environment.NewLine}");
239 } 245 }
240   246  
241 private void OnMqttClientDisconnected(object sender, MQTTnet.Client.MqttClientDisconnectedEventArgs e) 247 private void OnMqttClientDisconnected(object sender, MQTTnet.Client.MqttClientDisconnectedEventArgs e)
242 { 248 {
243 ActivityTextBox.AppendText( 249 ActivityTextBox.AppendText(
244 $"{Strings.Client_disconnected}{Environment.NewLine}"); 250 $"{Strings.Client_disconnected}{Environment.NewLine}");
245 } 251 }
246   252  
247 private void OnMqttClientConnectionFailed(object sender, MqttManagedProcessFailedEventArgs e) 253 private void OnMqttClientConnectionFailed(object sender, MqttManagedProcessFailedEventArgs e)
248 { 254 {
249 ActivityTextBox.AppendText( 255 ActivityTextBox.AppendText(
250 $"{Strings.Client_connection_failed}{Environment.NewLine}"); 256 $"{Strings.Client_connection_failed}{Environment.NewLine}");
251 } 257 }
252   258  
253 private void OnMqttServerAuthenticationFailed(object sender, MqttAuthenticationFailureEventArgs e) 259 private void OnMqttServerAuthenticationFailed(object sender, MqttAuthenticationFailureEventArgs e)
254 { 260 {
255 ActivityTextBox.AppendText( 261 ActivityTextBox.AppendText(
256 $"{Strings.Failed_to_authenticate_client} : {e.Exception}{Environment.NewLine}"); 262 $"{Strings.Failed_to_authenticate_client} : {e.Exception}{Environment.NewLine}");
257 } 263 }
258   264  
259 private void OnMqttClientAuthenticationFailed(object sender, MqttAuthenticationFailureEventArgs e) 265 private void OnMqttClientAuthenticationFailed(object sender, MqttAuthenticationFailureEventArgs e)
260 { 266 {
261 ActivityTextBox.AppendText( 267 ActivityTextBox.AppendText(
262 $"{Strings.Failed_to_authenticate_with_server} : {e.Exception}{Environment.NewLine}"); 268 $"{Strings.Failed_to_authenticate_with_server} : {e.Exception}{Environment.NewLine}");
263 } 269 }
264   270  
265 private void OnMouseKeyBindingsSynchronized(object sender, KeyBindingsSynchronizerEventArgs e) 271 private void OnMouseKeyBindingsSynchronized(object sender, KeyBindingsSynchronizerEventArgs e)
266 { 272 {
267 ActivityTextBox.AppendText( 273 ActivityTextBox.AppendText(
268 $"{Strings.Synchronized_bindings_with_client} : {e.Bindings.Nick} : {e.Bindings.KeyBindings.Count}{Environment.NewLine}"); 274 $"{Strings.Synchronized_bindings_with_client} : {e.Bindings.Nick} : {e.Bindings.KeyBindings.Count}{Environment.NewLine}");
269   275  
270 var exchangeBindings = KeyBindingsExchange.ExchangeBindings.FirstOrDefault(exchangeBinding => 276 var exchangeBindings = KeyBindingsExchange.ExchangeBindings.FirstOrDefault(exchangeBinding =>
271 string.Equals(exchangeBinding.Nick, e.Bindings.Nick, StringComparison.Ordinal)); 277 string.Equals(exchangeBinding.Nick, e.Bindings.Nick, StringComparison.Ordinal));
272   278  
273 // If the nick does not exist then add it. 279 // If the nick does not exist then add it.
274 if (exchangeBindings == null) 280 if (exchangeBindings == null)
275 { 281 {
276 KeyBindingsExchange.ExchangeBindings.Add(e.Bindings); 282 KeyBindingsExchange.ExchangeBindings.Add(e.Bindings);
277 RemoteBindingsComboBoxSource.ResetBindings(false); 283 RemoteBindingsComboBoxSource.ResetBindings(false);
278 UpdateRemoteItems(); 284 UpdateRemoteItems();
279 return; 285 return;
280 } 286 }
281   287  
282 // If the bindings for the nick have not changed then do not update. 288 // If the bindings for the nick have not changed then do not update.
283 if (exchangeBindings.KeyBindings.SequenceEqual(e.Bindings.KeyBindings)) 289 if (exchangeBindings.KeyBindings.SequenceEqual(e.Bindings.KeyBindings))
284 { 290 {
285 RemoteBindingsComboBoxSource.ResetBindings(false); 291 RemoteBindingsComboBoxSource.ResetBindings(false);
286 UpdateRemoteItems(); 292 UpdateRemoteItems();
287 return; 293 return;
288 } 294 }
289   295  
290 // Update the bindings. 296 // Update the bindings.
291 exchangeBindings.KeyBindings = e.Bindings.KeyBindings; 297 exchangeBindings.KeyBindings = e.Bindings.KeyBindings;
292 RemoteBindingsComboBoxSource.ResetBindings(false); 298 RemoteBindingsComboBoxSource.ResetBindings(false);
293 UpdateRemoteItems(); 299 UpdateRemoteItems();
294 } 300 }
295   301  
296 private void UpdateRemoteItems() 302 private void UpdateRemoteItems()
297 { 303 {
298 var exchangeBindings = (List<KeyBinding>) RemoteBindingsComboBox.SelectedValue; 304 var exchangeBindings = (List<KeyBinding>) RemoteBindingsComboBox.SelectedValue;
299 if (exchangeBindings == null) 305 if (exchangeBindings == null)
300 return; 306 return;
301   307  
302 var replaceMouseBindings = new ObservableCollection<RemoteKeyBinding>(); 308 var replaceMouseBindings = new ObservableCollection<RemoteKeyBinding>();
303 foreach (var remoteBinding in RemoteKeyBindings.Bindings) 309 foreach (var remoteBinding in RemoteKeyBindings.Bindings)
304 { 310 {
305 if (!exchangeBindings.Any(binding => 311 if (!exchangeBindings.Any(binding =>
306 string.Equals(binding.Name, remoteBinding.Name, StringComparison.Ordinal))) 312 string.Equals(binding.Name, remoteBinding.Name, StringComparison.Ordinal)))
307 continue; 313 continue;
308   314  
309 replaceMouseBindings.Add(remoteBinding); 315 replaceMouseBindings.Add(remoteBinding);
310 } 316 }
311   317  
312 RemoteKeyBindings.Bindings.Clear(); 318 RemoteKeyBindings.Bindings.Clear();
313 foreach (var binding in replaceMouseBindings) RemoteKeyBindings.Bindings.Add(binding); 319 foreach (var binding in replaceMouseBindings) RemoteKeyBindings.Bindings.Add(binding);
314   320  
315 RemoteBindingsListBox.Items.Clear(); 321 RemoteBindingsListBox.Items.Clear();
316 RemoteBindingsListBox.DisplayMember = "Name"; 322 RemoteBindingsListBox.DisplayMember = "Name";
317 RemoteBindingsListBox.ValueMember = "Name"; 323 RemoteBindingsListBox.ValueMember = "Name";
318 var bindings = exchangeBindings.Select(binding => (object) binding.Name).ToArray(); 324 var bindings = exchangeBindings.Select(binding => (object) binding.Name).ToArray();
319 if (bindings.Length == 0) 325 if (bindings.Length == 0)
320 return; 326 return;
321   327  
322 RemoteBindingsListBox.Items.AddRange(bindings); 328 RemoteBindingsListBox.Items.AddRange(bindings);
323 } 329 }
324   330  
325 private void OnLobbyMessageReceived(object sender, LobbyMessageReceivedEventArgs e) 331 private void OnLobbyMessageReceived(object sender, LobbyMessageReceivedEventArgs e)
326 { 332 {
327 notifyIcon1.BalloonTipTitle = Strings.Lobby_message; 333 notifyIcon1.BalloonTipTitle = Strings.Lobby_message;
328 notifyIcon1.BalloonTipText = $"{e.Nick} : {e.Message}{Environment.NewLine}"; 334 notifyIcon1.BalloonTipText = $"{e.Nick} : {e.Message}{Environment.NewLine}";
329 notifyIcon1.ShowBalloonTip(1000); 335 notifyIcon1.ShowBalloonTip(1000);
330   336  
331 LobbyTextBox.AppendText($"{e.Nick} : {e.Message}{Environment.NewLine}"); 337 LobbyTextBox.AppendText($"{e.Nick} : {e.Message}{Environment.NewLine}");
332 } 338 }
333   339  
334 private void AddressTextBoxClick(object sender, EventArgs e) 340 private void AddressTextBoxClick(object sender, EventArgs e)
335 { 341 {
336 Address.BackColor = Color.Empty; 342 Address.BackColor = Color.Empty;
337 } 343 }
338   344  
339 private void PortTextBoxClick(object sender, EventArgs e) 345 private void PortTextBoxClick(object sender, EventArgs e)
340 { 346 {
341 Port.BackColor = Color.Empty; 347 Port.BackColor = Color.Empty;
342 } 348 }
343   349  
344 private async void HostButtonClickAsync(object sender, EventArgs e) 350 private async void HostButtonClickAsync(object sender, EventArgs e)
345 { 351 {
346 // Stop the MQTT server if it is running. 352 // Stop the MQTT server if it is running.
347 if (MqttCommunication.Running) 353 if (MqttCommunication.Running)
348 { 354 {
349 await MqttCommunication.Stop(); 355 await MqttCommunication.Stop();
350 HostButton.BackColor = Color.Empty; 356 HostButton.BackColor = Color.Empty;
351   357  
352 // Enable controls. 358 // Enable controls.
353 ConnectButton.Enabled = true; 359 ConnectButton.Enabled = true;
354 Address.Enabled = true; 360 Address.Enabled = true;
355 Port.Enabled = true; 361 Port.Enabled = true;
356 Nick.Enabled = true; 362 Nick.Enabled = true;
357 Password.Enabled = true; 363 Password.Enabled = true;
358 return; 364 return;
359 } 365 }
360   366  
361 if (!ValidateConnectionParameters(out var ipAddress, out var port, out var nick, out var password)) 367 if (!ValidateConnectionParameters(out var ipAddress, out var port, out var nick, out var password))
362 return; 368 return;
363   369  
364 StoreConnectionAutocomplete(); 370 StoreConnectionAutocomplete();
365   371  
366 // Try to reserve port: try UPnP followed by PMP. 372 // Try to reserve port: try UPnP followed by PMP.
367 if (!await Discovery.CreateMapping(DiscoveryType.UPnP, port) && 373 if (!await Discovery.CreateMapping(DiscoveryType.UPnP, port) &&
368 !await Discovery.CreateMapping(DiscoveryType.PMP, port)) 374 !await Discovery.CreateMapping(DiscoveryType.PMP, port))
369 ActivityTextBox.AppendText( 375 ActivityTextBox.AppendText(
370 $"{Strings.Failed_creating_automatic_port_mapping_please_make_sure_the_port_is_routed_properly}{Environment.NewLine}"); 376 $"{Strings.Failed_creating_automatic_port_mapping_please_make_sure_the_port_is_routed_properly}{Environment.NewLine}");
371   377  
372 // Start the MQTT server. 378 // Start the MQTT server.
373 if (!await MqttCommunication 379 if (!await MqttCommunication
374 .Start(MqttCommunicationType.Server, ipAddress, port, nick, password)) 380 .Start(MqttCommunicationType.Server, ipAddress, port, nick, password))
375 { 381 {
376 ActivityTextBox.AppendText( 382 ActivityTextBox.AppendText(
377 $"{Strings.Failed_starting_server}{Environment.NewLine}"); 383 $"{Strings.Failed_starting_server}{Environment.NewLine}");
378 return; 384 return;
379 } 385 }
380   386  
381 HostButton.BackColor = Color.Aquamarine; 387 HostButton.BackColor = Color.Aquamarine;
382   388  
383 // Disable controls 389 // Disable controls
384 ConnectButton.Enabled = false; 390 ConnectButton.Enabled = false;
385 Address.Enabled = false; 391 Address.Enabled = false;
386 Port.Enabled = false; 392 Port.Enabled = false;
387 Nick.Enabled = false; 393 Nick.Enabled = false;
388 Password.Enabled = false; 394 Password.Enabled = false;
389 } 395 }
390   396  
391 private async void StoreConnectionAutocomplete() 397 private async void StoreConnectionAutocomplete()
392 { 398 {
393 Address.AutoCompleteCustomSource.Add(Address.Text); 399 Address.AutoCompleteCustomSource.Add(Address.Text);
394   400  
395 await AutoCompletion.Save(Address.Name, Address.AutoCompleteCustomSource); 401 await AutoCompletion.Save(Address.Name, Address.AutoCompleteCustomSource);
396   402  
397 Port.AutoCompleteCustomSource.Add(Port.Text); 403 Port.AutoCompleteCustomSource.Add(Port.Text);
398   404  
399 await AutoCompletion.Save(Port.Name, Port.AutoCompleteCustomSource); 405 await AutoCompletion.Save(Port.Name, Port.AutoCompleteCustomSource);
400   406  
401 Nick.AutoCompleteCustomSource.Add(Nick.Text); 407 Nick.AutoCompleteCustomSource.Add(Nick.Text);
402   408  
403 await AutoCompletion.Save(Nick.Name, Nick.AutoCompleteCustomSource); 409 await AutoCompletion.Save(Nick.Name, Nick.AutoCompleteCustomSource);
404 } 410 }
405   411  
406 private bool ValidateConnectionParameters( 412 private bool ValidateConnectionParameters(
407 out IPAddress address, 413 out IPAddress address,
408 out int port, 414 out int port,
409 out string nick, 415 out string nick,
410 out string password) 416 out string password)
411 { 417 {
412 address = IPAddress.Any; 418 address = IPAddress.Any;
413 port = 0; 419 port = 0;
414 nick = string.Empty; 420 nick = string.Empty;
415 password = string.Empty; 421 password = string.Empty;
416   422  
417 if (string.IsNullOrEmpty(Address.Text) && 423 if (string.IsNullOrEmpty(Address.Text) &&
418 string.IsNullOrEmpty(Port.Text) && 424 string.IsNullOrEmpty(Port.Text) &&
419 string.IsNullOrEmpty(Nick.Text) && 425 string.IsNullOrEmpty(Nick.Text) &&
420 string.IsNullOrEmpty(Password.Text)) 426 string.IsNullOrEmpty(Password.Text))
421 { 427 {
422 Address.BackColor = Color.LightPink; 428 Address.BackColor = Color.LightPink;
423 Port.BackColor = Color.LightPink; 429 Port.BackColor = Color.LightPink;
424 Nick.BackColor = Color.LightPink; 430 Nick.BackColor = Color.LightPink;
425 Password.BackColor = Color.LightPink; 431 Password.BackColor = Color.LightPink;
426 return false; 432 return false;
427 } 433 }
428   434  
429 if (!IPAddress.TryParse(Address.Text, out address)) 435 if (!IPAddress.TryParse(Address.Text, out address))
430 try 436 try
431 { 437 {
432 address = Dns.GetHostAddresses(Address.Text).FirstOrDefault(); 438 address = Dns.GetHostAddresses(Address.Text).FirstOrDefault();
433 } 439 }
434 catch (Exception ex) 440 catch (Exception ex)
435 { 441 {
436 ActivityTextBox.AppendText( 442 ActivityTextBox.AppendText(
437 $"{Strings.Could_not_resolve_hostname} : {ex.Message}{Environment.NewLine}"); 443 $"{Strings.Could_not_resolve_hostname} : {ex.Message}{Environment.NewLine}");
438   444  
439 Address.BackColor = Color.LightPink; 445 Address.BackColor = Color.LightPink;
440 return false; 446 return false;
441 } 447 }
442   448  
443 if (!uint.TryParse(Port.Text, out var uPort)) 449 if (!uint.TryParse(Port.Text, out var uPort))
444 { 450 {
445 Port.BackColor = Color.LightPink; 451 Port.BackColor = Color.LightPink;
446 return false; 452 return false;
447 } 453 }
448   454  
449 port = (int) uPort; 455 port = (int) uPort;
450   456  
451 if (string.IsNullOrEmpty(Nick.Text)) 457 if (string.IsNullOrEmpty(Nick.Text))
452 { 458 {
453 Nick.BackColor = Color.LightPink; 459 Nick.BackColor = Color.LightPink;
454 return false; 460 return false;
455 } 461 }
456   462  
457 nick = Nick.Text; 463 nick = Nick.Text;
458   464  
459 if (string.IsNullOrEmpty(Password.Text)) 465 if (string.IsNullOrEmpty(Password.Text))
460 { 466 {
461 Password.BackColor = Color.LightPink; 467 Password.BackColor = Color.LightPink;
462 return false; 468 return false;
463 } 469 }
464   470  
465 password = AES.ExpandKey(Password.Text); 471 password = AES.ExpandKey(Password.Text);
466   472  
467 Address.BackColor = Color.Empty; 473 Address.BackColor = Color.Empty;
468 Port.BackColor = Color.Empty; 474 Port.BackColor = Color.Empty;
469 Nick.BackColor = Color.Empty; 475 Nick.BackColor = Color.Empty;
470 Password.BackColor = Color.Empty; 476 Password.BackColor = Color.Empty;
471   477  
472 return true; 478 return true;
473 } 479 }
474   480  
475 private async void ConnectButtonClickAsync(object sender, EventArgs e) 481 private async void ConnectButtonClickAsync(object sender, EventArgs e)
476 { 482 {
477 if (MqttCommunication.Running) 483 if (MqttCommunication.Running)
478 { 484 {
479 await MqttCommunication.Stop(); 485 await MqttCommunication.Stop();
480 ConnectButton.Text = Strings.Connect; 486 ConnectButton.Text = Strings.Connect;
481 ConnectButton.BackColor = Color.Empty; 487 ConnectButton.BackColor = Color.Empty;
482   488  
483 Address.Enabled = true; 489 Address.Enabled = true;
484 Port.Enabled = true; 490 Port.Enabled = true;
485 Nick.Enabled = true; 491 Nick.Enabled = true;
486 Password.Enabled = true; 492 Password.Enabled = true;
487 HostButton.Enabled = true; 493 HostButton.Enabled = true;
488 return; 494 return;
489 } 495 }
490   496  
491 if (!ValidateConnectionParameters(out var ipAddress, out var port, out var nick, out var password)) 497 if (!ValidateConnectionParameters(out var ipAddress, out var port, out var nick, out var password))
492 return; 498 return;
493   499  
494 StoreConnectionAutocomplete(); 500 StoreConnectionAutocomplete();
495   501  
496 if (!await MqttCommunication 502 if (!await MqttCommunication
497 .Start(MqttCommunicationType.Client, ipAddress, port, nick, password)) 503 .Start(MqttCommunicationType.Client, ipAddress, port, nick, password))
498 { 504 {
499 ActivityTextBox.AppendText( 505 ActivityTextBox.AppendText(
500 $"{Strings.Failed_starting_client}{Environment.NewLine}"); 506 $"{Strings.Failed_starting_client}{Environment.NewLine}");
501 return; 507 return;
502 } 508 }
503   509  
504 ConnectButton.Text = Strings.Disconnect; 510 ConnectButton.Text = Strings.Disconnect;
505 ConnectButton.BackColor = Color.Aquamarine; 511 ConnectButton.BackColor = Color.Aquamarine;
506   512  
507 HostButton.Enabled = false; 513 HostButton.Enabled = false;
508 Address.Enabled = false; 514 Address.Enabled = false;
509 Port.Enabled = false; 515 Port.Enabled = false;
510 Nick.Enabled = false; 516 Nick.Enabled = false;
511 Password.Enabled = false; 517 Password.Enabled = false;
512 } 518 }
513   519  
514 private async void LobbySayTextBoxKeyDown(object sender, KeyEventArgs e) 520 private async void LobbySayTextBoxKeyDown(object sender, KeyEventArgs e)
515 { 521 {
516 // Do not send messages if the communication is not running. 522 // Do not send messages if the communication is not running.
517 if (!MqttCommunication.Running) 523 if (!MqttCommunication.Running)
518 return; 524 return;
519   525  
520 if (e.KeyCode != Keys.Enter) 526 if (e.KeyCode != Keys.Enter)
521 return; 527 return;
522   528  
523 await LobbyMessageSynchronizer.Broadcast(LobbySayTextBox.Text); 529 await LobbyMessageSynchronizer.Broadcast(LobbySayTextBox.Text);
524   530  
525 LobbySayTextBox.Text = string.Empty; 531 LobbySayTextBox.Text = string.Empty;
526 } 532 }
527   533  
528 private void LocalAddBindingButtonClick(object sender, EventArgs e) 534 private void LocalAddBindingButtonClick(object sender, EventArgs e)
529 { 535 {
530 if (string.IsNullOrEmpty(LocalNameTextBox.Text)) 536 if (string.IsNullOrEmpty(LocalNameTextBox.Text))
531 { 537 {
532 LocalNameTextBox.BackColor = Color.LightPink; 538 LocalNameTextBox.BackColor = Color.LightPink;
533 return; 539 return;
534 } 540 }
535   541  
536 // Only unique names allowed. 542 // Only unique names allowed.
537 if (LocalKeyBindings.Bindings.Any(binding => 543 if (LocalKeyBindings.Bindings.Any(binding =>
538 string.Equals(binding.Name, LocalNameTextBox.Text, StringComparison.Ordinal))) 544 string.Equals(binding.Name, LocalNameTextBox.Text, StringComparison.Ordinal)))
539 { 545 {
540 LocalNameTextBox.BackColor = Color.LightPink; 546 LocalNameTextBox.BackColor = Color.LightPink;
541 LocalBindingsCheckedListBox.BackColor = Color.LightPink; 547 LocalBindingsCheckedListBox.BackColor = Color.LightPink;
542 return; 548 return;
543 } 549 }
544   550  
545 LocalNameTextBox.BackColor = Color.Empty; 551 LocalNameTextBox.BackColor = Color.Empty;
546 LocalBindingsCheckedListBox.BackColor = Color.Empty; 552 LocalBindingsCheckedListBox.BackColor = Color.Empty;
547   553  
548 ShowOverlayPanel(); 554 ShowOverlayPanel();
549   555  
550 MouseKeyCombo = new List<string>(); 556 MouseKeyCombo = new List<string>();
551   557  
552 MouseKeyApplicationHook = Hook.GlobalEvents(); 558 MouseKeyApplicationHook = Hook.GlobalEvents();
553 MouseKeyApplicationHook.KeyUp += LocalMouseKeyHookOnKeyUp; 559 MouseKeyApplicationHook.KeyUp += LocalMouseKeyHookOnKeyUp;
554 MouseKeyApplicationHook.KeyDown += LocalMouseKeyHookOnKeyDown; 560 MouseKeyApplicationHook.KeyDown += LocalMouseKeyHookOnKeyDown;
555 } 561 }
556   562  
557 private void ShowOverlayPanel() 563 private void ShowOverlayPanel()
558 { 564 {
559 OverlayPanel.BringToFront(); 565 OverlayPanel.BringToFront();
560 OverlayPanel.Visible = true; 566 OverlayPanel.Visible = true;
561 OverlayPanel.Invalidate(); 567 OverlayPanel.Invalidate();
562 } 568 }
563   569  
564 private async void LocalMouseKeyHookOnKeyUp(object sender, KeyEventArgs e) 570 private async void LocalMouseKeyHookOnKeyUp(object sender, KeyEventArgs e)
565 { 571 {
566 LocalKeyBindings.Bindings.Add(new KeyBinding(LocalNameTextBox.Text, MouseKeyCombo)); 572 LocalKeyBindings.Bindings.Add(new KeyBinding(LocalNameTextBox.Text, MouseKeyCombo));
567   573  
568 LocalCheckedListBoxBindingSource.ResetBindings(false); 574 LocalCheckedListBoxBindingSource.ResetBindings(false);
569   575  
570 MouseKeyApplicationHook.KeyDown -= LocalMouseKeyHookOnKeyDown; 576 MouseKeyApplicationHook.KeyDown -= LocalMouseKeyHookOnKeyDown;
571 MouseKeyApplicationHook.KeyUp -= LocalMouseKeyHookOnKeyUp; 577 MouseKeyApplicationHook.KeyUp -= LocalMouseKeyHookOnKeyUp;
572   578  
573 MouseKeyApplicationHook.Dispose(); 579 MouseKeyApplicationHook.Dispose();
574   580  
575 LocalNameTextBox.Text = string.Empty; 581 LocalNameTextBox.Text = string.Empty;
576 HideOverlayPanel(); 582 HideOverlayPanel();
577   583  
578 await SaveLocalMouseKeyBindings(); 584 await SaveLocalMouseKeyBindings();
579 } 585 }
580   586  
581 private void HideOverlayPanel() 587 private void HideOverlayPanel()
582 { 588 {
583 OverlayPanel.SendToBack(); 589 OverlayPanel.SendToBack();
584 OverlayPanel.Visible = false; 590 OverlayPanel.Visible = false;
585 OverlayPanel.Invalidate(); 591 OverlayPanel.Invalidate();
586 } 592 }
587   593  
588 private void LocalMouseKeyHookOnKeyDown(object sender, KeyEventArgs e) 594 private void LocalMouseKeyHookOnKeyDown(object sender, KeyEventArgs e)
589 { 595 {
590 e.SuppressKeyPress = true; 596 e.SuppressKeyPress = true;
591   597  
592 KeyConversion.KeysToString.TryGetValue((byte) e.KeyCode, out var key); 598 KeyConversion.KeysToString.TryGetValue((byte) e.KeyCode, out var key);
593   599  
594 MouseKeyCombo.Add(key); 600 MouseKeyCombo.Add(key);
595 } 601 }
596   602  
597 private void LocalNameTextBoxClick(object sender, EventArgs e) 603 private void LocalNameTextBoxClick(object sender, EventArgs e)
598 { 604 {
599 LocalNameTextBox.BackColor = Color.Empty; 605 LocalNameTextBox.BackColor = Color.Empty;
600 } 606 }
601   607  
602 private async void LocalBindingsRemoveButtonClick(object sender, EventArgs e) 608 private async void LocalBindingsRemoveButtonClick(object sender, EventArgs e)
603 { 609 {
604 var helmBinding = (KeyBinding) LocalBindingsCheckedListBox.SelectedItem; 610 var helmBinding = (KeyBinding) LocalBindingsCheckedListBox.SelectedItem;
605 if (helmBinding == null) 611 if (helmBinding == null)
606 return; 612 return;
607   613  
608 LocalKeyBindings.Bindings.Remove(helmBinding); 614 LocalKeyBindings.Bindings.Remove(helmBinding);
609 LocalCheckedListBoxBindingSource.ResetBindings(false); 615 LocalCheckedListBoxBindingSource.ResetBindings(false);
610   616  
611 await SaveLocalMouseKeyBindings(); 617 await SaveLocalMouseKeyBindings();
612 } 618 }
613   619  
614 private async void LobbySayButtonClick(object sender, EventArgs e) 620 private async void LobbySayButtonClick(object sender, EventArgs e)
615 { 621 {
616 // Do not send messages if the communication is not running. 622 // Do not send messages if the communication is not running.
617 if (!MqttCommunication.Running) 623 if (!MqttCommunication.Running)
618 return; 624 return;
619   625  
620 await LobbyMessageSynchronizer.Broadcast(LobbySayTextBox.Text); 626 await LobbyMessageSynchronizer.Broadcast(LobbySayTextBox.Text);
621   627  
622 LobbySayTextBox.Text = string.Empty; 628 LobbySayTextBox.Text = string.Empty;
623 } 629 }
624   630  
625 private void RemoteBindingsComboBoxSelectionChangeCompleted(object sender, EventArgs e) 631 private void RemoteBindingsComboBoxSelectionChangeCompleted(object sender, EventArgs e)
626 { 632 {
627 UpdateRemoteItems(); 633 UpdateRemoteItems();
628 } 634 }
629   635  
630 private async void WingManFormOnLoad(object sender, EventArgs e) 636 private async void WingManFormOnLoad(object sender, EventArgs e)
631 { 637 {
632 await LoadLocalMouseKeyBindings(); 638 await LoadLocalMouseKeyBindings();
633   639  
634 await LoadRemoteMouseKeyBindings(); 640 await LoadRemoteMouseKeyBindings();
635 } 641 }
636   642  
637 private void RemoteBindingsBindButtonClicked(object sender, EventArgs e) 643 private void RemoteBindingsBindButtonClicked(object sender, EventArgs e)
638 { 644 {
639 if (string.IsNullOrEmpty((string) RemoteBindingsListBox.SelectedItem)) 645 if (string.IsNullOrEmpty((string) RemoteBindingsListBox.SelectedItem))
640 { 646 {
641 RemoteBindingsListBox.BackColor = Color.LightPink; 647 RemoteBindingsListBox.BackColor = Color.LightPink;
642 return; 648 return;
643 } 649 }
644   650  
645 RemoteBindingsListBox.BackColor = Color.Empty; 651 RemoteBindingsListBox.BackColor = Color.Empty;
646   652  
647 ShowOverlayPanel(); 653 ShowOverlayPanel();
648   654  
649 MouseKeyCombo = new List<string>(); 655 MouseKeyCombo = new List<string>();
650   656  
651 MouseKeyApplicationHook = Hook.GlobalEvents(); 657 MouseKeyApplicationHook = Hook.GlobalEvents();
652 MouseKeyApplicationHook.KeyUp += RemoteKeyHookOnKeyUp; 658 MouseKeyApplicationHook.KeyUp += RemoteKeyHookOnKeyUp;
653 MouseKeyApplicationHook.KeyDown += RemoteKeyHookOnKeyDown; 659 MouseKeyApplicationHook.KeyDown += RemoteKeyHookOnKeyDown;
654 } 660 }
655   661  
656 private void RemoteBindingsUnbindButtonClicked(object sender, EventArgs e) 662 private void RemoteBindingsUnbindButtonClicked(object sender, EventArgs e)
657 { 663 {
658 var item = (string) RemoteBindingsListBox.SelectedItem; 664 var item = (string) RemoteBindingsListBox.SelectedItem;
659 if (string.IsNullOrEmpty(item)) 665 if (string.IsNullOrEmpty(item))
660 { 666 {
661 RemoteBindingsListBox.BackColor = Color.LightPink; 667 RemoteBindingsListBox.BackColor = Color.LightPink;
662 return; 668 return;
663 } 669 }
664   670  
665 RemoteBindingsListBox.BackColor = Color.Empty; 671 RemoteBindingsListBox.BackColor = Color.Empty;
666   672  
667 var remoteKeyBinding = RemoteKeyBindings.Bindings.FirstOrDefault(binding => 673 var remoteKeyBinding = RemoteKeyBindings.Bindings.FirstOrDefault(binding =>
668 string.Equals(binding.Name, item, StringComparison.Ordinal)); 674 string.Equals(binding.Name, item, StringComparison.Ordinal));
669   675  
670 if (remoteKeyBinding == null) 676 if (remoteKeyBinding == null)
671 return; 677 return;
672   678  
673 RemoteKeyBindings.Bindings.Remove(remoteKeyBinding); 679 RemoteKeyBindings.Bindings.Remove(remoteKeyBinding);
674 RemoteBindingsBindToBox.Text = string.Empty; 680 RemoteBindingsBindToBox.Text = string.Empty;
675 } 681 }
676   682  
677 private void RemoteKeyHookOnKeyDown(object sender, KeyEventArgs e) 683 private void RemoteKeyHookOnKeyDown(object sender, KeyEventArgs e)
678 { 684 {
679 e.SuppressKeyPress = true; 685 e.SuppressKeyPress = true;
680   686  
681 if (!KeyConversion.KeysToString.TryGetValue((byte) e.KeyCode, out var key)) 687 if (!KeyConversion.KeysToString.TryGetValue((byte) e.KeyCode, out var key))
682 return; 688 return;
683   689  
684 MouseKeyCombo.Add(key); 690 MouseKeyCombo.Add(key);
685 } 691 }
686   692  
687 private async void RemoteKeyHookOnKeyUp(object sender, KeyEventArgs e) 693 private async void RemoteKeyHookOnKeyUp(object sender, KeyEventArgs e)
688 { 694 {
689 RemoteKeyBindings.Bindings.Add(new RemoteKeyBinding(RemoteBindingsComboBox.Text, 695 RemoteKeyBindings.Bindings.Add(new RemoteKeyBinding(RemoteBindingsComboBox.Text,
690 (string) RemoteBindingsListBox.SelectedItem, MouseKeyCombo)); 696 (string) RemoteBindingsListBox.SelectedItem, MouseKeyCombo));
691   697  
692 MouseKeyApplicationHook.KeyDown -= RemoteKeyHookOnKeyDown; 698 MouseKeyApplicationHook.KeyDown -= RemoteKeyHookOnKeyDown;
693 MouseKeyApplicationHook.KeyUp -= RemoteKeyHookOnKeyUp; 699 MouseKeyApplicationHook.KeyUp -= RemoteKeyHookOnKeyUp;
694   700  
695 MouseKeyApplicationHook.Dispose(); 701 MouseKeyApplicationHook.Dispose();
696   702  
697 RemoteBindingsBindToBox.Text = string.Join(" + ", MouseKeyCombo); 703 RemoteBindingsBindToBox.Text = string.Join(" + ", MouseKeyCombo);
698 HideOverlayPanel(); 704 HideOverlayPanel();
699   705  
700 await SaveRemoteMouseKeyBindings(); 706 await SaveRemoteMouseKeyBindings();
701 } 707 }
702   708  
703 private void RemoteBindingsListBoxSelectedValueChanged(object sender, EventArgs e) 709 private void RemoteBindingsListBoxSelectedValueChanged(object sender, EventArgs e)
704 { 710 {
705 RemoteBindingsBindToBox.Text = ""; 711 RemoteBindingsBindToBox.Text = "";
706   712  
707 var name = (string) RemoteBindingsListBox.SelectedItem; 713 var name = (string) RemoteBindingsListBox.SelectedItem;
708 if (string.IsNullOrEmpty(name)) 714 if (string.IsNullOrEmpty(name))
709 return; 715 return;
710   716  
711 var nick = RemoteBindingsComboBox.Text; 717 var nick = RemoteBindingsComboBox.Text;
712 if (string.IsNullOrEmpty(nick)) 718 if (string.IsNullOrEmpty(nick))
713 return; 719 return;
714   720  
715 foreach (var binding in RemoteKeyBindings.Bindings) 721 foreach (var binding in RemoteKeyBindings.Bindings)
716 { 722 {
717 if (!string.Equals(binding.Nick, nick) || !string.Equals(binding.Name, name)) 723 if (!string.Equals(binding.Nick, nick) || !string.Equals(binding.Name, name))
718 continue; 724 continue;
719   725  
720 RemoteBindingsBindToBox.Text = string.Join(" + ", binding.Keys); 726 RemoteBindingsBindToBox.Text = string.Join(" + ", binding.Keys);
721 break; 727 break;
722 } 728 }
723 } 729 }
724   730  
725 private void WingManFormResized(object sender, EventArgs e) 731 private void WingManFormResized(object sender, EventArgs e)
726 { 732 {
727 if (WindowState == FormWindowState.Minimized) Hide(); 733 if (WindowState == FormWindowState.Minimized) Hide();
728 } 734 }
729   735  
730 private void NotifyIconDoubleClick(object sender, EventArgs e) 736 private void NotifyIconDoubleClick(object sender, EventArgs e)
731 { 737 {
732 Show(); 738 Show();
733 WindowState = FormWindowState.Normal; 739 WindowState = FormWindowState.Normal;
734 } 740 }
735   741  
736 private async void LocalBindingsCheckedListBoxItemCheck(object sender, ItemCheckEventArgs e) 742 private async void LocalBindingsCheckedListBoxItemCheck(object sender, ItemCheckEventArgs e)
737 { 743 {
738 var helmBinding = (KeyBinding) LocalBindingsCheckedListBox.Items[e.Index]; 744 var helmBinding = (KeyBinding) LocalBindingsCheckedListBox.Items[e.Index];
739 if (helmBinding == null) 745 if (helmBinding == null)
740 return; 746 return;
741   747  
742 switch (e.NewValue) 748 switch (e.NewValue)
743 { 749 {
744 case CheckState.Checked: 750 case CheckState.Checked:
745 helmBinding.Enabled = true; 751 helmBinding.Enabled = true;
746 break; 752 break;
747 case CheckState.Unchecked: 753 case CheckState.Unchecked:
748 helmBinding.Enabled = false; 754 helmBinding.Enabled = false;
749 break; 755 break;
750 } 756 }
751   757  
752 await SaveLocalMouseKeyBindings(); 758 await SaveLocalMouseKeyBindings();
753 } 759 }
-   760  
-   761 private void WingManTabControlMouseDown(object sender, MouseEventArgs e)
-   762 {
-   763 if (e.Button != MouseButtons.Left) return;
-   764  
-   765 tabControlClickStartPosition = e.Location;
-   766 }
-   767  
-   768 private void WingManTabControlMouseMove(object sender, MouseEventArgs e)
-   769 {
-   770 if (e.Button == MouseButtons.Left)
-   771 {
-   772 var mouseOffsetX = tabControlClickStartPosition.X - e.X;
-   773 var mouseOffsetY = tabControlClickStartPosition.Y - e.Y;
-   774  
-   775 if (mouseOffsetX <= tabControlDetachPixelOffset && mouseOffsetY <= tabControlDetachPixelOffset)
-   776 return;
-   777  
-   778 tabControl1.DoDragDrop(tabControl1.SelectedTab, DragDropEffects.Move);
-   779 tabControlClickStartPosition = new Point();
-   780  
-   781 return;
-   782 }
-   783  
-   784 tabControlClickStartPosition = new Point();
-   785 }
-   786  
-   787 private void WingManTabControlGiveFeedback(object sender, GiveFeedbackEventArgs e)
-   788 {
-   789 e.UseDefaultCursors = false;
-   790 }
-   791  
-   792 private void WingManTabControlQueryContinueDrag(object sender, QueryContinueDragEventArgs e)
-   793 {
-   794 if (MouseButtons != MouseButtons.Left)
-   795 {
-   796 e.Action = DragAction.Cancel;
-   797  
-   798 DetachedForm = new Form
-   799 {
-   800 Size = new Size(
-   801 // Width = tab control width + tab control left and right margins + x-padding
-   802 tabControl1.Width +
-   803 tabControl1.Margin.Right +
-   804 tabControl1.Margin.Left +
-   805 tabControl1.Padding.X,
-   806 // Tab Height = tab control height - tab control tab page height
-   807 // Height = tab control height + Tab Height + top and bottom margin + x-padding
-   808 2 * tabControl1.Height -
-   809 tabControl1.SelectedTab.Height +
-   810 tabControl1.Margin.Top +
-   811 tabControl1.Margin.Bottom +
-   812 tabControl1.Padding.Y),
-   813 StartPosition = FormStartPosition.Manual,
-   814 Location = MousePosition,
-   815 MaximizeBox = false,
-   816 SizeGripStyle = SizeGripStyle.Hide,
-   817 FormBorderStyle = FormBorderStyle.FixedSingle
-   818 };
-   819  
-   820 DetachedTabControl = new TabControl
-   821 {
-   822 Dock = DockStyle.Fill,
-   823 SizeMode = TabSizeMode.Fixed
-   824 };
-   825 DetachedTabControl.TabPages.Add(tabControl1.SelectedTab);
-   826 DetachedForm.Controls.Add(DetachedTabControl);
-   827 DetachedForm.FormClosing += DetachedFormOnFormClosing;
-   828 DetachedForm.Show();
-   829 Cursor = Cursors.Default;
-   830 return;
-   831 }
-   832  
-   833 e.Action = DragAction.Continue;
-   834 Cursor = Cursors.SizeAll;
-   835 }
-   836  
-   837 private void DetachedFormOnFormClosing(object sender, FormClosingEventArgs e)
-   838 {
-   839 tabControl1.TabPages.Insert(DetachedTabControl.SelectedTab.TabIndex, DetachedTabControl.SelectedTab);
-   840 DetachedForm.FormClosing -= DetachedFormOnFormClosing;
-   841 }
754   842  
755 #region Saving and loading 843 #region Saving and loading
756   844  
757 private async Task SaveLocalMouseKeyBindings() 845 private async Task SaveLocalMouseKeyBindings()
758 { 846 {
759 try 847 try
760 { 848 {
761 using (var memoryStream = new MemoryStream()) 849 using (var memoryStream = new MemoryStream())
762 { 850 {
763 LocalKeyBindings.XmlSerializer.Serialize(memoryStream, LocalKeyBindings); 851 LocalKeyBindings.XmlSerializer.Serialize(memoryStream, LocalKeyBindings);
764   852  
765 memoryStream.Position = 0L; 853 memoryStream.Position = 0L;
766   854  
767 using (var fileStream = new FileStream("LocalKeyBindings.xml", FileMode.Create)) 855 using (var fileStream = new FileStream("LocalKeyBindings.xml", FileMode.Create))
768 { 856 {
769 await memoryStream.CopyToAsync(fileStream); 857 await memoryStream.CopyToAsync(fileStream);
770 } 858 }
771 } 859 }
772 } 860 }
773 catch (Exception) 861 catch (Exception)
774 { 862 {
775 ActivityTextBox.AppendText( 863 ActivityTextBox.AppendText(
776 $"{Strings.Failed_saving_local_bindings}{Environment.NewLine}"); 864 $"{Strings.Failed_saving_local_bindings}{Environment.NewLine}");
777 } 865 }
778 } 866 }
779   867  
780 private async Task LoadLocalMouseKeyBindings() 868 private async Task LoadLocalMouseKeyBindings()
781 { 869 {
782 try 870 try
783 { 871 {
784 using (var fileStream = new FileStream("LocalKeyBindings.xml", FileMode.Open)) 872 using (var fileStream = new FileStream("LocalKeyBindings.xml", FileMode.Open))
785 { 873 {
786 using (var memoryStream = new MemoryStream()) 874 using (var memoryStream = new MemoryStream())
787 { 875 {
788 await fileStream.CopyToAsync(memoryStream); 876 await fileStream.CopyToAsync(memoryStream);
789   877  
790 memoryStream.Position = 0L; 878 memoryStream.Position = 0L;
791   879  
792 var loadedBindings = 880 var loadedBindings =
793 (LocalKeyBindings) LocalKeyBindings.XmlSerializer.Deserialize(memoryStream); 881 (LocalKeyBindings) LocalKeyBindings.XmlSerializer.Deserialize(memoryStream);
794   882  
795 foreach (var binding in loadedBindings.Bindings) 883 foreach (var binding in loadedBindings.Bindings)
796 LocalKeyBindings.Bindings.Add(binding); 884 LocalKeyBindings.Bindings.Add(binding);
797   885  
798   886  
799 LocalCheckedListBoxBindingSource.ResetBindings(false); 887 LocalCheckedListBoxBindingSource.ResetBindings(false);
800 } 888 }
801 } 889 }
802 } 890 }
803 catch (Exception) 891 catch (Exception)
804 { 892 {
805 ActivityTextBox.AppendText( 893 ActivityTextBox.AppendText(
806 $"{Strings.Failed_loading_local_bindings}{Environment.NewLine}"); 894 $"{Strings.Failed_loading_local_bindings}{Environment.NewLine}");
807 } 895 }
808 } 896 }
809   897  
810 private async Task SaveRemoteMouseKeyBindings() 898 private async Task SaveRemoteMouseKeyBindings()
811 { 899 {
812 try 900 try
813 { 901 {
814 using (var memoryStream = new MemoryStream()) 902 using (var memoryStream = new MemoryStream())
815 { 903 {
816 RemoteKeyBindings.XmlSerializer.Serialize(memoryStream, RemoteKeyBindings); 904 RemoteKeyBindings.XmlSerializer.Serialize(memoryStream, RemoteKeyBindings);
817   905  
818 memoryStream.Position = 0L; 906 memoryStream.Position = 0L;
819   907  
820 using (var fileStream = new FileStream("RemoteKeyBindings.xml", FileMode.Create)) 908 using (var fileStream = new FileStream("RemoteKeyBindings.xml", FileMode.Create))
821 { 909 {
822 await memoryStream.CopyToAsync(fileStream); 910 await memoryStream.CopyToAsync(fileStream);
823 } 911 }
824 } 912 }
825 } 913 }
826 catch (Exception) 914 catch (Exception)
827 { 915 {
828 ActivityTextBox.AppendText( 916 ActivityTextBox.AppendText(
829 $"{Strings.Failed_saving_remote_bindings}{Environment.NewLine}"); 917 $"{Strings.Failed_saving_remote_bindings}{Environment.NewLine}");
830 } 918 }
831 } 919 }
832   920  
833 private async Task LoadRemoteMouseKeyBindings() 921 private async Task LoadRemoteMouseKeyBindings()
834 { 922 {
835 try 923 try
836 { 924 {
837 using (var fileStream = new FileStream("RemoteKeyBindings.xml", FileMode.Open)) 925 using (var fileStream = new FileStream("RemoteKeyBindings.xml", FileMode.Open))
838 { 926 {
839 using (var memoryStream = new MemoryStream()) 927 using (var memoryStream = new MemoryStream())
840 { 928 {
841 await fileStream.CopyToAsync(memoryStream); 929 await fileStream.CopyToAsync(memoryStream);
842   930  
843 memoryStream.Position = 0L; 931 memoryStream.Position = 0L;
844   932  
845 var loadedBindings = 933 var loadedBindings =
846 (RemoteKeyBindings) RemoteKeyBindings.XmlSerializer.Deserialize(memoryStream); 934 (RemoteKeyBindings) RemoteKeyBindings.XmlSerializer.Deserialize(memoryStream);
847   935  
848 foreach (var binding in loadedBindings.Bindings) 936 foreach (var binding in loadedBindings.Bindings)
849 RemoteKeyBindings.Bindings.Add(binding); 937 RemoteKeyBindings.Bindings.Add(binding);
850 } 938 }
851 } 939 }
852 } 940 }
853 catch (Exception) 941 catch (Exception)
854 { 942 {
855 ActivityTextBox.AppendText( 943 ActivityTextBox.AppendText(
856 $"{Strings.Failed_loading_remote_bindings}{Environment.NewLine}"); 944 $"{Strings.Failed_loading_remote_bindings}{Environment.NewLine}");
857 } 945 }
858 } 946 }
859   947  
860 #endregion 948 #endregion
861 } 949 }
862 } 950 }
863   951