一、开发目标:使用keybd_event和键盘HOOK实现一个按键模拟DNF中的技能指令。操作角色是红眼。
二、项目进度:初步实现技能指令释放,没有对键盘连按做处理,会有N多重复命令,导致角色会抽搐。没有做自定义按键,所有指令都是写到程序中的,不够灵活。
三、开发环境:Win11 ,VS 2022, .net6
四、详细介绍:
- 创建键盘钩子,拦截键盘操作
public class Hook
{
/// <summary>
/// 构造函数
/// </summary>
public Hook() { }
/// <summary>
/// 单例模式
/// </summary>
public static readonly Hook _HookClient = new Hook();
#region 钩子
//委托
public delegate int HookProc(int nCode, int wParam, IntPtr lParam);
HookProc KeyBoardHookProcedure;
public delegate void HookHandle(Keys key, int DownOrUp);
public event HookHandle EventHandle;
//钩子状态
public static int hHook = 0;
//键盘Hook结构函数
[StructLayout(LayoutKind.Sequential)]
public class KeyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
#region DllImport
//设置钩子
[DllImport("user32.dll")]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
//抽掉钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
//调用下一个钩子
[DllImport("user32.dll")]
public static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
//获取模块处理
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name);
/// <summary>
/// 获取按键状态
/// </summary>
/// <param name="nVirtKey"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern short GetKeyState(int nVirtKey);
const int WM_KEYUP = 0x101;//抬起
const int WM_KEYDOWN = 0x100;//按下
const int WM_SYSKEYDOWN = 0x0104;//系统键按下
const int WM_SYSKEYUP = 0x0105;//系统键抬起
const int WM_COPYDATA = 0x004A;//消息中的msg;
const int WH_KEYBOARD_LL = 13;//键盘获取级别(高),可获取系统按键(Ctrl、Shift等)
const int WH_KEYBOARD = 2;//键盘获取级别(低),不能可获取系统按键(Ctrl、Shift等)
#endregion
#region 自定义事件
public void Hook_Start()
{
// 安装键盘钩子
if (hHook == 0)
{
KeyBoardHookProcedure = new HookProc(KeyBoardHookProc);
//hHook = SetWindowsHookEx(WH_KEYBOARD_LL,KeyBoardHookProcedure,GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProcedure, GetModuleHandle("user32"), 0);
//如果设置钩子失败.
if (hHook == 0)
{
Hook_Clear();
throw new Exception("设置Hook失败!");
}
}
}
//取消钩子事件
public void Hook_Clear()
{
bool retKeyboard = true;
if (hHook != 0)
{
retKeyboard = UnhookWindowsHookEx(hHook);
hHook = 0;
}
//如果去掉钩子失败.
if (!retKeyboard)
{
//Debug.WriteLine("钩子注销失败!该钩子可能已经失效");
}
}
//这里可以添加自己想要的信息处理
public int KeyBoardHookProc(int nCode, int wParam, IntPtr lParam)
{
int sendW = wParam;
if (nCode >= 0)
{
KeyBoardHookStruct kbh = (KeyBoardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyBoardHookStruct));
//获取按键的键值
Keys key = (Keys)kbh.vkCode;
//处理键盘命令
EventHandle?.Invoke(key, wParam);
}
int ww = CallNextHookEx(hHook, nCode, wParam, lParam);
return ww;
}
#endregion
#endregion
}
- 创建一个窗口添加一个CheckBox用于启动和关闭模拟功能
- 双击checkbox 控件编写checkBox1_CheckedChanged事件
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (this.checkBox1.Checked)
{
Hook._HookClient.Hook_Start(); //加载钩子
Hook._HookClient.EventHandle += _HookClient_EventHandle;
Hook._HookClient.EventHandle11 += _HookClient_EventHandle11;
}
else
{
Hook._HookClient.EventHandle -= _HookClient_EventHandle;
Hook._HookClient.EventHandle11 -= _HookClient_EventHandle11;
Hook._HookClient.Hook_Clear();
}
}
- 使用User32标记创建Win32API调用方法
//模拟键盘API 键值用byte最准确
[DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
byte VK_LEFT = 0x64;//向左键(数字键盘4)
byte VK_UP = 0x68; //向上键(数字键盘8)
byte VK_RIGHT = 0x66; //向右键(数字键盘6)
byte VK_DOWN = 0x65; //向下键(数字键盘5)
byte VK_SPACE = 0x20; //空格键
byte VK_Z = 0x2c; //Z
byte CO_LEFT = 0x4b;//向左键(数字键盘4)
byte CO_UP = 0X48; //向上键(数字键盘8)
byte CO_RIGHT = 0x4d; //向右键(数字键盘6)
byte CO_DOWN = 0x4c; //向下键(数字键盘5)
byte CO_SPACE = 0x39; //空格键
byte CO_Z = 0x2c; //Z
/// <summary>
/// 按下
/// </summary>
const byte KEYEVENTF_KEYDOWN = 0;
/// <summary>
/// 抬起
/// </summary>
const byte KEYEVENTF_KEYUP = 2;
- 编写按键处理方法_HookClient_EventHandle
//创建一个随机数,用来随机按键按下的时长,更真实的模拟手动操作。
Random rd = new Random();
private void _HookClient_EventHandle(Keys key, int DownOrUp)
{
switch (key)
{
case Keys.A:
//下上上z
血气之刃();
break;
case Keys.B:
break;
case Keys.C:
break;
case Keys.D:
怒气爆发();
//噬魂之手();
break;
case Keys.E:
致命血陨();
break;
case Keys.F:
血气爆发();
break;
case Keys.G:
暴怒狂斩();
break;
case Keys.H:
疯魔血魂斩();
break;
case Keys.I:
break;
case Keys.J:
血魔弑天();
break;
case Keys.K:
break;
case Keys.L:
break;
case Keys.M:
break;
case Keys.N:
break;
case Keys.O:
break;
case Keys.P:
break;
case Keys.Q:
//下上下下z
噬魂封魔斩();
break;
case Keys.R:
浴血之怒();
break;
case Keys.S:
崩山击();
break;
case Keys.T:
崩山裂地斩();
break;
case Keys.U:
break;
case Keys.V:
灭世();
break;
case Keys.W:
鲜血暴掠();
break;
case Keys.X:
break;
case Keys.Y:
一觉();
break;
case Keys.Z:
break;
case Keys.Add:
回血();
break;
default:
break;
}
}
private void 暴怒狂斩()
{
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 回血()
{ //上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//空格
keybd_event(VK_SPACE, CO_SPACE, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_SPACE, CO_SPACE, KEYEVENTF_KEYUP, 0);
}
private void 疯魔血魂斩()
{
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 一觉()
{
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 灭世()
{ //下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 崩山裂地斩()
{
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 浴血之怒()
{
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 致命血陨()
{
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 鲜血暴掠()
{
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 血魔弑天()
{
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 封魔血魂斩()
{
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 血气爆发()
{
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 怒气爆发()
{
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 噬魂之手()
{
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 崩山击()
{ //上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 噬魂封魔斩()
{ //下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(100, 200));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
private void 血气之刃()
{
//下
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_DOWN, CO_DOWN, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//上
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYUP, 0);
Thread.Sleep(rd.Next(40, 60));
//Z
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(CO_Z, CO_Z, KEYEVENTF_KEYUP, 0);
}
- 修改游戏中操作指令,所有操作都改成上下+Z 或者空格。方便把握好左右。
- 整体代码完成,由于一开始不知道怎么使用方向键,所以把方向键改成了数字键盘。
- 重点:由于部分地图必须使用方向键才能操作,又对方向键的使用进行了研究。
//增加辅助键盘按下值
const byte KEYEVENTF_KEYDOWNFangXiang = 1;
//方向键的指令改成下面这样
keybd_event(VK_UP, CO_UP, KEYEVENTF_KEYDOWNFangXiang, 0);
Thread.Sleep(rd.Next(50, 60));
keybd_event(VK_UP, CO_UP, (KEYEVENTF_KEYDOWNFangXiang | KEYEVENTF_KEYUP), 0);
Thread.Sleep(rd.Next(40, 60));
总结:整体代码比较简单,就是方向键研究了一下。同时因为没有适应指令释放技能的速度,最终只是实现了想要的功能进行了测试,最终被我放弃了。特此发出来分享一下。
预告:最近在研究.NET MAUI 想做一个手机操作软件,配合向日葵远程,或者其他远程。实现手机玩游戏。对于我来时比较难得是APP的界面制作,由于没有接触过android开发,步履蹒跚,有对.net MAUI 比较熟,或者对 xaml熟悉的兄弟留个言探讨一下。。