在C++ Builder中利用游戏哄骗杆
副标题#e#
在Windows情况下通过编程来哄骗鼠标、键盘是一件再简朴不外的事了,不外各人有没有想过要实验一下另一样我们较量常见的输入东西——游戏哄骗杆呢?在某些环境下,尤其是象体例一些小型的游戏软件的时候,插手对游戏哄骗杆的支持可以给利用者提供更为友好的人机界面,极大的提高游戏软件的可玩性。
C++Builder中没有专门节制哄骗杆函数(其实在常见的编程语言中根基上都没有),因此要增加对游戏哄骗杆的支持,就要和Windows的MCI API函数打交道,这里我们首先先容一些在读取哄骗杆的属性、状态,位置和按钮信息时要用到的API函数、常量及数据布局。
相关常量:
#define MM_JOY1MOVE 0x3A0 /* 用以通报哄骗杆当前状态的一些动静 */
#define MM_JOY2MOVE 0x3A1
#define MM_JOY1ZMOVE 0x3A2
#define MM_JOY2ZMOVE 0x3A3
#define MM_JOY1BUTTONDOWN 0x3B5
#define MM_JOY2BUTTONDOWN 0x3B6
#define MM_JOY1BUTTONUP 0x3B7
#define MM_JOY2BUTTONUP 0x3B8
#define JOY_BUTTON1 0x0001 /* 用以表白当前哄骗杆的状态 */
#define JOY_BUTTON2 0x0002
#define JOY_BUTTON3 0x0004
#define JOY_BUTTON4 0x0008
#define JOY_BUTTON1CHG 0x0100
#define JOY_BUTTON2CHG 0x0200
#define JOY_BUTTON3CHG 0x0400
#define JOY_BUTTON4CHG 0x0800
/* 游戏哄骗杆错误返回值 */
#define JOYERR_BASE 160
#define JOYERR_NOERROR (0) /* 正常 */
#define JOYERR_ParmS (JOYERR_BASE+5) /* 参数错误 */
#define JOYERR_NOCANDO (JOYERR_BASE+6) /* 无法正常事情 */
#define JOYERR_UNPLUGGED (JOYERR_BASE+7) /* 哄骗杆未毗连 */
/* 哄骗杆标识号 */
#define JOYSTICKID1 0
#define JOYSTICKID2 1
#p#副标题#e#
相关函数:
WINMMAPI UINT WINAPI joyGetNumDevs(void);
获取设备标识号。
MMRESULT WINAPI joyGetDevCaps(UINT uJoyID, LPJOYCAPS pjc, UINT cbjc);
获取哄骗杆属性信息,以布局体JoyCaps吸收。
WINMMAPI MMRESULT WINAPI joyGetPos(UINT uJoyID, LPJOYINFO pji);
获取哄骗杆位置和按钮状态,以布局体吸收。
WINMMAPI MMRESULT WINAPI joyGetThreshold(UINT uJoyID, LPUINT puThreshold);
读取哄骗杆移动阈值。
WINMMAPI MMRESULT WINAPI joyReleaseCapture(UINT uJoyID);
竣事对哄骗杆信息的吸收。
WINMMAPI MMRESULT WINAPI joySetCapture(HWND hwnd, UINT uJoyID, UINT uPeriod,
BOOL fChanged);
配置吸收某一哄骗杆的信息的窗口以及将何种频度吸收。
WINMMAPI MMRESULT WINAPI joySetThreshold(UINT uJoyID, UINT uThreshold);
配置哄骗杆移动阈值。
相关布局体: typedef struct joyCaps{
WORD wMid; /* 制造商标识 */
WORD wPid; /* 出产编号 */
char szPname[MAXPNAMELEN]; /* 产物名称 */
UINT wXmin; /* X轴最小值 */
UINT wXmax; /* X轴最大值 */
UINT wYmin; /* Y轴最小值 */
UINT wYmax; /* Y轴最大值 */
UINT wZmin; /* Z轴最小值 */
UINT wZmax; /* Z轴最大值 */
UINT wNumButtons; /* 按钮数 */
UINT wPeriodMin; /* 最小挪用隔断时间(单元 毫秒)*/
UINT wPeriodMax; /* 最大挪用隔断时间(单元 毫秒)*/
}JOYCAPS, *PJOYCAPS, NEAR *NPJOYCAPS, FAR *LPJOYCAPS;
typedef struct joyInfo{
UINT wXpos; /* x 轴位置 */
UINT wYpos; /* y 轴位置 */
UINT wZpos; /* z 轴位置 */
UINT wButtons; /* 按钮状态 */
} JOYINFO, *PJOYINFO, NEAR *NPJOYINFO, FAR *LPJOYINFO;
以上这些界说存储在mmsystem.h文件中,所以措施要包括这个头文件。
#p#分页标题#e#
措施需要首先查抄游戏哄骗杆的存在,这包罗了查抄驱动措施支持和确认哄骗杆已与系统相连的两项事情。joyGetNumDevs挪用查抄系统是否设置了游戏端口和驱动措施。假如返回值为零,表白不支持哄骗杆成果。假如joyGetNumDevs返回值不为零,则说明系统支持游戏哄骗杆成果。但joyGetNumDevs并不能确定哄骗杆是否已被毗连上了,通过挪用可以完成这些事情,并查抄是否有错误产生。
假如有游戏端口,joyGetNumDevs返回值凡是为16.
一旦确认了哄骗杆已连上,就可以接管器发来的动静。joySetCapture通知Windows哄骗杆动静应发送到那边机发送的频率如何。
joySetCapture中的第一个参数通知Windows谁将获得动静,第二个参数确定措施将从谁人哄骗杆吸收动静。第三个参数时暗示但愿以奈何的频度接管JM_MOVE动静(单元为毫秒),无论哄骗杆是否移动,都将以这个频度接管JM_MOVE动静。joySetCapture的四个参数答允措施当哄骗杆移动必然的间隔后才接管动静。该间隔由joySetThreshold配置。
joySetCapture被挪用后,窗口将接管哄骗杆事件。MM_JOYXMOVE(X=哄骗杆号)事件已joySetCapture界说的时距离断产生。只有当哄骗杆的按钮被按下时,MM_JOYXBUTTONUP和MM_JOYXBUTTONDOWN事件才产生。哄骗杆时间出发句柄,改变相应的标签状态信息。移动动静也同时通知措施在新的位置重画哄骗杆符号。挪用joyReleaseCapture通知Windows已竣事哄骗杆的挪用。
在实际体例措施时,应首先在Form1的头文件Form1.h中插手对mmsystem.h的引用,再插手一些相关的动静映射即对MM_JOYXMOVE、MM_JOYXBUTTONUP和MM_JOYXBUTTONDOWN事件的响应函数说明。
#include <mmsystem.h>
//--------------------
class Tform1:public TForm
{
__published:
...
...
private:
...
TPoint Position;//用于存储哄骗杆的坐标位置。
...
public:
MESSAGE_HANDLER(MM_JOY1BUTTONDOWN,TMessage,JMButonUpdate)
MESSAGE_HANDLER(MM_JOY1BUTTONUP,TMessage,JMButonUpdate)
MESSAGE_HANDLER(MM_JOY1MOVE,TMessage,JMMove)
END_MESSAGE_MAP(TForm)
};
在Form1的OnCreate事件中插手以下代码用以检测哄骗杆。
void __fastcall TForm1::FormCreate(TObject *Sender)
{
DriverCount = joyGetNumDevs();
Connected = false;
MMRESULT JoyResult;
JOYINFO JoyInfo;
//查抄系统是否设置了游戏端口和驱动措施。
if(DriverCount != 0)
{
//仍需挪用joyGetPos举办检测,假如返回JOYERR_NOERROR则暗示哄骗杆毗连正常。
//测试第一个哄骗杆。
JoyResult = joyGetPos(JOYSTICKID1,&JoyInfo);
if(JoyResult == JOYERR_NOERROR )
{
Connected = true;
JoystickID = JOYSTICKID1;
}
//假如产生INVALIDPARAM错误,则退出。
else if(JoyResult == MMSYSERR_INVALPARAM)
Application->MessageBox("An error occured while calling joyGetPos",
"Error", MB_OK);
// 假如第一个哄骗杆为毗连,则查抄第二个哄骗杆。
else if((JoyResult=joyGetPos(JOYSTICKID2,&JoyInfo)) == JOYERR_NOERROR)
{
Connected = true;
JoystickID = JOYSTICKID2;
}
}
}
在确定哄骗杆已正确毗连之后就可以读取哄骗杆的设备信息。
void TForm1::ShowDeviceInfo(void)
{
joyGetDevCaps(JoystickID,&JoyCaps, sizeof(JOYCAPS));
Label1->Caption = "Number of joysticks supported by driver = " +
IntToStr(DriverCount);
Label2->Caption = "Current Joystick ID = " +
IntToStr(intJoystickID);
Label3->Caption = "Manufacturer ID = " +
IntToStr(JoyCaps.wMid);
Label4->Caption = "Product ID = " +
IntToStr(JoyCaps.wPid);
Label5->Caption = "Number of buttons = "+
IntToStr(JoyCaps.wNumButtons);
.
.
.
// 配置当前窗口吸收哄骗杆信息。
if(Connected)
joySetCapture(Handle,JoystickID,2*JoyCaps.wPeriodMin,FALSE);
//计较哄骗杆勾当范畴和屏幕范畴的比率,在后头绘制哄骗杆符号时会用到。
XDivider = (JoyCaps.wXmax - JoyCaps.wXmin)/ Width;
YDivider = (JoyCaps.wYmax - JoyCaps.wYmin)/ Height;
}
读取哄骗杆位置信息和按钮状态:
void TForm1::ShowStatusInfo(void)
{
if(Connected)
{
JOYINFO JoyInfo;
TPoint Position;
joyGetPos(JoystickID,&JoyInfo);
Position.x = JoyInfo.wXpos;
Position.y = JoyInfo.wYpos;
//显示哄骗杆的X、Y轴位置。
Label6->Caption = "X Position = " + IntToStr(int(JoyInfo.wXpos));
Label7->Caption = "Y Position = " + IntToStr(int(JoyInfo.wYpos));
//判定某按钮是否被按下,这里只是指按钮初始的状态。
if(JoyInfo.wButtons & JOY_BUTTON1)
Label8->Caption = "Button 1 = Pressed";
else
Label8->Caption = "Button 1 = Not Pressed";
}
}
#p#分页标题#e#
下面可以编写用以响该当初在头文件中界说的事件JMMove、JMButtonUpdate的代码: JMButtonUpdate的代码:
void __fastcall TForm1::JMMove(TMessage &msg)
{
/*当哄骗杆位置产生变革时会自动挪用本函数。
在本函数中常常是按照哄骗杆当前的位置来绘制哄骗杆在屏幕上显示的符号,并擦 去本来的符号。这里只是简朴的改变Image的坐标位置来暗示哄骗杆为的移动。 */
Position.x = msg.LParamLo;
Position.y = msg.LParamHi;
//计较新的坐标。
ScreenX = (Position.x-JoyCaps.wXmin)/XDivider - ImageList1->Width/2;
ScreenY = (Position.y-JoyCaps.wYmin)/YDivider - ImageList1->Height/2;
//显示新位置的X、Y值。
Label6->Caption = "X Position = " + IntToStr(int(Position.x));
Label7->Caption = "Y Position = " + IntToStr(int(Position.y));
//移动Image的位置。
Image1->Top=ScreenY;
Image1->Left=ScreenX;
}
void __fastcall TForm1::JMButtonUpdate(TMessage &msg)
{
//当措施吸收到JM_BUTTONDOWN和JM_BUTTONUP动静时,即某一按钮的状态产生改变时,城市挪用本函数。
if(msg.WParam & JOY_BUTTON1) //判定按钮1是否被按下
Label8->Caption = "Button 1 = Pressed";
else
Label8->Caption = "Button 1 = Not Pressed";
}
最后在措施退出的时候要记得封锁对哄骗杆的挪用,即在FormDestroy事件中插手joyReleaseCapture(JoystickID)。
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
if(Connected)
joyReleaseCapture(JoystickID);
}
以上就是利用哄骗杆的常用要领,通过这些要领根基上就可以完成对哄骗杆的一般操纵,并且在相识了哄骗杆的动静通报机制之后,我们还可以编写出一些用哄骗杆模仿鼠标或是用鼠标/键盘来模仿哄骗杆的措施以及通过编程让一般的手柄也象那种专用于搏斗游戏的哄骗杆一样具有可以影象组合键的成果。不外要想更快速、更全面的操纵哄骗杆就需要用到Windows下高版本DirectX中的DirectInput技能了,鉴于篇幅以及利用较量繁琐的干系,这里就不予先容了。
#p#分页标题#e#
最后说明一下,本措施在 CBuilder4/PWin98 SE 情况下通过,在 WindowsNT 下用到的API函数将会与本措施中先容的函数有所差异,具体区别请参阅Windows API函数手册。别的在措施测试中,我仅利用了最一般的接在声卡上的那种普通4键模仿手柄。针对其他的哄骗杆及新型USB手柄/哄骗杆,还但愿有条件的伴侣本身去测试一下。