Pues eso… esto viene a raíz de una consulta sobre cómo detectar la pulsación de teclas en los formularios de Windows Forms, es decir, saber qué tecla se ha pulsado aunque ya se esté detectando en cajas de texto u otros controles.
En los controles no hay problemas para detectarlo, ya que solo tendremos que escribir código en los eventos de pulsación de teclas: KeyPress, KeyDown o KeyUp del control y asunto arreglado.
Pero cuando se trata de detectar esas pulsaciones a nivel de formulario, es decir, independientemente de qué control tenga el foco, también podemos usar esos tres métodos de evento en el formulario, pero antes debemos indicarle al runtime de .NET que queremos detectar esas pulsaciones de teclas.
Para ello debemos asignar un valor True a la propiedad KeyPreview del formulario.
Distinguir la pulsación en mayúsculas de minúsculas (o no)
Si queremos detectar la pulsación de teclas sin que nos importe si es una tecla mayúscula o minúscula lo mejor es hacerlo en cualquiera de los eventos KeyDown o KeyUp, ya que en esos eventos además de la tecla pulsada se puede saber si también se pulsa la tecla Shift (cambio de mayúsculas).
En caso de querer detectar la pulsación de letras en el evento KeyPress tendremos que hacer una doble comprobación, una para la letra en mayúscula y otra para saber si es minúscula.
Nota del 18/Sep/2020:
Si quieres detectar la pulsación con la tecla Control (CTRL) o Shift o Alt, es recomendable hacer algo como el código que te indico a continuación.
Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) If e.KeyCode = Keys.F3 Then e.Handled = True Buscar() ElseIf e.Control Then If e.KeyCode = Keys.F Then e.Handled = True esCtrlF = True Buscar() ElseIf e.KeyCode = Keys.H Then e.Handled = True Reemplazar() End If End If End Sub
private void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.F3) { e.Handled = true; Buscar(); } else if (e.Control) { if (e.KeyCode == Keys.F) { e.Handled = true; esCtrlF = true; Buscar(); } else if (e.KeyCode == Keys.H) { e.Handled = true; Reemplazar(); } } }
El orden de pulsación de teclas (en controles y formulario)
Debido a que podemos usar los tres eventos comentados al principio, lo mismo te interesa saber en qué orden se procesan los eventos.
El orden es el siguiente:
- KeyDown
- KeyPress
- KeyUp
Lista 1. Orden en que se procesan los eventos de pulsación de teclas
Y si estamos comprobando en el formulario además de en los controles, el orden global será el siguiente:
- KeyDown del formulario
- KeyDown del control
- KeyPress del formulario
- KeyPress del control
- KeyUp del formulario
- KeyUp del control
Lista 2. Orden en que se procesan los eventos de pulsación de teclas cuando se comprueba también en el formulario además de en los controles
Es decir, el mismo orden que en la lista 1, pero empezando siempre por el formulario y después en el control.
Veamos un poco de código de ejemplo
Para esta prueba creamos un proyecto nuevo y al formulario le añadimos los controles mostrados en la figura 1.
Figura 1. El formulario de prueba en modo de diseño
Creamos los eventos KeyDown, KeyPress y KeyUp tanto en el formulario como en las cajas de texto. Para este ejemplo, solo he puesto código para detectar la pulsación en la primera caja de textos (textBox1) y en el formulario (recuerda asignar un valor verdadero a la propiedad KeyPreview del formulario).
En este código (tanto para Visual Basic como para C#) detectamos la pulsación de las teclas S y W tanto en el textBox1 con en el propio formulario. Están contemplados los tres eventos comentados y en la caja de textos (textBox3) de la parte inferior, a la que he asignado un valor True a la propiedad MultiLine, así como el valor Vertical a la propiedad ScrollBars. con idea de que nos permita desplazarnos por el contenido y veamos la secuencia de pulsación de teclas.
Nota:
Más abajo tienes un enlace al proyecto del código de ejemplo.
Código de ejemplo para C#
Nota:
Recuerda asignar estos métodos a los eventos correspondientes.
// El orden "global" de pulsación es: // KeyDown en formulario // KeyDown en control // KeyPress en formulario // KeyPress en control // KeyUp en formulario // KeyUp en control // para que detecte las pulsaciones en el formulario // hay que asignar un valor True a la propiedad KeyPreview del formulario // en KeyDown no diferencia entre mayúsculas y minúsculas // en KeyPess si distingue la diferencia private void Form1_KeyPress(object sender, KeyPressEventArgs e) { switch (e.KeyChar) { case (char)Keys.W: // mayúsculas case (char)(Keys.W + 32): // minúsculas label3.Text += "\nTecla W en el formulario"; textBox3.Text += "\r\nTecla W en el formulario (KeyPress)"; break; case (char)Keys.S: case (char)(Keys.S + 32): // minúsculas label3.Text += "\nTecla S en el formulario"; break; } } private void Form1_KeyDown(object sender, KeyEventArgs e) { // da igual mayúsculas que minúsculas switch (e.KeyCode) { case Keys.S: label3.Text = "Tecla S en el formulario (KeyDown)"; break; case Keys.W: label3.Text = "Tecla W en el formulario (KeyDown)"; textBox3.Text += "\r\nTecla W en el formulario (KeyDown)"; break; } } private void Form1_KeyUp(object sender, KeyEventArgs e) { switch (e.KeyValue) { case (char)Keys.S: label3.Text = "Tecla S en el formulario (KeyUp)"; break; case (char)Keys.W: label3.Text = "Tecla W en el formulario (KeyUp)"; textBox3.Text += "\r\nTecla W en el formulario (KeyUp)"; break; } } // el orden de pulsación es: // KeyDown, KeyPress y KeyUp private void textBox1_KeyDown(object sender, KeyEventArgs e) { // e.KeyValue el código numérico textBox3.Text += "\r\ntextBox1_KeyDown, tecla: " + e.KeyCode; } private void textBox1_KeyPress(object sender, KeyPressEventArgs e) { textBox3.Text += "\r\ntextBox1_KeyPress, tecla: " + e.KeyChar; } private void textBox1_KeyUp(object sender, KeyEventArgs e) { textBox3.Text += "\r\ntextBox1_KeyUp, tecla: " + e.KeyValue; }
Código de ejemplo para VB:
Private Sub Form1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress Select Case e.KeyChar Case ChrW(Keys.W), ChrW(Keys.W + 32) ' mayúsculas y minúsculas label3.Text &= vbCrLf & "Tecla W en el formulario" textBox3.Text &= vbCrLf & "Tecla W en el formulario (KeyPress)" Case ChrW(Keys.S), ChrW(Keys.S + 32) label3.Text &= vbCrLf & "Tecla S en el formulario" End Select End Sub Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown ' da igual mayúsculas que minúsculas Select Case e.KeyCode Case Keys.S label3.Text = "Tecla S en el formulario (KeyDown)" Case Keys.W label3.Text = "Tecla W en el formulario (KeyDown)" textBox3.Text &= vbCrLf & "Tecla W en el formulario (KeyDown)" End Select End Sub Private Sub Form1_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp Select Case e.KeyCode Case Keys.S label3.Text = "Tecla S en el formulario (KeyUp)" Case Keys.W label3.Text = "Tecla W en el formulario (KeyUp)" textBox3.Text &= vbCrLf & "Tecla W en el formulario (KeyUp)" End Select End Sub ' el orden de pulsación es: ' KeyDown, KeyPress y KeyUp Private Sub textBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles textBox1.KeyDown ' e.KeyValue el código numérico textBox3.Text &= vbCrLf & "textBox1_KeyDown, tecla: " & e.KeyCode End Sub Private Sub textBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles textBox1.KeyPress textBox3.Text &= vbCrLf & "textBox1_KeyPress, tecla: " & e.KeyChar End Sub Private Sub textBox1_KeyUp(sender As Object, e As KeyEventArgs) Handles textBox1.KeyUp textBox3.Text &= vbCrLf & "textBox1_KeyUp, tecla: " & e.KeyValue End Sub
Y esto es todo, espero que te sea de utilidad.
Y si quieres ver más cosas de cómo detectar la tecla pulsada o cambiar el valor de esa pulsación, lee esto: Detectar la pulsación de teclas.
Nos vemos.
Guillermo
El código del ejemplo
Este es el proyecto del código mostrado.
Lo he creado con Visual Studio 2013 Preview, pero el código es completamente compatible con cualquier versión de Visual Studio .NET, aunque es posible que los proyectos solo los puedas abrir con Visual Studio 2010 o posterior (no lo he comprobado).
Lo que si es seguro es que si añades el formulario a un proyecto creado con cualquier versión de Visual Studio .NET que utilicen el .NET 2.0 o superior, si que te servirá.
Nombre fichero: Detectar_tecla_en_formulario.zip
Tamaño: 140 KB (143 434 bytes)
Fecha: 21 septiembre 2013 14:15:32
MD5: B80281EBF0C032FBF9487C5B251FD1BB
…
¿Y cómo escribo para que detecte las teclas cuando el formulario no tenga el foco o esté minimizado?
Por ejemplo: Quiero que cuando se pulse la tecla A y suene un sonido(y eso lo he conseguido con el formulario activo,pero no lo consigo cuando está inactivo),aunque escriba la «a» en Internet Explorer,el bloc de notas o cualquier otra aplicación.
Si pudieses ayudarme con una pieza de código te lo agradecerÃa un montón. He consultado en muchos foros y no me aclaro, y he probado muchos códigos;pero cómo lo que quiero es tan especÃfico…
Muchas gracias de antemano.
Feliz Año Nuevo.
Feliz año!!!
mejor prueba en otros foros (aparte de los que ya has probado) y suerte!!!
Hola Fran,
quisiera saber si lograste averiguar algo acerca de tu pregunta en este foro. Es posible que el programa capte las pulsaciones de las teclas incluso cuando esta minimizado o mientras trabajo en otro programa? actualmente necesito dar algunos comandos usando el teclado pero a la misma vez debo anotar unos valores en un excel y no se como hacer que los controles funcionen aun cuando estoy trabajando sobre otros archivos.
Te agradezco tu colaboración
Kate.
Saludos Kate:
Lo más interesante que pude encontrar fue esto:
Imports System.Runtime.InteropServices
Public Class KeyboardHook
_
Private Overloads Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal HookProc As KBDLLHookProc, ByVal hInstance As IntPtr, ByVal wParam As Integer) As Integer
End Function
_
Private Overloads Shared Function CallNextHookEx(ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function
_
Private Overloads Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
End Function
_
Private Structure KBDLLHOOKSTRUCT
Public vkCode As UInt32
Public scanCode As UInt32
Public flags As KBDLLHOOKSTRUCTFlags
Public time As UInt32
Public dwExtraInfo As UIntPtr
End Structure
_
Private Enum KBDLLHOOKSTRUCTFlags As UInt32
LLKHF_EXTENDED = &H1
LLKHF_INJECTED = &H10
LLKHF_ALTDOWN = &H20
End Enum
Public Shared Event KeyDown(ByVal Key As Keys)
Private Const WH_KEYBOARD_LL As Integer = 13
Private Const HC_ACTION As Integer = 0
Private Const WM_KEYDOWN = &H100
Private Const WM_SYSKEYDOWN = &H104
Private Delegate Function KBDLLHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
Private KBDLLHookProcDelegate As KBDLLHookProc = New KBDLLHookProc(AddressOf KeyboardProc)
Private HHookID As IntPtr = IntPtr.Zero
Private Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
If (nCode = HC_ACTION) Then
Dim struct As KBDLLHOOKSTRUCT
Select Case wParam
Case WM_KEYDOWN, WM_SYSKEYDOWN
RaiseEvent KeyDown(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys))
End Select
End If
Return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam)
End Function
Public Sub New()
HHookID = SetWindowsHookEx(WH_KEYBOARD_LL, KBDLLHookProcDelegate, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32, 0)
If HHookID = IntPtr.Zero Then
Throw New Exception(«Could not set keyboard hook»)
End If
End Sub
Protected Overrides Sub Finalize()
If Not HHookID = IntPtr.Zero Then
UnhookWindowsHookEx(HHookID)
End If
MyBase.Finalize()
End Sub
End Class
Lo único que tendrÃas que hacer serÃa agregar referencias(y creo que no me olvido de nada más)
Saludos y espero que te sirva.
Buenas tardes de ante mano gracias por tu ejemplo un consulta como puedo hacer para utilizar la tecla de window + d. Gracias
comprueba los distintos valores de las teclas especiales (no recuerdo ahora si hay un valor concreto para la tecla de Windows)
cómo puedo hacer para que oprima (por ejemplo) la tecla CONTROL+FLECHA_DERECHA y asà oprima el botón de siguiente registro, o por igual, estando el foco en un textbox oprimir tecla CONTROL+ENTER para que el foco se vaya al control anterior como un supuesto SHIFT+TAB puesto que por comodidad cambio el foco con la tecla ENTER
ahà tendrás que comprobar el uso de SendKeys o similar, creo que en mi sitio tendré algún ejemplo de eso, mira en esta sección: http://www.elguille.info/NET/comodotnet.aspx
Muchas gracias guille
una pregunta lo quiero hacer es que mi proyecto, al momento de yo igresar un usuario y contraseña, al presionar la tecla enter. acceda al formulario ya especificaado como lo haria un boton.
Hola, esa es pregunta para los foros 🙂
De todas formas, en mi sitio (www.elguille.info) seguro que encuentras algún que otro ejemplo sobre ese tema de «pulsar ENTER / INTRO en una caja de texto» 🙂