我一直试图将按键发送到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
命令,但我不是百分百肯定
// 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);
}
答案 0 :(得分:0)
我最终使用“InputManager”SendInput
包装器完成了所有工作。
using InputManager
//......
Keyboard.KeyPress(Keys.YourSelectedKeyHere);
事实证明,我不得不做的就是以管理员的身份运行我的代码......