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