diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2023-10-03 00:52:03 +0200 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2023-10-17 20:51:16 +0200 |
commit | 98889c2ffc4edf44bf5610898c62f07d6457d781 (patch) | |
tree | 3ce983db1a339631f5ccf8637316435e4e4a13d3 /src/gui/platform/darwin | |
parent | 039257038533467d5b72ff2523c6d0db688f6f7d (diff) |
macOS: Filter out and prioritise key combinations that produce the same key
An incoming key event with a set of modifiers can potentially match
a range of key combinations, depending on how the event's modifiers
are combined to produce "intermediate" representations of the event.
For example, given a normal US keyboard layout, the virtual key
23 combined with the Alt (⌥) and Shift (⇧) modifiers, can map
to the following key combinations:
- Alt+Shift+5 (Fully expressed combination)
- Alt+% (Shift consumed to produce %)
- Shift+∞ (Alt consumed to produce ∞)
- fi (Shift and Alt consumed to produce fi)
But in other cases the intermediate modifier combinations
produce the same key/symbol as other modifier combinations.
For example, pressing Alt (⌥) and Shift (⇧) with the 'c'
key on a US layout will produce:
- Alt+Shift+C (Fully expressed combination)
- Shift+Ç (Alt consumed to produce Ç)
- Ç (Shift and Alt consumed to produce Ç)
In this case, we don't want to reflect the standalone 'Ç',
as that has already been reflected in the more direct form
via Shift+Ç. Consuming the additional Shift modifier does
not produce any additional symbols.
The same can happen without the number of modifiers being
different, in case two modifiers produce the same symbol.
In this case we want to prioritize Command over Option
over Control over Shift.
There is similar logic in the Windows and XKB key mappers,
and the implementation in the Apple key mapper has been
adapted from the Windows key mapper.
Task-number: QTBUG-67200
Task-number: QTBUG-38137
Change-Id: I4f1aeebac78a5393f8da804b53cf588f7c802c1b
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'src/gui/platform/darwin')
-rw-r--r-- | src/gui/platform/darwin/qapplekeymapper.mm | 35 |
1 files changed, 32 insertions, 3 deletions
diff --git a/src/gui/platform/darwin/qapplekeymapper.mm b/src/gui/platform/darwin/qapplekeymapper.mm index 7863e53ce2..2601c13868 100644 --- a/src/gui/platform/darwin/qapplekeymapper.mm +++ b/src/gui/platform/darwin/qapplekeymapper.mm @@ -530,8 +530,6 @@ QList<QKeyCombination> QAppleKeyMapper::possibleKeyCombinations(const QKeyEvent // FIXME: We only compute the first 8 combinations. Why? for (int i = 1; i < 8; ++i) { auto keyAfterApplyingModifiers = keyMap[i]; - if (keyAfterApplyingModifiers == unmodifiedKey) - continue; if (!keyAfterApplyingModifiers) continue; @@ -542,8 +540,39 @@ QList<QKeyCombination> QAppleKeyMapper::possibleKeyCombinations(const QKeyEvent // If the event includes more modifiers than the candidate they // will need to be included in the resulting key combination. auto additionalModifiers = eventModifiers & ~candidateModifiers; - ret << QKeyCombination::fromCombined( + + auto keyCombination = QKeyCombination::fromCombined( int(additionalModifiers) + int(keyAfterApplyingModifiers)); + + // If there's an existing key combination with the same key, + // but a different set of modifiers, we want to choose only + // one of them, by priority (see below). + const auto existingCombination = std::find_if( + ret.begin(), ret.end(), [&](auto existingCombination) { + return existingCombination.key() == keyAfterApplyingModifiers; + }); + + if (existingCombination != ret.end()) { + // We prioritize the combination with the more specific + // modifiers. In the case where the number of modifiers + // are the same, we want to prioritize Command over Option + // over Control over Shift. Unfortunately the order (and + // hence value) of the modifiers in Qt::KeyboardModifier + // does not match our preferred order when Control and + // Meta is switched, but we can work around that by + // explicitly swapping the modifiers and using that + // for the comparison. This also works when the + // Qt::AA_MacDontSwapCtrlAndMeta application attribute + // is set, as the incoming modifiers are then left + // as is, and we can still trust the order. + auto existingModifiers = swapModifiersIfNeeded(existingCombination->keyboardModifiers()); + auto replacementModifiers = swapModifiersIfNeeded(additionalModifiers); + if (replacementModifiers > existingModifiers) + *existingCombination = keyCombination; + } else { + // All is good, no existing combination has this key + ret << keyCombination; + } } } |