2012-08-24 7 views
6

Obiettivo: scrivi un'app C# che viene eseguita in background, ascolta la combinazione di tasti Win-V e, quando ciò accade, incolla il contenuto degli appunti nella finestra attiva corrente (qualche app arbitraria). In sostanza sto cercando di imitare lo PureText, ma non mi preoccupo di convertire prima il testo in testo normale.Invia Win API incolla cmd dall'app background C#

Problema: incollare nelle finestre attualmente attive non funziona.

Dettagli: Per ascoltare in background per le pressioni dei tasti Sto utilizzando la classe diglobalKeyboardHook da A Simple C# Global Low Level Keyboard Hook. Sono in grado di catturare eventi Win-V, ma non riesco a inviare il comando incolla correttamente. Posso inviare la pasta utilizzando le funzioni SendKeys. Invia o keybd_event. Tuttavia, inviano un'altra "V" sulla conduttura che viene catturata dall'evento gkh_KeyDown e causa l'attivazione di più eventi Incolla.

mi aspetto che ho bisogno di usare SendMessage o PostMessage, ma tutti i miei tentativi di fare che hanno fallito finora. Di seguito è riportato il codice completo con l'ultima funzione, SendCtrlV, che è quello di interesse. I commenti spiegano tutto ciò che ho provato finora. Riesci a vedere cosa mi manca?

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, è don Sono sen d il messaggio 'WM_PASTE' su un handle di finestra; lo mandi all'handle del controllo su cui vuoi incollare il contenuto direttamente. Devi usare 'EnumChildWindows' su' hWnd' che ottieni da 'GetForegroundWindow' per trovare l'handle di quel controllo. (Non incollare in una finestra stessa, ma in un controllo di modifica sulla finestra.) –

+0

Ciò avrebbe sicuramente senso. Con una rapida ricerca su questo non ho trovato molto su come farlo, ma continuerò a cercare in quella direzione. –

+0

Se controlli i documenti per 'EnumChildWindows', dato il codice che hai scritto finora dubito che avrai troppi problemi a comprenderlo (sicuramente più facilmente di quanto potrei in C# - in C o Delphi è facile ) . A proposito, +1 per la domanda - ero così impegnato a scrivere il commento che mi sono dimenticato di farlo la prima volta. :-) –

risposta

1

Questi collegamenti aggiuntivi mi ha aiutato a portare alla risposta:

Ecco ciò che funziona per me:

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; 
}