在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
#defineMM_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
相关函数
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
驱动
程序需要首先检查游戏操纵杆的存在,这包括了检查驱动程序支持和确认操纵杆已与系统相连的两项工作。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
//--------------------
class Tform1:public TForm
{ __published:
private:
TPoint Position;//用于存储操纵杆的坐标位置。
public:
MESSAGE_HANDLER(MM_JOY1BUTTONDOWN,TMessage,JMButonUpdate)
应用
用游戏操纵杆摸拟鼠标
调用
API函数joySetCapture能捕获游戏操纵杆。调用joySetCapture函数后,操纵杆产生的所有消息将会发送到指定的窗口。它的原型为:
MMRESULT joySetCapture(HWND hwnd, UINT uJoyID, UINT uPeriod, BOOL fChanged );
其中,参数hwnd为接收操纵杆消息的窗口句柄;参数uJoyID为要捕获的操纵杆标识,它可以是JOYSTICKID1或是JOYSTICKID2,即第一、第二个游戏操纵杆;参数uPeriod为轮询的频率,单位为毫秒,它指定给应用程序发送有关操纵杆信息的间隔时间;参数fChanged为改变位置标识,可设为false。
要释放操纵杆的捕获时,使用joyReleaseCapture函数。它只有一个参数,就是操纵杆的标识JOYSTICKID1或JOYSTICKID2。