File indexing completed on 2024-12-08 09:38:03

0001 #include <QKeySequence>
0002 
0003 #include "kglobalshortcutinfo_p.h"
0004 #include "sequencehelpers_p.h"
0005 
0006 namespace Utils
0007 {
0008 QKeySequence reverseKey(const QKeySequence &key)
0009 {
0010     int k[maxSequenceLength] = {0, 0, 0, 0};
0011     int count = key.count();
0012     for (int i = 0; i < count; i++) {
0013 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0014         k[count - i - 1] = key[i].toCombined();
0015 #else
0016         k[count - i - 1] = key[i];
0017 #endif
0018     }
0019 
0020     return QKeySequence(k[0], k[1], k[2], k[3]);
0021 }
0022 
0023 QKeySequence cropKey(const QKeySequence &key, int count)
0024 {
0025     if (count < 1) {
0026         return key;
0027     }
0028 
0029     // Key is shorter than count we want to cut off
0030     if (key.count() < count) {
0031         return QKeySequence();
0032     }
0033 
0034     int k[maxSequenceLength] = {0, 0, 0, 0};
0035     // cut from beginning
0036     for (int i = count; i < key.count(); i++) {
0037 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0038         k[i - count] = key[i].toCombined();
0039 #else
0040         k[i - count] = key[i];
0041 #endif
0042     }
0043 
0044     return QKeySequence(k[0], k[1], k[2], k[3]);
0045 }
0046 
0047 bool contains(const QKeySequence &key, const QKeySequence &other)
0048 {
0049     int minLength = std::min(key.count(), other.count());
0050 
0051     // There's an empty key, assume it matches nothing
0052     if (!minLength) {
0053         return false;
0054     }
0055 
0056     bool ret = false;
0057     for (int i = 0; i <= other.count() - minLength; i++) {
0058         QKeySequence otherCropped = cropKey(other, i);
0059         if (key.matches(otherCropped) == QKeySequence::PartialMatch || reverseKey(key).matches(reverseKey(otherCropped)) == QKeySequence::PartialMatch) {
0060             ret = true;
0061             break;
0062         }
0063     }
0064 
0065     return ret;
0066 }
0067 
0068 bool matchSequences(const QKeySequence &key, const QList<QKeySequence> &keys)
0069 {
0070     // Since we're testing sequences, we need to check for all possible matches
0071     // between existing and new sequences.
0072 
0073     // Let's assume we have (Alt+B, Alt+F, Alt+G) assigned. Examples of bad shortcuts are:
0074     // 1) Exact matching: (Alt+B, Alt+F, Alt+G)
0075     // 2) Sequence shadowing: (Alt+B, Alt+F)
0076     // 3) Sequence being shadowed: (Alt+B, Alt+F, Alt+G, <any key>)
0077     // 4) Shadowing at the end: (Alt+F, Alt+G)
0078     // 5) Being shadowed from the end: (<any key>, Alt+B, Alt+F, Alt+G)
0079 
0080     for (const QKeySequence &otherKey : keys) {
0081         if (otherKey.isEmpty()) {
0082             continue;
0083         }
0084         if (key.matches(otherKey) == QKeySequence::ExactMatch || contains(key, otherKey) || contains(otherKey, key)) {
0085             return true;
0086         }
0087     }
0088     return false;
0089 }
0090 
0091 QKeySequence mangleKey(const QKeySequence &key)
0092 {
0093     // Qt triggers both shortcuts that include Shift+Backtab and Shift+Tab
0094     // when user presses Shift+Tab. Make no difference here.
0095     int k[maxSequenceLength] = {0, 0, 0, 0};
0096     for (int i = 0; i < key.count(); i++) {
0097         // Qt triggers both shortcuts that include Shift+Backtab and Shift+Tab
0098         // when user presses Shift+Tab. Make no difference here.
0099 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0100         int keySym = key[i].toCombined() & ~Qt::KeyboardModifierMask;
0101         int keyMod = key[i].toCombined() & Qt::KeyboardModifierMask;
0102 #else
0103         int keySym = key[i] & ~Qt::KeyboardModifierMask;
0104         int keyMod = key[i] & Qt::KeyboardModifierMask;
0105 #endif
0106         if ((keyMod & Qt::SHIFT) && (keySym == Qt::Key_Backtab || keySym == Qt::Key_Tab)) {
0107             k[i] = keyMod | Qt::Key_Tab;
0108         } else {
0109 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0110             k[i] = key[i].toCombined();
0111 #else
0112             k[i] = key[i];
0113 #endif
0114         }
0115     }
0116 
0117     return QKeySequence(k[0], k[1], k[2], k[3]);
0118 }
0119 
0120 } // namespace Utils