Задумывались ли вы, если вы могли бы использовать существующие вещи для чего-то нового? Я посмотрел некоторые кадры так называемого «контроллера Steam» (SC отныне) и посмотрел на свою игровую панель. Спрашивая себя, можно ли было бы использовать его по-парному, я нашел несколько библиотек Java и создал проект, которым я хотел бы поделиться с вами сегодня.
Конечно, было много устройств ввода (и особенно игровых контроллеров) задолго до выхода SC, но у него есть одно новое свойство, которое делает его особенным.
Он имеет две сенсорные панели, которые могут эмулировать ввод мыши или клавиатуры, чтобы иметь возможность играть (практически почти) в каждой игре. Как показывают некоторые ранние видеоролики, даже при использовании этого режима совместимости даже игра с интенсивным использованием мыши, такая как игра-головоломка «Портал», кажется играбельной.
Как энтузиаст геймеров и программист на 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-совместимый контроллер), и путь казался ясным:
- получить контроллеры
- получить их входные события
- и конвертировать их в виртуальные события для клавиатуры и мыши.
Собственные компоненты библиотеки для большой тройки ОС поставляются в архивах Java (по крайней мере, для Maven). Но, как вы, возможно, уже знаете, java.lang.System загружает только файлы, непосредственно доступные в файловой системе.
Второй шаг: так как же нам обойти это раздражающее ограничение?
После быстрого поиска я обнаружил wxmatthysen ‘mx-native-loader’, который показался мне полезным для извлечения JAR-файлов и загрузки нативных файлов. Но это не сработало, потому что библиотеки JInput упакованы в несколько файлов ‘jinput-platform — ***. Jar’ вместо одного большого куска в META-INF / lib, как предлагает этот загрузчик.
Таким образом, новая вспомогательная библиотека SuperLoader работает в следующих случаях:
- Создайте временный каталог для всех неприятных нативных библиотек, например, с помощью системного свойства ‘java.io.tmpdir’. Он также может быть указан пользователем напрямую, поскольку не имеет значения, где он находится.
- Получить все неприятные библиотеки из уже загруженных JAR-файлов; переберите все URL пути к классам и извлеките их или исключите большинство из них с помощью фильтра.
- Расширить существующий путь к библиотеке; одна вещь, которую не делала другая библиотека, и это очень раздражает, когда вы делаете это вручную, поэтому системное свойство ‘java.library.path’ должно быть расширено.
- Заставить 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).
Для получения дополнительной информации см .:
- JInput — https://java.net/projects/jinput
- AWT Robot — http://docs.oracle.com/javase/6/docs/api/java/awt/Robot.html