Java Jinput: rescan / reload controllers

早过忘川 提交于 2019-12-04 12:43:37

I encountered the same problem. The reason is that the actual hardware scan happens only once for each DefaultControllerEnvironment object. Since the only accessible instantiation is a singleton, it never does another scan.

A simple way to force a hardware scan is to create a new object, but neither the class nor the constructor are public. You can however work around this limitation by calling the constructor via reflection.

Rescan

private static ControllerEnvironment createDefaultEnvironment() throws ReflectiveOperationException {

    // Find constructor (class is package private, so we can't access it directly)
    Constructor<ControllerEnvironment> constructor = (Constructor<ControllerEnvironment>)
        Class.forName("net.java.games.input.DefaultControllerEnvironment").getDeclaredConstructors()[0];

    // Constructor is package private, so we have to deactivate access control checks
    constructor.setAccessible(true);

    // Create object with default constructor
    return constructor.newInstance();
}

Usage

// Be aware that creating a new environment is fairly expensive
Controller[] controllers = createDefaultEnvironment().getControllers();

Remove Windows 8 Warnings

/**
 * Fix windows 8 warnings by defining a working plugin
 */
static {

    AccessController.doPrivileged(new PrivilegedAction<Object>() {
        public Object run() {
            String os = System.getProperty("os.name", "").trim();
            if (os.startsWith("Windows 8")) {  // 8, 8.1 etc.

                // disable default plugin lookup
                System.setProperty("jinput.useDefaultPlugin", "false");

                // set to same as windows 7 (tested for windows 8 and 8.1)
                System.setProperty("net.java.games.input.plugins", "net.java.games.input.DirectAndRawInputEnvironmentPlugin");

            }
            return null;
        }
    });

}

If you use the accepted answer, you might want to consider killing the thread that was spawned by the previous environment before setting a new one because it won't be cleaned up otherwise. You can do so by calling something like:

final Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (final Thread thread : threadSet) {
  final String name = thread.getClass().getName();
  if (name.equals("net.java.games.input.RawInputEventQueue$QueueThread")) {
    thread.interrupt();
    try {
      thread.join();
    } catch (final InterruptedException e) {
      thread.interrupt();
    }
  }
}

The warning is because the last time I updated that code windows 7 wasn't even out IIRC, I'll update it.

The controller reload is a feature that has been requested a number of times, but no-one deems it important enough to spend any time implementing it. If you submit a patch I'll take a look and see about committing it. Until someone finds it important enough to spend the time to write it, it's just a missing feature.

I had the same problem before. I add the rescanning feature (for Windows back-end only) and post the patch on Java gaming forum but no ones seem interested in to integrate it.

So if you need it, apply my patch from here: http://www.java-gaming.org/topics/rescan-controllers/24782/msg/224604/view.html#msg224604

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!