2012-08-24 10 views
6

Ziel: Schreiben Sie eine C# -App, die im Hintergrund ausgeführt wird, wartet auf die Tastenkombination Win-V, und wenn das auftritt, den Inhalt der Zwischenablage in das aktuelle aktive Fenster (eine beliebige App). Im Wesentlichen versuche ich PureText zu imitieren, aber ich störe nicht zuerst den Text in reinen Text zu konvertieren.Senden Win API einfügen Cmd aus dem Hintergrund C# App

Problem: Einfügen in die derzeit aktiven Fenster funktioniert nicht.

Einzelheiten: Um im Hintergrund für Tastendrücke zu hören Ich bin mit der globalKeyboardHook Klasse von A Simple C# Global Low Level Keyboard Hook. Ich bin in der Lage, Win-V-Ereignisse abzufangen, aber ich kann den Befehl paste nicht richtig senden. Ich kann die Paste senden, indem die Funktionen über SendKeys.Send oder keybd_event. Sie sind jedoch eine andere „V“ drücken Sie die Pipeline senden, die durch die gkh_KeyDown Ereignis verfängt und verursacht mehrere Paste Ereignisse auszulösen.

Ich erwarte, dass ich Sendmessage oder Postmessage, aber alle meine Versuche verwenden müssen zu tun, die es bisher versäumt haben. Unten ist der vollständige Code mit der letzten Funktion, SendCtrlV, die von Interesse ist. Die Kommentare erklären alles, was ich bisher versucht habe. Kannst du sehen, was ich vermisse?

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, Sie don nicht sen d die 'WM_PASTE'-Nachricht an ein Fensterhandle; Sie senden es an das Steuerelement des Steuerelements, in das Sie den Inhalt direkt einfügen möchten. Sie müssen 'EnumChildWindows' auf der' hWnd' verwenden, die Sie von 'GetForegroundWindow' erhalten, um das Handle dieses Controls zu finden. (Sie fügen nicht in ein Fenster selbst, sondern in ein Bearbeitungssteuerelement im Fenster ein.) –

+0

Das wäre sicherlich sinnvoll. Mit einigen schnellen Recherchen habe ich nicht viel darüber herausgefunden, wie das geht, aber ich werde weiter in diese Richtung schauen. –

+0

Wenn Sie die Dokumentation für 'EnumChildWindows' überprüfen, da der Code, den Sie so weit werde ich bezweifle geschrieben haben Sie zu viel Mühe haben es herauszufinden (auf jeden Fall leicht mehr, als ich in C# könnte - in C oder Delphi ist es einfach ) . BTW, +1 für die Frage - Ich war so beschäftigt, den Kommentar zu schreiben, dass ich vergessen habe, es beim ersten Mal zu tun. :-) –

Antwort

1

Diese zusätzlichen Links half mir zur Antwort führen:

Hier ist, was für mich funktioniert hat:

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