C# 通过DirectInput 实现手柄操控

创作背景:近期,一友人希望使用手柄代替键盘玩格斗游戏,自行写了款手柄键盘模拟器,结果在游戏时无法正常运行,托在下看看。程序写得不错,手柄很准确地在记事本上输出键盘键码。

然而,进入游戏,却什么反应都没有。一个念头闪现出来,游戏的输入是通过directinput实现的,比WINDOWS API 更接近底层,这样可以赢取更短的响应时间,程序需向directinput改进,然而这里不得不说下:上网搜索大小网站都是那篇API 实现手柄信息获取的文章,和友人的代码90%的相似度,文章写得很好说真的,但全是这篇就有点过了。国内没有要找的就找下国外吧,百度的确有些害人,因为太懂中文,国外的directinput一张都没有,立马换了搜索页,2小时就用directinput完成了手柄信息获取,然而殊不知接下来的震动功能花费了4天时间…

完成后界面:

功能目标: 1、获取手柄方向、按键信息;2、使手柄震动

                注意,本程序只是通过DX发送震动信息,并不是什么万能手柄驱动啊

                测试手柄震动前,请确认使用的是震动手柄并安装了手柄驱动。

开发环境:Win7 (DX10传说中的DX11类库我没有找到,结果项目建了.NET 3.5)

                   Microsoft Visual Studio 2010

                     数据库无

                    代码在1920 X 1080 分辨率下无过长换行

                    编写人数 1人

参考资料:MSDN资料库

        言归正传,在.NET的高封装的环境下,directinput的使用简化了许多,不了解COM的朋友,甚至是不知道句柄、指针的新手也可以轻易掌握。

思路与实现:首先,我们要计算机找到我们的摇杆设备

foreach (DeviceInstance info in Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly))
{
               Device myJoy = new Device(info.InstanceGuid);
}


        然后控制设备,过去用c++的朋友很熟悉了,申请操作级别,这个真的很重要,在最后测试震动报了“没有独占打开无法操作”的异常,单步了整整一天,才发现是这里设错参了。

myJoy.SetCooperativeLevel(null, CooperativeLevelFlags.Background | CooperativeLevelFlags.Exclusive);


再设置其他参数

 

myJoy.Properties.AxisModeAbsolute = true;
myJoy.Properties.AutoCenter = false;
myJoy.Acquire();

int[] axis = null;
foreach (DeviceObjectInstance doi in myJoy.Objects)
{
      if ((doi.ObjectId & (int)DeviceObjectTypeFlags.Axis) != 0)
      {
             myJoy.Properties.SetRange(ParameterHow.ById, doi.ObjectId, new InputRange(-128, 128));
      }
}

       好了,目标1完成,很快是不?手柄的状态已经在myJoy. CurrentJoystickState下了,通过

myJoy. CurrentJoystickState. ToString() 你可以查看到摇杆状态(微软大费苦心啊,左摇杆、右摇杆、光枪,压杆,基本上能想到的有位移的操作杆都有了)

allJoystick.Joysticks[i].CurrentJoystickState.GetButtons()可以得到按下按钮组合的数组

 

        好,开始进军震动了。震动不同于按键捕捉、不同于模拟键盘、鼠标击键,因为这些计算机都是作为信息的接受方,然而这次是手柄作为接受方。也与一些挂起、响应的程序不同,挂起的程序用于监听端口,当有数据流后运算后反馈硬件。

        例如,我进入一款格斗游戏后不对手柄进行任何输入,时间到后自动选人开打,在被CPU攻击时手柄是有震感的。

也就是说震动指令是由计算机发起的,当时还真想用汇编给它来一段,装了个Bus Hound 5.0 抓包结果Win7蓝屏 花了1个多小时恢复。

        扯远了,手柄的震动是像声音一样播放的,看参考资料,资料中例举了使用SDK下的录制好的震动文件来驱动,国外一达人说该函数有BUG,刚好我又不想下载几百兆的SDK。故选择了最后一种方式,现场定制(录制)、现场播放。

 

代码不难,调试却很罗嗦。

//震动类型
public enum ForceType
{
            VeryBriefJolt,
            BriefJolt,
            LowRumble,
            HardRumble
}
//录制函数,照抄参考资料
public static EffectObject InitializeForce(Device Dev, EffectType Type, int[] Axis, int Magnitude, EffectFlags Flags, int Duration)
        {
            EffectObject eo = null;
            Effect e;

            foreach (EffectInformation ei in Dev.GetEffects(EffectType.All))
            {
                if (DInputHelper.GetTypeCode(ei.EffectType) == (int)Type)
                {
                    e = new Effect();
                    e.SetDirection(new int[Axis.Length]);
                    e.SetAxes(new int[1]);
                    e.EffectType = Type;
                    e.ConditionStruct = new Condition[Axis.Length];
                    e.Duration = Duration;
                    e.Gain = 10000;
                    e.Constant = new ConstantForce();
                    e.Constant.Magnitude = Magnitude;
                    e.SamplePeriod = 0;
                    e.TriggerButton = (int)Microsoft.DirectX.DirectInput.Button.NoTrigger;
                    e.TriggerRepeatInterval = (int)DI.Infinite;
                    e.Flags = Flags;
                    e.UsesEnvelope = false;

                    eo = new EffectObject(ei.EffectGuid, e, Dev);                    
                }
            }
            return eo;
        }

//播放
InitializeForce(myJoy, EffectType.ConstantForce, axis, 10000, EffectFlags.ObjectOffsets | EffectFlags.Spherical, 2000000).start(1);


        用震动来按摩还真不错,附上调试好的源码,与各位同僚共勉:

源码下载

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值