WingMan – Blame information for rev 37

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