Laden...

Globale Hotkey Klasse

Erstellt von AyrA vor 10 Jahren Letzter Beitrag vor 10 Jahren 6.386 Views
AyrA Themenstarter:in
60 Beiträge seit 2010
vor 10 Jahren
Globale Hotkey Klasse

Beschreibung:

Dies ist eine einzelne Klasse, die globale Hotkeys zur Verfügung stellt. Sie ist in einer Art und Weise geschrieben, dass nichts vom Benutzer gespeichert werden muss und sie räumt hinterher wieder auf beim beenden.
Funktioniert nur mit einem Application Message Loop, also nicht mit Konsolenanwendung (es sei denn Application.Run() wird aufgerufen und die Warteschlange von Hand (!!) immer wieder abgearbeitet).

Klasse:
Die Hotkey Klasse is sehr grosszügig Kommentiert. Alle Member besitzen entsprechende Kommentare.


using System.Windows.Forms;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace AyrA
{
    /// <summary>
    /// This class allows global hotkeys to be registered and deleted.
    /// </summary>
    public class Hotkey
    {
        /// <summary>
        /// Registers a hotkey.
        /// </summary>
        /// <param name="hWnd">Handle to the form, can receive messages. Easiest: a form with overridden WndProc method</param>
        /// <param name="id">ID. this needs to be unique in the application</param>
        /// <param name="fsModifiers">Modifiers (alt, shift, ctrl, win, none) or a combination of those</param>
        /// <param name="vk">Virtual key. Equivalent to <see cref="System.Windows.Forms.Keys"/></param>
        /// <returns>true on success</returns>
        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);

        /// <summary>
        /// Unregisters a hotkey
        /// </summary>
        /// <param name="hWnd">Handle used to register the hotkey</param>
        /// <param name="id">ID used to register the hotkey</param>
        /// <returns>true on success</returns>
        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        /// <summary>
        /// This is the message type that needs to be captured in the WndProc override
        /// </summary>
        public const int WM_HOTKEY_MSG_ID = 0x0312;

        /// <summary>
        /// List of active hotkey hooks
        /// </summary>
        private List<HookInfo> hookedKeys;
        /// <summary>
        /// ID, is increased with each call to "enable(...)"
        /// </summary>
        private int freeID;

        /// <summary>
        /// Contains informations about a hooked hotkey
        /// </summary>
        public struct HookInfo
        {
            /// <summary>
            /// ID used
            /// </summary>
            public int ID;
            /// <summary>
            /// Handle used
            /// </summary>
            public IntPtr hWnd;
            /// <summary>
            /// Constructs the struct with initial values
            /// </summary>
            /// <param name="Handle"></param>
            /// <param name="id"></param>
            public HookInfo(IntPtr Handle,int id)
            {
                ID = id;
                hWnd = Handle;
            }
        }

        /// <summary>
        /// Possible modifier keys, can be combined, for example: "Shift | Alt"
        /// </summary>
        [Flags]
        public enum Modifiers : int
        {
            Win = 8,
            Shift = 4,
            Ctrl = 2,
            Alt = 1,
            None = 0
        }

        /// <summary>
        /// Gets a list of all hoked keys.
        /// </summary>
        public HookInfo[] HookedKeys
        {
            get
            {
                return hookedKeys.ToArray();
            }
        }

        /// <summary>
        /// Initializes a new Hotkey class. You should create only one (if possible) to not end up in null pointers.
        /// </summary>
        public Hotkey()
        {
            hookedKeys = new List<HookInfo>();
            freeID = 0;
        }

        /// <summary>
        /// Destructor. Silently removes all hooks.
        /// </summary>
        ~Hotkey()
        {
            unhookAll();
        }

        /// <summary>
        /// Removes all registered hooks.
        /// </summary>
        public void unhookAll()
        {
            for (int i = 0; i < hookedKeys.Count; i++)
            {
                disable(hookedKeys[i]);
            }
        }

        /// <summary>
        /// Enables a global hotkey hook
        /// </summary>
        /// <param name="Handle">Handle to a form or application message processing class that can receive messages. Easiest: a form with overridden WndProc method</param>
        /// <param name="Mod">Modifiers (Alt, Shift, ...)</param>
        /// <param name="Key">Key to record</param>
        /// <returns>Hook information, required for disabling. Can also be obtained with HookedKeys property</returns>
        public HookInfo enable(IntPtr Handle,Modifiers Mod, Keys Key)
        {
            HookInfo i=new HookInfo(Handle,freeID++);
            hookedKeys.Add(i);
            RegisterHotKey(Handle, i.ID, (int)Mod, (int)Key);
            return i;
        }

        /// <summary>
        /// Removes a hotkey
        /// </summary>
        /// <param name="i">Hotkey info</param>
        public void disable(HookInfo i)
        {
            RemoveHook(i);
            UnregisterHotKey(i.hWnd, i.ID);
        }

        /// <summary>
        /// removes a HookInfo from the list of hooked keys
        /// </summary>
        /// <param name="hInfo">HookInfo of a registered key</param>
        private void RemoveHook(HookInfo hInfo)
        {
            for (int i = 0; i < hookedKeys.Count; i++)
            {
                if (hookedKeys[i].hWnd == hInfo.hWnd && hookedKeys[i].ID == hInfo.ID)
                {
                    hookedKeys.RemoveAt(i--);
                }
            }
        }
    }
}

Verwendung in einem Form (Teil 1):
Zeigt, wie Hotkeys registriert werden können, wenn das Form geladen wird.
Vom Rückgabewert der Enable Funktion, sollte die ID gespeichert werden, wenn vorher der Programm Ablauf nicht bekannt ist (z.B. wenn der Benutzer dynamisch welche registrieren kann). Grundsätzlich beginnt die ID bei 0 und wird mit jedem Aufruf der enable um 1 erhöht, auch wenn zwischendurch ein Aufruf an disable erfolgt.
Der Aufruf kann theoretisch jederzeit stattfinden und Das Handle kann von einem beliebigen Form in der Anwendung sein.


        private Hotkey HK;
        public frmMain()
        {
            InitializeComponent();

            HK = new Hotkey();
            HK.enable(this.Handle, Hotkey.Modifiers.Alt, Keys.Back);
            HK.enable(this.Handle, Hotkey.Modifiers.Alt | Hotkey.Modifiers.Ctrl, Keys.Back);
            HK.enable(this.Handle, Hotkey.Modifiers.Alt | Hotkey.Modifiers.Ctrl | Hotkey.Modifiers.Shift, Keys.Back);
        }


Verwendung in einem Form (Teil 2):
Nun wird die Methode WndProc ins Formular eingefügt. Die Methode muss in das Formular eingefügt werden, dessen Handle bei der enable() Funktion angegeben wurde.
Jedesmal, wenn eine Message ankommt (der Parameter Message is übrigens in System.Windows.Forms vorhanden) wird diese Funktion aufgerufen.
Wir prüfen auf den Typ WM_HOTKEY_MSG_ID, die Konstante ist in der Hotkey Klasse vorhanden. Dies ist wichtig, da auch andere Nachrichten typen ankommen. der Pointer WParam enthält die ID, die die enable() Funktion der Hotkey Klasse als Rückgabe ausgibt.


        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case Hotkey.WM_HOTKEY_MSG_ID:
                    switch ((int)m.WParam)
                    {
                        case 0:
                            //Erster registrierter Hotkey
                            break;
                        case 1:
                            //Zweiter registrierter Hotkey
                            break;
                        case 2:
                            //Dritter registrierter Hotkey
                            break;
                    }
                    break;
            }
            //WICHTIG! Folgende Zeile muss da sein,
            //sonst funktioniert die gesammte Anwendung nicht!
            base.WndProc(ref m);
        }

Beispiel
Die Klasse wird in diesem Projekt hier verwendet.

Schlagwörter: WinAPI API Keyboard Hook Hotkey Hotkeys global globale

**:::

Hinweis von herbivore vor 10 Jahren

Siehe auch Hotkey-Klasse