Короткий ответ
- Нативный Java (AWT/Swing, JavaFX) не даёт доступа к событиям «от конкретного физического устройства» — ОС уже агрегирует ввод.
- Чтобы получать события именно от конкретной клавиатуры или мыши, нужно работать с низкоуровневыми (платформенно-зависимыми) API ОС (Raw Input на Windows, evdev / XInput2 на Linux, IOKit/HID на macOS) — из Java это делается через JNI/JNA или готовые библиотеки.
Варианты и рекомендации
1) Попробовать готовые Java-библиотеки (лучше для новичка)
- JInput — кроссплатформенная библиотека для игровых контроллеров/клавиатур/мышей; умеет перечислять устройства и читать события от каждого отдельно. Может подойти, если она поддерживает вашу платформу в нужном режиме.
- hid4java (на базе hidapi) — работает с HID-устройствами (позволяет открыть конкретный HID-девайс по пути, VID/PID). Подходит для HID-совместимых клавиатур/мышей, но некоторые системные клавиатуры/мыши ОС «захватывает» и доступ блокируется или требует эксклюзивного доступа.
- JNativeHook — глобальные hook’и; удобен для перехвата ввода, но обычно не даёт детальной информации о том, с какого физического устройства пришло событие.
Если вы новичок — сначала попробуйте JInput или hid4java; это проще, чем писать JNI.
2) Windows — Raw Input (если нужен точный контроль)
- Используйте Windows Raw Input API: RegisterRawInputDevices → получают WM_INPUT сообщения → GetRawInputData даёт RAWINPUT с hDevice (идентификатор устройства).
- Из Java вызывайте API через JNA (или JNI). Нужно: создать (возможно невидимое) окно для получения сообщений, реализовать цикл сообщений и обрабатывать WM_INPUT.
- Ссылки: Microsoft Raw Input docs (RegisterRawInputDevices, GetRawInputData), JNA.
3) Linux
- Если система под X11: XInput2 расширение позволяет получать события с указанием устройства (device id) в X-сервере.
- Если низкоуровневый доступ: читать /dev/input/eventX (evdev) — даёт события от конкретного устройства. Требует прав (root или специальные права) и осторожности (могут потребоваться ioctl для идентификации устройств).
- Для Wayland ситуация сложнее: клиентам обычно даётся только агрегированный ввод; доступ к отдельным физическим устройствам ограничен.
- Для Java — использовать JNA/JNI для вызова libevdev или библиотеку-обёртку.
4) macOS
- Использовать IOKit/HIDManager (IOHIDManager) для перечисления HID-устройств и получения событий от конкретного устройства. Реализуется через JNI/JNA; доступ и поведение может отличаться.
Практические замечания
- Разные ОС по-разному трактуют устройства: иногда клавиатуры являются «композитными» HID-устройствами и часть событий обрабатывается на уровне драйвера/OS.
- Для чтения низкоуровневых событий часто нужны привилегии (root/admin) или специальные права.
- «Захват» (exclusive grab) устройства может помешать другим приложениям получать события.
- Кроссплатформенное решение потребует отдельной реализации для каждой ОС.
Что можно сделать прямо сейчас (план для новичка)
1. Скажите, для какой ОС (Windows / Linux / macOS) и какой у вас тип приложения (GUI на Swing/JavaFX, консольное, игра и т. п.). По этому я смогу дать конкретный пример.
2. Я могу:
- показать пример использования JInput или hid4java;
- или написать пример/набросок на JNA для Windows Raw Input (самый практичный путь на Windows);
- или показать, как читать /dev/input/eventX на Linux (через JNA/JNI) или как использовать XInput2.
Если хотите — начнём с того, какая у вас ОС и какие требования (только чтение событий, нужно ли блокировать остальные приложения, нужен ли кроссплатформенный код).