2024年10月2日发(作者:杞晶灵)
我现在所知道的获取游戏杆输入的方法有4种,第4种才是我要说的正题。
1.用DDK通过USB接口直接访问游戏杆
2.通过汇编访问游戏杆
据说在NT下不能这么用了
3.用Direct Input
也许会很方便,但我对之不感兴趣也不了解,这里只是提一下。不过这个方法似乎比其他
的都完善些,以后有空再研究。
4.用Windows API
在DDK的文档中,查到几个关于joystick的API,在中(受我查到的第一份
资料误导,我还以为只能用DDK来做,早知道就去查MSDN了)。要使用这几个API,VC
下编程时,需要连接,包含mmsystem.h头文件;Delphi下编程时需在uses子句
中加上mmsystem单元。这几个API的作用:
joyGetDevCaps 查询指定的游戏杆设备以确定其性能
joyGetNumDevs 返回系统支持的游戏杆设备的数量
joyGetPos 查询指定的游戏杆设备的位置和活动性
joyGetPosEx 查询一个游戏杆设备的位置和它的按扭状态
joyGetThreshold 查询指定的游戏杆设备的当前移动阈值
joyReleaseCapture 释放由JoySetCapture函数设置的在指定游戏杆设备上的
捕获
joySetCapture 发送一个游戏杆消息到指定的窗口
joySetThreshold 设置指定的游戏杆设备的移动阈值
用这些API访问游戏杆,主要有两种方式:消息和轮询。
消息:
使用joySetCapture函数,使指定的窗口接受游戏杆的消息。
JoySetCapture定义:
MMRESULT joySetCapture(HWND hwnd, UINT uJoyID, UINT uPeriod,BOOL fChanged);
[1] hwnd -----父窗口句柄。
[2] uJoyID ----指定游戏杆,它可以是JOYSTICKID1或JOYSTICKID2,即第一、第二个游
戏杆。
[3] uPeriod ----每隔给定的轮询间隔就给应用程序发送有关游戏杆的信息。这个参数是以毫
秒为单位的轮询间隔时间。
[4] fChanged ----改变位置标识,可设为false。
返回值:
/* joystick error return values */
#define JOYERR_NOERROR (0) /* no error */
#define JOYERR_PARMS (JOYERR_BASE+5) /* bad parameters */
#define JOYERR_NOCANDO (JOYERR_BASE+6) /*request not completed */
#define JOYERR_UNPLUGGED (JOYERR_BASE+7) /*joystick is unplugged */
然后就可以通过接受游戏杆消息来响应游戏杆了。
游戏杆消息:
#define MM_JOY1MOVE 0x3A0 /* joystick */
#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
要释放游戏杆的捕获时,使用joyReleaseCapture函数。它只有一个参数,就是游戏杆的标
识JOYSTICKID1或JOYSTICKID2。
注意:
1.我们一般喜欢在游戏的大循环中自己轮询输入信息,而不是监视消息队列。实际上,接
受消息的方式比下面要讲到的直接轮询的效率低一些,对游戏杆的反应有明显的延迟。
2.我用两个手柄来测试,一个北通,一个酷豹。酷豹总是被识别为JOYSTICKID1,而北通
总是被识别为JOYSTICKID2。然后我改用两个完全相同的北通手柄来测试,则其中 一个被
识别为JOYSTICKID2,另一个不被识别,而JOYSTICKID1则被认为未插入。这个问题我
现在还不知道原因和解决方法。另一个问题:倘若我只插入酷豹手柄,或者插入一个北通和
一个酷豹,则窗口可以正确接收手柄消息。但是只插入一个北通的话,可以正确检测到手柄
的存在,但是接受不到手柄的消息。莫非还缺少了什么步骤?还望高人指点。
轮询:
主要是利用joyGetPosEx函数主动取得游戏杆信息。这样我们就可以在游戏循环中对手柄
状态进行轮询。joyGetPosEx定义如下:
MMRESULT joyGetPosEx(UINT uJoyID, LPJOYINFOEX pji);
[1] uJoyID ----指定游戏杆,它可以是JOYSTICKID1或JOYSTICKID2,即第一、第二个游
戏杆。
[2] pji ---- 函数通过这个参数返回游戏杆的信息。参数的类型定义如下:
typedef struct joyinfoex_tag {
DWORD dwSize; /* size of structure */
DWORD dwFlags; /* flags to indicate what to return */
DWORD dwXpos; /* x position */
DWORD dwYpos; /* y position */
DWORD dwZpos; /* z position */
DWORD dwRpos; /* rudder/4th axis position */
DWORD dwUpos; /* 5th axis position */
DWORD dwVpos; /* 6th axis position */
DWORD dwButtons; /* button states */
DWORD dwButtonNumber; /* current button number pressed */
DWORD dwPOV; /* point of view state */
DWORD dwReserved1;
DWORD dwReserved2;
} JOYINFOEX, *PJOYINFOEX, NEAR *NPJOYINFOEX, FAR *LPJOYINFOEX;
使用此函数前要先通过设置pji->dwFlags的值来指定要返回的值,否则很可能会得不到想要
的信息,我因为没注意这点而郁闷了很久。dwFlags的值可用下列预定义常数来设置:
#define JOY_RETURNX 0x00000001l
#define JOY_RETURNY 0x00000002l
#define JOY_RETURNZ 0x00000004l
#define JOY_RETURNR 0x00000008l
#define JOY_RETURNU 0x00000010l /* axis 5 */
#define JOY_RETURNV 0x00000020l /* axis 6 */
#define JOY_RETURNPOV 0x00000040l
#define JOY_RETURNBUTTONS 0x00000080l
#define JOY_RETURNRAWDATA 0x00000100l
#define JOY_RETURNPOVCTS 0x00000200l
#define JOY_RETURNCENTERED 0x00000400l
#define JOY_USEDEADZONE 0x00000800l
#define JOY_RETURNALL (JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ |
JOY_RETURNR | JOY_RETURNU | JOY_RETURNV |
JOY_RETURNPOV | JOY_RETURNBUTTONS)
函数返回值与joySetCapture函数相同。
JOYINFOEX结构中我最常用到的是dwXpos, dwYpos, dwButtons。
dwButtons从低位到高位每一位分别对应手柄上的功能键1至32。以我现在用的手柄,只用
到前10位。每一位有一个对应的常数:
/* constants used with JOYINFO and JOYINFOEX structures and MM_JOY* messages */
#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
/* constants used with JOYINFOEX */
#define JOY_BUTTON5 0x00000010l
#define JOY_BUTTON6 0x00000020l
……
#define JOY_BUTTON31 0x40000000l
#define JOY_BUTTON32 0x80000000l
dwXpos, dwYpos用于测试方向键(未完)
注意:
1.同样存在不能同时接受两个北通手柄的问题。
其他几个API的作用就不细说了。但还有一个问题:用joyGetDevCaps函数获取手柄的
Product Name时,得到的都是”Microsoft PC-游戏杆驱动程序”。而用DDK做的时候,取得
的Product Name分别是:“USB Joystick”(北通)和“Generic USB Joystick”(酷豹)。
用Direct Input还可以获得更详细的信息。
[2] uJoyID ----指定游戏杆,它可以是JOYSTICKID1或JOYSTICKID2,即第一、第二个游
戏杆。#define MM_JOY1MOVE 0x3A0 /* joystick */[1] uJoyID ----指定游戏杆,它可以是
JOYSTICKID1或JOYSTICKID2,即第一、第二个游戏杆。#define JOY_RETURNALL
(JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNR | JOY_RETURNU |
JOY_RETURNV | JOY_RETURNPOV | JOY_RETURNBUTTONS)
2007/11/08/
2024年10月2日发(作者:杞晶灵)
我现在所知道的获取游戏杆输入的方法有4种,第4种才是我要说的正题。
1.用DDK通过USB接口直接访问游戏杆
2.通过汇编访问游戏杆
据说在NT下不能这么用了
3.用Direct Input
也许会很方便,但我对之不感兴趣也不了解,这里只是提一下。不过这个方法似乎比其他
的都完善些,以后有空再研究。
4.用Windows API
在DDK的文档中,查到几个关于joystick的API,在中(受我查到的第一份
资料误导,我还以为只能用DDK来做,早知道就去查MSDN了)。要使用这几个API,VC
下编程时,需要连接,包含mmsystem.h头文件;Delphi下编程时需在uses子句
中加上mmsystem单元。这几个API的作用:
joyGetDevCaps 查询指定的游戏杆设备以确定其性能
joyGetNumDevs 返回系统支持的游戏杆设备的数量
joyGetPos 查询指定的游戏杆设备的位置和活动性
joyGetPosEx 查询一个游戏杆设备的位置和它的按扭状态
joyGetThreshold 查询指定的游戏杆设备的当前移动阈值
joyReleaseCapture 释放由JoySetCapture函数设置的在指定游戏杆设备上的
捕获
joySetCapture 发送一个游戏杆消息到指定的窗口
joySetThreshold 设置指定的游戏杆设备的移动阈值
用这些API访问游戏杆,主要有两种方式:消息和轮询。
消息:
使用joySetCapture函数,使指定的窗口接受游戏杆的消息。
JoySetCapture定义:
MMRESULT joySetCapture(HWND hwnd, UINT uJoyID, UINT uPeriod,BOOL fChanged);
[1] hwnd -----父窗口句柄。
[2] uJoyID ----指定游戏杆,它可以是JOYSTICKID1或JOYSTICKID2,即第一、第二个游
戏杆。
[3] uPeriod ----每隔给定的轮询间隔就给应用程序发送有关游戏杆的信息。这个参数是以毫
秒为单位的轮询间隔时间。
[4] fChanged ----改变位置标识,可设为false。
返回值:
/* joystick error return values */
#define JOYERR_NOERROR (0) /* no error */
#define JOYERR_PARMS (JOYERR_BASE+5) /* bad parameters */
#define JOYERR_NOCANDO (JOYERR_BASE+6) /*request not completed */
#define JOYERR_UNPLUGGED (JOYERR_BASE+7) /*joystick is unplugged */
然后就可以通过接受游戏杆消息来响应游戏杆了。
游戏杆消息:
#define MM_JOY1MOVE 0x3A0 /* joystick */
#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
要释放游戏杆的捕获时,使用joyReleaseCapture函数。它只有一个参数,就是游戏杆的标
识JOYSTICKID1或JOYSTICKID2。
注意:
1.我们一般喜欢在游戏的大循环中自己轮询输入信息,而不是监视消息队列。实际上,接
受消息的方式比下面要讲到的直接轮询的效率低一些,对游戏杆的反应有明显的延迟。
2.我用两个手柄来测试,一个北通,一个酷豹。酷豹总是被识别为JOYSTICKID1,而北通
总是被识别为JOYSTICKID2。然后我改用两个完全相同的北通手柄来测试,则其中 一个被
识别为JOYSTICKID2,另一个不被识别,而JOYSTICKID1则被认为未插入。这个问题我
现在还不知道原因和解决方法。另一个问题:倘若我只插入酷豹手柄,或者插入一个北通和
一个酷豹,则窗口可以正确接收手柄消息。但是只插入一个北通的话,可以正确检测到手柄
的存在,但是接受不到手柄的消息。莫非还缺少了什么步骤?还望高人指点。
轮询:
主要是利用joyGetPosEx函数主动取得游戏杆信息。这样我们就可以在游戏循环中对手柄
状态进行轮询。joyGetPosEx定义如下:
MMRESULT joyGetPosEx(UINT uJoyID, LPJOYINFOEX pji);
[1] uJoyID ----指定游戏杆,它可以是JOYSTICKID1或JOYSTICKID2,即第一、第二个游
戏杆。
[2] pji ---- 函数通过这个参数返回游戏杆的信息。参数的类型定义如下:
typedef struct joyinfoex_tag {
DWORD dwSize; /* size of structure */
DWORD dwFlags; /* flags to indicate what to return */
DWORD dwXpos; /* x position */
DWORD dwYpos; /* y position */
DWORD dwZpos; /* z position */
DWORD dwRpos; /* rudder/4th axis position */
DWORD dwUpos; /* 5th axis position */
DWORD dwVpos; /* 6th axis position */
DWORD dwButtons; /* button states */
DWORD dwButtonNumber; /* current button number pressed */
DWORD dwPOV; /* point of view state */
DWORD dwReserved1;
DWORD dwReserved2;
} JOYINFOEX, *PJOYINFOEX, NEAR *NPJOYINFOEX, FAR *LPJOYINFOEX;
使用此函数前要先通过设置pji->dwFlags的值来指定要返回的值,否则很可能会得不到想要
的信息,我因为没注意这点而郁闷了很久。dwFlags的值可用下列预定义常数来设置:
#define JOY_RETURNX 0x00000001l
#define JOY_RETURNY 0x00000002l
#define JOY_RETURNZ 0x00000004l
#define JOY_RETURNR 0x00000008l
#define JOY_RETURNU 0x00000010l /* axis 5 */
#define JOY_RETURNV 0x00000020l /* axis 6 */
#define JOY_RETURNPOV 0x00000040l
#define JOY_RETURNBUTTONS 0x00000080l
#define JOY_RETURNRAWDATA 0x00000100l
#define JOY_RETURNPOVCTS 0x00000200l
#define JOY_RETURNCENTERED 0x00000400l
#define JOY_USEDEADZONE 0x00000800l
#define JOY_RETURNALL (JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ |
JOY_RETURNR | JOY_RETURNU | JOY_RETURNV |
JOY_RETURNPOV | JOY_RETURNBUTTONS)
函数返回值与joySetCapture函数相同。
JOYINFOEX结构中我最常用到的是dwXpos, dwYpos, dwButtons。
dwButtons从低位到高位每一位分别对应手柄上的功能键1至32。以我现在用的手柄,只用
到前10位。每一位有一个对应的常数:
/* constants used with JOYINFO and JOYINFOEX structures and MM_JOY* messages */
#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
/* constants used with JOYINFOEX */
#define JOY_BUTTON5 0x00000010l
#define JOY_BUTTON6 0x00000020l
……
#define JOY_BUTTON31 0x40000000l
#define JOY_BUTTON32 0x80000000l
dwXpos, dwYpos用于测试方向键(未完)
注意:
1.同样存在不能同时接受两个北通手柄的问题。
其他几个API的作用就不细说了。但还有一个问题:用joyGetDevCaps函数获取手柄的
Product Name时,得到的都是”Microsoft PC-游戏杆驱动程序”。而用DDK做的时候,取得
的Product Name分别是:“USB Joystick”(北通)和“Generic USB Joystick”(酷豹)。
用Direct Input还可以获得更详细的信息。
[2] uJoyID ----指定游戏杆,它可以是JOYSTICKID1或JOYSTICKID2,即第一、第二个游
戏杆。#define MM_JOY1MOVE 0x3A0 /* joystick */[1] uJoyID ----指定游戏杆,它可以是
JOYSTICKID1或JOYSTICKID2,即第一、第二个游戏杆。#define JOY_RETURNALL
(JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNR | JOY_RETURNU |
JOY_RETURNV | JOY_RETURNPOV | JOY_RETURNBUTTONS)
2007/11/08/