Establecer teclas de acceso rápido globales usando C#

Resuelto Crash893 asked hace 14 años • 3 respuestas

Necesito capturar una pulsación de tecla cuando mi programa no está enfocado. (es decir, Ctrl+ Alt+J ) y desencadenar un evento en mi programa.

Hasta ahora, encontré esta DLL que parece ser la ruta correcta:

[DllImport("user32.dll")]private static extern int RegisterHotKey(IntPtr hwnd, int id,int fsModifiers, int vk);

[DllImport("user32.dll")] private static extern int UnregisterHotKey(IntPtr hwnd, int id);
Crash893 avatar Mar 16 '10 03:03 Crash893
Aceptado

Tenga en cuenta que este código no activará eventos en proyectos de aplicaciones de consola . Tienes que usar WinFormsel proyecto para que los eventos se activen.

Este es el código correcto:

public sealed  class KeyboardHook : IDisposable
{
    // Registers a hot key with Windows.
    [DllImport("user32.dll")]
    private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
    // Unregisters the hot key with Windows.
    [DllImport("user32.dll")]
    private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

    /// <summary>
    /// Represents the window that is used internally to get the messages.
    /// </summary>
    private class Window : NativeWindow, IDisposable
    {
        private static int WM_HOTKEY = 0x0312;

        public Window()
        {
            // create the handle for the window.
            this.CreateHandle(new CreateParams());
        }

        /// <summary>
        /// Overridden to get the notifications.
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            // check if we got a hot key pressed.
            if (m.Msg == WM_HOTKEY)
            {
                // get the keys.
                Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
                ModifierKeys modifier = (ModifierKeys)((int)m.LParam & 0xFFFF);

                // invoke the event to notify the parent.
                if (KeyPressed != null)
                    KeyPressed(this, new KeyPressedEventArgs(modifier, key));
            }
        }

        public event EventHandler<KeyPressedEventArgs> KeyPressed;

        #region IDisposable Members

        public void Dispose()
        {
            this.DestroyHandle();
        }

        #endregion
    }

    private Window _window = new Window();
    private int _currentId;

    public KeyboardHook()
    {
        // register the event of the inner native window.
        _window.KeyPressed += delegate(object sender, KeyPressedEventArgs args)
        {
            if (KeyPressed != null)
                KeyPressed(this, args);
        };
    }

    /// <summary>
    /// Registers a hot key in the system.
    /// </summary>
    /// <param name="modifier">The modifiers that are associated with the hot key.</param>
    /// <param name="key">The key itself that is associated with the hot key.</param>
    public void RegisterHotKey(ModifierKeys modifier, Keys key)
    {
        // increment the counter.
        _currentId = _currentId + 1;

        // register the hot key.
        if (!RegisterHotKey(_window.Handle, _currentId, (uint)modifier, (uint)key))
            throw new InvalidOperationException("Couldn’t register the hot key.");
    }

    /// <summary>
    /// A hot key has been pressed.
    /// </summary>
    public event EventHandler<KeyPressedEventArgs> KeyPressed;

    #region IDisposable Members

    public void Dispose()
    {
        // unregister all the registered hot keys.
        for (int i = _currentId; i > 0; i--)
        {
            UnregisterHotKey(_window.Handle, i);
        }

        // dispose the inner native window.
        _window.Dispose();
    }

    #endregion
}

/// <summary>
/// Event Args for the event that is fired after the hot key has been pressed.
/// </summary>
public class KeyPressedEventArgs : EventArgs
{
    private ModifierKeys _modifier;
    private Keys _key;

    internal KeyPressedEventArgs(ModifierKeys modifier, Keys key)
    {
        _modifier = modifier;
        _key = key;
    }

    public ModifierKeys Modifier
    {
        get { return _modifier; }
    }

    public Keys Key
    {
        get { return _key; }
    }
}

/// <summary>
/// The enumeration of possible modifiers.
/// </summary>
[Flags]
public enum ModifierKeys : uint
{
    Alt = 1,
    Control = 2,
    Shift = 4,
    Win = 8
}

Para el caso de uso, tuve que editar las teclas modificadoras para emitirlas (modifier)1, (modifier)2etc.

public partial  class Form1 : Form
{
    KeyboardHook hook = new KeyboardHook();

    public Form1()
    {
        InitializeComponent();

        // register the event that is fired after the key press.
        hook.KeyPressed +=
            new EventHandler<KeyPressedEventArgs>(hook_KeyPressed);
        // register the control + alt + F12 combination as hot key.
        hook.RegisterHotKey(ModifierKeys.Control | ModifierKeys.Alt,
            Keys.F12);
    }

    void hook_KeyPressed(object sender, KeyPressedEventArgs e)
    {
        // show the keys pressed in a label.
        label1.Text = e.Modifier.ToString() + " + " + e.Key.ToString();
    }
}
AaronLS avatar Dec 05 '2014 05:12 AaronLS

Tomé la respuesta de AaronLS y la reescribí un poco para un registro simple de una sola línea.

El registro:

GlobalHotKey.RegisterHotKey("Alt + Shift + S", () => DoSomething());

La clase:

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

public class GlobalHotKey : IDisposable
{
    /// <summary>
    /// Registers a global hotkey
    /// </summary>
    /// <param name="aKeyGesture">e.g. Alt + Shift + Control + Win + S</param>
    /// <param name="aAction">Action to be called when hotkey is pressed</param>
    /// <returns>true, if registration succeeded, otherwise false</returns>
    public static bool RegisterHotKey(string aKeyGestureString, Action aAction)
    {
        var c = new KeyGestureConverter();
        KeyGesture aKeyGesture = (KeyGesture)c.ConvertFrom(aKeyGestureString);
        return RegisterHotKey(aKeyGesture.Modifiers, aKeyGesture.Key, aAction);
    }

    public static bool RegisterHotKey(ModifierKeys aModifier, Key aKey, Action aAction)
    {
        if(aModifier == ModifierKeys.None)
        {
            throw new ArgumentException("Modifier must not be ModifierKeys.None");
        }
        if (aAction is null)
        {
            throw new ArgumentNullException(nameof(aAction));
        }

        System.Windows.Forms.Keys aVirtualKeyCode = (System.Windows.Forms.Keys)KeyInterop.VirtualKeyFromKey(aKey);
        currentID = currentID + 1;
        bool aRegistered = RegisterHotKey(window.Handle, currentID,
                                    (uint)aModifier | MOD_NOREPEAT,
                                    (uint)aVirtualKeyCode);

        if(aRegistered)
        {
            registeredHotKeys.Add(new HotKeyWithAction(aModifier, aKey, aAction));
        }
        return aRegistered;
    }

    public void Dispose()
    {
        // unregister all the registered hot keys.
        for (int i = currentID; i > 0; i--)
        {
            UnregisterHotKey(window.Handle, i);
        }

        // dispose the inner native window.
        window.Dispose();
    }

    static GlobalHotKey()
    {
        window.KeyPressed += (s, e) =>
        {
            registeredHotKeys.ForEach(x =>
            {
                if (e.Modifier == x.Modifier && e.Key == x.Key)
                {
                    x.Action();
                }
            });
        };
    }

    private static readonly InvisibleWindowForMessages window = new InvisibleWindowForMessages();
    private static int currentID;
    private static uint MOD_NOREPEAT = 0x4000;
    private static List<HotKeyWithAction> registeredHotKeys = new List<HotKeyWithAction>();

    private class HotKeyWithAction
    {

        public HotKeyWithAction(ModifierKeys modifier, Key key, Action action)
        {
            Modifier = modifier;
            Key = key;
            Action = action;
        }

        public ModifierKeys Modifier { get; }
        public Key Key { get; }
        public Action Action { get; }
    }

    // Registers a hot key with Windows.
    [DllImport("user32.dll")]
    private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
    // Unregisters the hot key with Windows.
    [DllImport("user32.dll")]
    private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

    private class InvisibleWindowForMessages : System.Windows.Forms.NativeWindow, IDisposable
    {
        public InvisibleWindowForMessages()
        {
            CreateHandle(new System.Windows.Forms.CreateParams());
        }

        private static int WM_HOTKEY = 0x0312;
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == WM_HOTKEY)
            {
                var aWPFKey = KeyInterop.KeyFromVirtualKey(((int)m.LParam >> 16) & 0xFFFF);
                ModifierKeys modifier = (ModifierKeys)((int)m.LParam & 0xFFFF);
                if (KeyPressed != null)
                {
                    KeyPressed(this, new HotKeyPressedEventArgs(modifier, aWPFKey));
                }
            }
        }

        public class HotKeyPressedEventArgs : EventArgs
        {
            private ModifierKeys _modifier;
            private Key _key;

            internal HotKeyPressedEventArgs(ModifierKeys modifier, Key key)
            {
                _modifier = modifier;
                _key = key;
            }

            public ModifierKeys Modifier
            {
                get { return _modifier; }
            }

            public Key Key
            {
                get { return _key; }
            }
        }


        public event EventHandler<HotKeyPressedEventArgs> KeyPressed;

        #region IDisposable Members

        public void Dispose()
        {
            this.DestroyHandle();
        }

        #endregion
    }
}
 avatar Dec 22 '2020 16:12

Aquí hay un trabajovb.netpuerto de respuesta original :

TecladoHook.vb

Imports System.Runtime.InteropServices

Public NotInheritable Class KeyboardHook
    Implements IDisposable

    ' Registers a hot key with Windows.
    <DllImport("user32.dll")> _
    Private Shared Function RegisterHotKey(hWnd As IntPtr, id As Integer, fsModifiers As UInteger, vk As UInteger) As Boolean
    End Function

    ' Unregisters the hot key with Windows.
    <DllImport("user32.dll")> _
    Private Shared Function UnregisterHotKey(hWnd As IntPtr, id As Integer) As Boolean
    End Function

    ''' <summary>
    ''' Represents the window that is used internally to get the messages.
    ''' </summary>
    Private Class Window
        Inherits NativeWindow
        Implements IDisposable
        Private Shared WM_HOTKEY As Integer = &H312

        Public Sub New()
            ' create the handle for the window.
            Me.CreateHandle(New CreateParams())
        End Sub

        Public Event KeyPressed As EventHandler(Of KeyPressedEventArgs)

        ''' <summary>
        ''' Overridden to get the notifications.
        ''' </summary>
        ''' <param name="m"></param>
        Protected Overrides Sub WndProc(ByRef m As Message)
            MyBase.WndProc(m)

            ' check if we got a hot key pressed.
            If m.Msg = WM_HOTKEY Then
                ' get the keys.
                Dim key As Keys = DirectCast((CInt(m.LParam) >> 16) And &HFFFF, Keys)
                Dim modifier As ModifierKeys = DirectCast(CUInt(CInt(m.LParam) And &HFFFF), ModifierKeys)

                ' invoke the event to notify the parent.
                RaiseEvent KeyPressed(Me, New KeyPressedEventArgs(modifier, key))
            End If
        End Sub

#Region " IDisposable Members"

        Public Sub Dispose() Implements IDisposable.Dispose
            Me.DestroyHandle()
        End Sub

#End Region
    End Class

    Private _window As New Window()
    Private _currentId As Integer

    Public Sub New()
        ' register the event of the inner native window.
        AddHandler _window.KeyPressed, Sub(sender As Object, args As KeyPressedEventArgs)
                                           RaiseEvent KeyPressed(Me, args)
                                       End Sub
    End Sub

    ''' <summary>
    ''' Registers a hot key in the system.
    ''' </summary>
    ''' <param name="modifier">The modifiers that are associated with the hot key.</param>
    ''' <param name="key">The key itself that is associated with the hot key.</param>
    Public Sub RegisterHotKey(modifier As ModifierKeys, key As Keys)
        ' increment the counter.
        _currentId = _currentId + 1

        ' register the hot key.
        If Not RegisterHotKey(_window.Handle, _currentId, DirectCast(modifier, UInteger), CUInt(key)) Then
            'Throw New InvalidOperationException("Couldn’t register the hot key.")
            'or use MsgBox("Couldn’t register the hot key.")
        End If
    End Sub

    ''' <summary>
    ''' A hot key has been pressed.
    ''' </summary>
    Public Event KeyPressed As EventHandler(Of KeyPressedEventArgs)

#Region " IDisposable Members"

    Public Sub Dispose() Implements IDisposable.Dispose
        ' unregister all the registered hot keys.
        Dim i As Integer = _currentId
        While i > 0
            UnregisterHotKey(_window.Handle, i)
            System.Math.Max(System.Threading.Interlocked.Decrement(i), i + 1)
        End While

        ' dispose the inner native window.
        _window.Dispose()
    End Sub

#End Region
End Class

''' <summary>
''' Event Args for the event that is fired after the hot key has been pressed.
''' </summary>
Public Class KeyPressedEventArgs
    Inherits EventArgs
    Private _modifier As ModifierKeys
    Private _key As Keys

    Friend Sub New(modifier As ModifierKeys, key As Keys)
        _modifier = modifier
        _key = key
    End Sub

    Public ReadOnly Property Modifier() As ModifierKeys
        Get
            Return _modifier
        End Get
    End Property

    Public ReadOnly Property Key() As Keys
        Get
            Return _key
        End Get
    End Property
End Class

''' <summary>
''' The enumeration of possible modifiers.
''' </summary>
<Flags> _
Public Enum ModifierKeys As UInteger
    Alt = 1
    Control = 2
    Shift = 4
    Win = 8
End Enum

Formulario1.vb

Tareas:

  1. Reemplace 2 instancias de Application1lo siguiente con el nombre de su aplicación (se puede ver como la raíz del árbol en la ventana del Explorador de soluciones de Visual Studio ).
  2. Agregue una llamada AddGlobalHotkeySupport()a la etapa de inicialización de su aplicación.
  3. Agregue una llamada RemoveGlobalHotkeySupport()a la etapa de finalización de su solicitud.

Código:

Public Sub AddGlobalHotkeySupport()  'TODO: call this at initialization of the application

    ' register the event that is fired after the key press.
    AddHandler hook.KeyPressed, AddressOf hook_KeyPressed

    ' register the control + alt + F12 combination as hot key.
    hook.RegisterHotKey(Application1.ModifierKeys.Control Or Application1.ModifierKeys.Alt, Keys.F12)

End Sub

Public Sub RemoveGlobalHotkeySupport()  'TODO: call this at finalization of the application
    ' unregister all registered hot keys.
    hook.Dispose()
End Sub

Private Sub hook_KeyPressed(sender As Object, e As KeyPressedEventArgs)
    ' show the keys pressed in a label.
    MsgBox(e.Modifier.ToString() + " + " + e.Key.ToString())
End Sub
miroxlav avatar Jan 12 '2016 23:01 miroxlav