misu – Rev 8

Subversion Repositories:
Rev:
using System;
using System.ComponentModel;
using System.Configuration;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks.Dataflow;
using System.Windows.Forms;
using AutoUpdaterDotNET;
using Gma.System.MouseKeyHook;
using misu.Properties;

namespace misu
{
    public partial class MisuMainForm : Form
    {
        #region Private Delegates, Events, Enums, Properties, Indexers and Fields

        private BufferBlock<KeyEventArgs> PressedKeysBufferBlock { get; }

        private IKeyboardMouseEvents GlobalHook { get; }

        private AboutForm AboutForm { get; set; }

        private BindKeyForm BindKeyForm { get; set; }

        private volatile bool _lock;

        #endregion

        #region Constructors, Destructors and Finalizers

        public MisuMainForm()
        {
            InitializeComponent();
            AutoUpdater.Start("http://misu.grimore.org/update/update.xml");

            // Upgrade settings if required.
            if (!ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).HasFile)
            {
                Settings.Default.Upgrade();
            }

            // Bind to settings changed event.
            Settings.Default.SettingsLoaded += Default_SettingsLoaded;
            Settings.Default.SettingsSaving += Default_SettingsSaving;
            Settings.Default.PropertyChanged += Default_PropertyChanged;

            PressedKeysBufferBlock = new BufferBlock<KeyEventArgs>(new DataflowBlockOptions {EnsureOrdered = true});

            // Hook to global events.
            GlobalHook = Hook.GlobalEvents();

            // Bind to receive keyboard presses.
            GlobalHook.KeyDown += GlobalHook_KeyDown;
            GlobalHook.KeyUp += GlobalHook_KeyUp;

            GlobalHook.MouseUpExt += GlobalHook_BlockMouse;
            GlobalHook.MouseDragFinishedExt += GlobalHook_BlockMouse;
            GlobalHook.MouseDragStartedExt += GlobalHook_BlockMouse;
            GlobalHook.MouseWheelExt += GlobalHook_BlockMouse;
            GlobalHook.MouseMoveExt += GlobalHook_BlockMouse;
            GlobalHook.MouseDownExt += GlobalHook_BlockMouse;

            if (Settings.Default.Keys != null)
            {
                Notify("Shortcut is bound.",
                    $"Press {string.Join(" ", Settings.Default.Keys.OfType<string>())} to toggle locking.");
            }
        }

        #endregion

        #region Event Handlers

        private static void Default_SettingsSaving(object sender, CancelEventArgs e)
        {
        }

        private static void Default_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            Settings.Default.Save();
        }

        private static void Default_SettingsLoaded(object sender, SettingsLoadedEventArgs e)
        {
        }

        private void GlobalHook_BlockMouse(object sender, MouseEventExtArgs e)
        {
            // Do not perform any operations while the binding form is visible.
            if (BindKeyForm != null && BindKeyForm.Visible)
            {
                return;
            }

            if (_lock && Settings.Default.Mouse)
            {
                e.Handled = true;
            }
        }

        private void GlobalHook_KeyUp(object sender, KeyEventArgs e)
        {
            // Do not perform any operations while the binding form is visible.
            if (BindKeyForm != null && BindKeyForm.Visible)
            {
                return;
            }

            if (!PressedKeysBufferBlock.TryReceiveAll(out var keys))
            {
                return;
            }

            if (Settings.Default.Keys == null)
            {
                return;
            }

            if (!Settings.Default.Keys.OfType<string>().SequenceEqual(keys.Select(key => key.KeyCode.ToString())))
            {
                return;
            }

            _lock = !_lock;

            // Lock the cursor in position.
            switch (_lock)
            {
                case true:
                    Cursor.Clip = new Rectangle(Cursor.Position, new Size(1, 1));
                    break;
                default:
                    Cursor.Clip = Screen.PrimaryScreen.Bounds;
                    break;
            }

            // Dismiss the current keypress to avoid typing the key.
            e.Handled = true;
            e.SuppressKeyPress = true;

            Notify($"Mouse and Keyboard are {(_lock ? "locked" : "unlocked")}.",
                $"Press {string.Join(" ", Settings.Default.Keys.OfType<string>())} to toggle mouse and keyboard locking.");
        }

        private async void GlobalHook_KeyDown(object sender, KeyEventArgs e)
        {
            // Do not perform any operations while the binding form is visible.
            if (BindKeyForm != null && BindKeyForm.Visible)
            {
                return;
            }

            if (_lock && Settings.Default.Keyboard)
            {
                e.SuppressKeyPress = true;
                e.Handled = true;
            }

            await PressedKeysBufferBlock.SendAsync(e);
        }

        private void OnContextMenuAboutClick(object sender, EventArgs e)
        {
            // Show the about form.
            AboutForm = new AboutForm();
            AboutForm.Show();
        }

        private void OnContextMenuQuitClick(object sender, EventArgs e)
        {
            Close();

            Environment.Exit(0);
        }

        private void OnContextMenuLaunchOnBootChanged(object sender, EventArgs e)
        {
            Settings.Default.LaunchOnBoot = ((ToolStripMenuItem) sender).Checked;

            Utilities.LaunchOnBootSet(Settings.Default.LaunchOnBoot);
        }

        private void OnContextMenuBindKeyClick(object sender, EventArgs e)
        {
            BindKeyForm = new BindKeyForm(GlobalHook);
            BindKeyForm.KeyBound += BindKeyForm_KeyBound;
            BindKeyForm.Closing += BindKeyForm_Closing;
            BindKeyForm.Show();
        }

        private void BindKeyForm_Closing(object sender, CancelEventArgs e)
        {
            BindKeyForm.KeyBound -= BindKeyForm_KeyBound;
            BindKeyForm.Closing -= BindKeyForm_Closing;
        }

        private async void BindKeyForm_KeyBound(object sender, KeyBoundEventArgs e)
        {
            Notify("Shortcut key is bound.",
                $"Press {string.Join(" ", Settings.Default.Keys.OfType<string>())} to toggle between locked and unlocked keyboard and mouse.");
        }

        private void KeyboardToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
        {
            var item = (ToolStripMenuItem) sender;

            Settings.Default.Keyboard = item.Checked;
        }

        private void MouseToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
        {
            var item = (ToolStripMenuItem) sender;

            Settings.Default.Mouse = item.Checked;
        }

        private void ContextMenuStrip_Opening(object sender, CancelEventArgs e)
        {
            // Apply the settings to the menu items.
            launchOnBootToolStripMenuItem.Checked = Settings.Default.LaunchOnBoot;
            Utilities.LaunchOnBootSet(Settings.Default.LaunchOnBoot);

            mouseToolStripMenuItem.Checked = Settings.Default.Mouse;
            keyboardToolStripMenuItem.Checked = Settings.Default.Keyboard;
        }

        #endregion

        #region Private Methods

        private void Notify(string title, string message, int timeout = 10000)
        {
            misuNotificationIcon.BalloonTipTitle = title;
            misuNotificationIcon.BalloonTipText = message;
            // the timeout parameter is not used for Windows Vista and up
            misuNotificationIcon.ShowBalloonTip(timeout);
        }

        #endregion
    }
}

Generated by GNU Enscript 1.6.5.90.