[VB.NET] Pegar texto en otra ventana

Iniciado por EAX_, 4 Octubre 2012, 00:55 AM

0 Miembros y 1 Visitante están viendo este tema.

EAX_

Hola comunidad,
   He estado investigando sobre este tema en particular hace unos días y no he encontrado lo que necesito. Lo que quiero hacer es que mi programa envíe la instrucción de pegar (CTRL + V) en otra ventana al momento de que yo utilice un atajo de teclado.

Estuve buscando eventos que podrían ayudarme y al final me encontré con una función que me permitió bindear una tecla y pude enviar por teclado lo que quería pegar.

Código (vbnet) [Seleccionar]

   Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
       If msg.WParam.ToInt32 = CInt(Keys.F1) Then
           MsgBox("Tecla F1 pulsada")
       End If
      Return MyBase.ProcessCmdKey(msg, keyData)
    End Function


Enviaba la cadena que quiero pegar con Sendkeys.Send() pero el problema es que si no tengo activa la ventana de mi aplicación la tecla no es procesada por el programa.

Confío que alguien me podrá dar una ayudadita

Gracias de antemano y saludos
"Everyone is a genius. But if you judge a fish on its ability to climb a tree, it will live its whole life believing it is stupid." - Albert Einstein

Keyen Night

#1
El API SendMenssage, puede enviar pulsaciones de teclas a un handle correspondiente a una ventana especifica, usando los parámetros WM_KEYUP, WM_KEYCHAR y WM_KEYDOWN. Una vez realice una clase para ese propósito está en C# pero es fácilmente traducible a Vb.Net.

Código (c#) [Seleccionar]
   public sealed class Input
   
   {

     public enum WindowMessage : int
           {
               WM_KEYDOWN = 0x0100,
               WM_KEYUP = 0x0101,
               WM_CHAR = 0x0102,
               WM_LBUTTONDOWN = 0x201,
               WM_LBUTTONUP = 0x202
           }

       public static void SendKey(IntPtr WindowhWnd, Int32 key)
       {
           SendMessage(WindowhWnd, WindowMessage.WM_KEYDOWN, (int)key, 0);
           SendMessage(WindowhWnd, WindowMessage.WM_CHAR, (int)key, 0);
           SendMessage(WindowhWnd, WindowMessage.WM_KEYUP, (int)key, 0);
       }

       public static void SendClick(IntPtr WindowhWnd, int X, int Y)
       {
           SendMessage(WindowhWnd, WindowMessage.WM_LBUTTONUP, 0, 0);
           int lpara = MakeLParam(X, Y);
           SendMessage(WindowhWnd, WindowMessage.WM_LBUTTONDOWN, 0, lpara);
           SendMessage(WindowhWnd, .WindowMessage.WM_LBUTTONUP, 0, lpara);
           Thread.Sleep(25);
       }

       public static void SendString(IntPtr WindowhWnd, string String)
       {
           foreach (var x in String)
               SendKey(WindowhWnd, Convert.ToInt32(x));
           Thread.Sleep(3);
       }

       private static int MakeLParam(int LoWord, int HiWord) { return ((HiWord << 16) | (LoWord & 0xffff)); }
   }
La Fé Mueve Montañas...
                                    ...De Dinero

La programación es más que un trabajo es más que un hobby es una pasión...

EAX_

#2
Hola, gracias por responder. Tengo una duda. Con esa clase que me das se supone que envías mensajes a una ventana en especifico cierto?

Sabes si hay una forma de que (mientras la ventana no esté activa) siga monitoreando mis teclas y pueda activar un evento?

Me gustaría aprovechar el evento OnKeyPress del formulario para lograr enviar algun texto a nivel PC asi como un CTRL + V mientras mi formulario no está activo.

Con respecto a la clase, estuve tratando de entenderla y no lo logré.

Saludos
"Everyone is a genius. But if you judge a fish on its ability to climb a tree, it will live its whole life believing it is stupid." - Albert Einstein

Keyen Night

#3
Windows comunica muchas cosas a las aplicaciones a través de mensajes, y estos se envían por medio del API SendMessage, esta API es extremadamente dinámica, quiero decir que posee múltiples funcionalidades, para definir que tipo de tarea queremos que SendMessage efectué, existe una lista gigantesca de constantes WM_XXX, que describen situaciones, para este caso tenemos WM_KEYDOWN, WM_KEYUP, WM_CHAR, enviar tecla que se presiona, enviar tecla que se suelta y el Char que se imprime, respectivamente. Una vez definida la constate WM a pasar a SendMessage, entonces enviamos los parámetros para el trabajo que esta a punto de efectuar la función, en el caso de enviar una tecla construí la función SendKey:
Código (c#) [Seleccionar]

       public static void SendKey(IntPtr WindowhWnd, Int32 key)
       {
           SendMessage(WindowhWnd, WindowMessage.WM_KEYDOWN, (int)key, 0);
           SendMessage(WindowhWnd, WindowMessage.WM_CHAR, (int)key, 0);
           SendMessage(WindowhWnd, WindowMessage.WM_KEYUP, (int)key, 0);
       }


El primer parámetro es el Handle (hWnd) de la ventana al cuál se va a enviar el mensaje, el siguiente parámetro es la constante WM, el tercer parámetro es el valor ASCII de la tecla a enviar, el último se omite para este trabajo.

SendMenssage, imita en la ventana lo que el usuario hace para presionar una tecla, primero la pulsa (WM_KEYDOWN) luego se imprime (WM_CHAR) y la suelta (WM_KEYUP).

Para capturar las teclas que se presionan fuera de tu aplicación tienes las dos opciones más usadas: el API GetAsynKeyState y el Hook de Teclado, que es mucho más limpio y organizado el trabajo. Acerca de esto hay mucha documentación tanto en el foro como en internet en general ;)
La Fé Mueve Montañas...
                                    ...De Dinero

La programación es más que un trabajo es más que un hobby es una pasión...

EAX_

Agradezco tu respuesta, gracias a eso pude llegar a algo más acercado a mi realidad. Encontré algo interesante que es la función RegisterHotKey, con eso logré definir un atajo de teclado que fuera de la aplicación aun es posible ejecutarlo y, con eso, puedo hacer alguna acción (como enviar el texto que necesito) Ahora el único problema es que me gustaría que el HotKey fuese una sola tecla.

Si alguien sabe por favor responder.

Saludos

Código (vbnet) [Seleccionar]

Imports System.Runtime.InteropServices

Public Class Form1
   Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
       If m.Msg = WM_HOTKEY Then
           Dim id As IntPtr = m.WParam
           Select Case (id.ToString)
               Case "100"
                   SendKeys.Send("KEYS TO SEND")
           End Select
       End If
       MyBase.WndProc(m)
   End Sub

 
   Public Const WM_HOTKEY As Integer = &H312


   <DllImport("User32.dll")> _
 Public Shared Function RegisterHotKey(ByVal hwnd As IntPtr, _
                     ByVal id As Integer, ByVal fsModifiers As Integer, _
                     ByVal vk As Integer) As Integer
   End Function

   <DllImport("User32.dll")> _
   Public Shared Function UnregisterHotKey(ByVal hwnd As IntPtr, _
                       ByVal id As Integer) As Integer
   End Function

   Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
       UnregisterHotKey(Me.Handle, 100)
   End Sub

   Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
       RegisterHotKey(Me.Handle, 100, MOD_ALT, Keys.G)
   End Sub
End Class
"Everyone is a genius. But if you judge a fish on its ability to climb a tree, it will live its whole life believing it is stupid." - Albert Einstein