Spring – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
2 using System.Collections.Generic;
3 using System.Collections.Specialized;
4 using System.ComponentModel;
5 using System.Drawing;
6 using System.IO;
7 using System.Linq;
8 using System.Net;
9 using System.Reflection;
10 using System.Threading.Tasks;
11 using System.Threading.Tasks.Dataflow;
12 using System.Windows.Forms;
13 using Gma.System.MouseKeyHook;
14 using NetSparkleUpdater;
15 using NetSparkleUpdater.Enums;
16 using NetSparkleUpdater.SignatureVerifiers;
17 using NetSparkleUpdater.UI.WinForms;
18 using QRCoder;
19 using Spring.About;
20 using Spring.Charging;
21 using Spring.Discharging;
22 using Spring.Editing;
23 using Spring.HUD;
24 using Spring.MouseKeyboard;
25 using Spring.Properties;
26 using Spring.Serialization;
27 using Spring.Serialization.Combos;
28 using Spring.Serialization.Configuration;
29 using Spring.Settings;
30 using Spring.Utilities;
31 using Spring.Utilities.Collections.RangeTree;
32 using SpringCombos;
33  
34 namespace Spring.Main
35 {
36 public partial class MainForm : Form
37 {
38 #region Public Events & Delegates
39  
40 public event EventHandler<EventArgs> SpringKeyButtonClicked;
41  
42 public event EventHandler<EventArgs> SpringSlowButtonClicked;
43  
44 public event EventHandler<EventArgs> SpringSpeedButtonClicked;
45  
46 public event EventHandler<SpeedbarValueChangedEventArgs> SpeedbarValueChanged;
47  
48 public event EventHandler<ConfigurationRestoredEventArgs> ConfigurationRestored;
49  
50 #endregion
51  
52 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
53  
54 private Configuration.Configuration Configuration { get; set; }
55  
56 private OSD OSD { get; set; }
57  
58 private Key Key { get; set; }
59  
60 private KeyWatch WatchKey { get; set; }
61  
62 private Charge Charge { get; set; }
63  
64 private Discharge Discharge { get; set; }
65  
66 private IKeyboardMouseEvents KeyboardMouseEvents { get; }
67  
68 private EditorForm EditorForm { get; set; }
69  
70 private SettingsForm SettingsForm { get; set; }
71  
72 private BufferBlock<ComboQueueItem> ComboQueue { get; }
73  
74 private ActionBlock<ComboQueueItem> ComboQueueAction { get; }
75  
76 private static QRCodeGenerator QrGenerator { get; set; }
77  
78 private readonly IDisposable _comboQueueLink;
79  
80 private RangeTreeAction<TimeSpan, int> _rangeTree;
81 private readonly SparkleUpdater _sparkle;
82  
83 #endregion
84  
85 #region Constructors, Destructors and Finalizers
86  
87 public MainForm()
88 {
89 InitializeComponent();
90 Utilities.WindowState.FormTracker.Track(this);
91  
92 // Start application update.
93 var manifestModuleName = Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName;
94 var icon = Icon.ExtractAssociatedIcon(manifestModuleName);
95  
96 _sparkle = new SparkleUpdater("https://spring.grimore.org/update/appcast.xml",
97 new Ed25519Checker(SecurityMode.Strict, "LonrgxVjSF0GnY4hzwlRJnLkaxnDn2ikdmOifILzLJY="))
98 {
99 UIFactory = new UIFactory(icon),
100 RelaunchAfterUpdate = true,
101 SecurityProtocolType = SecurityProtocolType.Tls12
102 };
103 _sparkle.StartLoop(true, true);
104  
105 Directory.CreateDirectory(Constants.UserApplicationDirectory);
106  
107 QrGenerator = new QRCodeGenerator();
108  
109 ComboQueue =
110 new BufferBlock<ComboQueueItem>(new DataflowBlockOptions
111 { BoundedCapacity = 4, EnsureOrdered = true });
112  
113 ComboQueueAction = new ActionBlock<ComboQueueItem>(DoComboQueueAction,
114 new ExecutionDataflowBlockOptions { EnsureOrdered = true, BoundedCapacity = 4 });
115  
116 _comboQueueLink = ComboQueue.LinkTo(ComboQueueAction);
117  
118 toolStripStatusLabel1.Text = Strings.Welcome_to_Spring;
119  
120 ConfigurationRestored += MainForm_ConfigurationRestored;
121  
122 KeyboardMouseEvents = Hook.GlobalEvents();
123 }
124  
125 /// <summary>
126 /// Clean up any resources being used.
127 /// </summary>
128 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
129 protected override void Dispose(bool disposing)
130 {
131 if (disposing && components != null)
132 {
133 ConfigurationRestored -= MainForm_ConfigurationRestored;
134  
135 _comboQueueLink?.Dispose();
136 Discharge?.Dispose();
137 Charge?.Dispose();
138 WatchKey?.Dispose();
139 Key?.Dispose();
140  
141 components.Dispose();
142 }
143  
144 OSD?.Dispose();
145 OSD = null;
146  
147 base.Dispose(disposing);
148 }
149  
150 #endregion
151  
152 #region Event Handlers
153  
154 private void ComboQueuePictureBox_Click(object sender, EventArgs e)
155 {
156 var pictureBox = (PictureBox) sender;
157  
158 Charge.Load((Combos) pictureBox.Tag);
159 }
160  
161 private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
162 {
163 var aboutForm = new AboutForm();
164 aboutForm.Show();
165 }
166  
167 private void TutorialToolStripMenuItem_Click(object sender, EventArgs e)
168 {
169 new Tutorial.Tutorial(this, KeyboardMouseEvents).Show();
170 }
171  
172 private async void MainForm_ConfigurationRestored(object sender, ConfigurationRestoredEventArgs e)
173 {
174 await Initialize(e.Combos);
175 }
176  
177 private void SpeedBar_ValueChanged(object sender, EventArgs e)
178 {
179 var trackBar = (TrackBar) sender;
180 SpeedbarValueChanged?.Invoke(sender, new SpeedbarValueChangedEventArgs(trackBar.Value));
181 }
182  
183 private void QuitToolStripMenuItem_Click(object sender, EventArgs e)
184 {
185 Application.Exit();
186 }
187  
188 private void BindSpeedButton_Click(object sender, EventArgs e)
189 {
190 SpringSpeedButtonClicked?.Invoke(this, e);
191 }
192  
193 private void BindSlowButton_Click(object sender, EventArgs e)
194 {
195 SpringSlowButtonClicked?.Invoke(this, e);
196 }
197  
198 private void BindKeyButton_Click(object sender, EventArgs e)
199 {
200 SpringKeyButtonClicked?.Invoke(this, e);
201 }
202  
203 private async void SaveFileDialog1_FileOk(object sender, CancelEventArgs e)
204 {
205 switch (await Charge.Combos.Serialize(saveFileDialog1.FileName))
206 {
207 case SerializationSuccess<Combos> serializationSuccess:
208 toolStripStatusLabel1.Text = $"{Strings.Combos_wrote_successfully}";
209  
210 Charge.StartCharge(serializationSuccess.Result);
211  
212 Configuration.Spring.Store = saveFileDialog1.FileName;
213  
214 if (!Configuration.Spring.History.Contains(saveFileDialog1.FileName))
215 {
216 Configuration.Spring.History.Add(saveFileDialog1.FileName);
217 }
218  
219 break;
220  
221 case SerializationFailure serializationFailed:
222 toolStripStatusLabel1.Text =
223 $"{Strings.Failed_to_write_combos}: {serializationFailed.Exception.Message}";
224  
225 break;
226 }
227 }
228  
229 private async void OpenFileDialog1_FileOk(object sender, CancelEventArgs e)
230 {
231 var fileInfo = new FileInfo(openFileDialog1.FileName);
232  
233 var combos = await LoadCombos(fileInfo);
234  
235 if (combos == null)
236 {
237 return;
238 }
239  
240 Charge.StartCharge(combos);
241  
242 Configuration.Spring.Store = openFileDialog1.FileName;
243  
244 if (!Configuration.Spring.History.Contains(openFileDialog1.FileName))
245 {
246 Configuration.Spring.History.Add(openFileDialog1.FileName);
247 }
248 }
249  
250 private void ExportToolStripMenuItem_Click(object sender, EventArgs e)
251 {
252 saveFileDialog1.ShowDialog();
253 }
254  
255 private void ImportToolStripMenuItem_Click(object sender, EventArgs e)
256 {
257 openFileDialog1.ShowDialog();
258 }
259  
260 private async void MainForm_Load(object sender, EventArgs e)
261 {
262 var configurationFileInfo = new FileInfo(Constants.ConfigurationFilePath);
263  
264 // Load configuration.
265 switch (ConfigurationSerialization.Deserialize(configurationFileInfo))
266 {
267 case SerializationSuccess<Configuration.Configuration> serializationSuccess:
268 Configuration = serializationSuccess.Result;
269 toolStripStatusLabel1.Text = $"{Strings.Read_configuration_successfully}";
270  
271 break;
272  
273 case SerializationFailure serializationFailed:
274 toolStripStatusLabel1.Text =
275 $"{Strings.Failed_to_read_configuration}: {serializationFailed.Exception.Message}";
276  
277 // Attempt to load default configuration
278 var fileInfo = new FileInfo("Configuration.xml.default");
279  
280 switch (ConfigurationSerialization.Deserialize(fileInfo))
281 {
282 case SerializationSuccess<Configuration.Configuration> serializationSuccess:
283 toolStripStatusLabel1.Text =
284 $"{Strings.Read_default_configuration_successfully}";
285  
286 Configuration = serializationSuccess.Result;
287  
288 break;
289  
290 case SerializationFailure defaultSerializationFailure:
291 toolStripStatusLabel1.Text =
292 $"{Strings.Failed_to_read_default_configuration}: {defaultSerializationFailure.Exception.Message}";
293  
294 Configuration = new Configuration.Configuration();
295  
296 break;
297 }
298  
299 break;
300 }
301  
302 // Load combos.
303 if (string.IsNullOrEmpty(Configuration.Spring.Store))
304 {
305 ConfigurationRestored?.Invoke(this, new ConfigurationRestoredEventArgs(new Combos()));
306  
307 return;
308 }
309  
310 var storeFileInfo = new FileInfo(Configuration.Spring.Store);
311  
312 var combos = await LoadCombos(storeFileInfo);
313  
314 if (combos == null)
315 {
316 ConfigurationRestored?.Invoke(this, new ConfigurationRestoredEventArgs(new Combos()));
317  
318 return;
319 }
320  
321 await ComboQueue.SendAsync(new ComboQueueItem(comboQueuePictureBox1, combos));
322  
323 ConfigurationRestored?.Invoke(this, new ConfigurationRestoredEventArgs(combos));
324 }
325  
326 private void WatchKey_SpeedAdjusted(object sender, KeySpeedAdjustedEventArgs e)
327 {
328 this.InvokeIfRequired(form =>
329 {
330 switch (e.Multiplier)
331 {
332 case -1:
333 form.SpeedBar.Value = Math.Max(form.SpeedBar.Value - 1, form.SpeedBar.Minimum);
334  
335 break;
336  
337 case 1:
338 form.SpeedBar.Value = Math.Min(form.SpeedBar.Value + 1, form.SpeedBar.Maximum);
339  
340 break;
341 }
342 });
343 }
344  
345 private void Key_KeyMessage(object sender, KeyMessageEventArgs e)
346 {
347 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = e.Message; });
348 }
349  
350 private void Loading_PropertyChanged(object sender, PropertyChangedEventArgs e)
351 {
352 _rangeTree = new RangeTreeAction<TimeSpan, int>
353 {
354 {
355 TimeSpan.FromSeconds(0),
356 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
357 ActionNoCharge
358 },
359 {
360 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
361 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
362 ActionNoCharge
363 },
364 {
365 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
366 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats +
367 Configuration.Spring.Charge.ChargeSeconds),
368 ActionCharge
369 },
370 {
371 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats +
372 Configuration.Spring.Charge.ChargeSeconds),
373 TimeSpan.MaxValue, ActionNoCharge
374 }
375 };
376 }
377  
378 private void WatchKey_KeyUp(object sender, KeyUpEventArgs e)
379 {
380 OSD.Text = OSD.Symbols.KeyReleased();
381 }
382  
383 private void Charge_ChargeLoaded(object sender, ChargeLoadedEventArgs e)
384 {
385 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = Strings.Spring_charged; });
386  
387 if (e.Combos == null)
388 {
389 return;
390 }
391  
392 switch (e.Combos.ComboRepeat)
393 {
394 case 0:
395 OSD.Text = OSD.Symbols.ChargeStop(Resources.Infinity);
396  
397 break;
398  
399 default:
400 OSD.Text = OSD.Symbols.ChargeStop(e.Combos.ComboRepeat.ToString());
401  
402 break;
403 }
404 }
405  
406 private async void ChargeChanged(object sender, ChargeChangedEventArgs e)
407 {
408 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = Strings.Spring_charged; });
409  
410 if (e.Combos == null)
411 {
412 return;
413 }
414  
415 var combos = Charge.Combos;
416  
417 await ComboQueue.SendAsync(new ComboQueueItem(comboQueuePictureBox1, combos));
418  
419 switch (e.Combos.ComboRepeat)
420 {
421 case 0:
422 OSD.Text = OSD.Symbols.ChargeStop(Resources.Infinity);
423  
424 break;
425  
426 default:
427 OSD.Text = OSD.Symbols.ChargeStop(e.Combos.ComboRepeat.ToString());
428  
429 break;
430 }
431 }
432  
433 private void ChargeStart(object sender, ChargeStartEventArgs e)
434 {
435 if (Charge.Combos == null)
436 {
437 return;
438 }
439  
440 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = Strings.Spring_is_charging; });
441  
442 OSD.Text = OSD.Symbols.ChargeStart();
443 }
444  
445 private void Discharge_DischargeStart(object sender, DischargeStartEventArgs e)
446 {
447 this.InvokeIfRequired(form =>
448 {
449 form.toolStripStatusLabel1.Text = Strings.Spring_is_discharging;
450 form.toolStripProgressBar1.Value = 0;
451  
452 switch (e.Repeat)
453 {
454 case 0:
455 form.label5.Text = Resources.Infinity;
456 form.toolStripProgressBar1.Visible = false;
457  
458 OSD.Text = OSD.Symbols.DischargeProgress(Resources.Infinity);
459  
460 break;
461  
462 default:
463 form.label5.Text = e.Repeat.ToString();
464 form.toolStripProgressBar1.Visible = true;
465  
466 OSD.Text = OSD.Symbols.DischargeProgress(e.Repeat.ToString());
467  
468 break;
469 }
470 });
471 }
472  
473 private void Discharge_DischargeStop(object sender, DischargeStopEventArgs e)
474 {
475 OSD.Text = string.Empty;
476  
477 this.InvokeIfRequired(form =>
478 {
479 form.toolStripStatusLabel1.Text = Strings.Spring_discharge_cancelled;
480 form.toolStripProgressBar1.Visible = false;
481  
482 switch (e.Repeat)
483 {
484 case 0:
485 form.label5.Text = Resources.Infinity;
486  
487 OSD.Text = OSD.Symbols.DischargeStop(Resources.Infinity);
488  
489 break;
490  
491 default:
492 form.label5.Text = e.Repeat.ToString();
493  
494 OSD.Text = OSD.Symbols.DischargeStop(e.Repeat.ToString());
495  
496 break;
497 }
498 });
499 }
500  
501 private void Discharge_DischargeProgress(object sender, DischargeProgressEventArgs e)
502 {
503 this.InvokeIfRequired(form =>
504 {
505 switch (e.Repeat)
506 {
507 case 0:
508 break;
509  
510 default:
511 var progress = (int) (100f - 100f * e.Current / (e.Total * e.Repeat));
512  
513 if (progress < 0 || progress > 100)
514 {
515 break;
516 }
517  
518 form.toolStripProgressBar1.Value = progress;
519  
520 var repeats = (int) (1f * e.Current / e.Total);
521  
522 form.label5.Text = $@"{repeats}";
523  
524 OSD.Text = OSD.Symbols.DischargeProgress(repeats.ToString());
525  
526 break;
527 }
528 });
529 }
530  
531 private void WatchKey_KeyDown(object sender, KeyDownEventArgs e)
532 {
533 _rangeTree.Query(e.Elapsed);
534 }
535  
536 private async void MainForm_FormClosing(object sender, FormClosingEventArgs e)
537 {
538 // Save combos.
539 await SaveCombos(Configuration.Spring.Store);
540  
541 // Save configuration file.
542 switch (await Configuration.Serialize(Constants.ConfigurationFilePath))
543 {
544 case SerializationSuccess _:
545 toolStripStatusLabel1.Text = $"{Strings.Wrote_configuration_successfully}";
546  
547 break;
548  
549 case SerializationFailure serializationFailed:
550 toolStripStatusLabel1.Text =
551 $"{Strings.Failed_to_write_configuration}: {serializationFailed.Exception.Message}";
552  
553 break;
554 }
555 }
556  
557 private void EditorButton_Click(object sender, EventArgs e)
558 {
559 if (EditorForm != null)
560 {
561 return;
562 }
563  
564 EditorForm = new EditorForm(Configuration, Charge.Combos);
565 EditorForm.Closing += EditorForm_Closing;
566 EditorForm.Edited += EditorForm_Edited;
567 EditorForm.Show();
568 }
569  
570 private void EditorForm_Edited(object sender, EditEventArgs e)
571 {
572 switch (e)
573 {
574 case EditSuccessEventArgs editSuccessEventArgs:
575 Charge.StartCharge(editSuccessEventArgs.Combos);
576  
577 break;
578  
579 case EditFailureEventArgs editFailureEventArgs:
580 break;
581 }
582 }
583  
584 private void EditorForm_Closing(object sender, CancelEventArgs e)
585 {
586 if (EditorForm == null)
587 {
588 return;
589 }
590  
591 EditorForm.Closing -= EditorForm_Closing;
592 EditorForm.Edited -= EditorForm_Edited;
593 EditorForm.Dispose();
594 EditorForm = null;
595  
596 toolStripStatusLabel1.Text = $"{Strings.Combos_read_successfully}";
597 }
598  
599 private void SettingsButton_Click(object sender, EventArgs e)
600 {
601 if (SettingsForm != null)
602 {
603 return;
604 }
605  
606 SettingsForm = new SettingsForm(Configuration);
607 SettingsForm.FormClosing += SettingsForm_FormClosing;
608 SettingsForm.Show();
609 }
610  
611 private void SettingsForm_FormClosing(object sender, FormClosingEventArgs e)
612 {
613 if (SettingsForm == null)
614 {
615 return;
616 }
617  
618 SettingsForm.FormClosing -= SettingsForm_FormClosing;
619 SettingsForm.Dispose();
620 SettingsForm = null;
621 }
622  
623 private void History_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
624 {
625 RecreateHistoryMenu(e.NewItems.OfType<string>());
626 }
627  
628 private void Spring_PropertyChanged(object sender, PropertyChangedEventArgs e)
629 {
630 var springHistory = ((Configuration.Spring) sender).History;
631  
632 RecreateHistoryMenu(springHistory);
633 }
634  
635 private async void HistoryToolStripMenu_Click(object sender, EventArgs e)
636 {
637 var selectedFile = ((ToolStripMenuItem) sender).Text;
638  
639 if (string.IsNullOrEmpty(selectedFile))
640 {
641 return;
642 }
643  
644 var fileInfo = new FileInfo(selectedFile);
645  
646 var combos = await LoadCombos(fileInfo);
647  
648 if (combos == null)
649 {
650 return;
651 }
652  
653 Charge.StartCharge(combos);
654  
655 Configuration.Spring.Store = openFileDialog1.FileName;
656  
657 if (!Configuration.Spring.History.Contains(openFileDialog1.FileName))
658 {
659 Configuration.Spring.History.Add(openFileDialog1.FileName);
660 }
661 }
662  
663 private async void CheckForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
664 {
665 // Manually check for updates, this will not show a ui
666 var result = await _sparkle.CheckForUpdatesQuietly();
667 var updates = result.Updates;
668 if (result.Status == UpdateStatus.UpdateAvailable)
669 {
670 // if update(s) are found, then we have to trigger the UI to show it gracefully
671 _sparkle.ShowUpdateNeededUI();
672 return;
673 }
674  
675 MessageBox.Show("No updates available at this time.", "Spring", MessageBoxButtons.OK,
676 MessageBoxIcon.Asterisk,
677 MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false);
678 }
679  
680 #endregion
681  
682 #region Private Methods
683  
684 private async void DoComboQueueAction(ComboQueueItem springComboQueueItem)
685 {
686 var serialization = await springComboQueueItem.Combos.Serialize();
687  
688 switch (serialization)
689 {
690 case SerializationSuccess<Combos> serializationSuccess:
691 var comboText = serializationSuccess.Text;
692  
693 var qrCodeData = QrGenerator.CreateQrCode(Helpers.Sha1Hash(comboText),
694 QRCodeGenerator.ECCLevel.L,
695 false,
696 false,
697 QRCodeGenerator.EciMode.Default,
698 1);
699  
700 var qrCode = new QRCode(qrCodeData);
701 var qrCodeImage = qrCode.GetGraphic(20);
702 var image = Helpers.Crop(qrCodeImage);
703  
704 // Set the QR code hash and the combos.
705 comboQueuePictureBox4.BackgroundImage = comboQueuePictureBox3.BackgroundImage;
706 comboQueuePictureBox4.Tag = comboQueuePictureBox3.Tag;
707 comboQueuePictureBox3.BackgroundImage = comboQueuePictureBox2.BackgroundImage;
708 comboQueuePictureBox3.Tag = comboQueuePictureBox2.Tag;
709 comboQueuePictureBox2.BackgroundImage = comboQueuePictureBox1.BackgroundImage;
710 comboQueuePictureBox2.Tag = comboQueuePictureBox1.Tag;
711 comboQueuePictureBox1.BackgroundImage = image;
712 comboQueuePictureBox1.Tag = serializationSuccess.Result;
713  
714 break;
715  
716 case SerializationFailure serializationFailure:
717 break;
718 }
719 }
720  
721 private async Task<Combos> LoadCombos(FileInfo file)
722 {
723 switch (await ComboSerialization.Deserialize(file, 0))
724 {
725 case SerializationSuccess<Combos> serializationSuccess:
726 toolStripStatusLabel1.Text = $"{Strings.Combos_read_successfully}";
727  
728 return serializationSuccess.Result;
729  
730 case SerializationFailure deserializationFailure:
731 toolStripStatusLabel1.Text =
732 $"{Strings.Failed_to_read_combos}: {deserializationFailure.Exception.Message}";
733  
734 break;
735 }
736  
737 return null;
738 }
739  
740 /// <summary>
741 /// Serialize combos to file.
742 /// </summary>
743 /// <param name="file">the file to which the combos will be serialized</param>
744 /// <returns>an awaitable task</returns>
745 private async Task SaveCombos(string file)
746 {
747 switch (await Charge.Combos.Serialize(file))
748 {
749 case SerializationSuccess<Combos> serializationSuccess:
750 toolStripStatusLabel1.Text = $"{Strings.Combos_wrote_successfully}";
751  
752 break;
753  
754 case SerializationFailure deserializationFailure:
755 toolStripStatusLabel1.Text =
756 $"{Strings.Failed_to_write_combos}: {deserializationFailure.Exception.Message}";
757  
758 break;
759 }
760 }
761  
762 private void ActionCharge(TimeSpan x)
763 {
764 this.InvokeIfRequired(form =>
765 {
766 switch (x.Seconds - Configuration.Spring.Charge.ChargeSeconds)
767 {
768 case 0:
769 form.label5.Text = Resources.Infinity;
770 OSD.Text = OSD.Symbols.KeyDown(Resources.Infinity);
771  
772 break;
773  
774 default:
775 var comboText = (x.Seconds - Configuration.Spring.Charge.ChargeSeconds).ToString();
776  
777 form.label5.Text = comboText;
778  
779 OSD.Text = OSD.Symbols.KeyDown(comboText);
780  
781 break;
782 }
783 });
784 }
785  
786 private void ActionNoCharge(TimeSpan x)
787 {
788 this.InvokeIfRequired(form =>
789 {
790 switch (x.Seconds < Configuration.Spring.Charge.ChargeSeconds)
791 {
792 case true:
793 form.label5.Text = string.Empty;
794 OSD.Text = OSD.Symbols.KeyPressed();
795  
796 break;
797  
798 default:
799 form.label5.Text = Resources.Infinity;
800 OSD.Text = OSD.Symbols.KeyDown(Resources.Infinity);
801  
802 break;
803 }
804 });
805 }
806  
807 private async Task Initialize(Combos springCombos)
808 {
809 Key = new Key(this, Configuration, KeyboardMouseEvents);
810 Key.KeyMessage += Key_KeyMessage;
811 WatchKey = new KeyWatch(KeyboardMouseEvents, Key);
812 WatchKey.SpeedAdjusted += WatchKey_SpeedAdjusted;
813 WatchKey.KeyDown += WatchKey_KeyDown;
814 WatchKey.KeyUp += WatchKey_KeyUp;
815  
816 Charge = new Charge(springCombos, Configuration, KeyboardMouseEvents, Key, WatchKey);
817 Charge.ChargeStart += ChargeStart;
818 Charge.ChargeChanged += ChargeChanged;
819 Charge.ChargeLoaded += Charge_ChargeLoaded;
820  
821 Discharge = new Discharge(this, Configuration, Key, WatchKey, Charge, SpeedBar.Value);
822 Discharge.SpringDischargeStart += Discharge_DischargeStart;
823 Discharge.SpringDischargeStop += Discharge_DischargeStop;
824 Discharge.SpringDischargeProgress += Discharge_DischargeProgress;
825  
826 Configuration.Spring.Charge.PropertyChanged += Loading_PropertyChanged;
827 Configuration.Spring.PropertyChanged += Spring_PropertyChanged;
828 Configuration.Spring.History.CollectionChanged += History_CollectionChanged;
829  
830 OSD = new OSD(Configuration, KeyboardMouseEvents);
831  
832 if (OSD.Configuration.HUD.Enable)
833 {
834 OSD.Text = OSD.Symbols.HUDShown();
835 }
836  
837 _rangeTree = new RangeTreeAction<TimeSpan, int>
838 {
839 {
840 TimeSpan.FromSeconds(0),
841 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
842 ActionNoCharge
843 },
844 {
845 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
846 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
847 ActionNoCharge
848 },
849 {
850 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
851 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats +
852 Configuration.Spring.Charge.ChargeSeconds),
853 ActionCharge
854 },
855 {
856 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats +
857 Configuration.Spring.Charge.ChargeSeconds),
858 TimeSpan.MaxValue, ActionNoCharge
859 }
860 };
861  
862 RecreateHistoryMenu(Configuration.Spring.History);
863  
864 await Key.Load();
865 }
866  
867 private void RecreateHistoryMenu(IEnumerable<string> springHistory)
868 {
869 var history = springHistory.ToList();
870  
871 foreach (var toolStripMenuItem in
872 historyToolStripMenuItem.DropDownItems.OfType<ToolStripMenuItem>())
873 {
874 toolStripMenuItem.Click -= HistoryToolStripMenu_Click;
875  
876 history.Add(toolStripMenuItem.Text);
877 }
878  
879 historyToolStripMenuItem.DropDownItems.Clear();
880  
881 foreach (var item in history.Distinct())
882 {
883 if (string.IsNullOrEmpty(item))
884 {
885 continue;
886 }
887  
888 historyToolStripMenuItem.DropDownItems.Add(item, null, HistoryToolStripMenu_Click);
889 }
890 }
891  
892 #endregion
893 }
894 }