Spring – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | using System; |
2 | using System.ComponentModel; |
||
3 | using System.Diagnostics; |
||
4 | using System.Linq; |
||
5 | using System.Threading; |
||
6 | using System.Threading.Tasks; |
||
7 | using System.Threading.Tasks.Dataflow; |
||
8 | using System.Windows.Forms; |
||
9 | using Gma.System.MouseKeyHook; |
||
10 | using Spring.MouseKeyboard; |
||
11 | using Spring.Utilities; |
||
12 | using Spring.Utilities.Collections.RangeTree; |
||
13 | using SpringCombos; |
||
14 | using Debug = System.Diagnostics.Debug; |
||
15 | |||
16 | namespace Spring.Charging |
||
17 | { |
||
18 | public class Charge : IDisposable |
||
19 | { |
||
20 | #region Public Events & Delegates |
||
21 | |||
22 | public event EventHandler<ChargeLoadedEventArgs> ChargeLoaded; |
||
23 | |||
24 | public event EventHandler<ChargeChangedEventArgs> ChargeChanged; |
||
25 | |||
26 | public event EventHandler<ChargeStartEventArgs> ChargeStart; |
||
27 | |||
28 | #endregion |
||
29 | |||
30 | #region Public Enums, Properties and Fields |
||
31 | |||
32 | public Combos Combos { get; private set; } |
||
33 | |||
34 | public int Fuzz { get; set; } |
||
35 | |||
36 | public static Random Random { get; set; } |
||
37 | |||
38 | #endregion |
||
39 | |||
40 | #region Private Delegates, Events, Enums, Properties, Indexers and Fields |
||
41 | |||
42 | private KeyWatch WatchKey { get; } |
||
43 | |||
44 | private Key Key { get; } |
||
45 | |||
46 | private IKeyboardMouseEvents KeyboardMouseEvents { get; } |
||
47 | |||
48 | private Configuration.Configuration Configuration { get; } |
||
49 | |||
50 | private BufferBlock<Combo> RecordKeyComboInputBlock { get; } |
||
51 | |||
52 | private BufferBlock<Combo> RecordKeyComboOutputBlock { get; } |
||
53 | |||
54 | private TransformBlock<Combo, Combo> RecordKeyTransformBlock { get; } |
||
55 | |||
56 | private Stopwatch Stopwatch { get; } |
||
57 | |||
58 | private int ChargeRepeat { get; set; } |
||
59 | |||
60 | private RangeTreeFunc<TimeSpan, int> RangeTreeFunc { get; set; } |
||
61 | |||
62 | private long _comboCount; |
||
63 | |||
64 | private bool _disposing; |
||
65 | |||
66 | private volatile bool _isCharging; |
||
67 | |||
68 | #endregion |
||
69 | |||
70 | #region Constructors, Destructors and Finalizers |
||
71 | |||
72 | public Charge() => Stopwatch = new Stopwatch(); |
||
73 | |||
74 | public Charge(Combos springCombos, |
||
75 | Configuration.Configuration springConfiguration, |
||
76 | IKeyboardMouseEvents keyboardMouseEvents, |
||
77 | Key springKey, |
||
78 | KeyWatch watchKey) : this() |
||
79 | { |
||
80 | Combos = springCombos; |
||
81 | Configuration = springConfiguration; |
||
82 | KeyboardMouseEvents = keyboardMouseEvents; |
||
83 | Key = springKey; |
||
84 | WatchKey = watchKey; |
||
85 | |||
86 | Random = new Random(); |
||
87 | |||
88 | RangeTreeFunc = new RangeTreeFunc<TimeSpan, int> |
||
89 | { |
||
90 | { |
||
91 | TimeSpan.FromSeconds(0), |
||
92 | TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), |
||
93 | FuncNoCharge |
||
94 | }, |
||
95 | { |
||
96 | TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), |
||
97 | TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), |
||
98 | FuncNoCharge |
||
99 | }, |
||
100 | { |
||
101 | TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), |
||
102 | TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats + |
||
103 | Configuration.Spring.Charge.ChargeSeconds), |
||
104 | FuncCharge |
||
105 | }, |
||
106 | { |
||
107 | TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats + |
||
108 | Configuration.Spring.Charge.ChargeSeconds), |
||
109 | TimeSpan.MaxValue, FuncNoCharge |
||
110 | } |
||
111 | }; |
||
112 | |||
113 | RecordKeyComboInputBlock = new BufferBlock<Combo>(); |
||
114 | |||
115 | RecordKeyTransformBlock = |
||
116 | new TransformBlock<Combo, Combo>(TransformSpringCombos, |
||
117 | new ExecutionDataflowBlockOptions { EnsureOrdered = true }); |
||
118 | |||
119 | RecordKeyComboInputBlock.LinkTo(RecordKeyTransformBlock); |
||
120 | |||
121 | RecordKeyComboOutputBlock = new BufferBlock<Combo>(); |
||
122 | RecordKeyTransformBlock.LinkTo(RecordKeyComboOutputBlock, combo => combo != null); |
||
123 | RecordKeyTransformBlock.LinkTo(DataflowBlock.NullTarget<Combo>()); |
||
124 | |||
125 | Configuration.Spring.Charge.PropertyChanged += SpringLoading_PropertyChanged; |
||
126 | Configuration.Spring.PropertyChanged += Spring_PropertyChanged; |
||
127 | |||
128 | WatchKey.KeyUp += WatchKey_SpringKeyUp; |
||
129 | WatchKey.KeyDown += WatchKey_KeyDown; |
||
130 | } |
||
131 | |||
132 | public void Dispose() |
||
133 | { |
||
134 | if (_disposing) |
||
135 | { |
||
136 | return; |
||
137 | } |
||
138 | |||
139 | _disposing = true; |
||
140 | |||
141 | Configuration.Spring.Charge.PropertyChanged -= SpringLoading_PropertyChanged; |
||
142 | Configuration.Spring.PropertyChanged -= Spring_PropertyChanged; |
||
143 | |||
144 | WatchKey.KeyUp -= WatchKey_SpringKeyUp; |
||
145 | WatchKey.KeyDown -= WatchKey_KeyDown; |
||
146 | } |
||
147 | |||
148 | #endregion |
||
149 | |||
150 | #region Event Handlers |
||
151 | |||
152 | private void Spring_PropertyChanged(object sender, PropertyChangedEventArgs e) |
||
153 | { |
||
154 | Fuzz = ((Configuration.Spring) sender).Fuzz; |
||
155 | } |
||
156 | |||
157 | private void WatchKey_KeyDown(object sender, KeyDownEventArgs e) |
||
158 | { |
||
159 | if (_isCharging) |
||
160 | { |
||
161 | return; |
||
162 | } |
||
163 | |||
164 | ChargeRepeat = RangeTreeFunc.Query(e.Elapsed) |
||
165 | .SingleOrDefault(); |
||
166 | |||
167 | $"Loaded repeat: {ChargeRepeat}".ToDebugConsole(); |
||
168 | } |
||
169 | |||
170 | private void SpringLoading_PropertyChanged(object sender, PropertyChangedEventArgs e) |
||
171 | { |
||
172 | Configuration.Spring.Charge = (Configuration.Charge) sender; |
||
173 | |||
174 | RangeTreeFunc = new RangeTreeFunc<TimeSpan, int> |
||
175 | { |
||
176 | { |
||
177 | TimeSpan.FromSeconds(0), |
||
178 | TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), |
||
179 | FuncNoCharge |
||
180 | }, |
||
181 | { |
||
182 | TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), |
||
183 | TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), |
||
184 | FuncNoCharge |
||
185 | }, |
||
186 | { |
||
187 | TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), |
||
188 | TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats + |
||
189 | Configuration.Spring.Charge.ChargeSeconds), |
||
190 | FuncCharge |
||
191 | }, |
||
192 | { |
||
193 | TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats + |
||
194 | Configuration.Spring.Charge.ChargeSeconds), |
||
195 | TimeSpan.MaxValue, FuncNoCharge |
||
196 | } |
||
197 | }; |
||
198 | } |
||
199 | |||
200 | private void WatchKey_SpringKeyUp(object sender, KeyUpEventArgs e) |
||
201 | { |
||
202 | if (!Key.IsConfigured) |
||
203 | { |
||
204 | return; |
||
205 | } |
||
206 | |||
207 | StopCharging(); |
||
208 | |||
209 | // Do not record if press time is smaller than two seconds. |
||
210 | if (e.TimePressed < TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds)) |
||
211 | { |
||
212 | return; |
||
213 | } |
||
214 | |||
215 | StartCharging(); |
||
216 | } |
||
217 | |||
218 | private async void IKeyboardMouseEvents_MouseMove(object sender, MouseEventArgs e) |
||
219 | { |
||
220 | if (!Configuration.Spring.Charge.MouseMove) |
||
221 | { |
||
222 | return; |
||
223 | } |
||
224 | |||
225 | await StartCharge(new MouseCombo(e, ComboAction.Move)); |
||
226 | } |
||
227 | |||
228 | private async void IKeyboardMouseEvents_MouseUp(object sender, MouseEventArgs e) |
||
229 | { |
||
230 | if (!Configuration.Spring.Charge.MouseClick) |
||
231 | { |
||
232 | return; |
||
233 | } |
||
234 | |||
235 | await StartCharge(new MouseCombo(e, ComboAction.Up)); |
||
236 | } |
||
237 | |||
238 | private async void IKeyboardMouseEvents_MouseDown(object sender, MouseEventArgs e) |
||
239 | { |
||
240 | if (!Configuration.Spring.Charge.MouseClick) |
||
241 | { |
||
242 | return; |
||
243 | } |
||
244 | |||
245 | await StartCharge(new MouseCombo(e, ComboAction.Down)); |
||
246 | } |
||
247 | |||
248 | private async void IKeyboardMouseEvents_KeyDown(object sender, KeyEventArgs e) |
||
249 | { |
||
250 | if (!Configuration.Spring.Charge.Keyboard) |
||
251 | { |
||
252 | return; |
||
253 | } |
||
254 | |||
255 | await StartCharge(new KeyboardCombo(e, ComboAction.Down)); |
||
256 | } |
||
257 | |||
258 | private async void IKeyboardMouseEvents_KeyUp(object sender, KeyEventArgs e) |
||
259 | { |
||
260 | if (!Configuration.Spring.Charge.Keyboard) |
||
261 | { |
||
262 | return; |
||
263 | } |
||
264 | |||
265 | await StartCharge(new KeyboardCombo(e, ComboAction.Up)); |
||
266 | } |
||
267 | |||
268 | #endregion |
||
269 | |||
270 | #region Public Methods |
||
271 | |||
272 | public void StartCharge(Combos combos) |
||
273 | { |
||
274 | Combos = combos; |
||
275 | |||
276 | ChargeChanged?.Invoke(this, new ChargeChangedEventArgs(Combos)); |
||
277 | } |
||
278 | |||
279 | public void Load(Combos combos) |
||
280 | { |
||
281 | Combos = combos; |
||
282 | |||
283 | ChargeLoaded?.Invoke(this, new ChargeLoadedEventArgs(Combos)); |
||
284 | } |
||
285 | |||
286 | #endregion |
||
287 | |||
288 | #region Private Methods |
||
289 | |||
290 | private int FuncCharge(TimeSpan x) |
||
291 | { |
||
292 | var value = x.Seconds - Configuration.Spring.Charge.ChargeSeconds; |
||
293 | |||
294 | return value == 0 ? 0 : value; |
||
295 | } |
||
296 | |||
297 | private static int FuncNoCharge(TimeSpan _) => 0; |
||
298 | |||
299 | private async Task StartCharge<T>(T eventArgs) where T : Combo |
||
300 | { |
||
301 | var fuzz = Random.Next(0, Configuration.Spring.Fuzz); |
||
302 | |||
303 | var pauseCombo = new PauseCombo(Stopwatch.Elapsed) { Fuzz = fuzz }; |
||
304 | |||
305 | await RecordKeyComboInputBlock.SendAsync(pauseCombo); |
||
306 | |||
307 | Stopwatch.Restart(); |
||
308 | |||
309 | await RecordKeyComboInputBlock.SendAsync(eventArgs); |
||
310 | } |
||
311 | |||
312 | private void StopCharging() |
||
313 | { |
||
314 | Stopwatch.Stop(); |
||
315 | |||
316 | KeyboardMouseEvents.KeyUp -= IKeyboardMouseEvents_KeyUp; |
||
317 | KeyboardMouseEvents.KeyDown -= IKeyboardMouseEvents_KeyDown; |
||
318 | KeyboardMouseEvents.MouseDown -= IKeyboardMouseEvents_MouseDown; |
||
319 | KeyboardMouseEvents.MouseUp -= IKeyboardMouseEvents_MouseUp; |
||
320 | KeyboardMouseEvents.MouseMove -= IKeyboardMouseEvents_MouseMove; |
||
321 | |||
322 | if (!RecordKeyComboOutputBlock.TryReceiveAll(out var springCombos)) |
||
323 | { |
||
324 | return; |
||
325 | } |
||
326 | |||
327 | if (!_isCharging) |
||
328 | { |
||
329 | return; |
||
330 | } |
||
331 | |||
332 | var cleanCombos = springCombos.SequenceSubtract(Key.KeyCombo, CompareSpringKeys); |
||
333 | |||
334 | Combos = new Combos(cleanCombos, ChargeRepeat); |
||
335 | |||
336 | ChargeChanged?.Invoke(this, new ChargeChangedEventArgs(Combos)); |
||
337 | |||
338 | _isCharging = false; |
||
339 | } |
||
340 | |||
341 | private void StartCharging() |
||
342 | { |
||
343 | _isCharging = true; |
||
344 | |||
345 | Stopwatch.Restart(); |
||
346 | |||
347 | KeyboardMouseEvents.KeyUp += IKeyboardMouseEvents_KeyUp; |
||
348 | KeyboardMouseEvents.KeyDown += IKeyboardMouseEvents_KeyDown; |
||
349 | KeyboardMouseEvents.MouseDown += IKeyboardMouseEvents_MouseDown; |
||
350 | KeyboardMouseEvents.MouseUp += IKeyboardMouseEvents_MouseUp; |
||
351 | KeyboardMouseEvents.MouseMove += IKeyboardMouseEvents_MouseMove; |
||
352 | |||
353 | Interlocked.Exchange(ref _comboCount, 0); |
||
354 | |||
355 | ChargeStart?.Invoke(this, new ChargeStartEventArgs()); |
||
356 | } |
||
357 | |||
358 | private Combo TransformSpringCombos(Combo arg) |
||
359 | { |
||
360 | arg.Index = (int) Interlocked.Read(ref _comboCount); |
||
361 | |||
362 | switch (arg) |
||
363 | { |
||
364 | case PauseCombo _: |
||
365 | Interlocked.Increment(ref _comboCount); |
||
366 | |||
367 | return arg; |
||
368 | |||
369 | case KeyboardCombo _: |
||
370 | if (Configuration.Spring.Charge.Keyboard) |
||
371 | { |
||
372 | Interlocked.Increment(ref _comboCount); |
||
373 | |||
374 | return arg; |
||
375 | } |
||
376 | |||
377 | break; |
||
378 | |||
379 | case MouseCombo mouseCombo: |
||
380 | |||
381 | switch (mouseCombo.ComboAction) |
||
382 | { |
||
383 | case ComboAction.Move: |
||
384 | if (Configuration.Spring.Charge.MouseMove) |
||
385 | { |
||
386 | Interlocked.Increment(ref _comboCount); |
||
387 | |||
388 | return arg; |
||
389 | } |
||
390 | |||
391 | break; |
||
392 | case ComboAction.Up: |
||
393 | case ComboAction.Down: |
||
394 | if (Configuration.Spring.Charge.MouseClick) |
||
395 | { |
||
396 | Interlocked.Increment(ref _comboCount); |
||
397 | |||
398 | return arg; |
||
399 | } |
||
400 | |||
401 | break; |
||
402 | } |
||
403 | |||
404 | break; |
||
405 | |||
406 | default: |
||
407 | Debug.Assert(true, "Unknown combo found in combo record charge queue."); |
||
408 | |||
409 | break; |
||
410 | } |
||
411 | |||
412 | return null; |
||
413 | } |
||
414 | |||
415 | private static bool CompareSpringKeys(Combo combo, KeyAction keyAction) |
||
416 | { |
||
417 | if (!(combo is KeyboardCombo springKeyEventArgs) || !(keyAction is KeyActionKeys keyActionKeys)) |
||
418 | { |
||
419 | return false; |
||
420 | } |
||
421 | |||
422 | return springKeyEventArgs.Keys == keyActionKeys.Keys; |
||
423 | } |
||
424 | |||
425 | #endregion |
||
426 | } |
||
427 | } |