C#对游戏手柄的编程开发-API篇(2)
回顾被动方式开发
主动方式的开发
这时我们就要用到以下的API
/// summary
/// /summary
/// param name=uJoyID/param
/// param name=pji/param
/// returns/returns
[DllImport(winmm.dll)]
public static extern int joyGetPos(int uJoyID, ref JOYINFO pji);
/// summary
/// 获取操纵杆位置和按钮状态
/// /summary
/// param name=uJoyID/param
/// param name=pji/param
/// returns/returns
[DllImport(winmm.dll)]
public static extern int joyGetPosEx(int uJoyID, ref JOYINFOEX pji);
上面的两个API函数,我们可以从中任选一个,但joyGetPos函数只能取得1,2,3,4号四个按钮的状态。所以建议不用,下面只重讲解joyGetPosEx函数!
JOYINFO 与 JOYINFOEX 是属于结构体,它们的定义如下:
#region 游戏手柄的位置与按钮状态
/// summary
/// 游戏手柄的位置与按钮状态
/// /summary
[StructLayout(LayoutKind.Sequential)]
public struct JOYINFO
{
public int wXpos;
public int wYpos;
public int wZpos;
public int wButtons;
}
/// summary
/// 游戏手柄的位置与按钮状态
/// /summary
[StructLayout(LayoutKind.Sequential)]
public struct JOYINFOEX
{
/// summary
/// Size, in bytes, of this structure.
/// /summary
public int dwSize;
/// summary
/// Flags indicating the valid information returned in this structure. Members that do not contain valid information are set to zero.
/// /summary
public int dwFlags;
/// summary
/// Current X-coordinate.
/// /summary
public int dwXpos;
/// summary
/// Current Y-coordinate.
/// /summary
public int dwYpos;
/// summary
/// Current Z-coordinate.
/// /summary
public int dwZpos;
/// summary
/// Current position of the rudder or fourth joystick axis.
/// /summary
public int dwRpos;
/// summary
/// Current fifth axis position.
/// /summary
public int dwUpos;
/// summary
/// Current sixth axis position.
/// /summary
public int dwVpos;
/// summary
/// Current state of the 32 joystick buttons. The value of this member can be set to any combination of JOY_BUTTONn flags, where n is a value in the range of 1 through 32 corresponding to the button that is pressed.
/// /summary
public int dwButtons;
/// summary
/// Current button number that is pressed.
/// /summary
public int dwButtonNumber;
/// summary
/// Current position of the point-of-view control. Values for this member are in the range 0 through 35,900. These values represent the angle, in degrees, of each view multiplied by 100.
/// /summary
public int dwPOV;
/// summary
/// Reserved; do not use.
/// /summary
public int dwReserved1;
/// summary
/// Reserved; do not use.
/// /summary
public int dwReserved2;
}
#endregion
如我们使用joyGetPosEx获取
示例代码:
JoystickAPI.JOYINFOEX infoEx = new JoystickAPI.JOYINFOEX();
infoEx.dwSize = Marshal.SizeOf(typeof(JoystickAPI.JOYINFOEX));
infoEx.dwFlags = (int)JoystickAPI.JOY_RETURNBUTTONS;
int result = JoystickAPI.joyGetPosEx(this.Id, ref infoEx);
因为主动方式的时效性只有一次,所以为了能够随时监视到游戏手柄的按键事件,就必须进行轮循获取,当监视到游戏手柄有按键发生时就进行事件通知(噫?好像被动方式?嗯,其实当我们向系统申请捕捉某个游戏手柄时,系统最后也是在帮我们进行轮循操作!)。而实现轮循的方式则可以有多种方式,比如采用独立的线程进行一个死循环;或者采用Timer进行定时执行。
但当我们的
解决按钮重复状态的问题
我们通过API得到的是游戏手柄按钮当前的状态(被按下或未按下)。因此我们可以在轮循里,每当监视到游戏手柄在某次时间有某些按钮是处于按下状态时,就记录此次被按下的按钮号,这样当下一次轮循操作时,如果也监视到有按钮按下,则通过与上一次按下的按钮对比,如果还是相同的按钮,则表明本次按钮还是继续上次的按下状态,那就不再需要向程序里发出消息通知了。而如果不相同,则发出新的按钮按键通知,并记录本次按下的按钮号。
伪代码如下:
previousButtons = 无;
//死循环,进入轮循
while(true){
if(joyGetPosEx(手柄号,ref joyInfo) == 成功){
JoyButtons buttons = 取得当前按下的按钮(joyInfo);
if(buttons != 无){
if(buttons != previousButtons){
//本次按下的按钮不同于上次按下的按钮.所以进行通知
OnClick(buttons);
//记录本次按下的按钮
previousButtons = buttons;
}
}
}
暂停uPeriod毫秒;
}
经过这样的处理后,每按一次手柄的按钮我们的程序也只收到一次按键通知,看来我们的
取得当前按下的是右方向键(1) 取得当前按下的是右方向键(2) 取得当前按下的是右方向键与A键(3) 取得当前按下的是右方向键(4) 取得当前按下的是右方向键与B键(5) 取得当前按下的是右方向键(6)
让我们再仔细再看一下上面的那个流程中的(2)与(3)中的差别,明眼的你应该看出来了,它们之间只是多了一个A键。而如果右方向键在第一步时已发出了按键消息通知,那么在(3)步时,如果我们只发出A键的按键消息通知,也就说每次只发出本次按下的按键集合与上一次按下的按键集合的差的按键消息通知的话,那么在上面的流程中,发出的消息通知就只有:在(1)步时发出右方向键的按键通知、(3)步时发出A键的按键通知、(5)步时发出B键的按键通知。这样篇头中的问题就可以完美的解决了 !!
到此,C#对游戏手柄的编程开发的文章就讲解完了,下一篇我们会讲解一下怎么去实现第一篇中说的用游戏手柄模拟键盘或鼠标的软件 。很简单的说,有兴趣的朋友希望能回贴支持一下我
系列文章: