WingMan – Blame information for rev 33

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