您是否想过是否可以将现有的东西用于新的东西? 我看了一些所谓的“蒸汽控制器”(从现在开始为SC)的镜头,并看着我的游戏手柄。 问我自己是否有可能以类似蒸汽的方式使用它,我找到了一些Java库并创建了一个项目,今天想与您共享。
当然,早在SC发行之前就已经有很多输入设备(尤其是游戏控制器),但是它具有一个新特性,使其与众不同。
它具有两个触摸板,它们可以模拟鼠标或键盘的输入,以便能够(实际上几乎)玩每个游戏。 如一些早期视频所示,通过使用这种兼容模式,即使像益智游戏“ Portal”之类的鼠标密集型游戏也似乎可以玩。
作为游戏发烧友和Java程序员,我如何使用这样的东西(我已经拥有的XBOX控制器)来接近它?
一个名为“ StrangeCtrl”的小工具看到了世界的亮光。 与控制器对话需要一些JNI(例如,因为JVM中没有USB子系统),但是其余部分则是用纯Java编写的。 它位于系统托盘中,并且针对每个配置文件进行了手动配置,尽管也可以构建一个GUI。
它的依存关系是2.0.5版中的“ net.java.jinput.JInput”(仍适用于Windows 8.1)和我编写的一个小助手(“ com.xafero.SuperLoader” v0.1)。 现在,我将解释在此过程中采取的步骤。
第一步:我们如何让Java与我的控制器对话?
幸运的是,BSD许可的JInput项目正是这样做的。 例如,它连接到Microsoft的XInput接口,并用它获取的本机数据填充某些Java数据结构。 也涵盖Linux和Mac OS X,不用担心。
因此,我插入了游戏手柄(一个兼容XBOX的控制器),方法似乎很清楚:
- 得到控制器
- 得到他们的输入事件
- 并将它们转换为键盘和鼠标的虚拟事件。
三大操作系统的库的本机组件均以Java归档文件(至少每个Maven)提供。 但是,您可能已经知道,java.lang.System仅加载文件系统上直接可用的文件。
第二步:那么如何解决这个烦人的局限性呢?
快速搜索后,我发现wcmatthysen的“ mx-native-loader”似乎很有用,因为它声称可以提取JAR并加载本地内容。 但这没有用,因为JInput的库被打包到几个“ jinput-platform-***。jar”文件中,而不是像该加载器所建议的那样,被打包在META-INF / lib下的一个大块文件中。
因此,名为“ SuperLoader”的新帮助程序库可以在以下情况下工作:
- 为所有讨厌的本机库创建一个临时目录,例如,借助系统属性“ java.io.tmpdir”。 用户也可以直接指定它,因为它实际上并不重要。
- 从已经加载的JAR中获取所有讨厌的库; 遍历所有类路径的URL,并使用过滤器将其提取或排除其中的大多数。
- 扩展现有的库路径; 另一个库没有做的一件事,并且手动进行非常烦人,因此应扩展系统属性“ java.library.path”。
- 强制JVM更新系统路径; 可以通过将系统类加载器的“ sys_paths”字段重置为null来实现。 这迫使System类在您下次请求库时真正欣赏新情况。
现在,该应用程序将所有本机库预加载到一个临时文件夹中,例如,当要求JInput提供控制器列表时,不必为使用JAR文件而对其进行更改。 它完全可以像任何人一样使用System.loadLibrary。
第三步:可以模拟什么?
我们终于要阅读游戏手柄的事件了,那么我们该怎么办呢? 使用AWT的Robot类,自Java早期以来就可以模拟按键或鼠标移动等。 尽管机器人需要一个人来指定应该在其上工作的桌面,但它在多显示器系统上也可以正常工作。 唯一的区别是它生成的所有事件的偏移量–如果要单击PC屏幕的特定区域,这一点尤其重要。
到目前为止已实现的命令是:
- MouseMoveCmd –水平或垂直移动鼠标一定量
- MouseClickCmd –在当前屏幕位置单击给定的鼠标按钮
- KeyComboCmd –按一些键并以相反的顺序释放它们
为了实现某种程度的可扩展性,有一个接口可以接受机器人生成虚拟事件,当前图形设备以及JInput给定的值:
public interface ICommand {
void execute(Robot rbt, GraphicsDevice dev, float value);
}
它的抽象实现“ AbstractCmd”提供了一个接受一个字符串的构造函数。 作为处理的第一步,来自配置文件的原始字符串被一个空白分隔为一个字符串数组。
第四步:我们可以使用哪种配置格式?
有很多流行的格式,例如YAML,JSON等。但是Java已经为我们提供了一种简单的方法来实现这一目标。 因此,使用Java属性机制的XML变体来解析配置文件。 要使用与命令连接的字符串来构建实际地图,请使用类“ com.xafero.strangectrl.cmd.ConfigUtils”
- 加载配置,
- 遍历所有条目,
- 通过每个条目的值搜索命令,
- 并生成用于转换传入事件的实际地图。
第五步:实际工作
辅助类“ ControllerPoller”是一个定期执行的TimerTask,负责从任意数量的控制器中收集新的JInput事件,并将每个新内容通知调用者:
public void run() {
for (Controller controller : controllers) {
if (!controller.poll()) continue;
EventQueue queue = controller.getEventQueue();
Event event = new Event();
while (queue.getNextEvent(event))
callback.onNewEvent(this, controller, event);
}
}
调用方(在这种情况下,位于系统托盘中的所谓“ App”)仅实现回调接口,并在发生任何输入时免费获取所有信息:
public static interface IControllerCallback {
void onNewEvent(ControllerPoller p, Controller c, Event e);
}
“应用程序”的左侧是搜索与传入游戏手柄事件相关联的命令,并使用正确的参数执行这些命令。 现在我们可以用它来控制某些游戏,也许是波斯王子之类的旧游戏,或者是其他无法通过游戏手柄玩的游戏。 但是,让我们走开...
除了游戏以外的示例:如何为行动受限的人配置它?
为了仅显示另一个可能的应用领域,让我们为无法同时按下两个键的用户进行配置。 一个示例应用程序应该是Web浏览器。 在配置文件中,有以下设置:
<!-- Button A means now left mouse click -->
<entry key="Button 0">mouseClick 1</entry>
<!-- Button B will open a new tab -->
<entry key="Button 1">keyCombo CONTROL T</entry>
<!-- Button X will close an existing tab -->
<entry key="Button 2">keyCombo CONTROL W</entry>
此示例中的浏览器不必知道游戏控制器,因为操作系统将产生新的虚拟输入事件,并且将按要求运行。 通过使用Java并成为FOSS,该工具还可以进行自定义并且易于以各种方式理解(与模拟输入设备否则必须使用某些C / C ++代码相比)。
资源和链接
源代码位于https://github.com/xafero/StrangeCtrl 。 随时使用,共享或修改任何方面(根据GPL v3许可)。
有关更多信息,请参见:
- JInput – https://java.net/projects/jinput
- AWT机器人-http: //docs.oracle.com/javase/6/docs/api/java/awt/Robot.html
翻译自: https://www.javacodegeeks.com/2014/01/java-the-steam-controller-and-me.html