WingMan

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 9  →  ?path2? @ 10
/trunk/WingMan/MouseKey/KeyInterceptor.cs
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Gma.System.MouseKeyHook;
using WingMan.Communication;
 
namespace WingMan.MouseKey
{
public class KeyInterceptor : IDisposable
{
public delegate void MouseKeyBindingMatched(object sender, KeyBindingMatchedEventArgs args);
 
public KeyInterceptor(RemoteKeyBindings remoteKeyBindings, MqttCommunication mqttCommunication,
TaskScheduler taskScheduler, CancellationToken cancellationToken)
{
RemoteKeyBindings = remoteKeyBindings;
MqttCommunication = mqttCommunication;
TaskScheduler = taskScheduler;
CancellationToken = cancellationToken;
 
KeyCombo = new List<string>();
 
MouseKeyGloalHook = Hook.GlobalEvents();
MouseKeyGloalHook.KeyUp += MouseKeyGloalHookOnKeyUp;
MouseKeyGloalHook.KeyDown += MouseKeyGloalHookOnKeyDown;
}
 
private RemoteKeyBindings RemoteKeyBindings { get; }
private MqttCommunication MqttCommunication { get; }
private TaskScheduler TaskScheduler { get; }
private CancellationToken CancellationToken { get; }
 
private IKeyboardMouseEvents MouseKeyGloalHook { get; }
 
public List<string> KeyCombo { get; set; }
 
public void Dispose()
{
MouseKeyGloalHook.KeyUp -= MouseKeyGloalHookOnKeyUp;
MouseKeyGloalHook.KeyDown -= MouseKeyGloalHookOnKeyDown;
 
MouseKeyGloalHook.Dispose();
}
 
public event MouseKeyBindingMatched OnMouseKeyBindingMatched;
 
private void MouseKeyGloalHookOnKeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = false;
 
if (KeyConversion.KeysToString.TryGetValue((byte) e.KeyCode, out var key)) KeyCombo.Add(key);
}
 
private void MouseKeyGloalHookOnKeyUp(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = false;
 
var combo = new List<string>(KeyCombo);
 
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(() => SimulateMouseKey(new List<string>(combo)), CancellationToken);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
 
KeyCombo.Clear();
}
 
private async Task SimulateMouseKey(List<string> mouseKeyCombo)
{
foreach (var binding in RemoteKeyBindings.Bindings)
{
if (!binding.Keys.SequenceEqual(mouseKeyCombo))
continue;
 
// Raise the match event.
await Task.Delay(0, CancellationToken)
.ContinueWith(
_ => OnMouseKeyBindingMatched?.Invoke(this,
new KeyBindingMatchedEventArgs(binding.Nick, binding.Name, binding.Keys)),
CancellationToken,
TaskContinuationOptions.None, TaskScheduler);
 
using (var memoryStream = new MemoryStream())
{
ExecuteKeyBinding.XmlSerializer.Serialize(memoryStream,
new ExecuteKeyBinding(binding.Nick, binding.Name));
 
memoryStream.Position = 0L;
 
await MqttCommunication.Broadcast("execute", memoryStream.ToArray());
}
}
}
}
}