我一直在尝试发送按键到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);
}
我最终使用"InputManager" SendInput
包装器使一切工作完美。
using InputManager
//......
Keyboard.KeyPress(Keys.YourSelectedKeyHere);
结果,我所要做的就是以管理员的身份运行我的代码…