1

一段时间以来,我一直在尝试将按键发送到 DirectX 应用程序,并不断删除。我是 C# 的新手,所以一些更复杂的函数就在我的脑海中,但我一直在尽我所能把它拼凑起来。

SendInput 是我似乎无法理解的事情之一。

我尝试使用一些不同的 SendInput 包装器来为我简化事情,包括:

http://inputsimulator.codeplex.com/

http://www.codeproject.com/Articles/117657/InputManager-library-Track-user-input-and-simulate

另一个叫拦截器

它们都可以很好地向大多数应用程序发送按键,但我仍然无法让它们发送到活动的游戏窗口。

我也试过 SendKeys。

我曾尝试自己放置一个键盘挂钩,但它对我来说太先进了,无法自己弄清楚,而且我的代码最终充满了错误。

我希望如果我在这里发布我的代码(简单的服务器应用程序),有人可以向我解释在哪里以及如何放置键盘挂钩。

namespace ServerApp
{
public partial class Form1 : Form
{
    private TcpListener tcpListener;
    private Thread listenThread;
    private int connectedClients = 0;
    private delegate void WriteMessageDelegate(string msg);

    public Form1()
    {
        InitializeComponent();
        Server();
    }

    private void Server()
    {
        this.tcpListener = new TcpListener(IPAddress.Any, 8888);
        this.listenThread = new Thread(new ThreadStart(ListenForClients));
        this.listenThread.Start();
    }

    private void ListenForClients()
    {
        this.tcpListener.Start();

        while (true)
        {
            TcpClient client = this.tcpListener.AcceptTcpClient();

            connectedClients++;
            lblNumberOfConnections.Text = connectedClients.ToString();

            Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
            clientThread.Start(client);

        }
    }

    private void HandleClientComm(object client)
    {
        TcpClient tcpClient = (TcpClient)client;
        NetworkStream clientStream = tcpClient.GetStream();

        byte[] message = new byte[4096];
        int bytesRead;

        while (true)
        {
            bytesRead = 0;

            try
            {
                bytesRead = clientStream.Read(message, 0, 4096);
            }
            catch
            {
                break;
            }

            if (bytesRead == 0)
            {
                connectedClients--;
                lblNumberOfConnections.Text = connectedClients.ToString();
                break;
            }

            ASCIIEncoding encoder = new ASCIIEncoding();


            //Write message in RichTextBox

            string msg = encoder.GetString(message, 0, bytesRead);
            WriteMessage(msg);

        }

        tcpClient.Close();
    }

    private void WriteMessage(string msg)
    {
        if (this.rtbServer.InvokeRequired)
        {
            WriteMessageDelegate d = new WriteMessageDelegate(WriteMessage);
            this.rtbServer.Invoke(d, new object[] { msg });

        }
        else
        {
            this.rtbServer.AppendText(msg + Environment.NewLine);

            // SEND KEYSTROKES TO ACTIVE WINDOW
            if (msg.Equals("CTRL-T"))
            {
               // Keyboard.KeyDown(Keys.LControlKey);
               // Keyboard.KeyPress(Keys.T);             // I was using this for the InputManager Wrapper
               // Keyboard.KeyUp(Keys.LControlKey);
            }

在到处搜索之后,下面的代码片段似乎是让模拟击键在 DirectX 应用程序中工作的最佳机会,但我无法在没有大量错误和无法使用的代码的情况下将其实现到我的代码中。

namespace DirectInput
{
class cDirectInput
{
    [DllImport("user32.dll")]
    static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);

    [StructLayout(LayoutKind.Sequential)]
    struct MOUSEINPUT
    {
        public int dx;
        public int dy;
        public int mouseData;
        public int dwFlags;
        public int time;
        public IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct KEYBDINPUT
    {
        public short wVk;
        public short wScan;
        public int dwFlags;
        public int time;
        public IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct HARDWAREINPUT
    {
        public int uMsg;
        public short wParamL;
        public short wParamH;
    }

    [StructLayout(LayoutKind.Explicit)]
    struct INPUT
    {
        [FieldOffset(0)]
        public int type;
        [FieldOffset(4)]
        public MOUSEINPUT mi;
        [FieldOffset(4)]
        public KEYBDINPUT ki;
        [FieldOffset(4)]
        public HARDWAREINPUT hi;
    }

    const int KEYEVENTF_EXTENDEDKEY = 0x0001;
    const int KEYEVENTF_KEYUP = 0x0002;
    const int KEYEVENTF_UNICODE = 0x0004;
    const int KEYEVENTF_SCANCODE = 0x0008;

我相信以下部分对我发送CTRL+T命令有用,但我不确定 100%

    // SEND KEYSTROKES TO ACTIVE WINDOW

            if (msg.Equals("CTRL-T"))
{
        INPUT[] InputData = new INPUT[1];

        InputData[0].type = 1;
        InputData[0].ki.wScan = 0x1D;
        InputData[0].ki.time = 0;
        InputData[0].ki.dwExtraInfo = IntPtr.Zero;

        InputData[0].type = 1;
        InputData[0].ki.wScan = 0x14;            
        InputData[0].ki.time = 0;
        InputData[0].ki.dwExtraInfo = IntPtr.Zero;

        InputData[0].type = 1;
        InputData[0].ki.wScan = 0x1D;
        InputData[0].ki.dwFlags = 0x0002;
        InputData[0].ki.time = 0;
        InputData[0].ki.dwExtraInfo = IntPtr.Zero;

        SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));
}

我在这里真正苦苦挣扎的主要事情是如何将键盘挂钩放入我现有的代码中,并且仍然让我的服务器的其余部分正常运行。让这些击键工作是我项目的最后一部分,它开始变得非常令人沮丧,因此感谢任何帮助!



更新 我再次尝试,这次使用keybd_event(),但由于某种原因,我遇到了同样的问题;它在任何地方都可以工作,但在游戏中。

我使用的是 VK 代码,而不是 DirectInput 代码,我不确定这是否是这里的问题,但我担心如果我使用 DI 代码而不是代码的另一部分我需要更改它我不知道。

这是我这次尝试的一个片段:

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

    public const int KEYEVENTF_KEYUP = 0x0002; 
    public const int VK_LCONTROL = 0xA2; 
    public const int SEMICOLON = 0xBA; 
    public const int QUOTE = 0xDE; 
    public const int T = 0x54;
    public const int H = 0x48; 
    public const int R = 0x52; 
    public const int Z = 0x5A; 
    public const int X = 0x58; 
    public const int NUM8 = 0x68; 
    public const int NUM2 = 0x62; 
    public const int NUM4 = 0x64; 
    public const int NUM6 = 0x66; 
    public const int NUM5 = 0x65; 
    public const int UP = 0x26; 
    public const int DOWN = 0x28; 
    public const int LEFT = 0x25; 
    public const int RIGHT = 0x27; 
    public const int RETURN = 0x0D; 

// .....

if (msg.Equals("CTRL-T"))
     {
         keybd_event(VK_LCONTROL, 0, 0, 0);
         keybd_event(T, 0, 0, 0);
         keybd_event(T, 0, KEYEVENTF_KEYUP, 0);
         keybd_event(VK_LCONTROL, 0, KEYEVENTF_KEYUP, 0);
      }

我不知道我的代码是否有问题,或者我是否仍在使用错误的方法。



更新 2 我再次尝试,这次使用SendMessage,但我一直无法构建,因为我遇到了错误hWnd。“当前上下文中不存在名称 hWnd”

[DllImport("user32.dll")] 
    public static extern IntPtr SetActiveWindow(IntPtr hWnd);

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

    public const ushort WM_KEYDOWN = 0x0100;
    public const ushort WM_KEYUP = 0x0101;

    private void WriteMessage(string msg)
    {
        if (this.rtbServer.InvokeRequired)
        {
            WriteMessageDelegate d = new WriteMessageDelegate(WriteMessage);
            this.rtbServer.Invoke(d, new object[] { msg });

        }
        else
        {
            this.rtbServer.AppendText(msg + Environment.NewLine);

            // SEND KEYSTROKES TO ACTIVE WINDOW
            if (msg.Equals("CTRL-T"))
            {

                SetActiveWindow(hWnd);
                SendMessage(hWnd, WM_KEYDOWN, 0x1D, 0);
                SendMessage(hWnd, WM_KEYDOWN, 0x14, 0);
                SendMessage(hWnd, WM_KEYUP, 0x1D, 0);
                SendMessage(hWnd, WM_KEYUP, 0x14, 0);

            }
4

1 回答 1

0

我最终使用“InputManager”SendInput包装器让一切工作完美。

using InputManager

//......

Keyboard.KeyPress(Keys.YourSelectedKeyHere);

事实证明,我所要做的就是以管理员身份运行我的代码......

于 2015-10-27T17:57:37.167 回答