WingMan – Blame information for rev 33
?pathlinks?
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 | } |