2023-04-07 22:33:53 -03:00
|
|
|
/*
|
|
|
|
|
* 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 keyboard input module.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* Authors: RichardG, <richardg867@gmail.com>
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2023 RichardG.
|
|
|
|
|
*/
|
|
|
|
|
extern "C" {
|
2023-04-11 20:19:06 -03:00
|
|
|
#include <xkbcommon/xkbcommon.h>
|
2023-04-07 22:33:53 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
#include <QtDebug>
|
2023-04-08 17:58:55 -03:00
|
|
|
#include "evdev_keyboard.hpp"
|
2023-04-07 22:33:53 -03:00
|
|
|
|
2023-04-08 17:58:55 -03:00
|
|
|
#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')))
|
2023-04-07 22:33:53 -03:00
|
|
|
|
2023-04-08 18:45:10 -03:00
|
|
|
static std::unordered_map<std::string, uint16_t> xkb_keycodes = {
|
2023-04-07 22:33:53 -03:00
|
|
|
{"ESC", 0x01},
|
|
|
|
|
{"AE01", 0x02},
|
|
|
|
|
{"AE02", 0x03},
|
|
|
|
|
{"AE03", 0x04},
|
|
|
|
|
{"AE04", 0x05},
|
|
|
|
|
{"AE05", 0x06},
|
|
|
|
|
{"AE06", 0x07},
|
|
|
|
|
{"AE07", 0x08},
|
|
|
|
|
{"AE08", 0x09},
|
|
|
|
|
{"AE09", 0x0a},
|
|
|
|
|
{"AE10", 0x0b},
|
|
|
|
|
{"AE11", 0x0c},
|
|
|
|
|
{"AE12", 0x0d},
|
|
|
|
|
{"BKSP", 0x0e},
|
|
|
|
|
|
|
|
|
|
{"TAB", 0x0f},
|
|
|
|
|
{"AD01", 0x10},
|
|
|
|
|
{"AD02", 0x11},
|
|
|
|
|
{"AD03", 0x12},
|
|
|
|
|
{"AD04", 0x13},
|
|
|
|
|
{"AD05", 0x14},
|
|
|
|
|
{"AD06", 0x15},
|
|
|
|
|
{"AD07", 0x16},
|
|
|
|
|
{"AD08", 0x17},
|
|
|
|
|
{"AD09", 0x18},
|
|
|
|
|
{"AD10", 0x19},
|
|
|
|
|
{"AD11", 0x1a},
|
|
|
|
|
{"AD12", 0x1b},
|
|
|
|
|
{"RTRN", 0x1c},
|
2023-04-08 15:39:42 -03:00
|
|
|
{"LNFD", 0x1c}, /* linefeed => Enter */
|
2023-04-07 22:33:53 -03:00
|
|
|
|
|
|
|
|
{"LCTL", 0x1d},
|
|
|
|
|
{"AC01", 0x1e},
|
|
|
|
|
{"AC02", 0x1f},
|
|
|
|
|
{"AC03", 0x20},
|
|
|
|
|
{"AC04", 0x21},
|
|
|
|
|
{"AC05", 0x22},
|
|
|
|
|
{"AC06", 0x23},
|
|
|
|
|
{"AC07", 0x24},
|
|
|
|
|
{"AC08", 0x25},
|
|
|
|
|
{"AC09", 0x26},
|
|
|
|
|
{"AC10", 0x27},
|
|
|
|
|
{"AC11", 0x28},
|
|
|
|
|
|
|
|
|
|
{"TLDE", 0x29},
|
|
|
|
|
{"LFSH", 0x2a},
|
|
|
|
|
{"BKSL", 0x2b},
|
|
|
|
|
{"AB01", 0x2c},
|
|
|
|
|
{"AB02", 0x2d},
|
|
|
|
|
{"AB03", 0x2e},
|
|
|
|
|
{"AB04", 0x2f},
|
|
|
|
|
{"AB05", 0x30},
|
|
|
|
|
{"AB06", 0x31},
|
|
|
|
|
{"AB07", 0x32},
|
|
|
|
|
{"AB08", 0x33},
|
|
|
|
|
{"AB09", 0x34},
|
|
|
|
|
{"AB10", 0x35},
|
|
|
|
|
{"RTSH", 0x36},
|
|
|
|
|
|
|
|
|
|
{"KPMU", 0x37},
|
|
|
|
|
{"LALT", 0x38},
|
|
|
|
|
{"SPCE", 0x39},
|
|
|
|
|
{"CAPS", 0x3a},
|
|
|
|
|
{"FK01", 0x3b},
|
|
|
|
|
{"FK02", 0x3c},
|
|
|
|
|
{"FK03", 0x3d},
|
|
|
|
|
{"FK04", 0x3e},
|
|
|
|
|
{"FK05", 0x3f},
|
|
|
|
|
{"FK06", 0x40},
|
|
|
|
|
{"FK07", 0x41},
|
|
|
|
|
{"FK08", 0x42},
|
|
|
|
|
{"FK09", 0x43},
|
|
|
|
|
{"FK10", 0x44},
|
|
|
|
|
|
|
|
|
|
{"NMLK", 0x45},
|
|
|
|
|
{"SCLK", 0x46},
|
2023-04-08 19:39:11 -03:00
|
|
|
{"FK14", 0x46}, /* F14 => Scroll Lock (for Apple keyboards) */
|
2023-04-07 22:33:53 -03:00
|
|
|
{"KP7", 0x47},
|
|
|
|
|
{"KP8", 0x48},
|
|
|
|
|
{"KP9", 0x49},
|
|
|
|
|
{"KPSU", 0x4a},
|
|
|
|
|
{"KP4", 0x4b},
|
|
|
|
|
{"KP5", 0x4c},
|
|
|
|
|
{"KP6", 0x4d},
|
|
|
|
|
{"KPAD", 0x4e},
|
|
|
|
|
{"KP1", 0x4f},
|
|
|
|
|
{"KP2", 0x50},
|
|
|
|
|
{"KP3", 0x51},
|
|
|
|
|
{"KP0", 0x52},
|
|
|
|
|
{"KPDL", 0x53},
|
|
|
|
|
|
|
|
|
|
{"LSGT", 0x56},
|
|
|
|
|
{"FK11", 0x57},
|
|
|
|
|
{"FK12", 0x58},
|
2023-04-08 19:39:11 -03:00
|
|
|
{"FK16", 0x5d}, /* F16 => F13 */
|
|
|
|
|
{"FK17", 0x5e}, /* F17 => F14 */
|
|
|
|
|
{"FK18", 0x5f}, /* F18 => F15 */
|
2023-04-07 22:33:53 -03:00
|
|
|
|
|
|
|
|
/* Japanese keys. */
|
2023-04-08 19:36:48 -03:00
|
|
|
{"JPCM", 0x5c}, /* Num, */
|
|
|
|
|
{"KPDC", 0x5c},
|
2023-04-08 17:58:55 -03:00
|
|
|
{"HKTG", 0x70}, /* hiragana-katakana toggle */
|
2023-04-07 22:33:53 -03:00
|
|
|
{"AB11", 0x73}, /* \_ and Brazilian /? */
|
2023-04-08 17:58:55 -03:00
|
|
|
{"HZTG", 0x76}, /* hankaku-zenkaku toggle */
|
|
|
|
|
{"HIRA", 0x77},
|
|
|
|
|
{"KATA", 0x78},
|
2023-04-07 22:33:53 -03:00
|
|
|
{"HENK", 0x79},
|
2023-04-09 18:24:26 -03:00
|
|
|
{"KANA", 0x79}, /* kana => henkan (for Apple keyboards) */
|
2023-04-07 22:33:53 -03:00
|
|
|
{"MUHE", 0x7b},
|
2023-04-09 18:24:26 -03:00
|
|
|
{"EISU", 0x7b}, /* eisu => muhenkan (for Apple keyboards) */
|
2023-04-07 22:33:53 -03:00
|
|
|
{"AE13", 0x7d}, /* \| */
|
|
|
|
|
{"KPPT", 0x7e}, /* Brazilian Num. */
|
|
|
|
|
{"I06", 0x7e}, /* alias of KPPT on keycodes/xfree86 (i.e. X11 forwarding) */
|
|
|
|
|
|
|
|
|
|
/* Korean keys. */
|
|
|
|
|
{"HJCV", 0xf1}, /* hancha toggle */
|
|
|
|
|
{"HNGL", 0xf2}, /* latin toggle */
|
|
|
|
|
|
|
|
|
|
{"KPEN", 0x11c},
|
|
|
|
|
{"RCTL", 0x11d},
|
|
|
|
|
{"KPDV", 0x135},
|
|
|
|
|
{"PRSC", 0x137},
|
|
|
|
|
{"SYRQ", 0x137},
|
2023-04-08 19:39:11 -03:00
|
|
|
{"FK13", 0x137}, /* F13 => SysRq (for Apple keyboards) */
|
2023-04-07 22:33:53 -03:00
|
|
|
{"RALT", 0x138},
|
2023-04-08 21:48:01 -03:00
|
|
|
{"ALGR", 0x138},
|
2023-04-09 20:18:51 -03:00
|
|
|
{"LVL3", 0x138}, /* observed on TigerVNC with AltGr-enabled layout */
|
2023-04-08 01:03:21 -03:00
|
|
|
{"PAUS", 0x145},
|
2023-04-08 19:39:11 -03:00
|
|
|
{"FK15", 0x145}, /* F15 => Pause (for Apple keyboards) */
|
2023-04-08 15:39:42 -03:00
|
|
|
{"BRK", 0x145},
|
2023-04-07 22:33:53 -03:00
|
|
|
{"HOME", 0x147},
|
|
|
|
|
{"UP", 0x148},
|
|
|
|
|
{"PGUP", 0x149},
|
|
|
|
|
{"LEFT", 0x14b},
|
|
|
|
|
{"RGHT", 0x14d},
|
|
|
|
|
{"END", 0x14f},
|
|
|
|
|
{"DOWN", 0x150},
|
|
|
|
|
{"PGDN", 0x151},
|
|
|
|
|
{"INS", 0x152},
|
|
|
|
|
{"DELE", 0x153},
|
|
|
|
|
|
|
|
|
|
{"LWIN", 0x15b},
|
2023-04-08 15:39:42 -03:00
|
|
|
{"LMTA", 0x15b},
|
2023-04-07 22:33:53 -03:00
|
|
|
{"RWIN", 0x15c},
|
2023-04-08 15:39:42 -03:00
|
|
|
{"RMTA", 0x15c},
|
|
|
|
|
{"MENU", 0x15d},
|
|
|
|
|
{"COMP", 0x15d}, /* Compose as Menu */
|
2023-04-07 22:33:53 -03:00
|
|
|
|
2023-04-08 17:58:55 -03:00
|
|
|
/* Multimedia keys. Same notes as evdev_keyboard apply here. */
|
2023-04-07 22:33:53 -03:00
|
|
|
{"KPEQ", 0x59}, /* Num= */
|
|
|
|
|
{"FRNT", 0x101}, /* # Logitech Task Select */
|
2023-04-08 02:19:26 -03:00
|
|
|
{"UNDO", 0x108}, /* # */
|
2023-04-07 22:33:53 -03:00
|
|
|
{"PAST", 0x10a}, /* # Paste */
|
|
|
|
|
{"FIND", 0x112}, /* # Logitech */
|
2023-04-08 02:19:26 -03:00
|
|
|
{"CUT", 0x117}, /* # */
|
|
|
|
|
{"COPY", 0x118}, /* # */
|
2023-04-07 22:33:53 -03:00
|
|
|
{"MUTE", 0x120},
|
|
|
|
|
{"VOL-", 0x12e},
|
|
|
|
|
{"VOL+", 0x130},
|
2023-04-08 17:58:55 -03:00
|
|
|
{"HELP", 0x13b},
|
|
|
|
|
{"OPEN", 0x13f},
|
2023-04-07 22:33:53 -03:00
|
|
|
{"POWR", 0x15e},
|
|
|
|
|
{"STOP", 0x168},
|
|
|
|
|
};
|
|
|
|
|
struct xkb_keymap *xkbcommon_keymap = nullptr;
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
xkbcommon_init(struct xkb_keymap *keymap)
|
|
|
|
|
{
|
2023-04-08 00:31:25 -03:00
|
|
|
if (keymap)
|
|
|
|
|
xkbcommon_keymap = keymap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
xkbcommon_close()
|
|
|
|
|
{
|
2023-04-09 18:24:26 -03:00
|
|
|
xkbcommon_keymap = nullptr;
|
2023-04-07 22:33:53 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t
|
|
|
|
|
xkbcommon_translate(uint32_t keycode)
|
|
|
|
|
{
|
|
|
|
|
const char *key_name = xkb_keymap_key_get_name(xkbcommon_keymap, keycode);
|
|
|
|
|
|
2023-04-08 15:39:42 -03:00
|
|
|
/* 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];
|
2023-04-07 22:33:53 -03:00
|
|
|
|
2023-04-08 15:39:42 -03:00
|
|
|
/* Observed with multimedia keys on Windows VcXsrv. */
|
2023-04-07 22:33:53 -03:00
|
|
|
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);
|
|
|
|
|
|
2023-04-08 17:58:55 -03:00
|
|
|
/* 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);
|
|
|
|
|
|
2023-04-07 22:33:53 -03:00
|
|
|
if (!ret)
|
2023-04-15 13:38:38 -03:00
|
|
|
qWarning() << "XKB Keyboard: Unknown key" << QString::number(keycode, 16) << QString::fromStdString(key_name_s);
|
|
|
|
|
#if 1
|
2023-04-07 22:33:53 -03:00
|
|
|
else
|
2023-04-15 13:38:38 -03:00
|
|
|
qInfo() << "XKB Keyboard: Key" << QString::number(keycode, 16) << QString::fromStdString(key_name_s) << "scancode" << QString::number(ret, 16);
|
2023-04-07 22:33:53 -03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|