Auto-Type: Reimplement X11 keysym emulation (#7098)

* Fix Regression since 4d07507

* Auto-Type: Workaround X server default keymap bug

If there's a system wide configuration through xorg.conf for a default keyboard layout and it's not updated by the WM/DE at startup the Xkb extension seems to be somewhat confused with XTEST and the layout somehow defaults to US ANSI.

Reading the keyboard description and writing it back without changes works around this.
This commit is contained in:
Toni Spets 2021-11-05 05:01:47 +02:00 committed by GitHub
parent 20db504c3a
commit 3b1acd0831
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 9 deletions

View File

@ -295,12 +295,23 @@ void AutoTypePlatformX11::updateKeymap()
} }
m_xkb = XkbGetMap(m_dpy, XkbAllClientInfoMask, XkbUseCoreKbd); m_xkb = XkbGetMap(m_dpy, XkbAllClientInfoMask, XkbUseCoreKbd);
/* workaround X11 bug https://gitlab.freedesktop.org/xorg/xserver/-/issues/1155 */
XkbSetMap(m_dpy, XkbAllClientInfoMask, m_xkb);
XSync(m_dpy, False);
/* Build updated keymap */ /* Build updated keymap */
m_keymap.clear(); m_keymap.clear();
m_remapKeycode = 0;
for (int ckeycode = m_xkb->min_key_code; ckeycode < m_xkb->max_key_code; ckeycode++) { for (int ckeycode = m_xkb->min_key_code; ckeycode < m_xkb->max_key_code; ckeycode++) {
int groups = XkbKeyNumGroups(m_xkb, ckeycode); int groups = XkbKeyNumGroups(m_xkb, ckeycode);
/* track highest remappable keycode, don't add to keymap */
if (groups == 0) {
m_remapKeycode = ckeycode;
continue;
}
for (int cgroup = 0; cgroup < groups; cgroup++) { for (int cgroup = 0; cgroup < groups; cgroup++) {
XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, ckeycode, cgroup); XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, ckeycode, cgroup);
@ -357,6 +368,7 @@ void AutoTypePlatformX11::SendKeyEvent(unsigned keycode, bool press)
XTestFakeKeyEvent(m_dpy, keycode, press, 0); XTestFakeKeyEvent(m_dpy, keycode, press, 0);
XFlush(m_dpy); XFlush(m_dpy);
XSync(m_dpy, False);
XSetErrorHandler(oldHandler); XSetErrorHandler(oldHandler);
} }
@ -399,9 +411,43 @@ bool AutoTypePlatformX11::GetKeycode(KeySym keysym, int* keycode, int* group, un
return true; return true;
} }
/* if we can't find an existing key for this keysym, try remapping */
if (RemapKeycode(keysym)) {
*keycode = m_remapKeycode;
*group = 0;
*mask = 0;
return true;
}
return false; return false;
} }
/*
* Get remapped keycode for any keysym.
*/
bool AutoTypePlatformX11::RemapKeycode(KeySym keysym)
{
if (!m_remapKeycode) {
return false;
}
if (keysym != NoSymbol) {
int type = XkbOneLevelIndex;
if (XkbChangeTypesOfKey(m_xkb, m_remapKeycode, 1, XkbGroup1Mask, &type, NULL) != Success) {
return false;
}
XkbKeySymEntry(m_xkb, m_remapKeycode, 0, 0) = keysym;
} else {
XkbChangeTypesOfKey(m_xkb, m_remapKeycode, 0, XkbGroup1Mask, NULL, NULL);
}
XkbSetMap(m_dpy, XkbAllClientInfoMask, m_xkb);
XFlush(m_dpy);
XSync(m_dpy, False);
return true;
}
/* /*
* Send sequence of KeyPressed/KeyReleased events to the focused * Send sequence of KeyPressed/KeyReleased events to the focused
* window to simulate keyboard. If modifiers (shift, control, etc) * window to simulate keyboard. If modifiers (shift, control, etc)
@ -426,14 +472,6 @@ AutoTypeAction::Result AutoTypePlatformX11::sendKey(KeySym keysym, unsigned int
/* tell GetKeycode we would prefer a key from active group */ /* tell GetKeycode we would prefer a key from active group */
group = group_active; group = group_active;
/* determine keycode, group and mask for the given keysym */
if (!GetKeycode(keysym, &keycode, &group, &wanted_mask)) {
return AutoTypeAction::Result::Failed(tr("Unable to get valid keycode for key: ")
+ QString(XKeysymToString(keysym)));
}
wanted_mask |= modifiers;
Window root, child; Window root, child;
int root_x, root_y, x, y; int root_x, root_y, x, y;
unsigned int original_mask; unsigned int original_mask;
@ -451,6 +489,14 @@ AutoTypeAction::Result AutoTypePlatformX11::sendKey(KeySym keysym, unsigned int
return AutoTypeAction::Result::Retry(tr("Sequence aborted: Modifier keys held by user")); return AutoTypeAction::Result::Retry(tr("Sequence aborted: Modifier keys held by user"));
} }
/* determine keycode, group and mask for the given keysym */
if (!GetKeycode(keysym, &keycode, &group, &wanted_mask)) {
return AutoTypeAction::Result::Failed(tr("Unable to get valid keycode for key: ")
+ QString(XKeysymToString(keysym)));
}
wanted_mask |= modifiers;
/* modifiers that need to be held but aren't */ /* modifiers that need to be held but aren't */
unsigned int press_mask = wanted_mask & ~original_mask; unsigned int press_mask = wanted_mask & ~original_mask;
@ -474,6 +520,11 @@ AutoTypeAction::Result AutoTypePlatformX11::sendKey(KeySym keysym, unsigned int
XFlush(m_dpy); XFlush(m_dpy);
} }
/* reset remap to prevent leaking remap keysyms longer than necessary */
if (keycode == m_remapKeycode) {
RemapKeycode(NoSymbol);
}
return AutoTypeAction::Result::Ok(); return AutoTypeAction::Result::Ok();
} }

View File

@ -58,7 +58,7 @@ private:
bool isTopLevelWindow(Window window); bool isTopLevelWindow(Window window);
XkbDescPtr getKeyboard(); XkbDescPtr getKeyboard();
int AddKeysym(KeySym keysym); bool RemapKeycode(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);
bool GetKeycode(KeySym keysym, int* keycode, int* group, unsigned int* mask); bool GetKeycode(KeySym keysym, int* keycode, int* group, unsigned int* mask);
@ -88,6 +88,7 @@ private:
XkbDescPtr m_xkb; XkbDescPtr m_xkb;
QList<KeyDesc> m_keymap; QList<KeyDesc> m_keymap;
KeyCode m_modifier_keycode[N_MOD_INDICES]; KeyCode m_modifier_keycode[N_MOD_INDICES];
KeyCode m_remapKeycode;
bool m_loaded; bool m_loaded;
}; };