WingMan – Diff between revs 33 and 36

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