最近做毕业设计,需要用unity实现场景内的反馈到手柄的功能,授之以渔不如授之以鱼,耐心看完这片文章相信你可以diy自己的通用接口手柄。由于usb协议太过于复杂,C#也没有好用的HID设备类,找遍了内网外网的资料,没多少人经行研究。C#的实现方法倒是有例如CyUSB,USBlib.NET等等资料和接口我全部都找了并且试了个遍,要么用不了,要么运行闪退并且用不了。有的代码比较简洁的接口却不能用于Win10,都不能在unity里用,心态崩了。
最后想一下还得用unity里自带的接口
之前看到有一个UP主写HID通讯的文章——Unity中向HID设备发送数据 - 哔哩哔哩
这兄弟是我查阅上千资料中唯一一个实现了该功能的大佬,他还把研究成果做成插件上传到了unity的asset store,但是由于他的文章教程不够详尽,而且每个人DIY的HID手柄不一样,我想想吧还是的自己研究(不是因为穷买不起大佬的插件)然后就开始了input system的研究。根据文章主题吧,我先说unity的部分:
unity部分
在开始之前先导入input system包。
根据大佬的文章和input system的api手册(手册链接::Input System | Input System | 1.2.0(想了解更多输入系统的可以去学习))
我知道了发送数据用的函数是ExecuteCommand<TCommand>(ref TCommand),
所以这两句代码便是用于HID数据传递的:
var c = MyControlCommand.Create(0x04, 0x00);
var res= HID.all[3].ExecuteCommand(ref c);
print("res:" + res);
其中先说说MyControlCommand,查了很多资料,最后我借鉴了B站这个大佬的
//HID设备配置
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct MyControlCommand : IInputDeviceCommandInfo
{
public static FourCC Type { get { return new FourCC('H', 'I', 'D', 'O'); } }
internal const int id = 0;
internal const int kSize = InputDeviceCommand.BaseCommandSize + 2;
[FieldOffset(0)]
public InputDeviceCommand baseCommand;
[FieldOffset(InputDeviceCommand.BaseCommandSize)]
public byte reportId;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 1)]
public byte DataType;
[FieldOffset(InputDeviceCommand.BaseCommandSize + 2)]
public byte Data;
//Add data here
public FourCC typeStatic
{
get { return Type; }
}
public static MyControlCommand Create(byte dataType, byte data)
{
return new MyControlCommand
{
baseCommand = new InputDeviceCommand(Type, kSize),
reportId = id,
DataType = dataType,
Data = data
};
}
}
/* 可以复制过去粘贴在自己创建的Mono派生类里面去用, 按提示引入命名空间即可,但是其中你要注意第六行;这里的2要HID与接收字节相对应, 我只接收一个字节,加上ID是2;这里单片机部分还会详细说,记 住这个字节数大了小了都发送不了一定要注意。
internal const int kSize = InputDeviceCommand.BaseCommandSize + 2; */
然后再说说比较重要的一点,也是我一直踩坑的,就是这里的HID.all[3];
其实就是我的手柄啦,其实它与Gamepad,Joystick一样是一个InputDevice的派生类,你用前两个类也是可以的,分别写为
Gamepad.current 或者 Joystick.current
这里的主要问题是怎么知道current就是我的手柄了呢?
这边打开这个分析工具
编辑切换为居中
添加图片注释,不超过 140 字(可选)
你看看自己的手柄是否出现在这里被支持的设备了
编辑切换为居中
添加图片注释,不超过 140 字(可选)
如果不支持,那很遗憾,这里就通讯不了了。没错我的就是不支持,我尝试用input system里的AddDevice()方法去添加我的HID设备但是无法,它一直找不到这个名字的HID设备。要添加组件的HID设备看我的这篇文章吧:
unity如何添加自定义HID设备,自己开发的手柄如何支持unity。 - 知乎
那我们怎样才能让我的设备支持Input system呢?下面让我们来看看单片机部分:
单片机部分
我们要把单片机作为通用的可收发数据的HID设备这里有一篇比较好的博客参照:STM32 使用Cubemx 建一个USB(HID)设备下位机,实现数据收发 - 白菜没我白 - 博客园
其中因为我们要做的是HID手柄就需要配置手柄的报告描述符,这是官网的教程:HID报告描述符教程 手把手教你编写HID报告描述符 - USB中文网
描述符配置不按unity的标准unity就不识别,就是前面说的它显示不支持此设备。那么unity支持的标准是什么呢?我也不知道,自己配了几百遍unity就是不认这个小三,显示它是不支持的设备。。。
然后我没办法用了USB的官方例程描述符
编辑切换为居中
添加图片注释,不超过 140 字(可选)
unity瞬间就识别了,挺好的,但是问题来了报告描述符里只有输入,没有输出,也就是不下发,这个简单,我在遥感中间加了一句输出的代码:
编辑切换为居中
添加图片注释,不超过 140 字(可选)
然后就即识别也可接收数据了。。。。。
下位机关键代码更改部分(配置部分上边给了博客的):
描述符
编辑切换为居中
添加图片注释,不超过 140 字(可选)
编辑切换为居中
Hid的部分配置代码
差不多就是这样了,查资料的过程中真的是累死了,本生自己又菜,感觉很无助,还花钱下了一些资料,结果没啥用要的还不少,那时就在想要是我实现了这个功能一定把它免费分享到网上,,,如果你也在做类似的功能希望这篇文章能对你有所帮助。有什么问题的话可以留言啊咱可以一起讨论。