Как реализовать глобальный перехват нажатия клавиш клавиатуры (hook)?

В хуке, который я нашел на просторах сети, вроде-бы все понятно и просто, но до меня не доходит как его вызывать, и не понимаю как объявить вместо клавиши с "d" с параметром Keys (В основной форме - NewForm), только одну, ту которую нажимаешь в 2 форме и которая хранится в Storage.cs.

P.S. [HookKeyBoard] - Все связанное с хуком.

UPD: Загрузил все на яндекс.диск, с гитом пока-что не в ладах, поэтому и выбрал яд. Очень надеюсь что поможете..
https://yadi.sk/d/RNTbfC9kfCXiZw

Сам хук
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SplashSpamKey
{
    class GlobalKeyHook
    {
        /// <summary>
        /// Specifies key modifiers.
        /// </summary>
        [Flags]
        public enum KeyModifiers : uint
        {
            /// <summary>
            /// Empty modifiers
            /// </summary>
            None = 0x0000,
            /// <summary>
            /// Either ALT key must be held down.
            /// </summary>
            Alt = 0x0001,
            /// <summary>
            /// Either CTRL key must be held down.
            /// </summary>
            Control = 0x0002,
            /// <summary>
            /// Either SHIFT key must be held down.
            /// </summary>
            Shift = 0x0004,
            /// <summary>
            /// Either WINDOWS key was held down. 
            /// These keys are labeled with the Windows logo. 
            /// Keyboard shortcuts that involve the WINDOWS key are reserved for use by the operating system.
            /// </summary>
            Windows = 0x0008,
            //IgnoreAllModifier   = 0x0400,
            //OnKeyUp             = 0x0800,
            //MouseRight          = 0x4000,
            //MouseLeft           = 0x8000,
        }

        //Сам хук [HookKeyBoard]

        public class HotKey : IMessageFilter, IDisposable
        {
            #region Extern
            const int WM_HOTKEY = 0x312;
            const int ERROR_HOTKEY_ALREADY_REGISTERED = 0x581;

            [DllImport("user32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool RegisterHotKey(IntPtr hWnd, IntPtr id, KeyModifiers fsModifiers, Keys vk);

            [DllImport("user32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool UnregisterHotKey(IntPtr hWnd, IntPtr id);
            #endregion

            private IntPtr windowHandle;
            public event HandledEventHandler Pressed;

            public HotKey()
                : this(Keys.None, KeyModifiers.None)
            {
            }

            public HotKey(Keys keyCode, KeyModifiers modifiers)
            {
                this.KeyCode = keyCode;
                this.Modifiers = modifiers;
                Application.AddMessageFilter(this);
            }

            ~HotKey()
            {
                this.Dispose();
            }

            public void Dispose()
            {
                if (this.IsRegistered)
                    this.Unregister();

                this.windowHandle = IntPtr.Zero;
                this.Modifiers = KeyModifiers.None;
                this.KeyCode = Keys.None;
                this.Tag = 0;
            }

            private bool OnPressed()
            {
                HandledEventArgs e = new HandledEventArgs(false);
                if (this.Pressed != null)
                    this.Pressed(this, e);

                return e.Handled;
            }

            /// <summary>
            /// Filters out a message before it is dispatched.
            /// </summary>
            /// <param name="message">
            /// The message to be dispatched. You cannot modify this message.
            /// </param>
            /// <returns>
            /// true to filter the message and stop it from being dispatched;
            /// false to allow the message to continue to the next filter or control.
            /// </returns>
            public bool PreFilterMessage(ref Message message)
            {
                if (message.Msg != WM_HOTKEY || !this.IsRegistered)
                    return false;

                if (message.WParam == this.Guid)
                    return this.OnPressed();

                return false;
            }

            /// <summary>
            /// Defines a system-wide hot key.
            /// </summary>
            /// <param name="windowControl">
            /// A handle to the window that will receive messages generated by the hot key. 
            /// </param>
            public void Register(Control window)
            {
                if (this.IsRegistered)
                    throw new NotSupportedException("Ты не можешь зарегистровать уже занятый хоткей");
                if (this.IsEmpty)
                    throw new NotSupportedException("Ты не можешь зарегистрировать пустой хоткей");
                if (window.IsDisposed)
                    throw new ArgumentNullException("window");

                this.windowHandle = window.Handle;
                if (!RegisterHotKey(this.windowHandle, this.Guid, this.Modifiers, this.KeyCode))
                {
                    if (Marshal.GetLastWin32Error() != ERROR_HOTKEY_ALREADY_REGISTERED)
                        throw new Win32Exception();
                }
                this.IsRegistered = true;
            }

            /// <summary>
            /// Frees a hot key previously registered by the calling thread.
            /// </summary>
            public void Unregister()
            {
                if (!this.IsRegistered)
                    return;

                if (!UnregisterHotKey(this.windowHandle, this.Guid))
                    throw new Win32Exception();

                this.IsRegistered = false;
            }

            public bool HasModifier(KeyModifiers modifiers)
            {
                return (this.Modifiers & modifiers) != 0;
            }

            public static HotKey Parse(object content)
            {
                if (content == null)
                    return new HotKey();

                return Parse(content.ToString());
            }
            #region Fields

            private IntPtr Guid
            {
                get { return new IntPtr((int)Modifiers << 16 | (int)KeyCode & 0xFFFF); }
            }

            public bool IsEmpty
            {
                get { return (this.KeyCode == Keys.None); }
            }
            public bool IsRegistered { get; private set; }
            public KeyModifiers Modifiers { get; private set; }
            public Keys KeyCode { get; private set; }
            public int Tag { get; set; }
            #endregion
        }
    }
}

Основная форма в которой и должен происходить хук и эмуляция нажатия клавиши
private void NewForm_KeyDown(object sender, KeyEventArgs e)
        {

            if (e.KeyValue == Storage.KeyData)
            {
                if (Storage.IsEnabled == false)
                {
                    Storage.IsEnabled = true;
                    Storage.RandValue = true;

                    StatusOnOff.BackColor = Color.Green;
                    timer1.Start();

                    //Пример использования хука [HookKeyBoard] Если не понятно что это вообще за проект и что он должен делать, закоментите пример ниже и запустите проект
                    var hkey = new HotKey(Keys.D, KeyModifiers.None); //Вместо "D" Нужна кнопка которую задает пользователь (Хранится в storage.cs)
                    hkey.Pressed += (o, e) => { timer1.Start(); e.Handled = true; };
                    hkey.Register(this);
                }
            }
        }
        private void NewForm_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyValue == Storage.KeyData)
            {
                if (Storage.IsEnabled == true)
                {
                    Storage.IsEnabled = false;
                    Storage.RandValue = false;

                    StatusOnOff.BackColor = Color.Red;
                    timer1.Stop();


                }
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Random rand = new Random();
            while (Storage.RandValue == true)
            {
                int kk = rand.Next(100, 250);
                timer1.Interval = kk;
                SendKeys.SendWait("{" + Storage.KeyStr + "}");
            }
        }

Форма в которой пользователь вводит клавишу, (которая при зажатии будет эмулировать своё-же нажатие по таймеру) - в 1 форме
private void ChooseKeyForm_KeyDown(object sender, KeyEventArgs e)
        {
            Storage.KeyStr = e.KeyCode.ToString();
            Storage.KeyData = e.KeyValue;
            this.Dispose();
        }

Класс в котором хранятся переменные, для того чтобы передавать их между формами
internal class Storage {
        public static string KeyStr { get; set; }
        public static int KeyData { get; set; }
        public static bool IsEnabled { get; set; }
        public static bool RandValue { get; set; }
    }

Уточняю что мне нужно сделать. В хуке идет отлов нажатий всех клавиш с модификаторами и в последствии их регистрация. Мне-же нужно сделать отлов только одной клавиши (пользователь сам её выбирает) с модификаторами (ALT,WIN,SHIFT,CTRL) - эти модификаторы уже написаны, поэтому их трогать не нужно. Но я столкнулся с проблемой регистрации этой клавиши, так как в хуке регистрация на прямую через Keys, а мне нужно сделать эту регистрацию через ту клавишу, которая хранится в классе Storage (которую задает пользователь)
  • Вопрос задан
  • 2237 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы