Cómo hacer que un teclado sea global en todos los procesos

Intento crear una aplicación de teclado útil para que pueda hacer cosas como matar un proceso preprogtwigdo o lanzar algo. Estoy pensando que debería mantener el cmd en cualquier aplicación, luego tecleo una clave de comando de 4 dígitos para poder ejecutar o matar algo rápidamente mientras programo, depuro viendo un video, etc.

Descubrí cómo obtener la callback del teclado, pero por alguna razón, una vez que hago clic en otra aplicación, mi herramienta de pulsación de teclas no recibe más teclas. Incluso si hago clic nuevamente en la ventana de mi consola o msvc, no recibiré ninguna entrada. Esto a menos que sea global, entonces, ¿cómo configuro el gancho para que sea global?

Mi código es

int main() { hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, GetModuleHandle(0), 0); MSG msg; while(GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } UnhookWindowsHookEx(hook); } 

Para que su gancho de teclado sea accesible desde todos los procesos, debe colocarse en una DLL que luego se cargará en el espacio de direcciones de cada proceso. Una cosa importante a tener en cuenta es que, dado que cada instancia de la DLL se carga en un proceso separado, cada una tendrá su propia copia de cualquier variable global en la DLL. Si necesita compartir datos entre estas instancias, la forma más sencilla es crear un segmento de datos compartidos en la DLL. El siguiente código es de un progtwig de monitoreo RSI que escribí.

 // // some data will be shared across all // instances of the DLL // #pragma comment(linker, "/SECTION:.SHARED,RWS") #pragma data_seg(".SHARED") int iKeyCount = 0; HHOOK hKeyboardHook = 0; HHOOK hMouseHook = 0; #pragma data_seg() // // instance specific data // HMODULE hInstance = 0; // // DLL load/unload entry point // BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH : hInstance = (HINSTANCE) hModule; break; case DLL_THREAD_ATTACH : break; case DLL_THREAD_DETACH : break; case DLL_PROCESS_DETACH : break; } return TRUE; } // // keyboard hook // LRESULT CALLBACK KeyboardProc(int code, // hook code WPARAM wParam, // virtual-key code LPARAM lParam) // keystroke-message information { if ((lParam & 0x80000000) != 0) { ++iKeyCount; } return CallNextHookEx(hKeyboardHook, code, wParam, lParam); } // // mouse hook // LRESULT CALLBACK MouseProc(int code, // hook code WPARAM wParam, // message identifier LPARAM lParam) // mouse coordinates { switch (wParam) { case WM_LBUTTONDOWN : case WM_MBUTTONDOWN : case WM_RBUTTONDOWN : case WM_LBUTTONDBLCLK : case WM_MBUTTONDBLCLK : case WM_RBUTTONDBLCLK : ++iKeyCount; break; } return CallNextHookEx(hMouseHook, code, wParam, lParam); } // // install keyboard/mouse hooks // void KBM_API InstallHooks(void) { hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hInstance, 0); hMouseHook = SetWindowsHookEx(WH_MOUSE, MouseProc, hInstance, 0); } // // remove keyboard/mouse hooks // void KBM_API RemoveHooks(void) { UnhookWindowsHookEx(hKeyboardHook); UnhookWindowsHookEx(hMouseHook); hKeyboardHook = hMouseHook = 0; } // // retrieve number of keystrokes // int KBM_API FetchKeyCount(bool bClear) { int kc = iKeyCount; if (bClear) iKeyCount = 0; return kc; } 

Evite las muestras del proyecto de código. (muchos errores, malas copias de MSDN)

Vea las toneladas de ejemplos completos en MSDN en los ganchos (MSDN, SDK, KB, etc.)

Y no necesita ninguna DLL, solo use los ganchos LL

Para Glopbal Keyboard Hook solo para Hot Key, entonces Register hotkey es lo mejor (lo hace Microsoft):

https://msdn.microsoft.com/en-us/library/windows/desktop/ms646309(v=vs.85).aspx

Descargue la aplicación winform de muestra y compruébelo usted mismo:

https://code.msdn.microsoft.com/CppRegisterHotkey-7bd897a8 C ++ https://code.msdn.microsoft.com/CSRegisterHotkey-e3f5061e C # https://code.msdn.microsoft.com/VBRegisterHotkey-50af3179 VB.Net

Aplicación Winform:

 /****************************** Module Header ******************************\ * Module Name: MainForm.cs * Project: CSRegisterHotkey * Copyright (c) Microsoft Corporation. * * This is the main form of this application. It is used to initialize the UI * and handle the events. * * This source is subject to the Microsoft Public License. * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. * All other rights reserved. * * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. \***************************************************************************/ using System; using System.Runtime.InteropServices; using System.Windows.Forms; namespace CSRegisterHotkey { public partial class MainForm : Form { HotKeyRegister hotKeyToRegister = null; Keys registerKey = Keys.None; KeyModifiers registerModifiers = KeyModifiers.None; public MainForm() { InitializeComponent(); } ///  /// Handle the KeyDown of tbHotKey. In this event handler, check the pressed keys. /// The keys that must be pressed in combination with the key Ctrl, Shift or Alt, /// like Ctrl+Alt+T. The method HotKeyRegister.GetModifiers could check whether /// "T" is pressed. ///  private void tbHotKey_KeyDown(object sender, KeyEventArgs e) { // The key event should not be sent to the underlying control. e.SuppressKeyPress = true; // Check whether the modifier keys are pressed. if (e.Modifiers != Keys.None) { Keys key = Keys.None; KeyModifiers modifiers = HotKeyRegister.GetModifiers(e.KeyData, out key); // If the pressed key is valid... if (key != Keys.None) { this.registerKey = key; this.registerModifiers = modifiers; // Display the pressed key in the textbox. tbHotKey.Text = string.Format("{0}+{1}", this.registerModifiers, this.registerKey); // Enable the button. btnRegister.Enabled = true; } } } ///  /// Handle the Click event of btnRegister. ///  private void btnRegister_Click(object sender, EventArgs e) { try { // Register the hotkey. hotKeyToRegister = new HotKeyRegister(this.Handle, 100, this.registerModifiers, this.registerKey); // Register the HotKeyPressed event. hotKeyToRegister.HotKeyPressed += new EventHandler(HotKeyPressed); // Update the UI. btnRegister.Enabled = false; tbHotKey.Enabled = false; btnUnregister.Enabled = true; } catch (ArgumentException argumentException) { MessageBox.Show(argumentException.Message); } catch (ApplicationException applicationException) { MessageBox.Show(applicationException.Message); } } ///  /// Show a message box if the HotKeyPressed event is raised. ///  void HotKeyPressed(object sender, EventArgs e) { //Here is the magic!!!!!!!!' //DO SOMETHING COOL!!! Or Just activate this winform if (this.WindowState == FormWindowState.Minimized) { this.WindowState = FormWindowState.Normal; } this.Activate(); } ///  /// Handle the Click event of btnUnregister. ///  private void btnUnregister_Click(object sender, EventArgs e) { // Dispose the hotKeyToRegister. if (hotKeyToRegister != null) { hotKeyToRegister.Dispose(); hotKeyToRegister = null; } // Update the UI. tbHotKey.Enabled = true; btnRegister.Enabled = true; btnUnregister.Enabled = false; } ///  /// Dispose the hotKeyToRegister when the form is closed. ///  protected override void OnClosed(EventArgs e) { if (hotKeyToRegister != null) { hotKeyToRegister.Dispose(); hotKeyToRegister = null; } base.OnClosed(e); } } } 

HotKeyRegister.cs

 /****************************** Module Header ******************************\ * Module Name: HotKeyRegister.cs * Project: CSRegisterHotkey * Copyright (c) Microsoft Corporation. * * This class imports the method RegisterHotKey and UnregisterHotKey in * user32.dll to define or free a system-wide hot key. * * The method Application.AddMessageFilter is used to add a message filter to * monitor Windows messages as they are routed to their destinations. Before a * message is dispatched, the method PreFilterMessage could handle it. If a * WM_HOTKEY messages was generated by the hot key that was registered by this * HotKeyRegister object, then raise a HotKeyPressed event. * * This class also supplies a static method GetModifiers to get the modifiers * and key from the KeyData property of KeyEventArgs. * * This source is subject to the Microsoft Public License. * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. * All other rights reserved. * * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. \***************************************************************************/ using System; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Security.Permissions; namespace CSRegisterHotkey { public class HotKeyRegister : IMessageFilter, IDisposable { ///  /// Define a system-wide hot key. ///  ///  /// A handle to the window that will receive WM_HOTKEY messages generated by the /// hot key. If this parameter is NULL, WM_HOTKEY messages are posted to the /// message queue of the calling thread and must be processed in the message loop. ///  ///  /// The identifier of the hot key. If the hWnd parameter is NULL, then the hot /// key is associated with the current thread rather than with a particular /// window. ///  ///  /// The keys that must be pressed in combination with the key specified by the /// uVirtKey parameter in order to generate the WM_HOTKEY message. The fsModifiers /// parameter can be a combination of the following values. /// MOD_ALT 0x0001 /// MOD_CONTROL 0x0002 /// MOD_SHIFT 0x0004 /// MOD_WIN 0x0008 ///  /// The virtual-key code of the hot key. [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk); ///  /// Frees a hot key previously registered by the calling thread. ///  ///  /// A handle to the window associated with the hot key to be freed. This parameter /// should be NULL if the hot key is not associated with a window. ///  ///  /// The identifier of the hot key to be freed. ///  [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); ///  /// Get the modifiers and key from the KeyData property of KeyEventArgs. ///  ///  /// The KeyData property of KeyEventArgs. The KeyData is a key in combination /// with modifiers. ///  /// The pressed key. public static KeyModifiers GetModifiers(Keys keydata, out Keys key) { key = keydata; KeyModifiers modifers = KeyModifiers.None; // Check whether the keydata contains the CTRL modifier key. // The value of Keys.Control is 131072. if ((keydata & Keys.Control) == Keys.Control) { modifers |= KeyModifiers.Control; key = keydata ^ Keys.Control; } // Check whether the keydata contains the SHIFT modifier key. // The value of Keys.Control is 65536. if ((keydata & Keys.Shift) == Keys.Shift) { modifers |= KeyModifiers.Shift; key = key ^ Keys.Shift; } // Check whether the keydata contains the ALT modifier key. // The value of Keys.Control is 262144. if ((keydata & Keys.Alt) == Keys.Alt) { modifers |= KeyModifiers.Alt; key = key ^ Keys.Alt; } // Check whether a key other than SHIFT, CTRL or ALT (Menu) is pressed. if (key == Keys.ShiftKey || key == Keys.ControlKey || key == Keys.Menu) { key = Keys.None; } return modifers; } ///  /// Specify whether this object is disposed. ///  bool disposed = false; ///  /// This constant could be found in WinUser.h if you installed Windows SDK. /// Each windows message has an identifier, 0x0312 means that the mesage is /// a WM_HOTKEY message. ///  const int WM_HOTKEY = 0x0312; ///  /// A handle to the window that will receive WM_HOTKEY messages generated by the /// hot key. ///  public IntPtr Handle { get; private set; } ///  /// A normal application can use any value between 0x0000 and 0xBFFF as the ID /// but if you are writing a DLL, then you must use GlobalAddAtom to get a /// unique identifier for your hot key. ///  public int ID { get; private set; } public KeyModifiers Modifiers { get; private set; } public Keys Key { get; private set; } ///  /// Raise an event when the hotkey is pressed. ///  public event EventHandler HotKeyPressed; public HotKeyRegister(IntPtr handle, int id, KeyModifiers modifiers, Keys key) { if (key == Keys.None || modifiers == KeyModifiers.None) { throw new ArgumentException("The key or modifiers could not be None."); } this.Handle = handle; this.ID = id; this.Modifiers = modifiers; this.Key = key; RegisterHotKey(); // Adds a message filter to monitor Windows messages as they are routed to // their destinations. Application.AddMessageFilter(this); } ///  /// Register the hotkey. ///  private void RegisterHotKey() { bool isKeyRegisterd = RegisterHotKey(Handle, ID, Modifiers, Key); // If the operation failed, try to unregister the hotkey if the thread // has registered it before. if (!isKeyRegisterd) { // IntPtr.Zero means the hotkey registered by the thread. UnregisterHotKey(IntPtr.Zero, ID); // Try to register the hotkey again. isKeyRegisterd = RegisterHotKey(Handle, ID, Modifiers, Key); // If the operation still failed, it means that the hotkey was already // used in another thread or process. if (!isKeyRegisterd) { throw new ApplicationException("The hotkey is in use"); } } } ///  /// Filters out a message before it is dispatched. ///  [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")] public bool PreFilterMessage(ref Message m) { // The property WParam of Message is typically used to store small pieces // of information. In this scenario, it stores the ID. if (m.Msg == WM_HOTKEY && m.HWnd == this.Handle && m.WParam == (IntPtr)this.ID && HotKeyPressed != null) { // Raise the HotKeyPressed event if it is an WM_HOTKEY message. HotKeyPressed(this, EventArgs.Empty); // True to filter the message and stop it from being dispatched. return true; } // Return false to allow the message to continue to the next filter or // control. return false; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ///  /// Unregister the hotkey. ///  protected virtual void Dispose(bool disposing) { // Protect from being called multiple times. if (disposed) { return; } if (disposing) { // Removes a message filter from the message pump of the application. Application.RemoveMessageFilter(this); UnregisterHotKey(Handle, ID); } disposed = true; } } } 

KeyModifiers.cs:

 /****************************** Module Header ******************************\ * Module Name: KeyModifiers.cs * Project: CSRegisterHotkey * Copyright (c) Microsoft Corporation. * * This enum defines the modifiers to generate the WM_HOTKEY message. * See http://msdn.microsoft.com/en-us/library/ms646309(VS.85).aspx. * * This source is subject to the Microsoft Public License. * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. * All other rights reserved. * * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. \***************************************************************************/ using System; namespace CSRegisterHotkey { [Flags] public enum KeyModifiers { None = 0, Alt = 1, Control = 2, Shift = 4, // 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. Windows = 8 } } 

Vuelva a leer la introducción a los ganchos en la guía Win32. (Un buen lugar para comenzar está aquí .)

Específicamente, si desea enlazar eventos en otros procesos, debe colocar su callback en una DLL, que Win32 inyectará en otros procesos. Del código que ha proporcionado, no puedo decir si KeyboardProc está en una DLL o en el progtwig principal. No se ve así, teniendo en cuenta el HINSTANCE que está pasando.

Tuve que meterme con ganchos globales cuando escribía una especie de aplicación “Picture in Picture”. Este artículo y el código de muestra me ayudaron tremendamente:

http://www.codeproject.com/KB/system/WilsonSystemGlobalHooks.aspx