Статьи

Java, контроллер Steam и я

Задумывались ли вы, если вы могли бы использовать существующие вещи для чего-то нового? Я посмотрел некоторые кадры так называемого «контроллера Steam» (SC отныне) и посмотрел на свою игровую панель. Спрашивая себя, можно ли было бы использовать его по-парному, я нашел несколько библиотек Java и создал проект, которым я хотел бы поделиться с вами сегодня.

SteamController Конечно, было много устройств ввода (и особенно игровых контроллеров) задолго до выхода SC, но у него есть одно новое свойство, которое делает его особенным.

Он имеет две сенсорные панели, которые могут эмулировать ввод мыши или клавиатуры, чтобы иметь возможность играть (практически почти) в каждой игре. Как показывают некоторые ранние видеоролики, даже при использовании этого режима совместимости даже игра с интенсивным использованием мыши, такая как игра-головоломка «Портал», кажется играбельной.
steamworkshop_webupload_previewfile_172072817_preview Как энтузиаст геймеров и программист на Java, что я мог бы сделать с чем-то вроде этого (контроллер XBOX, который я уже получил), чтобы приблизиться к этому?

Маленький инструмент под названием «StrangeCtrl» увидел яркий свет в мире. Для разговора с контроллером требуется некоторый JNI (потому что в JVM нет подсистемы USB, например), но остальное написано на чистом Java. Он находится в системном трее и настраивается вручную для каждого файла конфигурации, хотя можно также создать графический интерфейс.

Его зависимости — «net.java.jinput.JInput» в версии 2.0.5 (все еще работает для Windows 8.1) и небольшой помощник, который я написал («com.xafero.SuperLoader» v0.1). Теперь я объясню шаги, предпринятые на пути.

Первый шаг: как заставить Java общаться с моим контроллером?

К счастью, лицензированный BSD проект JInput делает именно это. Например, он подключается к интерфейсу Microsoft XInput и заполняет некоторые структуры данных Java исходными данными, которые он получает. Linux и Mac OS X тоже охвачены, не волнуйтесь.

Поэтому я подключил свою игровую панель (один XBOX-совместимый контроллер), и путь казался ясным:

  1. получить контроллеры
  2. получить их входные события
  3. и конвертировать их в виртуальные события для клавиатуры и мыши.

Собственные компоненты библиотеки для большой тройки ОС поставляются в архивах Java (по крайней мере, для Maven). Но, как вы, возможно, уже знаете, java.lang.System загружает только файлы, непосредственно доступные в файловой системе.

Второй шаг: так как же нам обойти это раздражающее ограничение?

После быстрого поиска я обнаружил wxmatthysen ‘mx-native-loader’, который показался мне полезным для извлечения JAR-файлов и загрузки нативных файлов. Но это не сработало, потому что библиотеки JInput упакованы в несколько файлов ‘jinput-platform — ***. Jar’ вместо одного большого куска в META-INF / lib, как предлагает этот загрузчик.

Таким образом, новая вспомогательная библиотека SuperLoader работает в следующих случаях:

  1. Создайте временный каталог для всех неприятных нативных библиотек, например, с помощью системного свойства ‘java.io.tmpdir’. Он также может быть указан пользователем напрямую, поскольку не имеет значения, где он находится.
  2. Получить все неприятные библиотеки из уже загруженных JAR-файлов; переберите все URL пути к классам и извлеките их или исключите большинство из них с помощью фильтра.
  3. Расширить существующий путь к библиотеке; одна вещь, которую не делала другая библиотека, и это очень раздражает, когда вы делаете это вручную, поэтому системное свойство ‘java.library.path’ должно быть расширено.
  4. Заставить JVM обновить системные пути; это можно сделать, сбросив поле ‘sys_paths’ загрузчика системного класса на ноль. Это заставляет класс System по-настоящему оценить новые обстоятельства при следующем запросе библиотеки.

Теперь приложение предварительно загружает все собственные библиотеки во временную папку, и когда JInput запрашивается, например, для предоставления списка контроллеров, его не нужно менять для использования файлов JAR. Он просто может использовать System.loadLibrary, как и любой другой.

Третий шаг: что можно моделировать?

Мы наконец-то должны прочитать события игрового планшета, так что мы можем с этим сделать? С помощью класса роботов AWT можно с первых дней Java имитировать нажатие клавиш или движения мыши и тому подобное. Хотя роботу требуется один для указания рабочего стола, на котором он должен работать, он работает так же хорошо на системах с несколькими мониторами. Единственное отличие — это смещение всех событий, которые оно генерирует — аспект, особенно важный, если вы хотите нажать на определенные области экрана ПК.

На данный момент реализованы следующие команды:

  • MouseMoveCmd — перемещает мышь на некоторое количество по горизонтали или вертикали
  • MouseClickCmd — нажимает указанную кнопку мыши в текущей позиции экрана
  • KeyComboCmd — нажимает некоторые клавиши и отпускает их в обратном порядке

Чтобы обеспечить некоторую расширяемость, существует интерфейс, который принимает робота для генерации виртуальных событий, текущего графического устройства и значения, заданного JInput:

1
2
3
public interface ICommand {
    void execute(Robot rbt, GraphicsDevice dev, float value);
}

Его абстрактная реализация ‘AbstractCmd’ обеспечивает один конструктор, принимающий одну строку. В качестве первого шага обработки необработанная строка, поступающая из файла конфигурации, разделяется пустым пространством на массив строк.

Четвертый шаг: какой формат конфигурации мы можем использовать?

Есть много модных форматов, таких как YAML, JSON, … Но Java уже предоставляет нам простой способ достичь этого. Таким образом, файл конфигурации анализируется с помощью XML-варианта механизма свойств Java. Чтобы построить фактическую карту из строк, связанных с их командами, класс ‘com.xafero.strangectrl.cmd.ConfigUtils’

  • загружает конфигурацию,
  • перебирает все записи,
    • ищет команду по значению каждой записи,
    • загружает каждую команду, создавая ее текстовые аргументы,
    • помещает результат ключа (кнопка контроллера) и значение (связанная команда) в новую карту,
  • и создает фактическую карту, используемую для преобразования входящих событий.

Пятый шаг: фактическая работа …

Вспомогательный класс ControllerPoller — это периодически выполняемая функция TimerTask, которая отвечает за сбор новых событий JInput из произвольного количества контроллеров и информирует вызывающую сторону о каждом новом материале:

1
2
3
4
5
6
7
8
9
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);
}
}

Вызывающая сторона (в данном случае так называемое «приложение», находящееся в системном трее) просто реализует интерфейс обратного вызова и получает всю информацию бесплатно всякий раз, когда происходит какой-либо ввод:

1
2
3
public static interface IControllerCallback {
void onNewEvent(ControllerPoller p, Controller c, Event e);
}

Слева от «Приложения» находится поиск связанных команд для входящих событий игровой панели и их выполнение с правильными параметрами. Теперь мы можем использовать его для управления какой-нибудь игрой, возможно, старой, такой как Prince of Persia, или чем-то другим, что невозможно воспроизвести с помощью игрового планшета. Но давайте отойдем в сторону …

Пример помимо игр: как настроить его для людей с ограниченными возможностями движения?

Чтобы показать еще одну возможную область применения, давайте настроим ее для того, кто не может одновременно нажимать две клавиши. Примером приложения здесь должен быть веб-браузер. В файле конфигурации есть следующие настройки:

1
2
3
4
5
6
<!-- 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).

Для получения дополнительной информации см .:

Ссылка: Java, контроллер Steam и я от нашего партнера JCG Xafero в блоге Java Advent Calendar .