【ZT】DirectInput里的键盘鼠标的应用

掌握DirectInput处理鼠标事件的细节 本文深入探讨了如何在VB程序中通过DirectXEvent8接口处理鼠标的移动和按钮事件。首先介绍了鼠标处理程序和回调函数的使用,然后详细解释了如何通过回调过程检测鼠标移动和按钮事件,包括如何将相对鼠标位置转换为绝对位置。文章还通过一个名为MouseTest的程序,展示了如何捕获鼠标事件,并且详细解释了如何编写代码以响应这些事件。 阅读详情
2007年10月12日 01:50:00

设计一个PC游戏,键盘鼠标的输入是绝不能少。Windows也提供了诸如 WM_LBUTTONDOWN、WM_RBUTTONUP等鼠标消息以及WM_KEYDOWN、WM_KEYUP等键盘输入消息。但是 DirectInput中仍然提供了对鼠标键盘的支持,其原因就是DirectInput提供一个更直接更快捷的对输入设备的访问方法。就象我们在DOS 下直接接管键盘中断,而不是去用什么讨厌的INT16来处理键盘输入一样(用INT16来处理键盘输入其弊端在《金庸群侠传》中显得尤为明显,人物在走路 之前总要顿那么一下,就是这一下让我觉得非常之不爽!其原因我想我也不用罗嗦了)。

  当然Windows的键盘消息比之INT16当然有了长足的进步(因为它提供了一 个WM_KEYUP消息),但是在某些方面仍显不足。因为Windows的消息机制是一个缓冲(buffer)机制,未被处理的键盘鼠标消息都放在缓冲区 里等待下一次处理,这样对于一些应用软件是非常重要的,但是对游戏来说(特别是一些动作游戏,包括体育游戏)就显得有蛇足之嫌了。举个例子,在足球游戏 里,你去抢截对手的球——抢球和射门、铲断和长传(大脚)总是设成同一个键,这好像是个公认的标准了——但这时刚好对手的球脱脚了,球直接就到了你的脚 下,这时你本来想带球绕过他的,可是你的抢球键已经按过了,由于这个该死的缓冲机制,先要处理一下这个抢球键(也就是射门键),于是你的动作就变成了一次 盲目的后场远射(等同于大脚解围)了。控制不了自己的动作,做球员做到这个份儿上真是够失败的了。这里就是缓冲机制不适用的地方了。

  而DirectInput提供了缓冲和立即两种访问输入设备的方式,对于立即方 式,正好就是解决上面弊病的方法。DirectInput里关于键盘的初始化部分,已经在很早以前的一篇文章里给出来了。虽是针对于DirectX7的, 但关于DirectInput部分在DX8和DX7里差别不大,把LPDIRECTINPUT7换成LPDIRECTINPUT8、 LPDIRECTINPUTDEVICE7换成LPDIRECTINPUTDEVICE8就OK了,此外还有一点点需要改动的就是DirectInput 对象的创建,DX8里用的是下面这个函数:

DirectInput8Create(hInst, DIRECTINPUT_VERSION, IID_IDirectInput8,(LPVOID *)&lpDI, NULL);

  里面具体的参数大家看也看得出来,我就不多说了。

  下面说一下鼠标,鼠标的缓冲机制还是满重要的,鼠标的移动就建立在滚动计数累积的 基础上的。鼠标是每隔8ms采样一次(反正USB鼠标是这样,我估计一般鼠标也是一样),要是只获取当前状态的话,那这个鼠标移动起来就太慢了(应该不会 有人在应用程序里每隔8ms就调用一次鼠标的状态获取函数吧)。之所以采用DirectInput,不是因为缓冲这个原因,而是因为一个我个人的喜好因 素。一般的游戏在卷屏时是判断鼠标的位置是否在屏幕边缘,如果是就向这一方向卷屏。我个人不是很喜欢这种做法,可能因为我手比较笨,玩游戏是经常莫名其妙 地画面就移走了,这让我觉得很成问题,为什么光标指到屏幕边上就要卷屏?所以我希望鼠标的移动才是卷屏的依据,这在Windows的消息机制里就做不到 了。因为在Windows的消息机制里,当鼠标一到屏幕边上时再向外移动,应用程序是收不到WM_MOUSEMOVE消息的。但在DirectInput 里就可以由我自己来实现,DirectInput接收到的只是鼠标的滚动计数,它可没有什么光标位置的限制。

  下面就给出DirectInput鼠标对象的初始化代码,只能这么一步步的来,没什么好说的。


//=================================
LPDIRECTINPUT8  pDI;
LPDIRECTINPUTDEVICE8  lpMouse;

// 存放鼠标光标的Surface
LPDIRECT3DSURFACE8  lpDSCursor;
HANDLE  hMouseEvent;

//是有符号型,所以可以判断光标是否移出屏幕来决定是否卷屏
short  MouseX = FULLSCREEN_WIDTH/2,MouseY =FULLSCREEN_HEIGHT/2;

bool InitInput()
{
HRESULT   hres;
hres
= DirectInput8Create(hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID *)&lpDI, NULL);
if(FAILED(hres))
return FALSE;

hres
= lpDI-<CreateDevice(GUID_SysMouse, &lpMouse,NULL);
if(FAILED(hres))
return FALSE;

hres
= lpMouse-<SetDataFormat(&c_dfDIMouse);
if(FAILED(hres))
return FALSE;

hres
= lpMouse-<SetCooperativeLevel(hMainWnd,DISCL_EXCLUSIVE | DISCL_FOREGROUND);
if(FAILED(hres))
return FALSE;

hMouseEvent
= CreateEvent(NULL, FALSE, FALSE, NULL);
if(!hMouseEvent)
return FALSE;

hres
= lpMouse-<SetEventNotification(hMouseEvent);
if(FAILED(hres))
return FALSE;

DIPROPDWORD dipdw;
dipdw.diph.dwSize
= sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize
= sizeof(DIPROPHEADER);
dipdw.diph.dwObj
= 0;
dipdw.diph.dwHow
= DIPH_DEVICE;
dipdw.dwData
= MOUSE_SAMPLEBUFFER;  // 预定义为16
hres = lpMouse-<SetProperty(DIPROP_BUFFERSIZE,&dipdw.diph);
if(FAILED(hres))
return FALSE;

lpMouse
-<Acquire();

return TRUE;
}


现在是我们完全接管了鼠标,那么无可非议的,鼠标光标的显示任务也落到了我们头上,不过在D3D8入门里我提到了,光标的显示可以由D3D8支持。下面我们就来创建一个光标:

D3DLOCKED_RECT  dlr;
//光标的Surface只能是A8R8G8B8格式的,占了一个alpha字节又不支持半透明,真是shit 

hres
= lpDevice-<CreateImageSurface(32, 32, D3DFMT_A8R8G8B8,&lpDSCursor);
if(FAILED(hres))
return FALSE;

hres
= lpDSCursor-<LockRect(&dlr, NULL, 0);
if(FAILED(hres))
return FALSE;

// 往Surface里写数据呀,不用我说了吧
………………
hres
= lpDSCursor-<UnlockRect();
hres
= lpDevice-<SetCursorProperties(0, 0, lpDSCursor);
if(FAILED(hres))
return FALSE;

lpDevice
-<ShowCursor(TRUE);

接下来就是鼠标数据的存取了,这里我只处理了鼠标的移动。

void MouseEvent()
{
DIDEVICEOBJECTDATA od;
HRESULT  hres;
DWORD   count;
short   x = 0, y = 0;
while(1)
{
count
= 1;
hres
=lpMouse-<GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &od,&count, 0);
if(hres == DIERR_INPUTLOST)
{
lpMouse
-<Acquire();
return;
}

if(FAILED(hres) || !count)
break;

switch(od.dwOfs)
{
case DIMOFS_X:
x
+= (short)od.dwData;
break;
case DIMOFS_Y:
y
+= (short)od.dwData;
break;
//物理设备上左键或右键按下/释放,如有左右键交换可是要自己判断的
case DIMOFS_BUTTON0:
case DIMOFS_BUTTON1:
if(od.dwData & 0x80)
// 键按下
…………
    
else
// 键释放
…………    
}
}

if(x || y)
{
MouseX
+= x;
MouseY
+= y;
// 决定光标的位置以及是否卷屏等等
…………
lpDevice
-<SetCursorPosition(MouseX, MouseY,D3DCURSOR_IMMEDIATE_UPDATE);
}
}

  好了,现在算是完了。但是我个人觉得有一点小小的缺憾,大家如果试一下就会发现,鼠标移动的总比Windows下慢一些,这是为什么?我在Windows的鼠标设置里看到一个加速选项,觉得可能是由于这个原因。那就模拟一下了。(以下只列出上面函数的改动部分)

short xaccel,yaccel;
xaccel
= yaccel = 1;

while(1)
{
…………
switch(od.dwOfs)
{
case DIMOFS_X:
x
+= (short)od.dwData*xaccel;
xaccel
++;
break;
case DIMOFS_Y:
y
+= (short)od.dwData*yaccel;
yaccel
++;
break;
…………
}
………
}

经过这样改动后,鼠标再移动起来果然顺畅了很多。

  此外,DIDEVICEOBJECTDATA结构中还有一个时间标记,用这个可以 判断鼠标的双击,现在我们的鼠标模拟已经初具雏形。自己接管鼠标后,就可以定义方便自己的消息比如什么拖动啦(在Windows下判断拖动就是烦,自己定 义一个)、三击啦什么的,好处是不言而喻的,当然也带来了坏处——就是编写的代码就多了,不过这就是游戏程序员的职责呀。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1821041


几种模拟键盘按键的方法 一个可以模拟键盘按键的小程序,有前台和后台两种模式。 立即下载

相关推荐

XMouseControl:XInput2支持的键盘鼠标控件

#XMouseControl XMouseControl允许您从键盘控制鼠标。 这与X的内置有所不同,它一次支持多个方向。 此外,它不会占用您的整个键盘,并且支持多个主键盘(注意请参见错误) 要求 构建XMouseControl需要: Xlib头文件(Debian:libx11-dev,Arch:libx11) XTEST头文件(Debian:libxtst-dev,Arch:libx11) 制作 C99编译器 配置 在config.h设置键绑定 虫子 由于难以获得辅助键盘的KeyMap,因此启用快速重复功能的非默认主键盘可能会在快速按下键时错过键的释放。 只需按一下键即可解决此问题。 致谢 XMouseControl受到ptrkeys的启发,而受影响很大。 执照 麻省理工学院

DirectInput键盘鼠标应用

  设计一个PC游戏键盘鼠标的输入是绝不能少。Windows也提供了诸如WM_LBUTTONDOWN、WM_RBUTTONUP等鼠标消息以及WM_KEYDOWN、WM_KEYUP等键盘输入消息。但是DirectInput中仍然提供了对鼠标键盘的支持,其原因就是DirectInput提供一个更直接更快捷的对输入设备的访问方法。就象我们在DOS下直接接管键盘中断,而不是去用什么讨厌的INT16来处理

废弃blog 3895

【C++】DirectInput演示程序demo by浅墨

零资源分下载,分享精神至上。 这个demo很可爱的,是用鼠标键盘来操纵观察一个小萝莉的3D立体模型。 【Visual C++】游戏开发笔记之【浅墨DirectX提高班】系列博文 配套详细注释源码之十 源码配套博文 《【Visual C++】游戏开发笔记四十二 浅墨DirectX教程之十 游戏输入控制利器:DirectInput专场》 ,文章地址为http://blog.csdn.net/zhmxy555/article/details/8547531, 点击debug下的exe文件可以直接看到运行效果,运行需要DirectX运行库的支持。 编写环境:VS2010 我的博客地址是http://blog.csdn.net/zhmxy555,源码结合配套文章一起看效果更佳。 希望能和大家一起交流,共同学习,共同进步。 友情声明:源代码在D3Ddemo10/main.cpp中,浅墨上传的博文配套代码一直以来都是有源代码的,很多童鞋下载了自己找不到源码位置,就乱说没有源代码。既然有sln工程文件,就肯定有完整的源文件源代码啊,我就纳闷了这几位童鞋怎么想的- -不信大家看我前几次上传的资源的评论。晕死- - by浅墨

Python制作模拟按键摘录,pyautogui库及该库在某些窗口不生效的问题部分解决措施(PyDirectInput库、winio驱动级模拟)

因此,为了解决我们遇到的问题,我们只需要让 PyAutoGUI 使用 DirectInput Windows API,而不是它当前使用的 API。例如,当设置confidence为0.5时,函数将会搜索与给定图像相匹配的区域,并且只有当置信度大于等于0.5时,函数才会返回该区域的位置。因此,confidence的值可以影响函数的性能和准确性,取决于您所需要的搜索结果的精度和速度。PyAutoGUI 源代码,并且可以参考我已经完成的工作,所以它应该只是大量的复制/粘贴并填写空白类型的东西。

Salvator_的博客 1万+

DirectInput 编程入门

  游戏编程可不仅仅是图形程序的开发工作,实际上包含了许多方面,本文所要讲述的就是关于如何使用 DirectInput 来对键盘编程的问题。  在 DOS 时代,我们一般都习惯于接管键盘中断来加入自己的处理代码。但这一套生存方式在万恶的 Windows 社会下是行不通的,我们只能靠领 API 或者 DirectInput 的救济金过活。  在 Windows 的 API 中,有一个 GetAsyn

废弃blog 2666

DirectInput输入——鼠标设备

//主DInput COM对象 LPDIRECTINPUT8 lpdi = NULL; //键盘设备 LPDIRECTINPUTDEVICE8 lpdimouse = NULL; //获取的鼠标数据放在此结构中 DIMOUSESTATE mouse_state; int DInput_Init_Mouse(void); int DInput_Read_Mouse(voi...

weixin_33949359的博客 337

使用DirectInput进行交互

使用DirectInput进行交互 (转帖)

hjjdebug的专栏 7816

ZTDirectInput 鼠标编程入门

2007年10月12日 01:49:00 作者:樊一鹏前回同大家简单介绍了如何用 DirectInput 来进行键盘编程,本回所要讲述的就该是关于如何使用 DirectInput 来对另一个非常重要的输入设备----鼠标的编程问题。鼠标的编程同键盘编程的过程是非常相似的,有了上次的基础,你很快就能看出两者在形式上其实完全是大同小异的。DIRECTINPUT 的初始化同前面讲

秦梦瑶的专栏 968

一个DirectInput演示程序

一个DirectInput演示程序       使用DirectInput8组件,获取键盘鼠标的缓冲数据方式,并使用了事件通知将数据显示在屏幕上。程序首先创建DirectInput8对象、鼠标键盘设备,并为它们设置相应的方式,后进入主循环。主循环使用阻塞方式,等待鼠标键盘事件到来(鼠标移动、按键、滚轮,键盘击键),以下为全部代码,并附有详细注释。程序是VC6控制台模式下的,注意Win32函

dijkstar的专栏 3379

游戏外挂揭秘:模拟输入作弊全解析

摘要: 模拟输入类外挂通过伪造键盘/鼠标输入实现自动操作(如连点、压枪、连招等)。技术原理包括Windows API(SendInput、驱动级模拟)或硬件设备(Arduino)伪造输入信号。防御手段涵盖检测输入来源(硬件真实性)、行为异常分析(频率/规律)、反驱动监控及服务器行为校验。本质是区别人工与机器操作,综合运用客户端/服务端技术对抗作弊。 (字数:148)

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 3678

DirectX函数大全总结5

40 ----------------------- Page 41-----------------------            INT  Count,            //显示的文本字符串中字符的数量,如果为-1则 绘制到字符串结尾         LPRECT pRect,             //字符串绘制的位置         DWORD    Form

szygy的专栏 968

python 游戏按键精灵 PyDirectInput介绍

前言: 在python关于按键精灵得操作中常用的有PyAutoGUI,但在使用的过程中,针对一些游戏就直接失灵了,特别是一些以DirectX来开发的游戏或软件。我通过收索相关资料了解到之所以会这样,是因为PyAutoGUI使用的是Virtual Key Codes (VKs),也就是模拟按键码。而对于这些游戏或软件来说需要使用Directinput,这样就需要直接从设备中获取数据,而不是模拟的。而这个由github上Ben Johnson开发的PyDirectInput库就是针对此而设计的。 库安装..

lylelo的博客 2万+

关于Ogre自带输入系统OIS(Object-Oriented Input System)的源码分析

在看Ogre源码的时候注意到了这个开源的输入系统OIS,全称是Object-Oriented Input System。 好像我看到有人称为 Open Input System,不管叫什么总之还挺好用的。 OIS应该有其他平台的版本,但目前我只在Win32需要,所以其他平台的OIS版本不做讨论。 我使用的OIS版本是1.2.0, 现在应该已经有新的版本了,不过应该变化不会太大。 注

破烂熊 4347
上一篇: AutoCAD环境下实现地质图形自动屏幕数字化功能
下一篇: DirectX10方兴未艾 DirectX11展望分析
softart
博客等级 码龄19年 67粉丝 2569原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值