2012-05-02 26 views
17

Tôi tự hỏi, sau khi không quan tâm đến tất cả các loại vấn đề với SendInput, SendKeys, PostMessage, SendMessage, SendNotifyMessage, keybd_event, v.v. Để tìm ra điều đó ... cố gắng gửi một đầu vào bàn phím đến một tiến trình không tiền cảnh khác là khá khó hiểu và không đáng tin cậy.Gửi trực tiếp các lần nhấn phím đến một quy trình khác qua hooking

Tôi đã thử phương thức SendInput nơi tôi đánh dấu thứ tự Z (để giữ cửa sổ hiện tại ở trên cùng) và nhanh chóng đặt trước cửa sổ bên thứ ba, gửi đầu vào và đặt lại trước cửa sổ của tôi. Trong đó cuối cùng thất bại, và bằng cách nào đó, không chắc chắn lý do tại sao, cũng quản lý để proc cũng tổ hợp phím trên cửa sổ của tôi trong khi không foreground (gây ra một vòng lặp vô hạn của việc gửi và nhận giữa hai cửa sổ cho đến khi tôi quản lý để đóng quá trình).

Tôi đã thử các kết hợp khác nhau của SendMessage và PostMessage. Một cho xuống, một cho lên, như sử dụng cả hai cho xuống và lên dẫn đến các vấn đề, giống như với PostMessage cho cả hai, gây ra chìa khóa để nhân đôi trên cửa sổ tiếp nhận. hoặc SendMessage cho cả hai, gây ra vấn đề với nhập văn bản, nhưng các chức năng khác hoạt động tốt. SendMessage cho keydown và PostMessage cho keyUp làm việc cho tất cả các chức năng, nhưng tốc độ tin cậy giảm đáng kể, cũng như thêm độ trễ vào các sự kiện quan trọng. Chỉ có một sự kết hợp của PostMessage cho keydown, và SendMessage cho keyup quản lý để làm bất cứ điều gì hữu ích, với một tỷ lệ thất bại có thể 5-10% của đăng ký keyup. Cùng đi cho SentNotifyMessage (hoạt động cơ bản trong cùng một thời trang như SendMessage như xa như độ tin cậy đi). Vì vậy, về cơ bản, tôi đang ở cuối của whit, và tôi muốn biết về trực tiếp tiêm móc vào cửa sổ mục tiêu, và làm một số voodoo để gửi tổ hợp phím để nó theo cách đó, bỏ qua hàng đợi tin nhắn vv. Làm như vậy trong một cách mà sẽ không proc sự kiện quan trọng toàn cầu, và chỉ ảnh hưởng đến cửa sổ mục tiêu. Chỉ có điều là tôi khá không thể hiểu được khi nói đến tiêm/hooking, vv Vì vậy, tôi quay sang bạn, cộng đồng.

Wut làm gì?

+0

Sau khi bạn gửi đầu vào, bạn cần đợi một lúc để nó được gửi trước khi bạn đặt lại quy trình của riêng bạn về nền trước. Mặc dù tên, SendInput thực sự * bài viết * đầu vào cho hàng đợi đầu vào; nếu cửa sổ của bạn lấy tiêu điểm ngay lập tức sau đó, sau đó khi đầu vào được xử lý bởi hệ thống, nó có thể kết thúc lên cửa sổ của bạn! – BrendanMcK

+0

Và đối với những gì nó có giá trị, gửi đầu vào đến một ứng dụng không phải là tiền cảnh thực sự không được hỗ trợ; không có cách nào đáng tin cậy để làm điều đó. Làm cho ứng dụng mục tiêu nền trước và sử dụng SendInput là cách đáng tin cậy duy nhất. SendMessage và PostMessage đều có vấn đề. Vấn đề lớn hơn mà bạn đang cố gắng giải quyết ở đây là gì - tại sao bạn lại cố gắng gửi đầu vào ở nơi đầu tiên? – BrendanMcK

+0

Cảm ơn bạn đã trả lời, BrendanMcK. Tôi có thể thử và chơi với thời gian tái sắp xếp lại cửa sổ, nhưng về cơ bản tôi muốn tránh 100% đó. Lý do tôi cần đầu vào, tôi đang viết một bộ ghép kênh cho đầu vào bàn phím/chuột trên nhiều ứng dụng và máy vật lý trên mạng LAN. Trong số đó được sử dụng trong các trò chơi video đa đấm bốc (thường là các game MMO và RTS). Kịch bản trường hợp tốt nhất đối với tôi, nếu tôi có thể tìm ra cách để làm điều đó, là móc trực tiếp vào quy trình của bên thứ ba và bằng cách nào đó, hãy gửi đầu vào cho nó theo cách đó. Điều gì sẽ là lựa chọn của tôi để làm điều đó? Tôi nên điểm nghiên cứu của mình ở đâu? – Hydra

Trả lời

13

Đây là một mã nhỏ mà cho phép bạn gửi tin nhắn đến một ứng dụng background. Để gửi "A" char ví dụ, chỉ cần gọi sendKeystroke (Keys.A), và đừng quên sử dụng không gian tên System.windows.forms để có thể sử dụng đối tượng Keys.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 

namespace keybound 
{ 
class WindowHook 
{ 
    [DllImport("user32.dll")] 
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 
    [DllImport("user32.dll")] 
    public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 
    [DllImport("user32.dll")] 
    public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 

    public static void sendKeystroke(ushort k) 
    { 
     const uint WM_KEYDOWN = 0x100; 
     const uint WM_SYSCOMMAND = 0x018; 
     const uint SC_CLOSE = 0x053; 

     IntPtr WindowToFind = FindWindow(null, "Untitled1 - Notepad++"); 

     IntPtr result3 = SendMessage(WindowToFind, WM_KEYDOWN, ((IntPtr)k), (IntPtr)0); 
     //IntPtr result3 = SendMessage(WindowToFind, WM_KEYUP, ((IntPtr)c), (IntPtr)0); 
    } 
} 
} 
+2

PostMessage đã làm việc tuyệt vời cho việc này. Sử dụng Spy ++ đã giúp tôi cấu trúc các thông điệp trông chính xác như chúng đã đến từ bàn phím thực của tôi. – Hydra

+0

Chỉ cần thử điều này trên Windows 10 và nó không có hiệu lực. Không chắc chắn nếu tôi đã làm điều gì đó sai hoặc nó không hoạt động nữa? – Sam

5

Bạn có thể phải lo lắng về điều này nhưng bạn có thể gửi dữ liệu qua quy trình. Điều này có thể không phù hợp với hoàn cảnh của bạn nhưng đó là một ý nghĩ.

using System; 
using System.Runtime.InteropServices; 
using System.Diagnostics; 

    [DllImport("user32.dll", EntryPoint = "FindWindowEx")] 
    public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,   string lpszClass, string lpszWindow); 
    [DllImport("User32.dll")] 
    public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam); 

    static void Send(string message) 
    { 
     Process[] notepads = Process.GetProcessesByName("notepad"); 

     if (notepads.Length == 0) 
      return; 

     if (notepads[0] != null) 
     { 
      IntPtr child = FindWindowEx(notepads[0].MainWindowHandle, 
       new IntPtr(0), "Edit", null); 

      SendMessage(child, 0x000C, 0, message); 
     } 
    } 

Nếu điều đó không làm việc, bạn luôn có thể làm:

System.Threading.Thread.Sleep(1000); 
//User clicks on active form. 
System.Windows.Forms.Sendkeys.Sendwait("<Message>"); 
+0

Đây chính xác là những gì tôi cần. Làm thế nào để tôi biết lpszClass cho quá trình của mình là gì? – FinnTheHuman

+0

Bạn có thể sử dụng Spy ++ để tìm hiểu lpClassName là gì. Nếu lpClassName là NULL, FindWindow sẽ tìm thấy bất kỳ cửa sổ nào có tiêu đề khớp với tham số lpWindowName. (https://msdn.microsoft.com/en-us/library/windows/desktop/ms633499(v=vs.85).aspx) –