Auto-Type: Support multiple Xkb layouts

Completely rewritten XCB Auto-Type keymap system.

 - supports multiple simultaneous layouts
 - prefers current layout if it has all keysyms available
 - removed hardcoded KeySymMap
 - removed clunky custom KeySym emulation

Biggest breaking change is removing KeySym emulation for keys that
do not exist in any of the layouts currently in use. It would be
possible to make it work but if you are trying to type syms that
are not available in any of your layouts you are abusing it. It
also adds unnecessary complexity and opens up timing issues when
the keymap is modified on-the-fly. Now we are just reading it.

This also workarounds a Qt related issue where QX11Info::display()
returns a connection to X server that fails to receive updated
keymap data when client settings change. We use our own connection
now to get it working.
This commit is contained in:
Toni Spets 2021-03-08 20:37:00 +02:00 committed by Jonathan White
parent 2423bede60
commit 4d07507739
15 changed files with 120 additions and 348 deletions

View File

@ -496,6 +496,7 @@ AutoType::parseSequence(const QString& entrySequence, const Entry* entry, QStrin
const int maxRepetition = 100; const int maxRepetition = 100;
QList<QSharedPointer<AutoTypeAction>> actions; QList<QSharedPointer<AutoTypeAction>> actions;
actions << QSharedPointer<AutoTypeBegin>::create();
actions << QSharedPointer<AutoTypeDelay>::create(qMax(0, config()->get(Config::AutoTypeDelay).toInt()), true); actions << QSharedPointer<AutoTypeDelay>::create(qMax(0, config()->get(Config::AutoTypeDelay).toInt()), true);
// Replace escaped braces with a template for easier regex // Replace escaped braces with a template for easier regex

View File

@ -58,3 +58,8 @@ void AutoTypeClearField::exec(AutoTypeExecutor* executor) const
{ {
executor->execClearField(this); executor->execClearField(this);
} }
void AutoTypeBegin::exec(AutoTypeExecutor* executor) const
{
executor->execBegin(this);
}

View File

@ -61,10 +61,17 @@ public:
void exec(AutoTypeExecutor* executor) const override; void exec(AutoTypeExecutor* executor) const override;
}; };
class KEEPASSXC_EXPORT AutoTypeBegin : public AutoTypeAction
{
public:
void exec(AutoTypeExecutor* executor) const override;
};
class KEEPASSXC_EXPORT AutoTypeExecutor class KEEPASSXC_EXPORT AutoTypeExecutor
{ {
public: public:
virtual ~AutoTypeExecutor() = default; virtual ~AutoTypeExecutor() = default;
virtual void execBegin(const AutoTypeBegin* action) = 0;
virtual void execType(const AutoTypeKey* action) = 0; virtual void execType(const AutoTypeKey* action) = 0;
virtual void execClearField(const AutoTypeClearField* action) = 0; virtual void execClearField(const AutoTypeClearField* action) = 0;

View File

@ -215,6 +215,11 @@ AutoTypeExecutorMac::AutoTypeExecutorMac(AutoTypePlatformMac* platform)
{ {
} }
void AutoTypeExecutorMac::execBegin(const AutoTypeBegin* action)
{
Q_UNUSED(action);
}
void AutoTypeExecutorMac::execType(const AutoTypeKey* action) void AutoTypeExecutorMac::execType(const AutoTypeKey* action)
{ {
if (action->modifiers & Qt::ShiftModifier) { if (action->modifiers & Qt::ShiftModifier) {

View File

@ -57,6 +57,7 @@ class AutoTypeExecutorMac : public AutoTypeExecutor
public: public:
explicit AutoTypeExecutorMac(AutoTypePlatformMac* platform); explicit AutoTypeExecutorMac(AutoTypePlatformMac* platform);
void execBegin(const AutoTypeBegin* action) override;
void execType(const AutoTypeKey* action) override; void execType(const AutoTypeKey* action) override;
void execClearField(const AutoTypeClearField* action) override; void execClearField(const AutoTypeClearField* action) override;

View File

@ -102,6 +102,11 @@ AutoTypeExecutorTest::AutoTypeExecutorTest(AutoTypePlatformTest* platform)
{ {
} }
void AutoTypeExecutorTest::execBegin(const AutoTypeBegin* action)
{
Q_UNUSED(action);
}
void AutoTypeExecutorTest::execType(const AutoTypeKey* action) void AutoTypeExecutorTest::execType(const AutoTypeKey* action)
{ {
m_platform->addAction(action); m_platform->addAction(action);

View File

@ -64,6 +64,7 @@ class AutoTypeExecutorTest : public AutoTypeExecutor
public: public:
explicit AutoTypeExecutorTest(AutoTypePlatformTest* platform); explicit AutoTypeExecutorTest(AutoTypePlatformTest* platform);
void execBegin(const AutoTypeBegin* action) override;
void execType(const AutoTypeKey* action) override; void execType(const AutoTypeKey* action) override;
void execClearField(const AutoTypeClearField* action) override; void execClearField(const AutoTypeClearField* action) override;

View File

@ -226,6 +226,11 @@ AutoTypeExecutorWin::AutoTypeExecutorWin(AutoTypePlatformWin* platform)
{ {
} }
void AutoTypeExecutorWin::execBegin(const AutoTypeBegin* action)
{
Q_UNUSED(action);
}
void AutoTypeExecutorWin::execType(const AutoTypeKey* action) void AutoTypeExecutorWin::execType(const AutoTypeKey* action)
{ {
if (action->modifiers & Qt::ShiftModifier) { if (action->modifiers & Qt::ShiftModifier) {

View File

@ -54,6 +54,7 @@ class AutoTypeExecutorWin : public AutoTypeExecutor
public: public:
explicit AutoTypeExecutorWin(AutoTypePlatformWin* platform); explicit AutoTypeExecutorWin(AutoTypePlatformWin* platform);
void execBegin(const AutoTypeBegin* action) override;
void execType(const AutoTypeKey* action) override; void execType(const AutoTypeKey* action) override;
void execClearField(const AutoTypeClearField* action) override; void execClearField(const AutoTypeClearField* action) override;

View File

@ -21,7 +21,8 @@
AutoTypePlatformX11::AutoTypePlatformX11() AutoTypePlatformX11::AutoTypePlatformX11()
{ {
m_dpy = QX11Info::display(); // Qt handles XCB slightly differently so we open our own connection
m_dpy = XOpenDisplay(XDisplayString(QX11Info::display()));
m_rootWindow = QX11Info::appRootWindow(); m_rootWindow = QX11Info::appRootWindow();
m_atomWmState = XInternAtom(m_dpy, "WM_STATE", True); m_atomWmState = XInternAtom(m_dpy, "WM_STATE", True);
@ -42,15 +43,9 @@ AutoTypePlatformX11::AutoTypePlatformX11()
m_classBlacklist << "xfdesktop" m_classBlacklist << "xfdesktop"
<< "xfce4-panel"; // Xfce 4 << "xfce4-panel"; // Xfce 4
m_keysymTable = nullptr;
m_xkb = nullptr; m_xkb = nullptr;
m_remapKeycode = 0;
m_currentRemapKeysym = NoSymbol;
m_loaded = true; m_loaded = true;
connect(nixUtils(), &NixUtils::keymapChanged, this, [this] { updateKeymap(); });
updateKeymap();
} }
bool AutoTypePlatformX11::isAvailable() bool AutoTypePlatformX11::isAvailable()
@ -65,34 +60,21 @@ bool AutoTypePlatformX11::isAvailable()
return false; return false;
} }
if (!m_xkb) {
XkbDescPtr kbd = getKeyboard();
if (!kbd) {
return false;
}
XkbFreeKeyboard(kbd, XkbAllComponentsMask, True);
}
return true; return true;
} }
void AutoTypePlatformX11::unload() void AutoTypePlatformX11::unload()
{ {
// Restore the KeyboardMapping to its original state. m_keymap.clear();
if (m_currentRemapKeysym != NoSymbol) {
AddKeysym(NoSymbol);
}
if (m_keysymTable) {
XFree(m_keysymTable);
}
if (m_xkb) { if (m_xkb) {
XkbFreeKeyboard(m_xkb, XkbAllComponentsMask, True); XkbFreeKeyboard(m_xkb, XkbAllComponentsMask, True);
m_xkb = nullptr;
} }
XCloseDisplay(m_dpy);
m_dpy = nullptr;
m_loaded = false; m_loaded = false;
} }
@ -304,22 +286,30 @@ void AutoTypePlatformX11::updateKeymap()
if (m_xkb) { if (m_xkb) {
XkbFreeKeyboard(m_xkb, XkbAllComponentsMask, True); XkbFreeKeyboard(m_xkb, XkbAllComponentsMask, True);
} }
m_xkb = getKeyboard(); m_xkb = XkbGetMap(m_dpy, XkbAllClientInfoMask, XkbUseCoreKbd);
XDisplayKeycodes(m_dpy, &m_minKeycode, &m_maxKeycode); /* Build updated keymap */
if (m_keysymTable != nullptr) { m_keymap.clear();
XFree(m_keysymTable);
}
m_keysymTable = XGetKeyboardMapping(m_dpy, m_minKeycode, m_maxKeycode - m_minKeycode + 1, &m_keysymPerKeycode);
/* determine the keycode to use for remapped keys */ for (int ckeycode = m_xkb->min_key_code; ckeycode < m_xkb->max_key_code; ckeycode++) {
if (m_remapKeycode == 0 || !isRemapKeycodeValid()) { int groups = XkbKeyNumGroups(m_xkb, ckeycode);
for (int keycode = m_minKeycode; keycode <= m_maxKeycode; keycode++) {
int inx = (keycode - m_minKeycode) * m_keysymPerKeycode; for (int cgroup = 0; cgroup < groups; cgroup++) {
if (m_keysymTable[inx] == NoSymbol) { XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, ckeycode, cgroup);
m_remapKeycode = keycode;
m_currentRemapKeysym = NoSymbol; for (int clevel = 0; clevel < type->num_levels; clevel++) {
break; KeySym sym = XkbKeycodeToKeysym(m_dpy, ckeycode, cgroup, clevel);
int mask = 0;
for (int nmap = 0; nmap < type->map_count; nmap++) {
XkbKTMapEntryRec map = type->map[nmap];
if (map.active && map.level == clevel) {
mask = map.mods.mask;
break;
}
}
m_keymap.append(AutoTypePlatformX11::KeyDesc{sym, ckeycode, cgroup, mask});
} }
} }
} }
@ -337,70 +327,12 @@ void AutoTypePlatformX11::updateKeymap()
} }
} }
XFreeModifiermap(modifiers); XFreeModifiermap(modifiers);
/* Xlib needs some time until the mapping is distributed to
all clients */
Tools::sleep(30);
}
bool AutoTypePlatformX11::isRemapKeycodeValid()
{
int baseKeycode = (m_remapKeycode - m_minKeycode) * m_keysymPerKeycode;
for (int i = 0; i < m_keysymPerKeycode; i++) {
if (m_keysymTable[baseKeycode + i] == m_currentRemapKeysym) {
return true;
}
}
return false;
}
XkbDescPtr AutoTypePlatformX11::getKeyboard()
{
int num_devices;
XID keyboard_id = XkbUseCoreKbd;
XDeviceInfo* devices = XListInputDevices(m_dpy, &num_devices);
if (!devices) {
return nullptr;
}
for (int i = 0; i < num_devices; i++) {
if (QString(devices[i].name) == "Virtual core XTEST keyboard") {
keyboard_id = devices[i].id;
break;
}
}
XFreeDeviceList(devices);
return XkbGetKeyboard(m_dpy, XkbCompatMapMask | XkbGeometryMask, keyboard_id);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// The following code is taken from xvkbd 3.0 and has been slightly modified. // The following code is taken from xvkbd 3.0 and has been slightly modified.
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/*
* Insert a specified keysym on the dedicated position in the keymap
* table.
*/
int AutoTypePlatformX11::AddKeysym(KeySym keysym)
{
if (m_remapKeycode == 0) {
return 0;
}
int inx = (m_remapKeycode - m_minKeycode) * m_keysymPerKeycode;
m_keysymTable[inx] = keysym;
m_currentRemapKeysym = keysym;
XChangeKeyboardMapping(m_dpy, m_remapKeycode, m_keysymPerKeycode, &m_keysymTable[inx], 1);
XFlush(m_dpy);
updateKeymap();
return m_remapKeycode;
}
/* /*
* Send event to the focused window. * Send event to the focused window.
* If input focus is specified explicitly, select the window * If input focus is specified explicitly, select the window
@ -435,42 +367,26 @@ void AutoTypePlatformX11::SendModifiers(unsigned int mask, bool press)
* Determines the keycode and modifier mask for the given * Determines the keycode and modifier mask for the given
* keysym. * keysym.
*/ */
int AutoTypePlatformX11::GetKeycode(KeySym keysym, unsigned int* mask) bool AutoTypePlatformX11::GetKeycode(KeySym keysym, int* keycode, int* group, unsigned int* mask)
{ {
int keycode = XKeysymToKeycode(m_dpy, keysym); const KeyDesc* desc = nullptr;
if (keycode && keysymModifiers(keysym, keycode, mask)) { for (const auto& key : m_keymap) {
return keycode; if (key.sym == keysym) {
} // pick this description if we don't have any for this sym or this matches the current group
if (desc == nullptr || key.group == *group) {
/* no modifier matches => resort to remapping */ desc = &key;
keycode = AddKeysym(keysym);
if (keycode && keysymModifiers(keysym, keycode, mask)) {
return keycode;
}
*mask = 0;
return 0;
}
bool AutoTypePlatformX11::keysymModifiers(KeySym keysym, int keycode, unsigned int* mask)
{
int shift, mod;
unsigned int mods_rtrn;
/* determine whether there is a combination of the modifiers
(Mod1-Mod5) with or without shift which returns keysym */
for (shift = 0; shift < 2; shift++) {
for (mod = ControlMapIndex; mod <= Mod5MapIndex; mod++) {
KeySym keysym_rtrn;
*mask = (mod == ControlMapIndex) ? shift : shift | (1 << mod);
XkbTranslateKeyCode(m_xkb, keycode, *mask, &mods_rtrn, &keysym_rtrn);
if (keysym_rtrn == keysym) {
return true;
} }
} }
} }
if (desc) {
*keycode = desc->code;
*group = desc->group;
*mask = desc->mask;
return true;
}
return false; return false;
} }
@ -487,14 +403,24 @@ void AutoTypePlatformX11::sendKey(KeySym keysym, unsigned int modifiers)
} }
int keycode; int keycode;
int group;
int group_active;
unsigned int wanted_mask; unsigned int wanted_mask;
/* determine keycode and mask for the given keysym */ /* pull current active layout group */
keycode = GetKeycode(keysym, &wanted_mask); XkbStateRec state;
if (keycode < 8 || keycode > 255) { XkbGetState(m_dpy, XkbUseCoreKbd, &state);
group_active = state.group;
/* tell GeyKeycode we would prefer a key from active group */
group = group_active;
/* determine keycode, group and mask for the given keysym */
if (!GetKeycode(keysym, &keycode, &group, &wanted_mask)) {
qWarning("Unable to get valid keycode for key: keysym=0x%lX", keysym); qWarning("Unable to get valid keycode for key: keysym=0x%lX", keysym);
return; return;
} }
wanted_mask |= modifiers; wanted_mask |= modifiers;
Window root, child; Window root, child;
@ -541,6 +467,12 @@ void AutoTypePlatformX11::sendKey(KeySym keysym, unsigned int modifiers)
release_mask = release_check_mask; release_mask = release_check_mask;
} }
/* change layout group if necessary */
if (group_active != group) {
XkbLockGroup(m_dpy, XkbUseCoreKbd, group);
XFlush(m_dpy);
}
/* set modifiers mask */ /* set modifiers mask */
if ((release_mask | press_mask) & LockMask) { if ((release_mask | press_mask) & LockMask) {
SendModifiers(LockMask, true); SendModifiers(LockMask, true);
@ -560,6 +492,12 @@ void AutoTypePlatformX11::sendKey(KeySym keysym, unsigned int modifiers)
SendModifiers(LockMask, true); SendModifiers(LockMask, true);
SendModifiers(LockMask, false); SendModifiers(LockMask, false);
} }
/* reset layout group if necessary */
if (group_active != group) {
XkbLockGroup(m_dpy, XkbUseCoreKbd, group_active);
XFlush(m_dpy);
}
} }
int AutoTypePlatformX11::MyErrorHandler(Display* my_dpy, XErrorEvent* event) int AutoTypePlatformX11::MyErrorHandler(Display* my_dpy, XErrorEvent* event)
@ -579,6 +517,12 @@ AutoTypeExecutorX11::AutoTypeExecutorX11(AutoTypePlatformX11* platform)
{ {
} }
void AutoTypeExecutorX11::execBegin(const AutoTypeBegin* action)
{
Q_UNUSED(action);
m_platform->updateKeymap();
}
void AutoTypeExecutorX11::execType(const AutoTypeKey* action) void AutoTypeExecutorX11::execType(const AutoTypeKey* action)
{ {
if (action->key != Qt::Key_unknown) { if (action->key != Qt::Key_unknown) {

View File

@ -54,6 +54,7 @@ public:
QString activeWindowTitle() override; QString activeWindowTitle() override;
bool raiseWindow(WId window) override; bool raiseWindow(WId window) override;
AutoTypeExecutor* createExecutor() override; AutoTypeExecutor* createExecutor() override;
void updateKeymap();
void sendKey(KeySym keysym, unsigned int modifiers = 0); void sendKey(KeySym keysym, unsigned int modifiers = 0);
@ -65,13 +66,10 @@ private:
bool isTopLevelWindow(Window window); bool isTopLevelWindow(Window window);
XkbDescPtr getKeyboard(); XkbDescPtr getKeyboard();
void updateKeymap();
bool isRemapKeycodeValid();
int AddKeysym(KeySym keysym); int AddKeysym(KeySym keysym);
void SendKeyEvent(unsigned keycode, bool press); void SendKeyEvent(unsigned keycode, bool press);
void SendModifiers(unsigned int mask, bool press); void SendModifiers(unsigned int mask, bool press);
int GetKeycode(KeySym keysym, unsigned int* mask); bool GetKeycode(KeySym keysym, int* keycode, int* group, unsigned int* mask);
bool keysymModifiers(KeySym keysym, int keycode, unsigned int* mask);
static int MyErrorHandler(Display* my_dpy, XErrorEvent* event); static int MyErrorHandler(Display* my_dpy, XErrorEvent* event);
@ -87,14 +85,16 @@ private:
Atom m_atomWindow; Atom m_atomWindow;
QSet<QString> m_classBlacklist; QSet<QString> m_classBlacklist;
typedef struct
{
KeySym sym;
int code;
int group;
int mask;
} KeyDesc;
XkbDescPtr m_xkb; XkbDescPtr m_xkb;
KeySym* m_keysymTable; QList<KeyDesc> m_keymap;
int m_minKeycode;
int m_maxKeycode;
int m_keysymPerKeycode;
/* dedicated keycode for remapped keys */
unsigned int m_remapKeycode;
KeySym m_currentRemapKeysym;
KeyCode m_modifier_keycode[N_MOD_INDICES]; KeyCode m_modifier_keycode[N_MOD_INDICES];
bool m_loaded; bool m_loaded;
}; };
@ -104,6 +104,7 @@ class AutoTypeExecutorX11 : public AutoTypeExecutor
public: public:
explicit AutoTypeExecutorX11(AutoTypePlatformX11* platform); explicit AutoTypeExecutorX11(AutoTypePlatformX11* platform);
void execBegin(const AutoTypeBegin* action) override;
void execType(const AutoTypeKey* action) override; void execType(const AutoTypeKey* action) override;
void execClearField(const AutoTypeClearField* action) override; void execClearField(const AutoTypeClearField* action) override;

View File

@ -1,171 +0,0 @@
/*
* Automatically generated by keysymmap.py from parsing keysymdef.h.
*/
const int unicodeToKeysymLen = 632;
// clang-format off
const uint unicodeToKeysymKeys[] = {
0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107,
0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e, 0x010f,
0x0110, 0x0111, 0x0112, 0x0113, 0x0116, 0x0117, 0x0118, 0x0119,
0x011a, 0x011b, 0x011c, 0x011d, 0x011e, 0x011f, 0x0120, 0x0121,
0x0122, 0x0123, 0x0124, 0x0125, 0x0126, 0x0127, 0x0128, 0x0129,
0x012a, 0x012b, 0x012e, 0x012f, 0x0130, 0x0131, 0x0134, 0x0135,
0x0136, 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d,
0x013e, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147,
0x0148, 0x014a, 0x014b, 0x014c, 0x014d, 0x0150, 0x0151, 0x0152,
0x0153, 0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015a,
0x015b, 0x015c, 0x015d, 0x015e, 0x015f, 0x0160, 0x0161, 0x0162,
0x0163, 0x0164, 0x0165, 0x0166, 0x0167, 0x0168, 0x0169, 0x016a,
0x016b, 0x016c, 0x016d, 0x016e, 0x016f, 0x0170, 0x0171, 0x0172,
0x0173, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d, 0x017e,
0x0192, 0x02c7, 0x02d8, 0x02d9, 0x02db, 0x02dd, 0x0385, 0x0386,
0x0388, 0x0389, 0x038a, 0x038c, 0x038e, 0x038f, 0x0390, 0x0391,
0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399,
0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0, 0x03a1,
0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa,
0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03b0, 0x03b1, 0x03b2,
0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba,
0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c2,
0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03ca,
0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x0401, 0x0402, 0x0403, 0x0404,
0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040b, 0x040c,
0x040e, 0x040f, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415,
0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d,
0x041e, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425,
0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d,
0x042e, 0x042f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435,
0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d,
0x043e, 0x043f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445,
0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d,
0x044e, 0x044f, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456,
0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045e, 0x045f,
0x0490, 0x0491, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5,
0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd,
0x05de, 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5,
0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x060c, 0x061b, 0x061f,
0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628,
0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, 0x0630,
0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, 0x0638,
0x0639, 0x063a, 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645,
0x0646, 0x0647, 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d,
0x064e, 0x064f, 0x0650, 0x0651, 0x0652, 0x0e01, 0x0e02, 0x0e03,
0x0e04, 0x0e05, 0x0e06, 0x0e07, 0x0e08, 0x0e09, 0x0e0a, 0x0e0b,
0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, 0x0e10, 0x0e11, 0x0e12, 0x0e13,
0x0e14, 0x0e15, 0x0e16, 0x0e17, 0x0e18, 0x0e19, 0x0e1a, 0x0e1b,
0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, 0x0e20, 0x0e21, 0x0e22, 0x0e23,
0x0e24, 0x0e25, 0x0e26, 0x0e27, 0x0e28, 0x0e29, 0x0e2a, 0x0e2b,
0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, 0x0e30, 0x0e31, 0x0e32, 0x0e33,
0x0e34, 0x0e35, 0x0e36, 0x0e37, 0x0e38, 0x0e39, 0x0e3a, 0x0e3f,
0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47,
0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0e50, 0x0e51,
0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, 0x0e58, 0x0e59,
0x2002, 0x2003, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, 0x200a,
0x2012, 0x2013, 0x2014, 0x2015, 0x2017, 0x2018, 0x2019, 0x201a,
0x201c, 0x201d, 0x201e, 0x2020, 0x2021, 0x2025, 0x2026, 0x2030,
0x2032, 0x2033, 0x2038, 0x203e, 0x20ac, 0x2105, 0x2116, 0x2117,
0x211e, 0x2122, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158,
0x2159, 0x215a, 0x215b, 0x215c, 0x215d, 0x215e, 0x2190, 0x2191,
0x2192, 0x2193, 0x21d2, 0x21d4, 0x2202, 0x2207, 0x2218, 0x221a,
0x221d, 0x221e, 0x2227, 0x2228, 0x2229, 0x222a, 0x222b, 0x2234,
0x223c, 0x2243, 0x2260, 0x2261, 0x2264, 0x2265, 0x2282, 0x2283,
0x22a2, 0x22a3, 0x22a4, 0x22a5, 0x2308, 0x230a, 0x2315, 0x2320,
0x2321, 0x2395, 0x239b, 0x239d, 0x239e, 0x23a0, 0x23a1, 0x23a3,
0x23a4, 0x23a6, 0x23a8, 0x23ac, 0x23b7, 0x23ba, 0x23bb, 0x23bc,
0x23bd, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x2424, 0x2500,
0x2502, 0x250c, 0x2510, 0x2514, 0x2518, 0x251c, 0x2524, 0x252c,
0x2534, 0x253c, 0x2592, 0x25c6, 0x25cb, 0x260e, 0x2640, 0x2642,
0x2663, 0x2665, 0x2666, 0x266d, 0x266f, 0x2713, 0x2717, 0x271d,
0x2720, 0x3001, 0x3002, 0x300c, 0x300d, 0x309b, 0x309c, 0x30a1,
0x30a2, 0x30a3, 0x30a4, 0x30a5, 0x30a6, 0x30a7, 0x30a8, 0x30a9,
0x30aa, 0x30ab, 0x30ad, 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7,
0x30b9, 0x30bb, 0x30bd, 0x30bf, 0x30c1, 0x30c3, 0x30c4, 0x30c6,
0x30c8, 0x30ca, 0x30cb, 0x30cc, 0x30cd, 0x30ce, 0x30cf, 0x30d2,
0x30d5, 0x30d8, 0x30db, 0x30de, 0x30df, 0x30e0, 0x30e1, 0x30e2,
0x30e3, 0x30e4, 0x30e5, 0x30e6, 0x30e7, 0x30e8, 0x30e9, 0x30ea,
0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f2, 0x30f3, 0x30fb, 0x30fc
};
const uint unicodeToKeysymValues[] = {
0x03c0, 0x03e0, 0x01c3, 0x01e3, 0x01a1, 0x01b1, 0x01c6, 0x01e6,
0x02c6, 0x02e6, 0x02c5, 0x02e5, 0x01c8, 0x01e8, 0x01cf, 0x01ef,
0x01d0, 0x01f0, 0x03aa, 0x03ba, 0x03cc, 0x03ec, 0x01ca, 0x01ea,
0x01cc, 0x01ec, 0x02d8, 0x02f8, 0x02ab, 0x02bb, 0x02d5, 0x02f5,
0x03ab, 0x03bb, 0x02a6, 0x02b6, 0x02a1, 0x02b1, 0x03a5, 0x03b5,
0x03cf, 0x03ef, 0x03c7, 0x03e7, 0x02a9, 0x02b9, 0x02ac, 0x02bc,
0x03d3, 0x03f3, 0x03a2, 0x01c5, 0x01e5, 0x03a6, 0x03b6, 0x01a5,
0x01b5, 0x01a3, 0x01b3, 0x01d1, 0x01f1, 0x03d1, 0x03f1, 0x01d2,
0x01f2, 0x03bd, 0x03bf, 0x03d2, 0x03f2, 0x01d5, 0x01f5, 0x13bc,
0x13bd, 0x01c0, 0x01e0, 0x03a3, 0x03b3, 0x01d8, 0x01f8, 0x01a6,
0x01b6, 0x02de, 0x02fe, 0x01aa, 0x01ba, 0x01a9, 0x01b9, 0x01de,
0x01fe, 0x01ab, 0x01bb, 0x03ac, 0x03bc, 0x03dd, 0x03fd, 0x03de,
0x03fe, 0x02dd, 0x02fd, 0x01d9, 0x01f9, 0x01db, 0x01fb, 0x03d9,
0x03f9, 0x13be, 0x01ac, 0x01bc, 0x01af, 0x01bf, 0x01ae, 0x01be,
0x08f6, 0x01b7, 0x01a2, 0x01ff, 0x01b2, 0x01bd, 0x07ae, 0x07a1,
0x07a2, 0x07a3, 0x07a4, 0x07a7, 0x07a8, 0x07ab, 0x07b6, 0x07c1,
0x07c2, 0x07c3, 0x07c4, 0x07c5, 0x07c6, 0x07c7, 0x07c8, 0x07c9,
0x07ca, 0x07cb, 0x07cc, 0x07cd, 0x07ce, 0x07cf, 0x07d0, 0x07d1,
0x07d2, 0x07d4, 0x07d5, 0x07d6, 0x07d7, 0x07d8, 0x07d9, 0x07a5,
0x07a9, 0x07b1, 0x07b2, 0x07b3, 0x07b4, 0x07ba, 0x07e1, 0x07e2,
0x07e3, 0x07e4, 0x07e5, 0x07e6, 0x07e7, 0x07e8, 0x07e9, 0x07ea,
0x07eb, 0x07ec, 0x07ed, 0x07ee, 0x07ef, 0x07f0, 0x07f1, 0x07f3,
0x07f2, 0x07f4, 0x07f5, 0x07f6, 0x07f7, 0x07f8, 0x07f9, 0x07b5,
0x07b9, 0x07b7, 0x07b8, 0x07bb, 0x06b3, 0x06b1, 0x06b2, 0x06b4,
0x06b5, 0x06b6, 0x06b7, 0x06b8, 0x06b9, 0x06ba, 0x06bb, 0x06bc,
0x06be, 0x06bf, 0x06e1, 0x06e2, 0x06f7, 0x06e7, 0x06e4, 0x06e5,
0x06f6, 0x06fa, 0x06e9, 0x06ea, 0x06eb, 0x06ec, 0x06ed, 0x06ee,
0x06ef, 0x06f0, 0x06f2, 0x06f3, 0x06f4, 0x06f5, 0x06e6, 0x06e8,
0x06e3, 0x06fe, 0x06fb, 0x06fd, 0x06ff, 0x06f9, 0x06f8, 0x06fc,
0x06e0, 0x06f1, 0x06c1, 0x06c2, 0x06d7, 0x06c7, 0x06c4, 0x06c5,
0x06d6, 0x06da, 0x06c9, 0x06ca, 0x06cb, 0x06cc, 0x06cd, 0x06ce,
0x06cf, 0x06d0, 0x06d2, 0x06d3, 0x06d4, 0x06d5, 0x06c6, 0x06c8,
0x06c3, 0x06de, 0x06db, 0x06dd, 0x06df, 0x06d9, 0x06d8, 0x06dc,
0x06c0, 0x06d1, 0x06a3, 0x06a1, 0x06a2, 0x06a4, 0x06a5, 0x06a6,
0x06a7, 0x06a8, 0x06a9, 0x06aa, 0x06ab, 0x06ac, 0x06ae, 0x06af,
0x06bd, 0x06ad, 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5,
0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced,
0x0cee, 0x0cef, 0x0cf0, 0x0cf1, 0x0cf2, 0x0cf3, 0x0cf4, 0x0cf5,
0x0cf6, 0x0cf7, 0x0cf8, 0x0cf9, 0x0cfa, 0x05ac, 0x05bb, 0x05bf,
0x05c1, 0x05c2, 0x05c3, 0x05c4, 0x05c5, 0x05c6, 0x05c7, 0x05c8,
0x05c9, 0x05ca, 0x05cb, 0x05cc, 0x05cd, 0x05ce, 0x05cf, 0x05d0,
0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8,
0x05d9, 0x05da, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5,
0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x05eb, 0x05ec, 0x05ed,
0x05ee, 0x05ef, 0x05f0, 0x05f1, 0x05f2, 0x0da1, 0x0da2, 0x0da3,
0x0da4, 0x0da5, 0x0da6, 0x0da7, 0x0da8, 0x0da9, 0x0daa, 0x0dab,
0x0dac, 0x0dad, 0x0dae, 0x0daf, 0x0db0, 0x0db1, 0x0db2, 0x0db3,
0x0db4, 0x0db5, 0x0db6, 0x0db7, 0x0db8, 0x0db9, 0x0dba, 0x0dbb,
0x0dbc, 0x0dbd, 0x0dbe, 0x0dbf, 0x0dc0, 0x0dc1, 0x0dc2, 0x0dc3,
0x0dc4, 0x0dc5, 0x0dc6, 0x0dc7, 0x0dc8, 0x0dc9, 0x0dca, 0x0dcb,
0x0dcc, 0x0dcd, 0x0dce, 0x0dcf, 0x0dd0, 0x0dd1, 0x0dd2, 0x0dd3,
0x0dd4, 0x0dd5, 0x0dd6, 0x0dd7, 0x0dd8, 0x0dd9, 0x0dda, 0x0ddf,
0x0de0, 0x0de1, 0x0de2, 0x0de3, 0x0de4, 0x0de5, 0x0de6, 0x0de7,
0x0de8, 0x0de9, 0x0dea, 0x0deb, 0x0dec, 0x0ded, 0x0df0, 0x0df1,
0x0df2, 0x0df3, 0x0df4, 0x0df5, 0x0df6, 0x0df7, 0x0df8, 0x0df9,
0x0aa2, 0x0aa1, 0x0aa3, 0x0aa4, 0x0aa5, 0x0aa6, 0x0aa7, 0x0aa8,
0x0abb, 0x0aaa, 0x0aa9, 0x07af, 0x0cdf, 0x0ad0, 0x0ad1, 0x0afd,
0x0ad2, 0x0ad3, 0x0afe, 0x0af1, 0x0af2, 0x0aaf, 0x0aae, 0x0ad5,
0x0ad6, 0x0ad7, 0x0afc, 0x047e, 0x20ac, 0x0ab8, 0x06b0, 0x0afb,
0x0ad4, 0x0ac9, 0x0ab0, 0x0ab1, 0x0ab2, 0x0ab3, 0x0ab4, 0x0ab5,
0x0ab6, 0x0ab7, 0x0ac3, 0x0ac4, 0x0ac5, 0x0ac6, 0x08fb, 0x08fc,
0x08fd, 0x08fe, 0x08ce, 0x08cd, 0x08ef, 0x08c5, 0x0bca, 0x08d6,
0x08c1, 0x08c2, 0x08de, 0x08df, 0x08dc, 0x08dd, 0x08bf, 0x08c0,
0x08c8, 0x08c9, 0x08bd, 0x08cf, 0x08bc, 0x08be, 0x08da, 0x08db,
0x0bfc, 0x0bdc, 0x0bc2, 0x0bce, 0x0bd3, 0x0bc4, 0x0afa, 0x08a4,
0x08a5, 0x0bcc, 0x08ab, 0x08ac, 0x08ad, 0x08ae, 0x08a7, 0x08a8,
0x08a9, 0x08aa, 0x08af, 0x08b0, 0x08a1, 0x09ef, 0x09f0, 0x09f2,
0x09f3, 0x09e2, 0x09e5, 0x09e9, 0x09e3, 0x09e4, 0x09e8, 0x09f1,
0x09f8, 0x09ec, 0x09eb, 0x09ed, 0x09ea, 0x09f4, 0x09f5, 0x09f7,
0x09f6, 0x09ee, 0x09e1, 0x09e0, 0x0bcf, 0x0af9, 0x0af8, 0x0af7,
0x0aec, 0x0aee, 0x0aed, 0x0af6, 0x0af5, 0x0af3, 0x0af4, 0x0ad9,
0x0af0, 0x04a4, 0x04a1, 0x04a2, 0x04a3, 0x04de, 0x04df, 0x04a7,
0x04b1, 0x04a8, 0x04b2, 0x04a9, 0x04b3, 0x04aa, 0x04b4, 0x04ab,
0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc,
0x04bd, 0x04be, 0x04bf, 0x04c0, 0x04c1, 0x04af, 0x04c2, 0x04c3,
0x04c4, 0x04c5, 0x04c6, 0x04c7, 0x04c8, 0x04c9, 0x04ca, 0x04cb,
0x04cc, 0x04cd, 0x04ce, 0x04cf, 0x04d0, 0x04d1, 0x04d2, 0x04d3,
0x04ac, 0x04d4, 0x04ad, 0x04d5, 0x04ae, 0x04d6, 0x04d7, 0x04d8,
0x04d9, 0x04da, 0x04db, 0x04dc, 0x04a6, 0x04dd, 0x04a5, 0x04b0
};
// clang-format on

View File

@ -16,7 +16,6 @@
*/ */
#include "NixUtils.h" #include "NixUtils.h"
#include "KeySymMap.h"
#include "core/Tools.h" #include "core/Tools.h"
#include <QApplication> #include <QApplication>
@ -184,25 +183,6 @@ bool NixUtils::nativeEventFilter(const QByteArray& eventType, void* message, lon
auto* keyPressEvent = static_cast<xcb_key_press_event_t*>(message); auto* keyPressEvent = static_cast<xcb_key_press_event_t*>(message);
auto modifierMask = ControlMask | ShiftMask | Mod1Mask | Mod4Mask; auto modifierMask = ControlMask | ShiftMask | Mod1Mask | Mod4Mask;
return triggerGlobalShortcut(keyPressEvent->detail, keyPressEvent->state & modifierMask); return triggerGlobalShortcut(keyPressEvent->detail, keyPressEvent->state & modifierMask);
} else if (type == XCB_MAPPING_NOTIFY) {
auto* mappingNotifyEvent = static_cast<xcb_mapping_notify_event_t*>(message);
if (mappingNotifyEvent->request == XCB_MAPPING_KEYBOARD
|| mappingNotifyEvent->request == XCB_MAPPING_MODIFIER) {
XMappingEvent xMappingEvent;
memset(&xMappingEvent, 0, sizeof(xMappingEvent));
xMappingEvent.type = MappingNotify;
xMappingEvent.display = dpy;
if (mappingNotifyEvent->request == XCB_MAPPING_KEYBOARD) {
xMappingEvent.request = MappingKeyboard;
} else {
xMappingEvent.request = MappingModifier;
}
xMappingEvent.first_keycode = mappingNotifyEvent->first_keycode;
xMappingEvent.count = mappingNotifyEvent->count;
XRefreshKeyboardMapping(&xMappingEvent);
// Notify listeners that the keymap has changed
emit keymapChanged();
}
} }
return false; return false;

View File

@ -48,9 +48,6 @@ public:
return false; return false;
} }
signals:
void keymapChanged();
private: private:
explicit NixUtils(QObject* parent = nullptr); explicit NixUtils(QObject* parent = nullptr);
~NixUtils() override; ~NixUtils() override;

View File

@ -17,7 +17,6 @@
#include "X11Funcs.h" #include "X11Funcs.h"
#include "KeySymMap.h"
#include "core/Tools.h" #include "core/Tools.h"
#include <X11/Xutil.h> #include <X11/Xutil.h>
@ -31,18 +30,9 @@ KeySym qcharToNativeKeyCode(const QChar& ch)
return unicode; return unicode;
} }
/* mapping table generated from keysymdef.h */ /* request other characters from X server */
const uint* match = Tools::binaryFind(unicodeToKeysymKeys, unicodeToKeysymKeys + unicodeToKeysymLen, unicode); QString ustr = QString("U%1").arg(unicode, 4, 16, QLatin1Char('0'));
int index = match - unicodeToKeysymKeys; return XStringToKeysym(ustr.toStdString().c_str());
if (index != unicodeToKeysymLen) {
return unicodeToKeysymValues[index];
}
if (unicode >= 0x0100) {
return unicode | 0x01000000;
}
return NoSymbol;
} }
KeySym qtToNativeKeyCode(Qt::Key key) KeySym qtToNativeKeyCode(Qt::Key key)