【问题标题】:Simulate keyboard click in GTA:SA在 GTA:SA 中模拟键盘点击
【发布时间】:2026-02-15 08:35:01
【问题描述】:

我正在尝试运行一个有时会在 GTA:SA 中模拟点击的程序。问题是它在运行时什么都不做。到目前为止,我已经尝试过这段代码:

IntPtr calculatorHandle = FindWindow(null, "GTA:SA:MP");
if (calculatorHandle == IntPtr.Zero)
{
    MessageBox.Show("GTA:SA:MP isn't running");
    return;
}
SetForegroundWindow(calculatorHandle);
SendKeys.SendWait("T123");

如果你能告诉我我的代码是否有问题,我会很高兴。谢谢!

编辑

这是我添加尼尔的代码后的代码:

IntPtr calculatorHandle = FindWindow(null, "GTA:SA:MP");
if (calculatorHandle == IntPtr.Zero)
{
    MessageBox.Show("GTA:SA:MP isn't running");
    return;
}
SetForegroundWindow(calculatorHandle);
short key = 0x14;
WindowsMessageService.SendKey(key, KeyFlag.KeyDown);
Thread.Sleep(10);
WindowsMessageService.SendKey(key, KeyFlag.KeyUp);

【问题讨论】:

    标签: c# winforms sendkeys intptr


    【解决方案1】:

    您的第一个问题是大多数游戏都使用 DirectX 输入。您必须使用以下方法将密钥发送到游戏。此外,您需要发送向上和向下键来模拟游戏的按键操作。

    [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 KeyboardInput
    {
        public short wVk;      //Virtual KeyCode (not needed here)
        public short wScan;    //Directx Keycode 
        public int dwFlags;    //This tells you what is use (Keyup, Keydown..)
        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 KeyboardInput ki;
        [FieldOffset(4)]
        public HardwareInput hi;
    }
    
    [Flags]
    public enum KeyFlag
    {       
        KeyDown = 0x0000,
        ExtendedKey = 0x0001,
        KeyUp = 0x0002,
        UniCode = 0x0004,
        ScanCode = 0x0008
    }
    
    public static class WindowsMessageService
    {
        [DllImport("user32.dll")]
        private static extern UInt32 SendInput(UInt32 nInputs,[MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] Input[] pInputs, Int32 cbSize);
    
        public static void SendInput(short keycode, KeyFlag keyFlag)
        {
            var inputData = new Input[1];
    
            inputData[0].type = 1;
            inputData[0].ki.wScan = keycode;
            inputData[0].ki.dwFlags = (int)keyFlag;
            inputData[0].ki.time = 0;
            inputData[0].ki.dwExtraInfo = IntPtr.Zero;
    
            SendInput(1, inputData, Marshal.SizeOf(typeof(Input)));
        }
    
        public static void SendKey(short keyCode, KeyFlag keyFlag)
        {
            SendInput(keyCode, keyFlag | KeyFlag.ScanCode);
        }
    }
    

    使用示例:

    short key = 0x3B; // F1 key
    
    WindowsMessageService.SendKey(key, KeyFlag.KeyDown);
    
    Thread.Sleep(10);
    
    WindowsMessageService.SendKey(key, KeyFlag.KeyUp);
    

    【讨论】:

    • 我刚刚用short key = 0x14;(T 键)尝试过,但它也不起作用。
    • 你确定你有指向GTA进程的MainWindow的指针吗?
    • 我所做的是使用 ProcessStartInfo 和 Process.Start 自己启动游戏。流程实例提供 MainWindow 属性,您必须在发送密钥之前将其用于 SetForegroundWindow。或者您可以使用:Process.GetProcessesByName(processName).FirstOrDefault() 附加到游戏的运行进程。
    • 我已经用我的新代码编辑了我的帖子,那里有什么问题吗?
    • 没关系,我已经解决了。它不起作用,因为我以管理员身份运行 GTA,所以我也必须以管理员身份运行程序。现在我的问题是是否可以从字符串中发送一个键序列。如何将字符翻译成代码?