F
F
Fire Place2020-02-16 18:12:27
Keyboard
Fire Place, 2020-02-16 18:12:27

How to implement global interception of keyboard key presses (hook)?

In the hook that I found on the web, everything seems to be clear and simple, but it doesn’t reach me how to call it, and I don’t understand how to declare instead of the key with "d" with the Keys parameter (In the main form - NewForm), only one, the one that you click in the 2nd form and which is stored in Storage.cs.

PS [HookKeyBoard] - Everything related to the hook.

UPD: I uploaded everything to Yandex.disk, so far I'm not in trouble with the git, that's why I chose poison. I really hope that you can help ..
https://yadi.sk/d/RNTbfC9kfCXiZw

Hook itself
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
        }
    }
}

The main form in which the hook and keystroke emulation should occur
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 + "}");
            }
        }

The form in which the user enters a key (which, when pressed, will emulate its own pressing on a timer) - in 1 form
private void ChooseKeyForm_KeyDown(object sender, KeyEventArgs e)
        {
            Storage.KeyStr = e.KeyCode.ToString();
            Storage.KeyData = e.KeyValue;
            this.Dispose();
        }

The class in which variables are stored in order to pass them between forms
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; }
    }

I clarify what I need to do. The hook catches all keystrokes with modifiers and subsequently registers them. I also need to catch only one key (the user selects it himself) with modifiers (ALT, WIN, SHIFT, CTRL) - these modifiers are already written, so you don’t need to touch them. But I ran into the problem of registering this key, since in the hook the registration is done directly through Keys, and I need to do this registration through the key that is stored in the Storage class (which is set by the user)

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question