Input4j is a modern Java input library built on the Foreign Function & Memory API (FFM).
It provides fast, cross-platform controller and gamepad input without requiring JNI or native binaries.
- ๐ฎ Game controller input support
- โก Native performance via Java FFM API
- ๐งฉ No JNI required
- ๐ฅ Cross-platform (Windows / Linux / macOS)
- ๐ฆ Available on Maven Central
- ๐งช Lightweight and dependency-free
- Cross-Platform Input handling: Fully compatible with Windows, Linux, and OSX.
- Performance: Optimized for high performance with minimal overhead.
- Flexible Input Handling: Supports both polling and event-based input mechanisms.
- Simplicity: Easy to integrate and use with straightforward APIs.
- Future-Proof: Built on the latest Java technologies, ensuring long-term support and compatibility.
Input4j offers several advantages over traditional libraries like JInput by leveraging the new Foreign Function & Memory API (FFM API) instead of using Java Native Interface (JNI). It is a more modern and efficient JNI alternative and an easy way to interact with native input libraries, providing the following benefits:
- No Native Artifacts & No Dependencies: Direct interaction with native libraries without the need for additional native artifacts simplifies the build and deployment process.
- Performance: Based on the FFM API, this library reduces the overhead associated with native calls, resulting in significantly faster performance then Java JNI.
- Safety: Safer memory management and access patterns reduce the risk of memory leaks and buffer overflows.
- Ease of Use: A more straightforward and modern API makes it easier to write and maintain code.
- Future-Proof: Built on the latest Java technologies, ensuring long-term support and compatibility with future Java versions.
Add the following dependency to your build.gradle file to start using Input4j:
dependencies {
implementation 'de.gurkenlabs:input4j:1.0.0'
}<dependency>
<groupId>de.gurkenlabs</groupId>
<artifactId>input4j</artifactId>
<version>1.0.0</version>
</dependency>try (var inputDevices = InputDevices.init()) {
while (!inputDevices.getAll().isEmpty()) {
// iterate all available input devices and poll their data every second
for (var inputDevice : inputDevices.getAll()) {
inputDevice.poll();
System.out.println(inputDevice.getInstanceName() + ":" + inputDevice.getComponents());
}
Thread.sleep(1000);
}
}try (var devices = InputDevices.init()) {
var device = devices.getAll().stream().findFirst().orElse(null);
if (device == null) {
System.out.println("No input devices found.");
return;
}
device.onInputValueChanged(e -> System.out.println("Value changed: " + e.component() + " -> " + e.newValue()));
device.onButtonPressed(XInput.X, () -> System.out.println("X button pressed"));
device.onAxisChanged(Axis.AXIS_X, value -> System.out.println("X axis: " + value));
// simulate external polling loop
while (true) {
device.poll();
Thread.sleep(1000);
}
}input4j is the input system used by the LITIENGINE Java game engine.
-
Windows: DirectInput โ
- Full implementation using
dinput.h - Supports legacy and modern input devices
- Full implementation using
-
Windows: XInput โ
- Modern gamepad support via
xinput.h - Xbox controller compatibility
- Modern gamepad support via
-
Linux: evdev โ
- Event interface via
/dev/input
- Event interface via
-
macOS: IOKit โ
- HID device provisioning via
IOHIDManager
- HID device provisioning via
- Java Runtime: 22+
On Linux, Input4j uses the modern evdev API (/dev/input/event*) which provides detailed input information. This is the same approach used by SDL2 and other modern gamepad libraries.
The /dev/input/event* devices are owned by root:input with restricted access (640).
Quick fix - Add user to input group:
sudo usermod -a -G input $USER
# Log out and log back in for changes to take effectPermanent solution - Create udev rules:
Create /etc/udev/rules.d/99-input4j.rules:
SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="1", MODE="0666"
Then reload the rules:
sudo udevadm control --reload-rules
# Reconnect your gamepadVerify your setup:
# Check device permissions
ls -la /dev/input/event*
# Check if user is in input group
getent group inputNote: Input4j uses the modern evdev API (
/dev/input/event*) rather than the legacy joystick API (/dev/input/js*). Both require the same permissions, but evdev provides more detailed input information. This is the standard approach used by SDL2 and other modern Linux input libraries.