diff --git a/tigervnc-add-new-keycodes-for-unknown-keysyms.patch b/tigervnc-add-new-keycodes-for-unknown-keysyms.patch new file mode 100644 index 0000000..d4fd2b3 --- /dev/null +++ b/tigervnc-add-new-keycodes-for-unknown-keysyms.patch @@ -0,0 +1,199 @@ +From ccbd491fa48f1c43daeb1a6c5ee91a1a8fa3db88 Mon Sep 17 00:00:00 2001 +From: Jan Grulich +Date: Tue, 9 Aug 2022 14:31:07 +0200 +Subject: [PATCH] x0vncserver: add new keysym in case we don't find a matching + keycode + +We might often fail to find a matching X11 keycode when the client has +a different keyboard layout and end up with no key event. To avoid a +failure we add it as a new keysym/keycode pair so the next time a keysym +from the client that is unknown to the server is send, we will find a +match and proceed with key event. This is same behavior used in Xvnc or +x11vnc, although Xvnc has more advanced mapping from keysym to keycode. +--- + unix/x0vncserver/XDesktop.cxx | 121 +++++++++++++++++++++++++++++++++- + unix/x0vncserver/XDesktop.h | 4 ++ + 2 files changed, 122 insertions(+), 3 deletions(-) + +diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx +index f2046e43e..933998f05 100644 +--- a/unix/x0vncserver/XDesktop.cxx ++++ b/unix/x0vncserver/XDesktop.cxx +@@ -31,6 +31,7 @@ + #include + + #include ++#include + #ifdef HAVE_XTEST + #include + #endif +@@ -50,6 +51,7 @@ void vncSetGlueContext(Display *dpy, void *res); + #include + #include + ++using namespace std; + using namespace rfb; + + extern const unsigned short code_map_qnum_to_xorgevdev[]; +@@ -264,6 +266,9 @@ void XDesktop::start(VNCServer* vs) { + void XDesktop::stop() { + running = false; + ++ // Delete added keycodes ++ deleteAddedKeysyms(dpy); ++ + #ifdef HAVE_XDAMAGE + if (haveDamage) + XDamageDestroy(dpy, damage); +@@ -383,6 +388,118 @@ KeyCode XDesktop::XkbKeysymToKeycode(Display* dpy, KeySym keysym) { + } + #endif + ++KeyCode XDesktop::addKeysym(Display* dpy, KeySym keysym) ++{ ++ int types[1]; ++ unsigned int key; ++ XkbDescPtr xkb; ++ XkbMapChangesRec changes; ++ KeySym *syms; ++ KeySym upper, lower; ++ ++ xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd); ++ ++ if (!xkb) ++ return 0; ++ ++ for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) { ++ if (XkbKeyNumGroups(xkb, key) == 0) ++ break; ++ } ++ ++ if (key < xkb->min_key_code) ++ return 0; ++ ++ memset(&changes, 0, sizeof(changes)); ++ ++ XConvertCase(keysym, &lower, &upper); ++ ++ if (upper == lower) ++ types[XkbGroup1Index] = XkbOneLevelIndex; ++ else ++ types[XkbGroup1Index] = XkbAlphabeticIndex; ++ ++ XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes); ++ ++ syms = XkbKeySymsPtr(xkb,key); ++ if (upper == lower) ++ syms[0] = keysym; ++ else { ++ syms[0] = lower; ++ syms[1] = upper; ++ } ++ ++ changes.changed |= XkbKeySymsMask; ++ changes.first_key_sym = key; ++ changes.num_key_syms = 1; ++ ++ if (XkbChangeMap(dpy, xkb, &changes)) { ++ vlog.info("Added unknown keysym %s to keycode %d", XKeysymToString(keysym), key); ++ addedKeysyms[keysym] = key; ++ return key; ++ } ++ ++ return 0; ++} ++ ++void XDesktop::deleteAddedKeysyms(Display* dpy) { ++ XkbDescPtr xkb; ++ xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd); ++ ++ if (!xkb) ++ return; ++ ++ XkbMapChangesRec changes; ++ memset(&changes, 0, sizeof(changes)); ++ ++ KeyCode lowestKeyCode = xkb->max_key_code; ++ KeyCode highestKeyCode = xkb->min_key_code; ++ std::map::iterator it; ++ for (it = addedKeysyms.begin(); it != addedKeysyms.end(); it++) { ++ if (XkbKeyNumGroups(xkb, it->second) != 0) { ++ // Check if we are removing keysym we added ourself ++ if (XkbKeysymToKeycode(dpy, it->first) != it->second) ++ continue; ++ ++ XkbChangeTypesOfKey(xkb, it->second, 0, XkbGroup1Mask, NULL, &changes); ++ ++ if (it->second < lowestKeyCode) ++ lowestKeyCode = it->second; ++ ++ if (it->second > highestKeyCode) ++ highestKeyCode = it->second; ++ } ++ } ++ ++ changes.changed |= XkbKeySymsMask; ++ changes.first_key_sym = lowestKeyCode; ++ changes.num_key_syms = highestKeyCode - lowestKeyCode + 1; ++ XkbChangeMap(dpy, xkb, &changes); ++ ++ addedKeysyms.clear(); ++} ++ ++KeyCode XDesktop::keysymToKeycode(Display* dpy, KeySym keysym) { ++ int keycode = 0; ++ ++ // XKeysymToKeycode() doesn't respect state, so we have to use ++ // something slightly more complex ++ keycode = XkbKeysymToKeycode(dpy, keysym); ++ ++ if (keycode != 0) ++ return keycode; ++ ++ // TODO: try to further guess keycode with all possible mods as Xvnc does ++ ++ keycode = addKeysym(dpy, keysym); ++ ++ if (keycode == 0) ++ vlog.error("Failure adding new keysym 0x%lx", keysym); ++ ++ return keycode; ++} ++ ++ + void XDesktop::keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) { + #ifdef HAVE_XTEST + int keycode = 0; +@@ -398,9 +515,7 @@ void XDesktop::keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) { + if (pressedKeys.find(keysym) != pressedKeys.end()) + keycode = pressedKeys[keysym]; + else { +- // XKeysymToKeycode() doesn't respect state, so we have to use +- // something slightly more complex +- keycode = XkbKeysymToKeycode(dpy, keysym); ++ keycode = keysymToKeycode(dpy, keysym); + } + } + +diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h +index 840d43316..6ebcd9f8a 100644 +--- a/unix/x0vncserver/XDesktop.h ++++ b/unix/x0vncserver/XDesktop.h +@@ -55,6 +55,9 @@ class XDesktop : public rfb::SDesktop, + const char* userName); + virtual void pointerEvent(const rfb::Point& pos, int buttonMask); + KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym); ++ KeyCode addKeysym(Display* dpy, KeySym keysym); ++ void deleteAddedKeysyms(Display* dpy); ++ KeyCode keysymToKeycode(Display* dpy, KeySym keysym); + virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down); + virtual void clientCutText(const char* str); + virtual unsigned int setScreenLayout(int fb_width, int fb_height, +@@ -78,6 +81,7 @@ class XDesktop : public rfb::SDesktop, + bool haveXtest; + bool haveDamage; + int maxButtons; ++ std::map addedKeysyms; + std::map pressedKeys; + bool running; + #ifdef HAVE_XDAMAGE diff --git a/tigervnc.spec b/tigervnc.spec index 813e0f5..6481504 100644 --- a/tigervnc.spec +++ b/tigervnc.spec @@ -5,7 +5,7 @@ Name: tigervnc Version: 1.12.0 -Release: 7%{?dist} +Release: 8%{?dist} Summary: A TigerVNC remote display system %global _hardened_build 1 @@ -28,7 +28,10 @@ Patch50: tigervnc-selinux-restore-context-in-case-of-different-policies.p Patch51: tigervnc-fix-typo-in-mirror-monitor-detection.patch Patch52: tigervnc-root-user-selinux-context.patch Patch53: tigervnc-vncsession-restore-script-systemd-service.patch +# https://github.com/TigerVNC/tigervnc/pull/1513 Patch54: tigervnc-fix-ghost-cursor-in-zaphod-mode.patch +# https://github.com/TigerVNC/tigervnc/pull/1510 +Patch55: tigervnc-add-new-keycodes-for-unknown-keysyms.patch # This is tigervnc-%%{version}/unix/xserver116.patch rebased on the latest xorg Patch100: tigervnc-xserver120.patch @@ -36,7 +39,6 @@ Patch100: tigervnc-xserver120.patch Patch101: 0001-rpath-hack.patch # Upstreamable patches -# https://github.com/TigerVNC/tigervnc/pull/1513 BuildRequires: gcc-c++ BuildRequires: libX11-devel, automake, autoconf, libtool, gettext, gettext-autopoint @@ -169,6 +171,8 @@ popd %patch52 -p1 -b .root-user-selinux-context %patch53 -p1 -b .vncsession-restore-script-systemd-service %patch54 -p1 -b .fix-ghost-cursor-in-zaphod-mode +%patch55 -p1 -b .add-new-keycodes-for-unknown-keysyms + %build %ifarch sparcv9 sparc64 s390 s390x @@ -323,6 +327,10 @@ fi %ghost %verify(not md5 size mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} %changelog +* Fri Nov 18 2022 Jan Grulich - 1.12.0-8 +- x0vncserver: add new keysym in case we don't find matching keycode + Resolves: bz#1437569 + * Wed Aug 24 2022 Jan Grulich - 1.12.0-7 - x0vncserver: fix ghost cursor in zaphod mode (better version) Resolves: bz#2109679