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