qt: Add evdev keycode mapper
This commit is contained in:
@@ -365,7 +365,7 @@ endif()
|
||||
if (UNIX AND NOT APPLE AND NOT HAIKU)
|
||||
find_package(X11 REQUIRED)
|
||||
target_link_libraries(ui PRIVATE X11::X11 X11::Xi)
|
||||
target_sources(ui PRIVATE xinput2_mouse.cpp)
|
||||
target_sources(ui PRIVATE evdev_keyboard.cpp xinput2_mouse.cpp)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBEVDEV IMPORTED_TARGET libevdev)
|
||||
if (LIBEVDEV_FOUND)
|
||||
|
134
src/qt/evdev_keyboard.cpp
Normal file
134
src/qt/evdev_keyboard.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* evdev keyboard input module.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2023 RichardG.
|
||||
*/
|
||||
#include <unordered_map>
|
||||
#include <QtDebug>
|
||||
|
||||
static std::unordered_map<uint32_t, uint16_t> evdev_keycodes{
|
||||
{99, 0x54}, /* SYSRQ */
|
||||
{86, 0x56}, /* 102ND */
|
||||
{87, 0x57}, /* F11 */
|
||||
{88, 0x58}, /* F12 */
|
||||
{117, 0x59}, /* KPEQUAL */
|
||||
{95, 0x5c}, /* KPJPCOMMA */
|
||||
{183, 0x5d}, /* F13 */
|
||||
{184, 0x5e}, /* F14 */
|
||||
{185, 0x5f}, /* F15 */
|
||||
{93, 0x70}, /* KATAKANAHIRAGANA */
|
||||
{89, 0x73}, /* RO */
|
||||
{85, 0x76}, /* ZENKAKUHANKAKU */
|
||||
{91, 0x77}, /* HIRAGANA */
|
||||
{90, 0x78}, /* KATAKANA */
|
||||
{92, 0x79}, /* HENKAN */
|
||||
{94, 0x7b}, /* MUHENKAN */
|
||||
{124, 0x7d}, /* YEN */
|
||||
{121, 0x7e}, /* KPCOMMA */
|
||||
|
||||
/* Multimedia keys. Guideline is to try and follow the Microsoft standard, then
|
||||
fill in remaining scancodes with OEM-specific keys for redundancy sake. Keys
|
||||
marked with # are not translated into evdev codes by the standard atkbd driver. */
|
||||
{117, 0x59}, /* Num= */
|
||||
{418, 0x6a}, /* ZOOMIN# => Logitech */
|
||||
{420, 0x6b}, /* ZOOMRESET# => Logitech */
|
||||
{223, 0x6d}, /* CANCEL# => Logitech */
|
||||
{132, 0x101}, /* # Logitech Task Select */
|
||||
{148, 0x102}, /* PROG1# => Samsung */
|
||||
{149, 0x103}, /* PROG2# => Samsung */
|
||||
{419, 0x104}, /* ZOOMOUT# => Logitech */
|
||||
{144, 0x105}, /* FILE# => Messenger/Files */
|
||||
{216, 0x105}, /* CHAT# => Messenger/Files */
|
||||
{430, 0x105}, /* MESSENGER# */
|
||||
{182, 0x107}, /* REDO# */
|
||||
{131, 0x108}, /* UNDO# */
|
||||
{135, 0x10a}, /* PASTE# */
|
||||
{177, 0x10b}, /* SCROLLUP# => normal speed */
|
||||
{165, 0x110}, /* PREVIOUSSONG */
|
||||
{136, 0x112}, /* FIND# => Logitech */
|
||||
{421, 0x113}, /* WORDPROCESSOR# => Word */
|
||||
{423, 0x114}, /* SPREADSHEET# => Excel */
|
||||
{397, 0x115}, /* CALENDAR# */
|
||||
{433, 0x116}, /* LOGOFF# */
|
||||
{137, 0x117}, /* CUT# */
|
||||
{133, 0x118}, /* COPY# */
|
||||
{163, 0x119}, /* NEXTSONG */
|
||||
{154, 0x11e}, /* CYCLEWINDOWS => Application Right (no left counterpart) */
|
||||
{113, 0x120}, /* MUTE */
|
||||
{140, 0x121}, /* CALC */
|
||||
{164, 0x122}, /* PLAYPAUSE */
|
||||
{432, 0x123}, /* SPELLCHECK# */
|
||||
{166, 0x124}, /* STOPCD */
|
||||
{139, 0x126}, /* MENU# => Shortcut/Menu/Help for a few OEMs */
|
||||
{114, 0x12e}, /* VOL- */
|
||||
{160, 0x12f}, /* CLOSECD# => Logitech Eject */
|
||||
{161, 0x12f}, /* EJECTCD# => Logitech */
|
||||
{162, 0x12f}, /* EJECTCLOSECD# => Logitech */
|
||||
{115, 0x130}, /* VOL+ */
|
||||
{150, 0x132}, /* WWW# */
|
||||
{172, 0x132}, /* HOMEPAGE */
|
||||
{634, 0x137}, /* SELECTIVE_SCREENSHOT# => SysRq */
|
||||
{138, 0x13b}, /* HELP# */
|
||||
{213, 0x13c}, /* SOUND# => My Music/Office Home */
|
||||
{360, 0x13c}, /* VENDOR# => My Music/Office Home */
|
||||
{204, 0x13d}, /* DASHBOARD# => Task Pane */
|
||||
{181, 0x13e}, /* NEW# */
|
||||
{134, 0x13f}, /* OPEN# */
|
||||
{206, 0x140}, /* CLOSE# */
|
||||
{232, 0x141}, /* REPLY# */
|
||||
{233, 0x142}, /* FORWARDMAIL# */
|
||||
{231, 0x143}, /* SEND# */
|
||||
{151, 0x144}, /* MSDOS# */
|
||||
{112, 0x14c}, /* MACRO */
|
||||
{179, 0x14c}, /* KPLEFTPAREN# */
|
||||
{118, 0x14e}, /* KPPLUSMINUS */
|
||||
{235, 0x155}, /* DOCUMENTS# => Logitech */
|
||||
{234, 0x157}, /* SAVE# */
|
||||
{210, 0x158}, /* PRINT# */
|
||||
{116, 0x15e}, /* POWER */
|
||||
{142, 0x15f}, /* SLEEP */
|
||||
{143, 0x163}, /* WAKEUP */
|
||||
{180, 0x164}, /* KPRIGHTPAREN# */
|
||||
{212, 0x164}, /* CAMERA# => My Pictures */
|
||||
{217, 0x165}, /* SEARCH */
|
||||
{156, 0x166}, /* BOOKMARKS => Favorites */
|
||||
{364, 0x166}, /* FAVORITES# */
|
||||
{173, 0x167}, /* REFRESH */
|
||||
{128, 0x168}, /* STOP */
|
||||
{159, 0x169}, /* FORWARD */
|
||||
{158, 0x16a}, /* BACK */
|
||||
{157, 0x16b}, /* COMPUTER */
|
||||
{155, 0x16c}, /* MAIL */
|
||||
{215, 0x16c}, /* EMAIL# */
|
||||
{226, 0x16d}, /* MEDIA */
|
||||
{167, 0x178}, /* RECORD# => Logitech */
|
||||
{152, 0x17a}, /* COFFEE/SCREENLOCK# */
|
||||
{178, 0x18b}, /* SCROLLDOWN# => normal speed */
|
||||
};
|
||||
|
||||
uint16_t
|
||||
evdev_translate(uint32_t keycode)
|
||||
{
|
||||
/* "for 1-83 (0x01-0x53) scancode equals keycode" */
|
||||
auto ret = (keycode <= 0x53) ? keycode : evdev_keycodes[keycode];
|
||||
|
||||
if (!ret)
|
||||
qWarning() << "Evdev Keyboard: Unknown key" << keycode;
|
||||
#if 0
|
||||
else
|
||||
qInfo() << "Evdev Keyboard: Key" << keycode << "scancode" << Qt::hex << ret;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
20
src/qt/evdev_keyboard.hpp
Normal file
20
src/qt/evdev_keyboard.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Definitions for evdev keyboard input module.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2023 RichardG.
|
||||
*/
|
||||
#ifndef EVDEV_KEYBOARD_HPP
|
||||
#define EVDEV_KEYBOARD_HPP
|
||||
uint16_t evdev_translate(uint32_t keycode);
|
||||
#endif
|
@@ -96,6 +96,9 @@ extern int qt_nvr_save(void);
|
||||
#include "qt_util.hpp"
|
||||
|
||||
#if defined __unix__ && !defined __HAIKU__
|
||||
# ifndef Q_OS_MACOS
|
||||
# include "evdev_keyboard.hpp"
|
||||
# endif
|
||||
# ifdef XKBCOMMON
|
||||
# include "xkbcommon_keyboard.hpp"
|
||||
# ifdef XKBCOMMON_X11
|
||||
@@ -1378,27 +1381,6 @@ std::array<uint32_t, 256> darwin_to_xt {
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__unix__) && !defined(__HAIKU__)
|
||||
static std::unordered_map<uint32_t, uint16_t> evdev_to_xt = {
|
||||
{96, 0x11C},
|
||||
{ 97, 0x11D},
|
||||
{ 98, 0x135},
|
||||
{ 99, 0x71 },
|
||||
{ 100, 0x138},
|
||||
{ 101, 0x1C },
|
||||
{ 102, 0x147},
|
||||
{ 103, 0x148},
|
||||
{ 104, 0x149},
|
||||
{ 105, 0x14B},
|
||||
{ 106, 0x14D},
|
||||
{ 107, 0x14F},
|
||||
{ 108, 0x150},
|
||||
{ 109, 0x151},
|
||||
{ 110, 0x152},
|
||||
{ 111, 0x153}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
static std::unordered_map<uint8_t, uint16_t> be_to_xt = {
|
||||
{0x01, 0x01 },
|
||||
@@ -1528,28 +1510,25 @@ x11_keycode_to_keysym(uint32_t keycode)
|
||||
if (xkbcommon_keymap) {
|
||||
finalkeycode = xkbcommon_translate(keycode);
|
||||
} else
|
||||
# endif
|
||||
# ifdef EVDEV_KEYBOARD_HPP
|
||||
if (QApplication::platformName().contains("eglfs")) {
|
||||
finalkeycode = evdev_translate(keycode);
|
||||
} else
|
||||
# endif
|
||||
{
|
||||
static Display *x11display = nullptr;
|
||||
if (QApplication::platformName().contains("eglfs")) {
|
||||
keycode -= 8;
|
||||
if (keycode <= 88)
|
||||
finalkeycode = keycode;
|
||||
else
|
||||
finalkeycode = evdev_to_xt[keycode];
|
||||
} else {
|
||||
if (QApplication::platformName().contains("wayland")) {
|
||||
if (QApplication::platformName().contains("wayland")) {
|
||||
selected_keycode = x11_to_xt_2;
|
||||
} else if (!x11display) {
|
||||
x11display = XOpenDisplay(nullptr);
|
||||
if (XKeysymToKeycode(x11display, XK_Home) == 110) {
|
||||
selected_keycode = x11_to_xt_2;
|
||||
} else if (!x11display) {
|
||||
x11display = XOpenDisplay(nullptr);
|
||||
if (XKeysymToKeycode(x11display, XK_Home) == 110) {
|
||||
selected_keycode = x11_to_xt_2;
|
||||
} else if (XKeysymToKeycode(x11display, XK_Home) == 69) {
|
||||
selected_keycode = x11_to_xt_vnc;
|
||||
}
|
||||
} else if (XKeysymToKeycode(x11display, XK_Home) == 69) {
|
||||
selected_keycode = x11_to_xt_vnc;
|
||||
}
|
||||
finalkeycode = selected_keycode[keycode];
|
||||
}
|
||||
finalkeycode = selected_keycode[keycode];
|
||||
}
|
||||
#endif
|
||||
/* Special case for Ctrl+Pause. */
|
||||
|
@@ -20,10 +20,12 @@ extern "C" {
|
||||
|
||||
#include <unordered_map>
|
||||
#include <QtDebug>
|
||||
#include "evdev_keyboard.hpp"
|
||||
|
||||
#define IS_HEX_DIGIT(c) ((((c) >= '0') && ((c) <= '9')) || (((c) >= 'A') && ((c) <= 'F')) || (((c) >= 'a') && ((c) <= 'f')))
|
||||
#define IS_DEC_DIGIT(c) (((c) >= '0') && ((c) <= '9'))
|
||||
#define IS_HEX_DIGIT(c) (IS_DEC_DIGIT(c) || (((c) >= 'A') && ((c) <= 'F')) || (((c) >= 'a') && ((c) <= 'f')))
|
||||
|
||||
std::unordered_map<std::string, uint16_t> xkb_keycodes{
|
||||
static std::unordered_map<std::string, uint16_t> xkb_keycodes{
|
||||
{"ESC", 0x01},
|
||||
{"AE01", 0x02},
|
||||
{"AE02", 0x03},
|
||||
@@ -100,7 +102,6 @@ std::unordered_map<std::string, uint16_t> xkb_keycodes{
|
||||
|
||||
{"NMLK", 0x45},
|
||||
{"SCLK", 0x46},
|
||||
{"FK14", 0x46}, /* F14 => Scroll Lock */
|
||||
{"KP7", 0x47},
|
||||
{"KP8", 0x48},
|
||||
{"KP9", 0x49},
|
||||
@@ -118,19 +119,22 @@ std::unordered_map<std::string, uint16_t> xkb_keycodes{
|
||||
{"LSGT", 0x56},
|
||||
{"FK11", 0x57},
|
||||
{"FK12", 0x58},
|
||||
{"FK13", 0x5d},
|
||||
{"FK14", 0x5e},
|
||||
{"FK15", 0x5f},
|
||||
|
||||
/* Japanese keys. */
|
||||
{"HZTG", 0x29}, /* hankaku-zenkaku toggle => ~ */
|
||||
{"HKTG", 0x70}, /* hiragana-katakana toggle... */
|
||||
{"HIRA", 0x70}, /* ...and individual keys */
|
||||
{"KATA", 0x70},
|
||||
{"JPCM", 0x5c}, /* evdev KPJPCOMMA */
|
||||
{"HKTG", 0x70}, /* hiragana-katakana toggle */
|
||||
{"AB11", 0x73}, /* \_ and Brazilian /? */
|
||||
{"HZTG", 0x76}, /* hankaku-zenkaku toggle */
|
||||
{"HIRA", 0x77},
|
||||
{"KATA", 0x78},
|
||||
{"HENK", 0x79},
|
||||
{"MUHE", 0x7b},
|
||||
{"AE13", 0x7d}, /* \| */
|
||||
{"KPPT", 0x7e}, /* Brazilian Num. */
|
||||
{"I06", 0x7e}, /* alias of KPPT on keycodes/xfree86 (i.e. X11 forwarding) */
|
||||
{"I129", 0x7e}, /* another alias: evdev KPCOMMA */
|
||||
|
||||
/* Korean keys. */
|
||||
{"HJCV", 0xf1}, /* hancha toggle */
|
||||
@@ -141,11 +145,9 @@ std::unordered_map<std::string, uint16_t> xkb_keycodes{
|
||||
{"KPDV", 0x135},
|
||||
{"PRSC", 0x137},
|
||||
{"SYRQ", 0x137},
|
||||
{"FK13", 0x137}, /* F13 => SysRq */
|
||||
{"RALT", 0x138},
|
||||
{"PAUS", 0x145},
|
||||
{"BRK", 0x145},
|
||||
{"FK15", 0x145}, /* F15 => Pause */
|
||||
{"HOME", 0x147},
|
||||
{"UP", 0x148},
|
||||
{"PGUP", 0x149},
|
||||
@@ -164,84 +166,21 @@ std::unordered_map<std::string, uint16_t> xkb_keycodes{
|
||||
{"MENU", 0x15d},
|
||||
{"COMP", 0x15d}, /* Compose as Menu */
|
||||
|
||||
/* Multimedia keys, using Linux evdev-specific keycodes where required. Guideline is to try
|
||||
and follow the Microsoft standard, then fill in some OEM-specific keys for redundancy sake.
|
||||
Keys marked with # are not translated into evdev codes by the standard atkbd driver. */
|
||||
/* Multimedia keys. Same notes as evdev_keyboard apply here. */
|
||||
{"KPEQ", 0x59}, /* Num= */
|
||||
{"I426", 0x6a}, /* ZOOMIN# => Logitech */
|
||||
{"I428", 0x6b}, /* ZOOMRESET# => Logitech */
|
||||
{"I231", 0x6d}, /* CANCEL# => Logitech */
|
||||
{"FRNT", 0x101}, /* # Logitech Task Select */
|
||||
{"I156", 0x102}, /* PROG1# => Samsung */
|
||||
{"I157", 0x103}, /* PROG2# => Samsung */
|
||||
{"I427", 0x104}, /* ZOOMOUT# => Logitech */
|
||||
{"I152", 0x105}, /* FILE# => Messenger/Files */
|
||||
{"I224", 0x105}, /* CHAT# => Messenger/Files */
|
||||
{"I438", 0x105}, /* MESSENGER# */
|
||||
{"I190", 0x107}, /* REDO# */
|
||||
{"UNDO", 0x108}, /* # */
|
||||
{"PAST", 0x10a}, /* # Paste */
|
||||
{"I185", 0x10b}, /* SCROLLUP# => normal speed */
|
||||
{"I173", 0x110}, /* PREVIOUSSONG */
|
||||
{"FIND", 0x112}, /* # Logitech */
|
||||
{"I429", 0x113}, /* WORDPROCESSOR# => Word */
|
||||
{"I431", 0x114}, /* SPREADSHEET# => Excel */
|
||||
{"I405", 0x115}, /* CALENDAR# */
|
||||
{"I441", 0x116}, /* LOGOFF# */
|
||||
{"CUT", 0x117}, /* # */
|
||||
{"COPY", 0x118}, /* # */
|
||||
{"I171", 0x119}, /* NEXTSONG */
|
||||
{"I162", 0x11e}, /* CYCLEWINDOWS => Application Right (no left counterpart) */
|
||||
{"MUTE", 0x120},
|
||||
{"I148", 0x121}, /* CALC */
|
||||
{"I172", 0x122}, /* PLAYPAUSE */
|
||||
{"I440", 0x123}, /* SPELLCHECK# */
|
||||
{"I174", 0x124}, /* STOPCD */
|
||||
{"I147", 0x126}, /* MENU# => Shortcut/Menu/Help for a few OEMs */
|
||||
{"VOL-", 0x12e},
|
||||
{"I168", 0x12f}, /* CLOSECD# => Logitech Eject */
|
||||
{"I169", 0x12f}, /* EJECTCD# => Logitech */
|
||||
{"I170", 0x12f}, /* EJECTCLOSECD# => Logitech */
|
||||
{"VOL+", 0x130},
|
||||
{"I158", 0x132}, /* WWW# */
|
||||
{"I180", 0x132}, /* HOMEPAGE */
|
||||
{"I642", 0x137}, /* SELECTIVE_SCREENSHOT# => SysRq */
|
||||
{"HELP", 0x13b}, /* # */
|
||||
{"I221", 0x13c}, /* SOUND# => My Music/Office Home */
|
||||
{"I368", 0x13c}, /* VENDOR# => My Music/Office Home */
|
||||
{"I212", 0x13d}, /* DASHBOARD# => Task Pane */
|
||||
{"I189", 0x13e}, /* NEW# */
|
||||
{"OPEN", 0x13f}, /* # */
|
||||
{"I214", 0x140}, /* CLOSE# */
|
||||
{"I240", 0x141}, /* REPLY# */
|
||||
{"I241", 0x142}, /* FORWARDMAIL# */
|
||||
{"I239", 0x143}, /* SEND# */
|
||||
{"I159", 0x144}, /* MSDOS# */
|
||||
{"I120", 0x14c}, /* MACRO */
|
||||
{"I187", 0x14c}, /* KPLEFTPAREN# */
|
||||
{"I126", 0x14e}, /* KPPLUSMINUS */
|
||||
{"I243", 0x155}, /* DOCUMENTS# => Logitech */
|
||||
{"I242", 0x157}, /* SAVE# */
|
||||
{"I218", 0x158}, /* PRINT# */
|
||||
{"HELP", 0x13b},
|
||||
{"OPEN", 0x13f},
|
||||
{"POWR", 0x15e},
|
||||
{"I150", 0x15f}, /* SLEEP */
|
||||
{"I151", 0x163}, /* WAKEUP */
|
||||
{"I188", 0x164}, /* KPRIGHTPAREN# */
|
||||
{"I220", 0x164}, /* CAMERA# => My Pictures */
|
||||
{"I225", 0x165}, /* SEARCH */
|
||||
{"I164", 0x166}, /* BOOKMARKS => Favorites */
|
||||
{"I372", 0x166}, /* FAVORITES# */
|
||||
{"I181", 0x167}, /* REFRESH */
|
||||
{"STOP", 0x168},
|
||||
{"I167", 0x169}, /* FORWARD */
|
||||
{"I166", 0x16a}, /* BACK */
|
||||
{"I165", 0x16b}, /* COMPUTER */
|
||||
{"I163", 0x16c}, /* MAIL */
|
||||
{"I223", 0x16c}, /* EMAIL# */
|
||||
{"I234", 0x16d}, /* MEDIA */
|
||||
{"I175", 0x178}, /* RECORD# => Logitech */
|
||||
{"I160", 0x17a}, /* COFFEE/SCREENLOCK# */
|
||||
{"I186", 0x18b}, /* SCROLLDOWN# => normal speed */
|
||||
};
|
||||
struct xkb_keymap *xkbcommon_keymap = nullptr;
|
||||
|
||||
@@ -272,6 +211,10 @@ xkbcommon_translate(uint32_t keycode)
|
||||
if (!ret && (key_name_s.length() == 3) && (key_name_s[0] == 'I') && IS_HEX_DIGIT(key_name_s[1]) && IS_HEX_DIGIT(key_name_s[2]))
|
||||
ret = 0x100 | stoi(key_name_s.substr(1), nullptr, 16);
|
||||
|
||||
/* Translate unnamed evdev-specific keycodes. */
|
||||
if (!ret && (key_name_s.length() >= 2) && (key_name_s[0] == 'I') && IS_DEC_DIGIT(key_name_s[1]))
|
||||
ret = evdev_translate(stoi(key_name_s.substr(1)) - 8);
|
||||
|
||||
if (!ret)
|
||||
qWarning() << "XKB Keyboard: Unknown key" << Qt::hex << keycode << QString::fromStdString(key_name_s);
|
||||
#if 0
|
||||
|
Reference in New Issue
Block a user