Hola, buenas a todos. Me propusieron un problema muy interesante pero no consigo dar con la solución. Estoy trabajando con VS2008 usando VB.NET Net Framework 3.5 bajo windows 7.
La idea es la siguiente: enviar por medio de una aplicación las pulsaciones de teclado a una aplicación externa.
Cuál es el problema? Cuando se trabaja con aplicaciones que reciben texto no hay problema, pero supongamos que la aplicación tiene varias ventanas, una ventana donde se muestra una imagen, otra ventana con accesos directos de teclado, otra con iconos, etc..., estas ventanas no reciben texto sino pulsaciones de teclado. Estas pulsaciones son lo que se denomina "hotKey".
Bien, he problado con:
- SendKeys.Send() pero no funciona salvo para la ventana que recibe texto, si ésta ventana está activa.
- API Keybd_event pero hace exactamente lo mismo que el anterior.
- He usado los eventos KeyDown, KeyUp, etc, de los controles que van a enviar el hotkey y tampoco funciona.
- Probé también pasar el caracter a byte con la función ASC pero me hace lo mismo.
- Probé al enviar el hotket con keys.[El caracter o tecla de función que necesite], como por ejemplo "Keys.LControlKey" o "Keys.Enter" pero obtengo los mismos resultados.
Con la curiosidad probé la aplicación que trae el windows 7 "Teclado en Pantalla" y "voila" ahi si sirve todo sobre la aplicación externa.
Entonces lo que necesito es saber como rayos trabaja el teclado en pantalla del windows, supongo que estará programado en C++ o C#, pero aun así, usará un link a una DLL de una API para trabajar el teclado a bajo nivel para conseguir lo que quiero.
Una cosa más, cuando uso "SendKeys.Send("{ENTER}") si funciona en la aplicación externa, pero si hago esto "SendKeys.Send("T")" no funciona como hotkey excepto si la ventana para recibir el texto está activa.
En otras palabras los caracteres los recibe como texto cuando los envio por SendKeys.Send o cuando lo envio usando Keybd_event, pero no como pulsación del teclado. Esto no pasa con el "teclado en pantalla" del windows, que cuando le doy a T del teclado en pantalla éste si funciona como hotKey.
Cualquier información que puedan pasarme sobre el trabajo a bajo nivel de teclado por medio de VB.NET se los agradeceré.
Les adjunto el código de lo que tengo hecho en VB.NET para que vean.
Código VB.NET:
Ver originalImports System.Runtime.InteropServices
Public Class Form1
Const KEYEVENTF_KEYUP = &H2
Const KEYEVENTF_EXTENDEDKEY = &H1
<DllImport("user32.dll", EntryPoint:="keybd_event", CharSet:=CharSet.Auto, ExactSpelling:=True)> _
Public Shared Sub Keybd_event(ByVal vk As Byte, ByVal scan As Byte, ByVal flags As Integer, ByVal extrainfo As Integer)
End Sub
Declare Function VkKeyScan Lib "user32" Alias "VkKeyScanA" (ByVal cChar_Renamed As Byte) As Short
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
sTimer(TextBox2, TextBox1)
End Sub
Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick
sTimer(TextBox4, TextBox3)
End Sub
Private Sub Timer3_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer3.Tick
sTimer(TextBox6, TextBox5)
End Sub
Private Sub Timer4_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer4.Tick
sTimer(TextBox8, TextBox7)
End Sub
Private Sub Timer5_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer5.Tick
sTimer(TextBox10, TextBox9)
End Sub
Private Sub Timer6_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer6.Tick
sTimer(TextBox12, TextBox11)
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Timer1.Enabled = True
Timer2.Enabled = True
Timer3.Enabled = True
Timer4.Enabled = True
Timer5.Enabled = True
Timer6.Enabled = True
End Sub
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
Timer1.Enabled = False
Timer2.Enabled = False
Timer3.Enabled = False
Timer4.Enabled = False
Timer5.Enabled = False
Timer6.Enabled = False
End Sub
Private Sub sTimer(ByVal txt As TextBox, ByVal txtEnvio As TextBox)
'Se comprueba que exista texto en la caja correspondiente y que su valor sea mayor que 0...
If Not (txt
.Text = "") And IsNumeric(txt
.Text) Then If CLng(txt.Text) > 0 Then
txt.Text = CStr(CLng(txt.Text) - 1)
End If
Else
Exit Sub
End If
Dim time_t As Integer
time_t = CInt(txt.Text) 'Se transforma el valor de la caja de texto al tipo integer...
If CInt(txt.Text) = 0 Then
txt.Text = time_t.ToString() 'El valor del time_t se pasa a string y se le asigna a la caja de texto...
End If
Dim tiempomuerto As Integer
tiempomuerto = 1
If CInt(txt.Text) = tiempomuerto Then 'Si el valor es igual a 1 entonces...
'MsgBox(Asc(txtEnvio.Text), MsgBoxStyle.OkOnly, "Prueba")
SendKeys.Send(Keys.Enter)
'Pulsar(CByte(Asc(txtEnvio.Text))) 'se envía lo que exista en la caja de texto...
End If
End Sub
Private Sub Pulsar(ByVal tecla As Byte)
Keybd_event(tecla, 0, 0, 0)
Keybd_event(tecla, 0, KEYEVENTF_KEYUP, 0)
End Sub
End Class
Es un formulario con 12 cajas de texto y 6 timer, pero con 2 cajas y un timer bastará para probar.
La caja de texto par, (textbox2, textbox4, textbox6, etc), es donde se coloca el tiempo antes de que se envíe el hotkey, (va en cuenta regresiva).
La caja de texto impar, (textbox1, textbox3, textbox5, etc), es donde se coloca el caracter que será el hotkey a enviar a la aplicación externa.
Button3, empieza la cuenta regresiva, Button4 detiene los timers.
Saludos y muchas gracias de antemano.