WingMan – Rev 10

Subversion Repositories:
Rev:
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using MQTTnet;
using SimWinInput;
using WingMan.Communication;

namespace WingMan.MouseKey
{
    public class KeySimulator : IDisposable
    {
        public delegate void MouseKeyBindingExecuting(object sender, KeyBindingExecutingEventArgs args);

        public KeySimulator(LocalKeyBindings localLocalKeyBindings, MqttCommunication mqttCommunication,
            TaskScheduler formTaskScheduler, CancellationToken cancellationToken)
        {
            LocalLocalKeyBindings = localLocalKeyBindings;
            MqttCommunication = mqttCommunication;
            TaskScheduler = formTaskScheduler;
            CancellationToken = cancellationToken;

            MqttCommunication.OnMessageReceived += OnMqttMessageReceived;
        }

        private MqttCommunication MqttCommunication { get; }
        private TaskScheduler TaskScheduler { get; }
        private CancellationToken CancellationToken { get; }
        private LocalKeyBindings LocalLocalKeyBindings { get; }

        public void Dispose()
        {
            MqttCommunication.OnMessageReceived -= OnMqttMessageReceived;
        }

        public event MouseKeyBindingExecuting OnMouseKeyBindingExecuting;

        private async void OnMqttMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
        {
            if (e.ApplicationMessage.Topic != "execute")
                return;

            using (var memoryStream = new MemoryStream(e.ApplicationMessage.Payload))
            {
                var executeMouseKeyBinding =
                    (ExecuteKeyBinding) ExecuteKeyBinding.XmlSerializer.Deserialize(memoryStream);

                // Do not process own mouse key bindings.
                if (!string.Equals(executeMouseKeyBinding.Nick, MqttCommunication.Nick, StringComparison.Ordinal))
                    return;

                await Task.Delay(0, CancellationToken)
                    .ContinueWith(
                        _ => OnMouseKeyBindingExecuting?.Invoke(sender,
                            new KeyBindingExecutingEventArgs(executeMouseKeyBinding.Nick,
                                executeMouseKeyBinding.Name)),
                        CancellationToken,
                        TaskContinuationOptions.None, TaskScheduler);

                Simulate(executeMouseKeyBinding);
            }
        }

        private void Simulate(ExecuteKeyBinding executeBinding)
        {
            foreach (var localBinding in LocalLocalKeyBindings.Bindings)
            {
                if (!string.Equals(localBinding.Name, executeBinding.Name, StringComparison.Ordinal))
                    continue;

                // Press
                foreach (var key in localBinding.Keys)
                {
                    if (KeyConversion.StringToKeys.TryGetValue(key, out var pressKey))
                    {
                        SimKeyboard.KeyDown(pressKey);
                        continue;
                    }

                    if (KeyConversion.StringToMouseButtons.TryGetValue(key, out var pressMouse))
                        switch (pressMouse)
                        {
                            case MouseButtons.Left:
                                SimMouse.Act(SimMouse.Action.LeftButtonDown, Cursor.Position.X, Cursor.Position.Y);
                                break;
                            case MouseButtons.Middle:
                                SimMouse.Act(SimMouse.Action.MiddleButtonDown, Cursor.Position.X, Cursor.Position.Y);
                                break;
                            case MouseButtons.Right:
                                SimMouse.Act(SimMouse.Action.RightButtonDown, Cursor.Position.X, Cursor.Position.Y);
                                break;
                        }
                }

                // Depress
                foreach (var key in localBinding.Keys)
                {
                    if (KeyConversion.StringToKeys.TryGetValue(key, out var pressKey))
                    {
                        SimKeyboard.KeyUp(pressKey);
                        continue;
                    }

                    if (KeyConversion.StringToMouseButtons.TryGetValue(key, out var pressMouse))
                        switch (pressMouse)
                        {
                            case MouseButtons.Left:
                                SimMouse.Act(SimMouse.Action.LeftButtonUp, Cursor.Position.X, Cursor.Position.Y);
                                break;
                            case MouseButtons.Middle:
                                SimMouse.Act(SimMouse.Action.MiddleButtonUp, Cursor.Position.X, Cursor.Position.Y);
                                break;
                            case MouseButtons.Right:
                                SimMouse.Act(SimMouse.Action.RightButtonUp, Cursor.Position.X, Cursor.Position.Y);
                                break;
                        }
                }
            }
        }
    }
}