This commit is contained in:
OBattler
2023-04-09 00:59:18 +02:00
12 changed files with 524 additions and 480 deletions

View File

@@ -68,6 +68,7 @@ AppDir:
- libxcb-shm0 # if QT:BOOL=ON
- libxcb-xfixes0 # if QT:BOOL=ON
- libxkbcommon-x11-0 # if QT:BOOL=ON
- qtwayland5 # if QT:BOOL=ON
- zlib1g
files:
exclude:

View File

@@ -629,7 +629,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(ENV{PKG_CONFIG_PATH} "")
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/$libdir/pkgconfig:/usr/share/$libdir/pkgconfig")
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/$libdir/pkgconfig:/usr/share/$libdir/pkgconfig:/usr/share/pkgconfig")
include("$(realpath "$toolchain_file")")
EOF
@@ -948,7 +948,6 @@ else
-S "$prefix" -B "$prefix_build" || exit 99
cmake --build "$prefix_build" -j$(nproc) || exit 99
cmake --install "$prefix_build" || exit 99
cp -p "$cwd_root/archive_tmp/usr/bin/fluidsynth" fluidsynth
# Build SDL2 for joystick and FAudio support, with most components
# disabled to remove the dependencies on PulseAudio and libdrm.

2
.gitignore vendored
View File

@@ -34,6 +34,8 @@ Makefile
*.tar.*
*.AppImage
/appimage-builder-cache
/appimage-build
/AppImageBuilder-generated.yml
# Visual Studio Code
/.vs

View File

@@ -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)
@@ -402,6 +402,9 @@ if (UNIX AND NOT APPLE AND NOT HAIKU)
ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1)
target_include_directories(ui PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${Qt${QT_MAJOR}Gui_PRIVATE_INCLUDE_DIRS})
target_sources(ui PRIVATE ${WL_SOURCE_VAR} wl_mouse.cpp)
if (XKBCOMMON_FOUND)
target_sources(ui PRIVATE xkbcommon_wl_keyboard.cpp)
endif()
target_compile_definitions(ui PRIVATE WAYLAND)
endif()
endif()

162
src/qt/evdev_keyboard.cpp Normal file
View File

@@ -0,0 +1,162 @@
/*
* 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 */
{183, 0x5d}, /* F13 */
{184, 0x5e}, /* F14 */
{185, 0x5f}, /* F15 */
/* Japanese keys. */
{95, 0x5c}, /* KPJPCOMMA */
{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 */
/* Korean keys. */
{123, 0xf1}, /* HANJA */
{122, 0xf2}, /* HANGUL */
{96, 0x11c}, /* KPENTER */
{97, 0x11d}, /* RIGHTCTRL */
{98, 0x135}, /* KPSLASH */
{99, 0x137}, /* SYSRQ */
{100, 0x138}, /* RIGHTALT */
{119, 0x145}, /* PAUSE */
{411, 0x145}, /* BREAK */
{102, 0x147}, /* HOME */
{103, 0x148}, /* UP */
{104, 0x149}, /* PAGEUP */
{105, 0x14b}, /* LEFT */
{106, 0x14d}, /* RIGHT */
{107, 0x14f}, /* END */
{108, 0x150}, /* DOWN */
{109, 0x151}, /* PAGEDOWN */
{110, 0x152}, /* INSERT */
{111, 0x153}, /* DELETE */
{125, 0x15b}, /* LEFTMETA */
{126, 0x15c}, /* RIGHTMETA */
{127, 0x15d}, /* COMPOSE => Menu */
/* 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
View 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

View File

@@ -96,11 +96,17 @@ 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
# include "xkbcommon_x11_keyboard.hpp"
# endif
# ifdef WAYLAND
# include "xkbcommon_wl_keyboard.hpp"
# endif
# endif
# include <X11/Xlib.h>
# include <X11/keysym.h>
@@ -652,9 +658,18 @@ MainWindow::MainWindow(QWidget *parent)
ui->actionCursor_Puck->setChecked(true);
}
#ifdef XKBCOMMON_X11
#ifdef XKBCOMMON
# ifdef XKBCOMMON_X11
if (QApplication::platformName().contains("xcb"))
xkbcommon_x11_init();
else
# endif
# ifdef WAYLAND
if (QApplication::platformName().contains("wayland"))
xkbcommon_wl_init();
else
# endif
{}
#endif
}
@@ -890,349 +905,6 @@ MainWindow::on_actionSettings_triggered()
plat_pause(currentPause);
}
#if defined(__unix__) && !defined(__HAIKU__)
std::array<uint32_t, 256> x11_to_xt_base {
0,
0,
0,
0,
0,
0,
0,
0,
0,
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0B,
0x0C,
0x0D,
0x0E,
0x0F,
0x10,
0x11,
0x12,
0x13,
0x14,
0x15,
0x16,
0x17,
0x18,
0x19,
0x1A,
0x1B,
0x1C,
0x1D,
0x1E,
0x1F,
0x20,
0x21,
0x22,
0x23,
0x24,
0x25,
0x26,
0x27,
0x28,
0x29,
0x2A,
0x2B,
0x2C,
0x2D,
0x2E,
0x2F,
0x30,
0x31,
0x32,
0x33,
0x34,
0x35,
0x36,
0x37,
0x38,
0x39,
0x3A,
0x3B,
0x3C,
0x3D,
0x3E,
0x3F,
0x40,
0x41,
0x42,
0x43,
0x44,
0x45,
0x46,
0x47,
0x48,
0x49,
0x4A,
0x4B,
0x4C,
0x4D,
0x4E,
0x4F,
0x50,
0x51,
0x52,
0x53,
0x54,
0x55,
0x56,
0x57,
0x58,
0x147,
0x148,
0x149,
0,
0x14B,
0,
0x14D,
0x14F,
0x150,
0x151,
0x152,
0x153,
0x11C,
0x11D,
0, // Pause/Break key.
0x137,
0x135,
0x138,
0, // Ditto as above comment.
0x15B,
0x15C,
0x15D,
};
std::array<uint32_t, 256> x11_to_xt_2 {
0,
0,
0,
0,
0,
0,
0,
0,
0,
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0B,
0x0C,
0x0D,
0x0E,
0x0F,
0x10,
0x11,
0x12,
0x13,
0x14,
0x15,
0x16,
0x17,
0x18,
0x19,
0x1A,
0x1B,
0x1C,
0x1D,
0x1E,
0x1F,
0x20,
0x21,
0x22,
0x23,
0x24,
0x25,
0x26,
0x27,
0x28,
0x29,
0x2A,
0x2B,
0x2C,
0x2D,
0x2E,
0x2F,
0x30,
0x31,
0x32,
0x33,
0x34,
0x35,
0x36,
0x37,
0x38,
0x39,
0x3A,
0x3B,
0x3C,
0x3D,
0x3E,
0x3F,
0x40,
0x41,
0x42,
0x43,
0x44,
0x45,
0x46,
0x47,
0x48,
0x49,
0x4A,
0x4B,
0x4C,
0x4D,
0x4E,
0x4F,
0x50,
0x51,
0x52,
0x53,
0x138,
0x55,
0x56,
0x57,
0x58,
0x56,
0x70,
0x7B,
0x7D,
0x2B,
0x7E,
0,
0x11C,
0x11D,
0x135,
0x137,
0x138,
0,
0x147,
0x148,
0x149,
0x14B,
0x14D,
0x14F,
0x150,
0x151,
0x152,
0x153,
0,
0, /* Mute */
0, /* Volume Down */
0, /* Volume Up */
0, /* Power Off */
0,
0,
0,
0,
0,
0x70,
0x7B,
0x73,
0x15B,
0x15C,
0x15D
};
std::array<uint32_t, 256> x11_to_xt_vnc {
0,
0,
0,
0,
0,
0,
0,
0,
0x1D,
0x11D,
0x2A,
0x36,
0,
0,
0x38,
0x138,
0x39,
0x0B,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0C,
0x0D,
0x1A,
0x1B,
0x27,
0x28,
0x29,
0x33,
0x34,
0x35,
0x2B,
0x1E,
0x30,
0x2E,
0x20,
0x12,
0x21,
0x22,
0x23,
0x17,
0x24,
0x25,
0x26,
0x32,
0x31,
0x18,
0x19,
0x10,
0x13,
0x1F,
0x14,
0x16,
0x2F,
0x11,
0x2D,
0x15,
0x2C,
0x0E,
0x1C,
0x0F,
0x01,
0x153,
0x147,
0x14F,
0x149,
0x151,
0x148,
0x150,
0x14B,
0x14D,
};
#endif
#ifdef Q_OS_MACOS
std::array<uint32_t, 256> darwin_to_xt {
0x1E,
@@ -1366,27 +1038,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 },
@@ -1497,14 +1148,10 @@ static std::unordered_map<uint8_t, uint16_t> be_to_xt = {
};
#endif
#if defined(__unix__) && !defined(__HAIKU__)
static std::array<uint32_t, 256> &selected_keycode = x11_to_xt_base;
#endif
uint16_t
x11_keycode_to_keysym(uint32_t keycode)
{
uint16_t finalkeycode = 0;
uint16_t finalkeycode;
#if defined(Q_OS_WINDOWS)
finalkeycode = (keycode & 0xFFFF);
#elif defined(Q_OS_MACOS)
@@ -1513,33 +1160,20 @@ x11_keycode_to_keysym(uint32_t keycode)
finalkeycode = be_to_xt[keycode];
#else
# ifdef XKBCOMMON
if (xkbcommon_keymap) {
if (xkbcommon_keymap)
finalkeycode = xkbcommon_translate(keycode);
} else
else
# endif
# ifdef EVDEV_KEYBOARD_HPP
finalkeycode = evdev_translate(keycode - 8);
# else
finalkeycode = 0;
# 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")) {
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;
}
}
finalkeycode = selected_keycode[keycode];
}
}
#endif
/* Special case for Ctrl+Pause. */
if ((finalkeycode == 0x145) && (keyboard_recv(0x1d) || keyboard_recv(0x11d)))
finalkeycode = 0x146;
if (rctrl_is_lalt && finalkeycode == 0x11D)
finalkeycode = 0x38;
return finalkeycode;

View File

@@ -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},
@@ -53,6 +55,7 @@ std::unordered_map<std::string, uint16_t> xkb_keycodes{
{"AD11", 0x1a},
{"AD12", 0x1b},
{"RTRN", 0x1c},
{"LNFD", 0x1c}, /* linefeed => Enter */
{"LCTL", 0x1d},
{"AC01", 0x1e},
@@ -99,7 +102,6 @@ std::unordered_map<std::string, uint16_t> xkb_keycodes{
{"NMLK", 0x45},
{"SCLK", 0x46},
{"FK14", 0x46}, /* F14 as Scroll Lock */
{"KP7", 0x47},
{"KP8", 0x48},
{"KP9", 0x49},
@@ -117,12 +119,17 @@ std::unordered_map<std::string, uint16_t> xkb_keycodes{
{"LSGT", 0x56},
{"FK11", 0x57},
{"FK12", 0x58},
{"FK13", 0x5d},
{"FK14", 0x5e},
{"FK15", 0x5f},
/* Japanese keys. */
{"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}, /* \| */
@@ -138,10 +145,9 @@ std::unordered_map<std::string, uint16_t> xkb_keycodes{
{"KPDV", 0x135},
{"PRSC", 0x137},
{"SYRQ", 0x137},
{"FK13", 0x137}, /* F13 as SysRq */
{"RALT", 0x138},
{"PAUS", 0x146}, /* special case */
{"FK15", 0x146}, /* F15 as Pause */
{"PAUS", 0x145},
{"BRK", 0x145},
{"HOME", 0x147},
{"UP", 0x148},
{"PGUP", 0x149},
@@ -154,104 +160,66 @@ std::unordered_map<std::string, uint16_t> xkb_keycodes{
{"DELE", 0x153},
{"LWIN", 0x15b},
{"LMTA", 0x15b},
{"RWIN", 0x15c},
{"COMP", 0x15d},
{"RMTA", 0x15c},
{"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= */
{"FRNT", 0x101}, /* # Logitech Task Select */
{"I224", 0x105}, /* CHAT# => Messenger/Files */
{"I190", 0x107}, /* REDO */
{"UNDO", 0x108},
{"UNDO", 0x108}, /* # */
{"PAST", 0x10a}, /* # Paste */
{"I185", 0x10b}, /* SCROLLUP# => normal speed */
{"I173", 0x110}, /* PREVIOUSSONG */
{"FIND", 0x112}, /* # Logitech */
{"I156", 0x113}, /* PROG1# => Word */
{"I157", 0x114}, /* PROG2# => Excel */
{"I210", 0x115}, /* PROG3# => Calendar */
{"I182", 0x116}, /* EXIT# => Log Off */
{"CUT", 0x117},
{"COPY", 0x118},
{"I171", 0x119}, /* NEXTSONG */
{"I162", 0x11e}, /* CYCLEWINDOWS => Application Right (no left counterpart) */
{"CUT", 0x117}, /* # */
{"COPY", 0x118}, /* # */
{"MUTE", 0x120},
{"I148", 0x121}, /* CALC */
{"I172", 0x122}, /* PLAYPAUSE */
{"I158", 0x123}, /* WWW# => Compaq online start */
{"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},
{"I180", 0x132}, /* HOMEPAGE */
{"HELP", 0x13b}, /* # */
{"I221", 0x13c}, /* SOUND# => My Music */
{"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# */
{"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 */
{"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# */
{"I186", 0x18b}, /* SCROLLDOWN# => normal speed */
};
struct xkb_keymap *xkbcommon_keymap = nullptr;
void
xkbcommon_init(struct xkb_keymap *keymap)
{
xkbcommon_keymap = keymap;
if (keymap)
xkbcommon_keymap = keymap;
}
void
xkbcommon_close()
{
xkbcommon_keymap = NULL;
}
uint16_t
xkbcommon_translate(uint32_t keycode)
{
const char *key_name = xkb_keymap_key_get_name(xkbcommon_keymap, keycode);
if (!key_name) {
qWarning() << "XKB Keyboard: Unknown keycode" << Qt::hex << keycode;
return 0;
}
std::string key_name_s(key_name);
uint16_t ret = xkb_keycodes[key_name_s];
/* If XKB doesn't know the key name for this keycode, assume an unnamed Ixxx key.
This is useful for older XKB versions with an incomplete evdev keycode map. */
auto key_name_s = key_name ? std::string(key_name) : QString("I%1").arg(keycode).toStdString();
auto ret = xkb_keycodes[key_name_s];
/* Observed with multimedia keys on a Windows X11 client. */
/* Observed with multimedia keys on Windows VcXsrv. */
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);
qWarning() << "XKB Keyboard: Unknown key" << Qt::hex << keycode << QString::fromStdString(key_name_s);
#if 0
else
qInfo() << "XKB Keyboard: Key" << Qt::hex << keycode << "/" << QString::fromStdString(key_name_s) << "scancode" << Qt::hex << ret;
qInfo() << "XKB Keyboard: Key" << Qt::hex << keycode << QString::fromStdString(key_name_s) << "scancode" << Qt::hex << ret;
#endif
return ret;

View File

@@ -16,4 +16,5 @@
*/
extern void *xkbcommon_keymap;
void xkbcommon_init(struct xkb_keymap *keymap);
void xkbcommon_close();
uint16_t xkbcommon_translate(uint32_t keycode);

View File

@@ -0,0 +1,236 @@
/*
* 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.
*
* xkbcommon Wayland keyboard input module.
*
* Heavily inspired by libxkbcommon interactive-wayland.c
*
*
*
* Authors: RichardG, <richardg867@gmail.com>
*
* Copyright 2023 RichardG.
*/
extern "C" {
#include <sys/mman.h>
#include <unistd.h>
#include <xkbcommon/xkbcommon.h>
#include <86box/86box.h>
};
#include "xkbcommon_keyboard.hpp"
#include <wayland-client.h>
#include <wayland-util.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtDebug>
#include <QGuiApplication>
typedef struct {
struct wl_seat *wl_seat;
struct wl_keyboard *wl_kbd;
uint32_t version;
struct xkb_keymap *keymap;
struct wl_list link;
} seat_t;
static bool wl_init_ok = false;
static struct wl_list seats;
static struct xkb_context *ctx;
static void
xkbcommon_wl_set_keymap()
{
/* Grab keymap from the first seat with one. */
seat_t *seat, *tmp;
wl_list_for_each_safe(seat, tmp, &seats, link) {
if (seat->keymap) {
xkbcommon_init(seat->keymap);
return;
}
}
xkbcommon_close(); /* none found */
}
static void
kbd_keymap(void *data, struct wl_keyboard *wl_kbd, uint32_t format,
int fd, uint32_t size)
{
seat_t *seat = (seat_t *) data;
char *buf = (char *) mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (!buf) {
qWarning() << "XKB Keyboard: Failed to mmap keymap with error" << errno;
return;
}
seat->keymap = xkb_keymap_new_from_buffer(ctx, buf, size - 1,
XKB_KEYMAP_FORMAT_TEXT_V1,
XKB_KEYMAP_COMPILE_NO_FLAGS);
munmap(buf, size);
close(fd);
if (!seat->keymap) {
qWarning() << "XKB Keyboard: Keymap compilation failed";
return;
}
xkbcommon_wl_set_keymap();
}
static void
kbd_enter(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
struct wl_surface *surf, struct wl_array *keys)
{
}
static void
kbd_leave(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
struct wl_surface *surf)
{
}
static void
kbd_key(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, uint32_t time,
uint32_t key, uint32_t state)
{
}
static void
kbd_modifiers(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group)
{
}
static void
kbd_repeat_info(void *data, struct wl_keyboard *wl_kbd, int32_t rate,
int32_t delay)
{
}
static const struct wl_keyboard_listener kbd_listener = {
kbd_keymap,
kbd_enter,
kbd_leave,
kbd_key,
kbd_modifiers,
kbd_repeat_info
};
static void
seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t caps)
{
seat_t *seat = (seat_t *) data;
if (!seat->wl_kbd && (caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
seat->wl_kbd = wl_seat_get_keyboard(seat->wl_seat);
wl_keyboard_add_listener(seat->wl_kbd, &kbd_listener, seat);
} else if (seat->wl_kbd && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
wl_keyboard_release(seat->wl_kbd);
else
wl_keyboard_destroy(seat->wl_kbd);
static struct xkb_keymap *keymap = seat->keymap;
seat->keymap = NULL;
xkbcommon_wl_set_keymap();
xkb_keymap_unref(keymap);
seat->wl_kbd = NULL;
}
}
static void
seat_name(void *data, struct wl_seat *wl_seat, const char *name)
{
}
static const struct wl_seat_listener seat_listener = {
seat_capabilities,
seat_name
};
static void
display_handle_global(void *data, struct wl_registry *wl_registry, uint32_t id,
const char *interface, uint32_t version)
{
if (!strcmp(interface, "wl_seat")) {
seat_t *seat = (seat_t *) malloc(sizeof(seat_t));
memset(seat, 0, sizeof(seat_t));
seat->wl_seat = (wl_seat *) wl_registry_bind(wl_registry, id, &wl_seat_interface, MIN(version, 5));
wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
wl_list_insert(&seats, &seat->link);
}
}
static void
display_global_remove(void *data, struct wl_registry *wl_registry, uint32_t id)
{
xkbcommon_close();
seat_t *seat, *tmp;
wl_list_for_each_safe(seat, tmp, &seats, link) {
if (seat->wl_kbd) {
if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
wl_keyboard_release(seat->wl_kbd);
else
wl_keyboard_destroy(seat->wl_kbd);
xkb_keymap_unref(seat->keymap);
}
if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
wl_seat_release(seat->wl_seat);
else
wl_seat_destroy(seat->wl_seat);
wl_list_remove(&seat->link);
free(seat);
}
}
static const struct wl_registry_listener registry_listener = {
display_handle_global,
display_global_remove
};
void
xkbcommon_wl_init()
{
if (wl_init_ok)
return;
wl_list_init(&seats);
ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!ctx) {
qWarning() << "XKB Keyboard: XKB context creation failed";
return;
}
wl_display *display = (wl_display *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_display");
if (display) {
auto registry = wl_display_get_registry(display);
if (registry) {
wl_registry_add_listener(registry, &registry_listener, nullptr);
wl_display_roundtrip(display);
wl_display_roundtrip(display);
} else {
goto err_ctx;
}
} else {
goto err_ctx;
}
wl_init_ok = true;
return;
err_ctx:
xkb_context_unref(ctx);
}

View File

@@ -0,0 +1,17 @@
/*
* 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 xkbcommon Wayland keyboard input module.
*
*
*
* Authors: RichardG, <richardg867@gmail.com>
*
* Copyright 2023 RichardG.
*/
void xkbcommon_wl_init();

View File

@@ -33,7 +33,9 @@ extern "C" {
};
#include "xkbcommon_keyboard.hpp"
#include <qpa/qplatformnativeinterface.h>
#include <QtDebug>
#include <QGuiApplication>
void
xkbcommon_x11_init()
@@ -43,9 +45,9 @@ xkbcommon_x11_init()
int32_t core_kbd_device_id;
struct xkb_keymap *keymap;
conn = xcb_connect(NULL, NULL);
if (!conn || xcb_connection_has_error(conn)) {
qWarning() << "XKB Keyboard: X server connection failed with error" << (conn ? xcb_connection_has_error(conn) : -1);
conn = (xcb_connection_t *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("connection");
if (!conn) {
qWarning() << "XKB Keyboard: X server connection failed";
return;
}
@@ -55,13 +57,13 @@ xkbcommon_x11_init()
NULL, NULL, NULL, NULL);
if (!ret) {
qWarning() << "XKB Keyboard: XKB extension setup failed";
goto err_conn;
return;
}
ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!ctx) {
qWarning() << "XKB Keyboard: XKB context creation failed";
goto err_conn;
return;
}
core_kbd_device_id = xkb_x11_get_core_keyboard_device_id(conn);
@@ -77,9 +79,8 @@ xkbcommon_x11_init()
}
xkbcommon_init(keymap);
return;
err_ctx:
xkb_context_unref(ctx);
err_conn:
xcb_disconnect(conn);
}