2008-11-21 14 views
5

¿Qué llamadas de win32 se pueden usar para detectar eventos de pulsación de tecla globalmente (no solo para 1 ventana, me gustaría recibir un mensaje CADA vez que se presiona una tecla) desde un servicio de Windows?Entrada de teclado de bajo nivel en Windows

Respuesta

4

Quiere usar Win32 Hooks. En particular, un gancho de teclado.

You can read more about it here

El tipo de gancho que quieres es WH_KEYBOARD y se puede establecer a través de la API de Win32 SetWindowsHookEx.

Básicamente Windows llamará a una función en un dll que usted crea cada vez que se presiona una tecla en cualquier sistema de aplicación.

El gancho llamará a la función que tendrá esta interfaz:

LRESULT CALLBACK KeyboardProc(  
    int code, 
    WPARAM wParam, 
    LPARAM lParam 
); 

More information about this callback here.

Con los ganchos de Windows no solo puede rastrear eventos de todo el sistema en todos los procesos, sino que también puede filtrarlos y detenerlos por completo.

2

Tome un vistazo a los ganchos que se pueden ajustar SetWindowHookEx:

http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx

Sin embargo, a menos que esté ejecutando un servicio "interactivo", que no tendrá acceso al escritorio (y usted no debe No se está ejecutando un servicio interactivo porque no funcionará correctamente en las versiones más nuevas de Windows). Deberá examinar las API de administración de sesión y escritorio para acceder al escritorio/consola.

0

Mira la API de entrada sin procesar en MSDN:

http://msdn.microsoft.com/en-us/library/ms645536(VS.85).aspx

Se le permite obtener el aporte de los teclados (entre otras cosas) sin jugar un poco con enlaces globales. Los ganchos globales solo deben usarse como último recurso, ya que pueden generar consecuencias imprevistas.

El único inconveniente de utilizar Raw Input es que puede no recibir correctamente las pulsaciones de teclado generadas por el software.

0

Si está implementando esto en una aplicación .net, recomendaría GlobalKeyboardHook, de lo contrario, vería su origen y tomaría lo que necesita, ya que está implementando las funciones de DLLImport mencionadas anteriormente.

1

Simplemente use la función nativa GetKeyState, o GetAsyncKeyState, o GetKeyboardState de la DLL de usuario32.

Usted puede leer acerca de cada función que he mencionado anteriormente en el sitio de MSDN:

h ttp: //msdn.microsoft.com/en-us/library/windows/desktop/ms646301 (v = vs.85) .aspx

para la GetKeyState, y

h ttp: //msdn.microsoft.com/en-us/library/windows/desktop/ms646293 (v = vs.85).aspx

para la GetAsyncKeyState, y

h ttp: //msdn.microsoft.com/en-us/library/windows/desktop/ms646299 (v = vs.85) .aspx

para GetKeyboardState.

Si programa en C# y luego:

Su código debe incluir la siguiente línea de salida de cualquier clase, la declaración de estructura o de enumeración:

using System.Runtime.InteropServices; 

Luego, en la clase que tiene el método en el desea detectar las teclas, definir una de las tres funciones anteriores para su elección, o qué funciona y qué no.

[DllImport("user32.dll")] 
static uint GetKeyState(byte virtualKeyCode); 

//or 

[DllImport("user32.dll")] 
static uint GetAsyncKeyState(byte virtualKeyCode); 

//or 

[DllImport("user32.dll")] 
static uint GetKeyboardState(byte[] virtualKeyCodes); 
//NOTE: The length of the byte array parameter must be always 256 bytes! 

Si no le gusta uint como tipo de retorno, también se puede cambiar a int.

Si las funciones nativas siempre devuelven 1 como verdadero o 0 como falso, entonces puede cambiar su tipo de devolución a bool, pero si lo hace, entonces creo que debería agregar otra línea de código por encima del original definición de función, que es:

[MarshalAs(UnmanagedType.Bool)] 

O se puede añadir la siguiente línea en el medio de la definición de la función nativa (por debajo de la línea en la que la palabra DllImport es, y por encima de la línea, donde el 'extern' la palabra es):

[return: MarshalAs(UnmanagedType.Bool)] 

El sitio de Pinvoke ofrece una mejor definición para estas funciones, por lo que no tiene que usar números enteros para mencionar una tecla particular de su teclado, sino una enumeración más comprensible.

El siguiente enlace conduce a la definición de la GetKeyState en C#:

h ttp: //www.pinvoke.net/default.aspx/user32.getkeystate

El siguiente enlace conduce a la definición de la GetAsyncKeyState en C#

h ttp: //www.pinvoke.net/default.aspx/user32.getasynckeystate

los followi enlace ng conduce a la definición de la GetKeyboardState en C#

h ttp: //www.pinvoke.net/default.aspx/user32.getkeyboardstate

Para detectar qué tecla se mantiene pulsado (en cualquier momento y en cualquier lugar) y luego llamar a la función GetKeyState o GetAsyncKeyState, en el único parámetro, mencionar la clave que desea detectar y luego añadir: & 0x8000 o & 0x80 después de la llamada. Si la tecla mencionada se mantiene presionada, el valor de retorno de la expresión no es cero, pero de lo contrario es cero. De acuerdo con el número entero devuelto de la expresión, puede determinar qué tecla se mantuvo presionada o no. Tenga en cuenta que si coloca código dentro de instrucción if con esa expresión! = 0 como condición de entrada, que está dentro de un bucle, el código en esa instrucción if se ejecutará más de una vez, en realidad muchas veces, cuando se presionó esa clave. Si quieres algo de código que se ejecuta una vez Cuando se pulsa una tecla y luego lo liberan, a continuación, el siguiente código es un truco que logra este objetivo:

while (boolean exression that will return false when you want to quit this loop) 
{ 
    if (boolean expression that will return true when particular key is **held down**) //This boolean expression calls either GetKeyState or GetAsyncKeyState with the & 0x8000 or & 0x80 after the call, and then != 0 to check for **held down** key 
     while (true) //It's purpose is to wait for the same key that was held down to be released. After code execution, it will encounter the break keyword that will finish him, even though that his enter condition is true. 
      if (boolean expression that will return true when the **same** particular key is **NOT** held down! (NOT held down, means that at that time, that key was released). You can copy the same condition from the first if statement, and just change **!=**, which is next to 0, to **==**, or instead add brackets to the condition '(' and ')', and in left of '(' add '!'). 
      { 
       //Put here the code that you want to execute once, when paticular key was pressed and then released. 
       break; //the while (true), which is the only way to get out of it 
      } 
} 
Cuestiones relacionadas