这几天都在忙着写一个老板提出的傻逼功能,大致说说需求,就是要用用Ios的虚拟按键去控制PC的角色移动,如果是Unity来制作这个功能并不难弄,因为这个只需要通过网络层来传递控制信号,然后PC端进行响应即可。但是好死不死的项目需求用到的不是unity开发。项目用到的引擎是CE,这个引擎为了性能的是直接截取底层键盘信息进行响应,这样对我来说真是噩耗(PS:大部分游戏引擎都是直接获取底层键盘按键的信号来获取更快的响应时间,所以大部分的游戏引擎是直接屏蔽掉WIn32.dll,但是为毛U3D没有屏蔽掉就不得而知了)
我找资料发现,国内很多人都在用一个叫Winio的动态运行库,这个库有好几个问题、数字证书、运行库不稳定、以及被大部分杀毒的软件屏蔽掉,所以用到项目上并不合适。(PS:某企鹅,某60等大多数杀毒都将winio库视为游戏外挂)最后我在一个小的论坛网站找到一个很不错的键盘底层输出运行库(驱动级的键盘输出模拟器运行库)官方的网址:http://www.ddxoft.com/
我们先去创建一个简单的C# 窗体应用程序,然后我们设计一个简单的界面来模拟游戏常用到的方向控制键。我简单弄了一个界面如图所示:
那么我们要将DD的接口实例化出来进行调用,这里DD的作者在例子里面用了委托提供我们去调用函数,这里我懒得去删去一下没用的代码,直接用他写好的类进行调用了。
using System;
using System.Runtime.InteropServices;
namespace DDInput
{
public enum KeyModifiers //组合键枚举
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8
}
public enum MouseBtn //鼠标按键枚举
{
左下 = 1,
左上 = 2,
右下 = 4,
右上 = 8
}
class CDD
{
~CDD()
{
if (!m_hinst.Equals(IntPtr.Zero))
{
bool b = FreeLibrary(m_hinst);
}
}
[DllImport("Kernel32")]
private static extern IntPtr LoadLibrary(string dllfile);
[DllImport("Kernel32")]
private static extern IntPtr GetProcAddress(System.IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
public delegate int pDD_btn(int btn);
public delegate int pDD_whl(int whl);
public delegate int pDD_key(int ddcode, int flag);
public delegate int pDD_mov(int x, int y);
public delegate int pDD_movR(int dx, int dy);
public delegate int pDD_str(string str);
public delegate int pDD_todc(int vkcode);
public pDD_btn btn; // 鼠标点击
public pDD_whl whl; // 鼠标滚轮
public pDD_mov mov; // 鼠标绝对移动
public pDD_movR movR; // 鼠标相对移动
public pDD_key key; // 键盘按键
public pDD_str str; // 键盘字符
public pDD_todc todc; // 标准虚拟键码转DD码
//增强版功能
public delegate Int32 pDD_MouseMove(IntPtr hwnd, Int32 x, Int32 y);
public delegate Int32 pDD_SnapPic(IntPtr hwnd, Int32 x, Int32 y, Int32 w, Int32 h);
public delegate Int32 pDD_PickColor(IntPtr hwnd, Int32 x, Int32 y, Int32 mode);
public delegate IntPtr pDD_GetActiveWindow();
public pDD_MouseMove MouseMove; //鼠标移动
public pDD_SnapPic SnapPic; //抓图
public pDD_PickColor PickColor; //取色
public pDD_GetActiveWindow GetActiveWindow; //取激活窗口句柄
private IntPtr m_hinst;
public int Load(string dllfile)
{
m_hinst = LoadLibrary(dllfile);
if (m_hinst.Equals(IntPtr.Zero))
{
return -2;
}
else
{
return GetDDfunAddress(m_hinst);
}
}
private int GetDDfunAddress(IntPtr hinst)
{
IntPtr ptr;
ptr = GetProcAddress(hinst, "DD_btn");
if (ptr.Equals(IntPtr.Zero)) { return -1; }
btn = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_btn)) as pDD_btn;
if (ptr.Equals(IntPtr.Zero)) { return -1; }
ptr = GetProcAddress(hinst, "DD_whl");
whl = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_whl)) as pDD_whl;
if (ptr.Equals(IntPtr.Zero)) { return -1; }
ptr = GetProcAddress(hinst, "DD_mov");
mov = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_mov)) as pDD_mov;
if (ptr.Equals(IntPtr.Zero)) { return -1; }
ptr = GetProcAddress(hinst, "DD_key");
key = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_key)) as pDD_key;
if (ptr.Equals(IntPtr.Zero)) { return -1; }
ptr = GetProcAddress(hinst, "DD_movR");
movR = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_movR)) as pDD_movR;
if (ptr.Equals(IntPtr.Zero)) { return -1; }
ptr = GetProcAddress(hinst, "DD_str");
str = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_str)) as pDD_str;
if (ptr.Equals(IntPtr.Zero)) { return -1; }
ptr = GetProcAddress(hinst, "DD_todc");
todc = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_todc)) as pDD_todc;
//下面四个函数,只有在增强版中才可用
ptr = GetProcAddress(hinst, "DD_MouseMove"); //鼠标移动
if (!ptr.Equals (IntPtr.Zero)) MouseMove = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_MouseMove)) as pDD_MouseMove;
ptr = GetProcAddress(hinst, "DD_SnapPic"); //抓取图片
if (!ptr.Equals (IntPtr.Zero)) SnapPic = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_SnapPic)) as pDD_SnapPic;
ptr = GetProcAddress(hinst, "DD_PickColor"); //取色
if (!ptr.Equals (IntPtr.Zero)) PickColor = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_PickColor)) as pDD_PickColor;
ptr = GetProcAddress(hinst, "DD_GetActiveWindow"); //获取激活窗口句柄
if (!ptr.Equals (IntPtr.Zero)) GetActiveWindow = Marshal.GetDelegateForFunctionPointer(ptr, typeof(pDD_GetActiveWindow)) as pDD_GetActiveWindow;
if (MouseMove==null || SnapPic==null || PickColor ==null || GetActiveWindow==null)
{
return 0;
}
return 1 ;
}
}
}
粗略的看了一下DD的作者提供的运行库还挺强大的,这个DLL库是非加强版的(PS:如果想要加强版功能就要去找本人要?)
然后我们继续在From1.cs编写模拟键盘的代码,因为很简单所以就直接放代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace DDInput
{
public partial class Form1 : Form
{
private CDD cdd;
private bool isUp = false;
private bool isDown = false;
private bool isLeft = false;
private bool isRight = false;
public Form1()
{
InitializeComponent();
cdd = new CDD();
groupBox1.Visible = false;
timer1.Enabled = false;
}
private void LoadDllFile(string dllfile)
{
System.IO.FileInfo fi = new System.IO.FileInfo(dllfile);
if (!fi.Exists)
{
MessageBox.Show("文件不存在");
return;
}
int ret = cdd.Load(dllfile);
if (ret == -2) { MessageBox.Show("装载库时发生错误"); return; }
if (ret == -1) { MessageBox.Show("取函数地址时发生错误"); return; }
if (ret == 0)
{
MessageBox.Show("成功安装驱动");
//isInit = true;
groupBox1.Visible = true;
timer1.Enabled = true;
button1.Visible = false;
}
return;
}
private void button1_Click(object sender, EventArgs e)
{
//可从注册表中直接获取
//string dllfile = ReadDataFromReg();
//LoadDllFile(dllfile);
//return;
//或手动定位
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "DD入口文件|*.DLL";
if (ofd.ShowDialog() != DialogResult.OK)
{
return;
}
LoadDllFile(ofd.FileName);
}
private void timer1_Tick(object sender, EventArgs e)
{
if (isUp)
cdd.key(302, 1);
if (isLeft)
cdd.key(401, 1);
if (isRight)
cdd.key(403, 1);
if (isDown)
cdd.key(402, 1);
}
private void button2_Click(object sender, EventArgs e)
{
isUp = !isUp;
if(!isUp)
cdd.key(302, 2);
}
private void button3_Click(object sender, EventArgs e)
{
isLeft = !isLeft;
if (!isLeft)
cdd.key(401, 2);
}
private void button5_Click(object sender, EventArgs e)
{
isRight = !isRight;
if (!isRight)
cdd.key(403, 2);
}
private void button4_Click(object sender, EventArgs e)
{
isDown = !isDown;
if (!isDown)
cdd.key(402, 2);
}
}
}
这里要注意DD的动态链接库是要安装的。
我就把测试文件放出来吧,源码都在上面了!别说啥了~~
链接:https://pan.baidu.com/s/1tunE4u-bu5k1igRp1TrEmA 密码:p32u