C#在游戏应用中按住按键

6

我正在尝试制作一个C#应用程序,用于控制游戏。我的目标是例如:按住A键150ms,按住左箭头500ms等。 我进行了大量搜索并找到了以下代码。我的程序首先针对游戏,然后按住键。

I'm holding the keys this way:

Keyboard.HoldKey(Keys.Left);
Thread.sleep(500);
Keyboard.ReleaseKey(Keys.Left);

以下是Keyboard类:

public class Keyboard
 {
    public Keyboard()
    {
    }

    [StructLayout(LayoutKind.Explicit, Size = 28)]
    public struct Input
    {
        [FieldOffset(0)]
        public uint type;
        [FieldOffset(4)]
        public KeyboardInput ki;
    }

    public struct KeyboardInput
    {
        public ushort wVk;
        public ushort wScan;
        public uint dwFlags;
        public long time;
        public uint dwExtraInfo;
    }

    const int KEYEVENTF_KEYUP = 0x0002;
    const int INPUT_KEYBOARD = 1;

    [DllImport("user32.dll")]
    public static extern int SendInput(uint cInputs, ref Input inputs, int cbSize);

    [DllImport("user32.dll")]
    static extern short GetKeyState(int nVirtKey);

    [DllImport("user32.dll")]
    static extern ushort MapVirtualKey(int wCode, int wMapType);


    public static bool IsKeyDown(Keys key)
    {
        return (GetKeyState((int)key) & -128) == -128;
    }

    public static void HoldKey(Keys vk)
    {
        ushort nScan = MapVirtualKey((ushort)vk, 0);

        Input input = new Input();
        input.type = INPUT_KEYBOARD;
        input.ki.wVk = (ushort)vk;
        input.ki.wScan = nScan;
        input.ki.dwFlags = 0;
        input.ki.time = 0;
        input.ki.dwExtraInfo = 0;
        SendInput(1, ref input, Marshal.SizeOf(input)).ToString();
    }

    public static void ReleaseKey(Keys vk)
    {
        ushort nScan = MapVirtualKey((ushort)vk, 0);

        Input input = new Input();
        input.type = INPUT_KEYBOARD;
        input.ki.wVk = (ushort)vk;
        input.ki.wScan = nScan;
        input.ki.dwFlags = KEYEVENTF_KEYUP;
        input.ki.time = 0;
        input.ki.dwExtraInfo = 0;
        SendInput(1, ref input, Marshal.SizeOf(input));
    }

    public static void PressKey(Keys vk)
    {
        HoldKey(vk);
        ReleaseKey(vk);
    }
}

它在记事本/浏览器等中正常工作,但无论是全屏还是窗口模式,在任何游戏中都无法正常工作。 你能帮我弄清楚如何在全屏应用程序/游戏中按住键吗? 谢谢!


5
你不能只是在谷歌上搜索一段代码,将其复制到应用程序中并期望它能够正常工作。"不正常工作"这个词非常广泛,具体指的是什么? - DGibbs
1
游戏通常通过DirectX获得键盘控制权,这是一种非常不同的处理方式。将Windows输入消息发送到这些应用程序是没有用的。例如 [PDF]。 - GSerg
我自己做了其他所有的事情,只是我不习惯使用Windows API。所谓的不工作是指我的应用程序针对游戏并尝试保持/释放箭头游戏,但在游戏中没有任何反应。如果我按键盘上的箭头键,它可以正常工作。 - Deepsy
@GSerg,你能给我一个小例子吗?我应该怎么做呢? - Deepsy
4个回答

4

按住A键150毫秒,按住左箭头500毫秒。

看看这是否有效:

        Keyboard.HoldKey((byte)Keys.A, 150);
        Keyboard.HoldKey((byte)Keys.Left, 500);

使用:

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

    const int KEY_DOWN_EVENT = 0x0001; //Key down flag
    const int KEY_UP_EVENT = 0x0002; //Key up flag

    public static void HoldKey(byte key, int duration)
    {
        int totalDuration = 0;
        while (totalDuration < duration)
        {
            keybd_event(key, 0, KEY_DOWN_EVENT, 0);
            keybd_event(key, 0, KEY_UP_EVENT, 0);
            System.Threading.Thread.Sleep(PauseBetweenStrokes);
            totalDuration += PauseBetweenStrokes;
        }
    }
}

你好。谢谢回答,但不幸的是,效果与我第一篇帖子中发布的代码相同:它在记事本/浏览器等中有效,但在游戏窗口中无效。 - Deepsy
我将HoldKey()更改为快速按/释放键,直到达到持续时间。看看这样是否更好... - Idle_Mind
仍然是一样的,似乎游戏处理按键的方式不同 :( - Deepsy
刚刚发现我没有包括“PauseBetweenStrokes”: const int PauseBetweenStrokes = 50;不过我认为这不会有太大的影响。很抱歉它没起作用,祝你好运! - Idle_Mind
是的,我尝试了1、10和20 :( 看来并不是每个游戏都能处理这样的操作。 - Deepsy
显示剩余2条评论

2
您可以使用该方法使其工作,这对于按住键盘按键非常有效:
    public class Keyboard
{

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

    const int KEY_DOWN_EVENT = 0x0001; //Key down flag
    const int KEY_UP_EVENT = 0x0002; //Key up flag

    public static void HoldKey(byte key, int duration)
    {
        keybd_event(key, 0, KEY_DOWN_EVENT, 0);
        System.Threading.Thread.Sleep(duration);
        keybd_event(key, 0, KEY_UP_EVENT, 0);
    }
}

0

我使用了Windows API和SendInput方法来完成它。


你能解释一下你的意思吗? - SJ10

0
如果您将Keyboard类定义为:

public static class Keyboard
    {   
        
        [DllImport("user32.dll", SetLastError = true)]
        static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
        
        public static void Delay(int delay)
        {
            System.Threading.Thread.Sleep(delay);
        }
        
        public static void KeyDown(KEYCODE keycode)
        {
            keybd_event((byte)keycode, 0x0, 0, 0);// presses
        }
        
        public static void KeyPress(KEYCODE keycode, int delay = 0)
        {
            keybd_event((byte)keycode, 0x0, 0, 0);// presses
            System.Threading.Thread.Sleep(delay);
            keybd_event((byte)keycode, 0x0, 2, 0); //releases
        }
        
        public static void KeyUp(KEYCODE keycode)
        {
            keybd_event((byte)keycode, 0, 2, 0); //release
        }
        
        public static void Type(string message)
        {
            System.Windows.Forms.SendKeys.SendWait(message);
        }
            
    }

以及密钥代码为

public enum KEYCODE {
    VK_A = 0x41, VK_B = 0x42, VK_C = 0x43, VK_D = 0x44, VK_E = 0x45, VK_F = 0x46, VK_G = 0x47, 
    VK_H = 0x48, VK_I = 0x49, VK_J = 0x4A, VK_K = 0x4B, VK_L = 0x4C, VK_M = 0x4D, VK_N = 0x4E, VK_O = 0x4F,
    VK_P = 0x50, VK_Q = 0x51, VK_R = 0x52, VK_S = 0x53, VK_T = 0x54, VK_U = 0x55, VK_V = 0x56, VK_W = 0x57, 
    VK_X = 0x58, VK_Y = 0x59, VK_Z = 0x5A, VK_LSHIFT = 0xA0, VK_RSHIFT = 0xA1, VK_LCONTROL = 0xA2, VK_RCONTROL = 0xA3
}

你可以运行以下代码:
Keyboard.KeyDown(KEYCODE.VK_LSHIFT);
    Keyboard.KeyPress(KEYCODE.VK_V);
Keyboard.KeyUp(KEYCODE.VK_LSHIFT);
    Keyboard.KeyPress(KEYCODE.VK_I);
    Keyboard.KeyPress(KEYCODE.VK_N);
    Keyboard.KeyPress(KEYCODE.VK_O);
    Keyboard.KeyPress(KEYCODE.VK_D);

它将打印出Vinod,其中V是大写的,因为Shift键被按下了。 但是,如果您要发送多个按键操作(如输入文本),可以使用Keyboard.Type()代替。

Keyboard.Type("+vino+d");

它将打印VinoD,使VD大写。如需更多帮助,请参阅文档here

即使我已经编写了一些东西叫做Robot.cs,其中包含键盘、鼠标和进程自动化的完整代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接