Skip to content

Instantly share code, notes, and snippets.

@jsm222
Created October 14, 2021 20:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsm222/6babf9c8660b628a47b5946a5e34627e to your computer and use it in GitHub Desktop.
Save jsm222/6babf9c8660b628a47b5946a5e34627e to your computer and use it in GitHub Desktop.
diff --git a/override.cpp b/override.cpp
index a5a38e3..119a2a9 100644
--- a/override.cpp
+++ b/override.cpp
@@ -11,57 +11,111 @@
#include <cstdlib>
#define _GNU_SOURCE
-#include <dlfcn.h>
-// Override
-// QString toString(SequenceFormat format = PortableText) const;
-// which is defined in /usr/local/include/qt5/QtGui/qkeysequence.h
-// and is implemented in
-// https://github.com/qt/qtbase/blob/7dd81686e8e9ee86624c5bcca10688cfb360dcb8/src/gui/kernel/qkeysequence.cpp#L1666-L1678
-
-// Found this by running
-// strings /usr/local/lib/qt5/* | grep KeySeq | grep tring | sort | uniq
-const char* FUNC_SYMBOL = "_ZNK12QKeySequence8toStringENS_14SequenceFormatE";
+static inline void addKey(QString &str, const QString &theKey, QKeySequence::SequenceFormat format);
+class QKeySequencePrivate
+{
+public:
+ enum { MaxKeyCount = 4 }; // also used in QKeySequenceEdit
+ inline QKeySequencePrivate() : ref(1)
+ {
+ std::fill_n(key, uint(MaxKeyCount), 0);
+ }
+ inline QKeySequencePrivate(const QKeySequencePrivate &copy) : ref(1)
+ {
+ std::copy(copy.key, copy.key + MaxKeyCount,
+ QT_MAKE_CHECKED_ARRAY_ITERATOR(key, MaxKeyCount));
+ }
+ QAtomicInt ref;
+ int key[MaxKeyCount];
+ static QString encodeString(int key, QKeySequence::SequenceFormat format);
+ // used in dbusmenu
+ Q_GUI_EXPORT static QString keyName(int key, QKeySequence::SequenceFormat format);
+ static int decodeString(QString accel, QKeySequence::SequenceFormat format);
+};
+QKeySequencePrivate *d;
+QString QKeySequence::toString(SequenceFormat format) const
+{
+ QString finalString;
+ // A standard string, with no translation or anything like that. In some ways it will
+ // look like our latin case on Windows and X11
+ int end = count();
+ for (int i = 0; i < end; ++i) {
+ finalString += d->encodeString(d->key[i], format);
+ finalString += QLatin1String(", ");
+ }
+ finalString.truncate(finalString.length() - 2);
+ return finalString;
+}
-static const int kShiftUnicode = 0x21E7;
-static const int kControlUnicode = 0x2303;
-static const int kOptionUnicode = 0x2325;
-static const int kCommandUnicode = 0x2318;
-typedef QString (*orig_func_f_type)(const QKeySequence *, QKeySequence::SequenceFormat format);
-QString QKeySequence::toString(SequenceFormat format) const
+QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat format)
{
-
- // Use some nuts function pointer black magic to access the original function
- orig_func_f_type orig_func;
- orig_func = (orig_func_f_type)dlsym(RTLD_NEXT, FUNC_SYMBOL);
- QString result = orig_func(this, format);
-
- // Replacements based on table from
- // https://github.com/qt/qtbase/blob/7dd81686e8e9ee86624c5bcca10688cfb360dcb8/src/gui/kernel/qkeysequence.cpp#L73-L94
- result.replace(QCoreApplication::translate("QShortcut", "Esc"), QChar(0x238B));
- result.replace(QCoreApplication::translate("QShortcut", "Tab"), QChar(0x21E5));
- result.replace(QCoreApplication::translate("QShortcut", "Backtab"), QChar(0x21E4));
- result.replace(QCoreApplication::translate("QShortcut", "Backspace"), QChar(0x232B));
- result.replace(QCoreApplication::translate("QShortcut", "Return"), QChar(0x21B5));
- result.replace(QCoreApplication::translate("QShortcut", "Enter"), QChar(0x2324));
- result.replace(QCoreApplication::translate("QShortcut", "Del"), QChar(0x2326));
- result.replace(QCoreApplication::translate("QShortcut", "Home"), QChar(0x2196));
- result.replace(QCoreApplication::translate("QShortcut", "End"), QChar(0x2198));
- result.replace(QCoreApplication::translate("QShortcut", "Left"), QChar(0x2190));
- result.replace(QCoreApplication::translate("QShortcut", "Up"), QChar(0x2191));
- result.replace(QCoreApplication::translate("QShortcut", "Right"), QChar(0x2192));
- result.replace(QCoreApplication::translate("QShortcut", "Down"), QChar(0x2193));
- result.replace(QCoreApplication::translate("QShortcut", "PgUp"), QChar(0x21DE));
- result.replace(QCoreApplication::translate("QShortcut", "PgDown"), QChar(0x21DF));
- result.replace(QCoreApplication::translate("QShortcut", "Shift"), QChar(kShiftUnicode));
- result.replace(QCoreApplication::translate("QShortcut", "Ctrl"), QChar(kCommandUnicode));
- result.replace(QCoreApplication::translate("QShortcut", "Meta"), QChar(kControlUnicode));
- result.replace(QCoreApplication::translate("QShortcut", "Alt"), QChar(kOptionUnicode));
- result.replace(QCoreApplication::translate("QShortcut", "CapsLock"), QChar(0x21EA));
-
- result.replace("+", "");
-
- return(result);
+ bool nativeText = (format == QKeySequence::NativeText);
+ QString s;
+ // Handle -1 (Invalid Key) and Qt::Key_unknown gracefully
+ if (key == -1 || key == Qt::Key_unknown)
+ return s;
+#if defined(Q_OS_MACX)
+ if (nativeText) {
+ // On OS X the order (by default) is Meta, Alt, Shift, Control.
+ // If the AA_MacDontSwapCtrlAndMeta is enabled, then the order
+ // is Ctrl, Alt, Shift, Meta. The macSymbolForQtKey does this swap
+ // for us, which means that we have to adjust our order here.
+ // The upshot is a lot more infrastructure to keep the number of
+ // if tests down and the code relatively clean.
+ static const int ModifierOrder[] = { Qt::META, Qt::ALT, Qt::SHIFT, Qt::CTRL, 0 };
+ static const int QtKeyOrder[] = { Qt::Key_Meta, Qt::Key_Alt, Qt::Key_Shift, Qt::Key_Control, 0 };
+ static const int DontSwapModifierOrder[] = { Qt::CTRL, Qt::ALT, Qt::SHIFT, Qt::META, 0 };
+ static const int DontSwapQtKeyOrder[] = { Qt::Key_Control, Qt::Key_Alt, Qt::Key_Shift, Qt::Key_Meta, 0 };
+ const int *modifierOrder;
+ const int *qtkeyOrder;
+ if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
+ modifierOrder = DontSwapModifierOrder;
+ qtkeyOrder = DontSwapQtKeyOrder;
+ } else {
+ modifierOrder = ModifierOrder;
+ qtkeyOrder = QtKeyOrder;
+ }
+ for (int i = 0; modifierOrder[i] != 0; ++i) {
+ if (key & modifierOrder[i])
+ s += qt_macSymbolForQtKey(qtkeyOrder[i]);
+ }
+ } else
+#endif
+ {
+ // On other systems the order is Meta, Control, Alt, Shift
+ if ((key & Qt::META) == Qt::META)
+ s = nativeText ? QCoreApplication::translate("QShortcut", "Meta") : QString::fromLatin1("Meta");
+ if ((key & Qt::CTRL) == Qt::CTRL)
+ addKey(s, nativeText ? QStringLiteral("⌘") : QStringLiteral("⌘"), format);
+ if ((key & Qt::ALT) == Qt::ALT)
+ addKey(s, nativeText ? QCoreApplication::translate("QShortcut", "Alt") : QString::fromLatin1("Alt"), format);
+ if ((key & Qt::SHIFT) == Qt::SHIFT)
+ addKey(s, nativeText ? QCoreApplication::translate("QShortcut", "Shift") : QString::fromLatin1("Shift"), format);
+ }
+ if ((key & Qt::KeypadModifier) == Qt::KeypadModifier)
+ addKey(s, nativeText ? QCoreApplication::translate("QShortcut", "Num") : QString::fromLatin1("Num"), format);
+ QString p = keyName(key, format);
+#if defined(Q_OS_OSX)
+ if (nativeText)
+ s += p;
+ else
+#endif
+ addKey(s, p, format);
+ return s;
}
+static inline void addKey(QString &str, const QString &theKey, QKeySequence::SequenceFormat format)
+{
+ if (!str.isEmpty()) {
+ if (format == QKeySequence::NativeText) {
+ //: Key separator in shortcut string
+ str += QCoreApplication::translate("QShortcut", "+");
+ } else {
+ str += QLatin1Char('+');
+ }
+ }
+ str += theKey;
+}
+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment