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