HowTo: Crear un hook de teclado para registrar una hotkey en nuestra aplicación

hook

Hola de nuevo,

En los grupos de MSDN suele haber bastantes preguntas acerca de crear hooks de teclado, para que nuestra aplicación pueda ejecutar alguna acción determinada, en respuesta a alguna pulsación de teclado, aunque no esté activa.

He creado una pequeña clase llamada WindowsShell que contiene el código necesario para registrar una hotkey y asociarla a un formulario:

   1: using System;
   2: using System.Runtime.InteropServices;
   3: using System.Windows.Forms;
   4:  
   5: namespace TestRegisterHotKey
   6: {
   7:     public class WindowsShell
   8:     {
   9:         public enum ModifierEnum
  10:         {
  11:             MOD_ALT = 0x1,
  12:             MOD_CONTROL = 0x2,
  13:             MOD_SHIFT = 0x4,
  14:             MOD_WIN = 0x8
  15:         }
  16:  
  17:         private static int keyId;
  18:         public static int WM_HOTKEY = 0x312;
  19:  
  20:         [DllImport("user32.dll")]
  21:         private static extern bool RegisterHotKey(
  22:             IntPtr hWnd, int id, int fsModifiers, int vlc);
  23:  
  24:         [DllImport("user32.dll")]
  25:         private static extern bool UnregisterHotKey(
  26:             IntPtr hWnd, int id);
  27:  
  28:         public static void RegisterHotKey(Form f, Keys key)
  29:         {
  30:             int modifiers = 0;
  31:             if ((key & Keys.Alt) == Keys.Alt)
  32:                 modifiers = modifiers | (int)WindowsShell.ModifierEnum.MOD_ALT;
  33:             if ((key & Keys.Control) == Keys.Control)
  34:                 modifiers = modifiers | (int)WindowsShell.ModifierEnum.MOD_CONTROL;
  35:             if ((key & Keys.Shift) == Keys.Shift)
  36:                 modifiers = modifiers | (int)WindowsShell.ModifierEnum.MOD_SHIFT;
  37:             Keys k = key & ~Keys.Control & ~Keys.Shift & ~Keys.Alt;
  38:             f.Invoke(new Action(() =>
  39:             {
  40:                 keyId = f.GetHashCode();
  41:                 RegisterHotKey((IntPtr)f.Handle, keyId, modifiers, (int)k);
  42:             }));
  43:         }
  44:  
  45:         public static void UnregisterHotKey(Form f)
  46:         {
  47:             try
  48:             {
  49:                 f.Invoke(new Action(() =>
  50:                 {
  51:                     UnregisterHotKey(f.Handle, keyId);
  52:                 }));
  53:             }
  54:             catch (Exception)
  55:             {
  56:                 throw;
  57:             }
  58:         }
  59:  
  60:     }
  61: }

Posteriormente, para poder usar esta clase en un formulario cualquiera debemos interceptar el bucle de mensajes de Windows, y preguntar si se ha producido el mensaje en cuestión, y si la pulsación corresponde a nuestra hotkey:

   1: using System;
   2: using System.Windows.Forms;
   3:  
   4: namespace TestRegisterHotKey
   5: {
   6:     public partial class Form1 : Form
   7:     {        
   8:         public Form1()
   9:         {
  10:             InitializeComponent();
  11:             this.Shown += Form1_Shown;
  12:             this.FormClosed += Form1_FormClosed;
  13:         }
  14:  
  15:         void Form1_FormClosed(object sender, FormClosedEventArgs e)
  16:         {
  17:             WindowsShell.UnregisterHotKey(this);
  18:         }
  19:  
  20:         void Form1_Shown(object sender, EventArgs e)
  21:         {
  22:             Keys k = Keys.A | Keys.Control;
  23:             WindowsShell.RegisterHotKey(this, k);
  24:         }
  25:  
  26:         protected override void WndProc(ref Message m)
  27:         {
  28:             if (m.Msg == WindowsShell.WM_HOTKEY)
  29:             {
  30:                 Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
  31:                 WindowsShell.ModifierEnum modifier = 
  32:                     (WindowsShell.ModifierEnum)((int)m.LParam & 0xFFFF);
  33:                 if (key == Keys.A && modifier == WindowsShell.ModifierEnum.MOD_CONTROL)
  34:                     showForm();
  35:             }
  36:             base.WndProc(ref m);
  37:         }
  38:  
  39:         private void showForm()
  40:         {
  41:             this.Text = 
  42:                 String.Format("Hokey pressed at: {0}", 
  43:                 DateTime.Now.ToLongTimeString());
  44:             this.Show();
  45:             if (this.WindowState == FormWindowState.Minimized)
  46:                 this.WindowState = FormWindowState.Normal;
  47:         }
  48:     }
  49: }

 

Espero que a más de uno le sirva,

HYEI :-)

Published 17/11/2010 13:59 por Lluis Franco
Archivado en: ,,
Comparte este post:

Comentarios

# re: HowTo: Crear un hook de teclado para registrar una hotkey en nuestra aplicación

Wednesday, November 17, 2010 4:16 PM por Juan Irigoyen

Un pequeño apunte, para capturar la pulsación de teclas en un formulario determinado quizás este método no sería necesario, se podría utilizar el método KeyDown del formulario o sobrescribir el método ProcessCmdKey sin necesidad de utilizar funciones de la Api de Windows, hay que tener en cuenta que añadir hooks al sistema no es algo que se debe tomar a la ligera, de hecho se debe liberar el hook en el  destructor de la clase, si no fuese así el hook estaría en el sistema hasta que se reinicie. Al hacer uso de la API Win32 no se programa como en c# en el que existen recolectores de basura y otros algoritmos para facilitarnos la vida, bajo Win32 es fácil dejar fugas de memoria, hooks enlazados, y otras series de cosas que pueden ocasionar que el sistema sea inestable.

Un saludo.

# re: HowTo: Crear un hook de teclado para registrar una hotkey en nuestra aplicación

Wednesday, November 17, 2010 5:21 PM por Javier Torrecilla

@Juan, el tema es para controlar si la aplicación se encuentra minimizada, creo recordar que si sobreescribes el processCMDKey no lo capturaría.

# re: HowTo: Crear un hook de teclado para registrar una hotkey en nuestra aplicación

Wednesday, November 17, 2010 5:41 PM por Lluis Franco

@Juan, el método que describes es válido sólo si el formulario tiene el foco.

El objetivo del hook es poder dirigir pulsaciones del s.o. hacia un formulario sin que éste tenga el foco.

Vaya, es ideal para crear un 'bicho' que lea las pulsaciones de teclado del usuario :-)))

# re: HowTo: Crear un hook de teclado para registrar una hotkey en nuestra aplicación

Wednesday, November 17, 2010 6:59 PM por Juan Irigoyen

Entiendo, lo habéis diseñado para hakear información... :)

# re: HowTo: Crear un hook de teclado para registrar una hotkey en nuestra aplicación

Wednesday, November 17, 2010 7:10 PM por Lluis Franco

Hombre! La técnica es la misma, pero es simplemente otro ejemplo más de un hook de teclado. Por ejemplo para tener tu aplicación minimizada en los iconos de notificación y poder mostrarla mediante una combinación de teclas :-)

Pero amos, que si, que también sirve para lo otro... :-P

# re: HowTo: Crear un hook de teclado para registrar una hotkey en nuestra aplicación

Wednesday, November 17, 2010 7:18 PM por Jorge Serrano

Es lo primero en lo que he pensado... ¡hombre un post para hacerme un logger!

# re: HowTo: Crear un hook de teclado para registrar una hotkey en nuestra aplicación

Thursday, November 18, 2010 8:17 AM por Eduard Tomàs i Avellana

Bueno...

Para hacer un keylogger y registrar todo lo que se pulse en el ordenador, necesitarías usar el hook WH_KEYBOARD_LL, no?? Con tu artículo tengo entendido que solo registras pulsaciones de hotkeys.

Un saludo maestro!

# re: HowTo: Crear un hook de teclado para registrar una hotkey en nuestra aplicación

Thursday, November 18, 2010 10:25 AM por Lluis Franco

Efestivamente Edu :-)

Basta con extender el WndProc e interceptar los mensajes que nos interesen.