2012-08-24 12 views
6

Objetivo: escribir una aplicación C# que se ejecuta en segundo plano, escucha la combinación de teclas Win-V y, cuando eso ocurre, pega los contenidos del portapapeles en la ventana activa actual (alguna aplicación arbitraria). Básicamente, estoy tratando de imitar a PureText, pero no me molesto en convertir primero el texto en texto sin formato.Enviar Win API pegar cmd desde fondo C# aplicación

Problema: no funciona el pegado en las ventanas actualmente activas.

detalles: Para escuchar en el fondo de pulsaciones de teclas que estoy usando el clase globalKeyboardHook de A Simple C# Global Low Level Keyboard Hook. Puedo atrapar eventos Win-V, pero no puedo enviar el comando pegar correctamente. Puedo enviar la pasta usando las funciones SendKeys.Send o keybd_event. Sin embargo, envían otra imprenta en "V" a través de la tubería que queda atrapada por el evento gkh_KeyDown y hace que se activen varios eventos de pegado.

Estoy esperando que necesito utilizar SendMessage o PostMessage, pero todos mis intentos de hacer que han fracasado hasta ahora. A continuación se muestra el código completo con la última función, SendCtrlV, siendo el de interés. Los comentarios explican todo lo que he intentado hasta ahora. ¿Puedes ver lo que me estoy perdiendo?

using System; 
using System.IO; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 
using Utilities; 

namespace KeyHookTest 
{ 
    public partial class Form1 : Form 
    { 
     private bool LWin_down; 
     private bool V_down; 
     globalKeyboardHook gkh = new globalKeyboardHook(); 

     [DllImport("user32.dll", CharSet = CharSet.Auto)] 
     static public extern IntPtr GetForegroundWindow(); 

     [DllImport("user32.dll")] 
     static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo); 

     [DllImport("user32.dll")] 
     private static extern int SendMessage(IntPtr hwnd, int msg, int wParam, int lParam); 

     [DllImport("user32.dll")] 
     public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      gkh.HookedKeys.Add(Keys.V); 
      gkh.HookedKeys.Add(Keys.LWin); 
      gkh.KeyDown += new KeyEventHandler(gkh_KeyDown); 
      gkh.KeyUp += new KeyEventHandler(gkh_KeyUp); 
     } 

     void gkh_KeyUp(object sender, KeyEventArgs e) 
     { 
      if (e.KeyCode == Keys.LWin) 
       LWin_down = false; 
      else 
       V_down = false; 
     } 

     void gkh_KeyDown(object sender, KeyEventArgs e) 
     { 
      if (e.KeyCode == Keys.LWin) 
       LWin_down = true; 
      else 
       V_down = true; 

      if (LWin_down && V_down) 
      { 
       LogDebug("Enter Win+V"); 

       try 
       { 
        SendCtrlV(); 
       } 
       catch { } 
      } 

     } 

     private void SendCtrlV() 
     { 
      uint KEYEVENTF_KEYUP = 2; 
      int KEYDOWN = 0x0100; 
      int KEYUP = 0x0101; 
      byte KEY_LCONTROL1 = 0x11; 
      IntPtr KEY_LCONTROL2 = new IntPtr(0x11); 
      byte KEY_V1 = 0x56; 
      IntPtr KEY_V2 = new IntPtr(0x56); 
      int WM_PASTE1 = 0x302; 
      uint WM_PASTE2 = 0x302; 

      IntPtr hWnd = GetForegroundWindow(); 

      // Works, but causes multiple gkh_KeyDown to fire so it's slow and buggy 
      /*keybd_event(KEY_LCONTROL1, 0, 0, 0); 
      keybd_event(KEY_V1, 0, 0, 0); 
      keybd_event(KEY_V1, 0, KEYEVENTF_KEYUP, 0); 
      keybd_event(KEY_LCONTROL1, 0, KEYEVENTF_KEYUP, 0);*/ 

      // Works, but causes multiple gkh_KeyDown to fire so it's slow and buggy 
      //SendKeys.Send("^v"); 

      // Doesn't work, causes UAC prompt 
      //SendKeys.Send("{^}v"); 

      // Doesn't work, nothing gets pasted to the foregroundwindow 
      //SendMessage(hWnd, WM_PASTE1, 0, 0); 

      // Doesn't work, nothing gets pasted to the foregroundwindow 
      //PostMessage(hWnd, WM_PASTE2, IntPtr.Zero, IntPtr.Zero); 

      // Doesn't work, nothing gets pasted to the foregroundwindow 
      /*SendMessage(hWnd, KEYDOWN, KEY_LCONTROL1, 0); 
      SendMessage(hWnd, KEYDOWN, KEY_V1, 0); 
      SendMessage(hWnd, KEYUP, KEY_V1, 0); 
      SendMessage(hWnd, KEYUP, KEY_LCONTROL1, 0);*/ 

      // Doesn't work, nothing gets pasted to the foregroundwindow 
      /*PostMessage(hWnd, 0x0100, KEY_LCONTROL2, IntPtr.Zero); 
      PostMessage(hWnd, 0x0100, KEY_V2, IntPtr.Zero); 
      PostMessage(hWnd, 0x0101, KEY_V2, IntPtr.Zero); 
      PostMessage(hWnd, 0x0101, KEY_LCONTROL2, IntPtr.Zero);*/ 
     } 

     private void LogDebug(string msg) 
     { 
      string logpath = Environment.GetEnvironmentVariable("USERPROFILE") + @"\Desktop\KeyHookTest.txt"; 
      File.AppendAllText(logpath, DateTime.Now.ToString("HH:mm:ss:fff") + ": " + msg + "\r\n"); 
     } 
    } 
} 
+0

IIRC, que Don 't sen d el mensaje 'WM_PASTE' a un identificador de ventana; lo envía al control en el que desea pegar el contenido directamente. Tienes que usar 'EnumChildWindows' en el' hWnd' que obtienes de 'GetForegroundWindow' para encontrar el control que maneja. (No pegues en una ventana, sino en un control de edición en la ventana.) –

+0

Eso ciertamente tendría sentido. Con una búsqueda rápida de eso, no he encontrado mucho sobre cómo hacerlo, pero seguiré buscando en esa dirección. –

+0

Si revisa los documentos de 'EnumChildWindows', dado el código que ha escrito hasta ahora, dudo que tenga demasiados problemas para descubrirlo (definitivamente más fácil que en C# - en C o Delphi es fácil ) . Por cierto, +1 para la pregunta - Estaba tan ocupado escribiendo el comentario que me olvidé de hacerlo la primera vez. :-) –

Respuesta

1

Estos enlaces adicionales me ayudaron a llevar a la respuesta:

Esto es lo que funciona para mí:

private void SendCtrlV() 
{ 
    IntPtr hWnd = GetFocusedHandle(); 
    PostMessage(hWnd, WM_PASTE, IntPtr.Zero, IntPtr.Zero); 
} 

static IntPtr GetFocusedHandle() 
{ 
    var info = new GuiThreadInfo(); 
    info.cbSize = Marshal.SizeOf(info); 
    if (!GetGUIThreadInfo(0, ref info)) 
     throw new Win32Exception(); 
    return info.hwndFocus; 
} 
Cuestiones relacionadas