Long live QKeyCombination!

C++20 via P1120 is deprecating arithmetic operations between
unrelated enumeration types, and GCC 10 is already complaining.
Hence, these operations might become illegal in C++23 or C++26 at
the latest.

A case of this that affects Qt is in key combinations: a
QKeySequence can be constructed by summing / ORing modifiers and a
key, for instance:

  Qt::CTRL + Qt::Key_A
  Qt::SHIFT | Qt::CTRL | Qt::Key_G (recommended, see below)

The problem is that the modifiers and the key belong to different
enumerations (and there's 2 enumerations for the modifier, and one
for the key).

To solve this: add a dedicated class to represent a combination of
keys, and operators between those enumerations to build instances
of this class.

I would've simply defined operator|, but again docs and pre-existing
code use operator+ as well, so added both to at least tackle simple
cases (modifier + key).

Multiple modifiers create a problem: operator+ between them yields
int, not the corresponding flags type (because operator+ is not
overloaded for this use case):

  Qt::CTRL + Qt::SHIFT + Qt::Key_A
  \__________________/      /
          int              /
           \______________/
                  int

Not only this loses track of the datatypes involved, but it would
also then "add" the key (with NO warnings, now its int + enum, so
it's not mixing enums!) and yielding int again.

I don't want to special-case this; the point of the class is
that int is the wrong datatype. Everything works just fine when
using operator| instead:

  Qt::CTRL | Qt::SHIFT | Qt::Key_A
  \__________________/      /
      Qt::Modifiers        /
           \______________/
            QKeyCombination

So I'm defining operator+ so that the simple cases still work,
but also deprecating it.

Port some code around Qt to the new class. In certain cases,
it's a huge win for clarity. In some others, I've just added
the necessary casts to make it still compile without warnings,
without attempting refactorings.

[ChangeLog][QtCore][QKeyCombination] New class to represent
a combination of a key and zero or more modifiers, to be used
when defining shortcuts or similar.

[ChangeLog][Potentially Source-Incompatible Changes] A keyboard
modifier (such as Qt::CTRL, Qt::AltModifier, etc.) should be
combined with a key (such as Qt::Key_A, Qt::Key_F1, etc.) by using
operator|, not operator+.  The result is now an object of type
QKeyCombination, that stores the key and the modifiers.

Change-Id: I657a3a328232f059023fff69c5031ee31cc91dd6
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Giuseppe D'Angelo 2020-04-19 19:56:18 +02:00
parent f03b2f7711
commit 25351dcc54
35 changed files with 813 additions and 67 deletions

View File

@ -90,7 +90,7 @@ Screenshot::Screenshot()
connect(saveScreenshotButton, &QPushButton::clicked, this, &Screenshot::saveScreenshot); connect(saveScreenshotButton, &QPushButton::clicked, this, &Screenshot::saveScreenshot);
buttonsLayout->addWidget(saveScreenshotButton); buttonsLayout->addWidget(saveScreenshotButton);
QPushButton *quitScreenshotButton = new QPushButton(tr("Quit"), this); QPushButton *quitScreenshotButton = new QPushButton(tr("Quit"), this);
quitScreenshotButton->setShortcut(Qt::CTRL + Qt::Key_Q); quitScreenshotButton->setShortcut(Qt::CTRL | Qt::Key_Q);
connect(quitScreenshotButton, &QPushButton::clicked, this, &QWidget::close); connect(quitScreenshotButton, &QPushButton::clicked, this, &QWidget::close);
buttonsLayout->addWidget(quitScreenshotButton); buttonsLayout->addWidget(quitScreenshotButton);
buttonsLayout->addStretch(); buttonsLayout->addStretch();

View File

@ -66,7 +66,7 @@ int main(int argc, char *argv[])
StorageModel *model = new StorageModel(&view); StorageModel *model = new StorageModel(&view);
model->refresh(); model->refresh();
QShortcut *refreshShortcut = new QShortcut(Qt::CTRL + Qt::Key_R, &view); QShortcut *refreshShortcut = new QShortcut(Qt::CTRL | Qt::Key_R, &view);
QObject::connect(refreshShortcut, &QShortcut::activated, model, &StorageModel::refresh); QObject::connect(refreshShortcut, &QShortcut::activated, model, &StorageModel::refresh);
view.setModel(model); view.setModel(model);

View File

@ -209,14 +209,14 @@ void TextEdit::setupFileActions()
const QIcon exportPdfIcon = QIcon::fromTheme("exportpdf", QIcon(rsrcPath + "/exportpdf.png")); const QIcon exportPdfIcon = QIcon::fromTheme("exportpdf", QIcon(rsrcPath + "/exportpdf.png"));
a = menu->addAction(exportPdfIcon, tr("&Export PDF..."), this, &TextEdit::filePrintPdf); a = menu->addAction(exportPdfIcon, tr("&Export PDF..."), this, &TextEdit::filePrintPdf);
a->setPriority(QAction::LowPriority); a->setPriority(QAction::LowPriority);
a->setShortcut(Qt::CTRL + Qt::Key_D); a->setShortcut(Qt::CTRL | Qt::Key_D);
tb->addAction(a); tb->addAction(a);
menu->addSeparator(); menu->addSeparator();
#endif #endif
a = menu->addAction(tr("&Quit"), this, &QWidget::close); a = menu->addAction(tr("&Quit"), this, &QWidget::close);
a->setShortcut(Qt::CTRL + Qt::Key_Q); a->setShortcut(Qt::CTRL | Qt::Key_Q);
} }
void TextEdit::setupEditActions() void TextEdit::setupEditActions()
@ -266,7 +266,7 @@ void TextEdit::setupTextActions()
const QIcon boldIcon = QIcon::fromTheme("format-text-bold", QIcon(rsrcPath + "/textbold.png")); const QIcon boldIcon = QIcon::fromTheme("format-text-bold", QIcon(rsrcPath + "/textbold.png"));
actionTextBold = menu->addAction(boldIcon, tr("&Bold"), this, &TextEdit::textBold); actionTextBold = menu->addAction(boldIcon, tr("&Bold"), this, &TextEdit::textBold);
actionTextBold->setShortcut(Qt::CTRL + Qt::Key_B); actionTextBold->setShortcut(Qt::CTRL | Qt::Key_B);
actionTextBold->setPriority(QAction::LowPriority); actionTextBold->setPriority(QAction::LowPriority);
QFont bold; QFont bold;
bold.setBold(true); bold.setBold(true);
@ -277,7 +277,7 @@ void TextEdit::setupTextActions()
const QIcon italicIcon = QIcon::fromTheme("format-text-italic", QIcon(rsrcPath + "/textitalic.png")); const QIcon italicIcon = QIcon::fromTheme("format-text-italic", QIcon(rsrcPath + "/textitalic.png"));
actionTextItalic = menu->addAction(italicIcon, tr("&Italic"), this, &TextEdit::textItalic); actionTextItalic = menu->addAction(italicIcon, tr("&Italic"), this, &TextEdit::textItalic);
actionTextItalic->setPriority(QAction::LowPriority); actionTextItalic->setPriority(QAction::LowPriority);
actionTextItalic->setShortcut(Qt::CTRL + Qt::Key_I); actionTextItalic->setShortcut(Qt::CTRL | Qt::Key_I);
QFont italic; QFont italic;
italic.setItalic(true); italic.setItalic(true);
actionTextItalic->setFont(italic); actionTextItalic->setFont(italic);
@ -286,7 +286,7 @@ void TextEdit::setupTextActions()
const QIcon underlineIcon = QIcon::fromTheme("format-text-underline", QIcon(rsrcPath + "/textunder.png")); const QIcon underlineIcon = QIcon::fromTheme("format-text-underline", QIcon(rsrcPath + "/textunder.png"));
actionTextUnderline = menu->addAction(underlineIcon, tr("&Underline"), this, &TextEdit::textUnderline); actionTextUnderline = menu->addAction(underlineIcon, tr("&Underline"), this, &TextEdit::textUnderline);
actionTextUnderline->setShortcut(Qt::CTRL + Qt::Key_U); actionTextUnderline->setShortcut(Qt::CTRL | Qt::Key_U);
actionTextUnderline->setPriority(QAction::LowPriority); actionTextUnderline->setPriority(QAction::LowPriority);
QFont underline; QFont underline;
underline.setUnderline(true); underline.setUnderline(true);
@ -298,31 +298,31 @@ void TextEdit::setupTextActions()
const QIcon leftIcon = QIcon::fromTheme("format-justify-left", QIcon(rsrcPath + "/textleft.png")); const QIcon leftIcon = QIcon::fromTheme("format-justify-left", QIcon(rsrcPath + "/textleft.png"));
actionAlignLeft = new QAction(leftIcon, tr("&Left"), this); actionAlignLeft = new QAction(leftIcon, tr("&Left"), this);
actionAlignLeft->setShortcut(Qt::CTRL + Qt::Key_L); actionAlignLeft->setShortcut(Qt::CTRL | Qt::Key_L);
actionAlignLeft->setCheckable(true); actionAlignLeft->setCheckable(true);
actionAlignLeft->setPriority(QAction::LowPriority); actionAlignLeft->setPriority(QAction::LowPriority);
const QIcon centerIcon = QIcon::fromTheme("format-justify-center", QIcon(rsrcPath + "/textcenter.png")); const QIcon centerIcon = QIcon::fromTheme("format-justify-center", QIcon(rsrcPath + "/textcenter.png"));
actionAlignCenter = new QAction(centerIcon, tr("C&enter"), this); actionAlignCenter = new QAction(centerIcon, tr("C&enter"), this);
actionAlignCenter->setShortcut(Qt::CTRL + Qt::Key_E); actionAlignCenter->setShortcut(Qt::CTRL | Qt::Key_E);
actionAlignCenter->setCheckable(true); actionAlignCenter->setCheckable(true);
actionAlignCenter->setPriority(QAction::LowPriority); actionAlignCenter->setPriority(QAction::LowPriority);
const QIcon rightIcon = QIcon::fromTheme("format-justify-right", QIcon(rsrcPath + "/textright.png")); const QIcon rightIcon = QIcon::fromTheme("format-justify-right", QIcon(rsrcPath + "/textright.png"));
actionAlignRight = new QAction(rightIcon, tr("&Right"), this); actionAlignRight = new QAction(rightIcon, tr("&Right"), this);
actionAlignRight->setShortcut(Qt::CTRL + Qt::Key_R); actionAlignRight->setShortcut(Qt::CTRL | Qt::Key_R);
actionAlignRight->setCheckable(true); actionAlignRight->setCheckable(true);
actionAlignRight->setPriority(QAction::LowPriority); actionAlignRight->setPriority(QAction::LowPriority);
const QIcon fillIcon = QIcon::fromTheme("format-justify-fill", QIcon(rsrcPath + "/textjustify.png")); const QIcon fillIcon = QIcon::fromTheme("format-justify-fill", QIcon(rsrcPath + "/textjustify.png"));
actionAlignJustify = new QAction(fillIcon, tr("&Justify"), this); actionAlignJustify = new QAction(fillIcon, tr("&Justify"), this);
actionAlignJustify->setShortcut(Qt::CTRL + Qt::Key_J); actionAlignJustify->setShortcut(Qt::CTRL | Qt::Key_J);
actionAlignJustify->setCheckable(true); actionAlignJustify->setCheckable(true);
actionAlignJustify->setPriority(QAction::LowPriority); actionAlignJustify->setPriority(QAction::LowPriority);
const QIcon indentMoreIcon = QIcon::fromTheme("format-indent-more", QIcon(rsrcPath + "/format-indent-more.png")); const QIcon indentMoreIcon = QIcon::fromTheme("format-indent-more", QIcon(rsrcPath + "/format-indent-more.png"));
actionIndentMore = menu->addAction(indentMoreIcon, tr("&Indent"), this, &TextEdit::indent); actionIndentMore = menu->addAction(indentMoreIcon, tr("&Indent"), this, &TextEdit::indent);
actionIndentMore->setShortcut(Qt::CTRL + Qt::Key_BracketRight); actionIndentMore->setShortcut(Qt::CTRL | Qt::Key_BracketRight);
actionIndentMore->setPriority(QAction::LowPriority); actionIndentMore->setPriority(QAction::LowPriority);
const QIcon indentLessIcon = QIcon::fromTheme("format-indent-less", QIcon(rsrcPath + "/format-indent-less.png")); const QIcon indentLessIcon = QIcon::fromTheme("format-indent-less", QIcon(rsrcPath + "/format-indent-less.png"));
actionIndentLess = menu->addAction(indentLessIcon, tr("&Unindent"), this, &TextEdit::unindent); actionIndentLess = menu->addAction(indentLessIcon, tr("&Unindent"), this, &TextEdit::unindent);
actionIndentLess->setShortcut(Qt::CTRL + Qt::Key_BracketLeft); actionIndentLess->setShortcut(Qt::CTRL | Qt::Key_BracketLeft);
actionIndentLess->setPriority(QAction::LowPriority); actionIndentLess->setPriority(QAction::LowPriority);
// Make sure the alignLeft is always left of the alignRight // Make sure the alignLeft is always left of the alignRight
@ -358,7 +358,7 @@ void TextEdit::setupTextActions()
const QIcon checkboxIcon = QIcon::fromTheme("status-checkbox-checked", QIcon(rsrcPath + "/checkbox-checked.png")); const QIcon checkboxIcon = QIcon::fromTheme("status-checkbox-checked", QIcon(rsrcPath + "/checkbox-checked.png"));
actionToggleCheckState = menu->addAction(checkboxIcon, tr("Chec&ked"), this, &TextEdit::setChecked); actionToggleCheckState = menu->addAction(checkboxIcon, tr("Chec&ked"), this, &TextEdit::setChecked);
actionToggleCheckState->setShortcut(Qt::CTRL + Qt::Key_K); actionToggleCheckState->setShortcut(Qt::CTRL | Qt::Key_K);
actionToggleCheckState->setCheckable(true); actionToggleCheckState->setCheckable(true);
actionToggleCheckState->setPriority(QAction::LowPriority); actionToggleCheckState->setPriority(QAction::LowPriority);
tb->addAction(actionToggleCheckState); tb->addAction(actionToggleCheckState);

View File

@ -1,6 +1,7 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2020 The Qt Company Ltd.
** Copyright (C) 2020 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the QtCore module of the Qt Toolkit. ** This file is part of the QtCore module of the Qt Toolkit.
@ -1094,6 +1095,8 @@ namespace Qt {
ALT = Qt::AltModifier, ALT = Qt::AltModifier,
MODIFIER_MASK = KeyboardModifierMask, MODIFIER_MASK = KeyboardModifierMask,
}; };
Q_DECLARE_FLAGS(Modifiers, Modifier)
Q_DECLARE_OPERATORS_FOR_FLAGS(Modifiers)
enum ArrowType { enum ArrowType {
NoArrow, NoArrow,
@ -1785,6 +1788,9 @@ namespace Qt {
Q_ENUM_NS(SortOrder) Q_ENUM_NS(SortOrder)
Q_ENUM_NS(CaseSensitivity) Q_ENUM_NS(CaseSensitivity)
Q_FLAG_NS(MatchFlags) Q_FLAG_NS(MatchFlags)
Q_ENUM_NS(Modifier)
Q_FLAG_NS(Modifiers)
Q_ENUM_NS(KeyboardModifier)
Q_FLAG_NS(KeyboardModifiers) Q_FLAG_NS(KeyboardModifiers)
Q_FLAG_NS(MouseButtons) Q_FLAG_NS(MouseButtons)
Q_ENUM_NS(WindowType) Q_ENUM_NS(WindowType)
@ -1863,6 +1869,156 @@ public:
static bool activateCallbacks(Callback, void **); static bool activateCallbacks(Callback, void **);
}; };
class QKeyCombination
{
int combination;
public:
constexpr /* implicit */ QKeyCombination(Qt::Key key = Qt::Key_unknown) noexcept
: combination(int(key))
{}
constexpr explicit QKeyCombination(Qt::Modifiers modifiers, Qt::Key key = Qt::Key_unknown) noexcept
: combination(int(modifiers) | int(key))
{}
constexpr explicit QKeyCombination(Qt::KeyboardModifiers modifiers, Qt::Key key = Qt::Key_unknown) noexcept
: combination(int(modifiers) | int(key))
{}
constexpr Qt::KeyboardModifiers keyboardModifiers() const noexcept
{
return Qt::KeyboardModifiers(combination & Qt::KeyboardModifierMask);
}
constexpr Qt::Key key() const noexcept
{
return Qt::Key(combination & ~Qt::KeyboardModifierMask);
}
static constexpr QKeyCombination fromCombined(int combined)
{
QKeyCombination result;
result.combination = combined;
return result;
}
constexpr int toCombined() const noexcept
{
return combination;
}
#if QT_DEPRECATED_SINCE(6, 0)
QT_DEPRECATED_VERSION_X(6, 0, "Use QKeyCombination instead of int")
constexpr /* implicit */ operator int() const noexcept
{
return combination;
}
#endif
friend constexpr bool operator==(QKeyCombination lhs, QKeyCombination rhs) noexcept
{
return lhs.combination == rhs.combination;
}
friend constexpr bool operator!=(QKeyCombination lhs, QKeyCombination rhs) noexcept
{
return lhs.combination != rhs.combination;
}
};
Q_DECLARE_TYPEINFO(QKeyCombination, Q_MOVABLE_TYPE);
constexpr QKeyCombination operator|(Qt::Modifier modifier, Qt::Key key) noexcept
{
return QKeyCombination(modifier, key);
}
constexpr QKeyCombination operator|(Qt::Modifiers modifiers, Qt::Key key) noexcept
{
return QKeyCombination(modifiers, key);
}
constexpr QKeyCombination operator|(Qt::KeyboardModifier modifier, Qt::Key key) noexcept
{
return QKeyCombination(modifier, key);
}
constexpr QKeyCombination operator|(Qt::KeyboardModifiers modifiers, Qt::Key key) noexcept
{
return QKeyCombination(modifiers, key);
}
constexpr QKeyCombination operator|(Qt::Key key, Qt::Modifier modifier) noexcept
{
return QKeyCombination(modifier, key);
}
constexpr QKeyCombination operator|(Qt::Key key, Qt::Modifiers modifiers) noexcept
{
return QKeyCombination(modifiers, key);
}
constexpr QKeyCombination operator|(Qt::Key key, Qt::KeyboardModifier modifier) noexcept
{
return QKeyCombination(modifier, key);
}
constexpr QKeyCombination operator|(Qt::Key key, Qt::KeyboardModifiers modifiers) noexcept
{
return QKeyCombination(modifiers, key);
}
#if QT_DEPRECATED_SINCE(6, 0)
QT_DEPRECATED_VERSION_X(6, 0, "Use operator| instead")
constexpr QKeyCombination operator+(Qt::Modifier modifier, Qt::Key key) noexcept
{
return QKeyCombination(modifier, key);
}
QT_DEPRECATED_VERSION_X(6, 0, "Use operator| instead")
constexpr QKeyCombination operator+(Qt::Modifiers modifiers, Qt::Key key) noexcept
{
return QKeyCombination(modifiers, key);
}
QT_DEPRECATED_VERSION_X(6, 0, "Use operator| instead")
constexpr QKeyCombination operator+(Qt::KeyboardModifier modifier, Qt::Key key) noexcept
{
return QKeyCombination(modifier, key);
}
QT_DEPRECATED_VERSION_X(6, 0, "Use operator| instead")
constexpr QKeyCombination operator+(Qt::KeyboardModifiers modifiers, Qt::Key key) noexcept
{
return QKeyCombination(modifiers, key);
}
QT_DEPRECATED_VERSION_X(6, 0, "Use operator| instead")
constexpr QKeyCombination operator+(Qt::Key key, Qt::Modifier modifier) noexcept
{
return QKeyCombination(modifier, key);
}
QT_DEPRECATED_VERSION_X(6, 0, "Use operator| instead")
constexpr QKeyCombination operator+(Qt::Key key, Qt::Modifiers modifiers) noexcept
{
return QKeyCombination(modifiers, key);
}
QT_DEPRECATED_VERSION_X(6, 0, "Use operator| instead")
constexpr QKeyCombination operator+(Qt::Key key, Qt::KeyboardModifier modifier) noexcept
{
return QKeyCombination(modifier, key);
}
QT_DEPRECATED_VERSION_X(6, 0, "Use operator| instead")
constexpr QKeyCombination operator+(Qt::Key key, Qt::KeyboardModifiers modifiers) noexcept
{
return QKeyCombination(modifiers, key);
}
#endif
QT_END_NAMESPACE QT_END_NAMESPACE
#endif // QNAMESPACE_H #endif // QNAMESPACE_H

View File

@ -1,6 +1,7 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2020 The Qt Company Ltd.
** Copyright (C) 2020 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the documentation of the Qt Toolkit. ** This file is part of the documentation of the Qt Toolkit.
@ -3246,3 +3247,201 @@
\sa QLabel::picture() \sa QLabel::picture()
\sa QLabel::pixmap() \sa QLabel::pixmap()
*/ */
/*!
\class QKeyCombination
\inmodule QtCore
\since 6.0
\brief The QKeyCombination class stores a combination of a key with optional modifiers.
The QKeyCombination class can be used to represent a combination of a key
with zero or more keyboard modifiers.
\sa QKeySequence
*/
/*!
\fn QKeyCombination::QKeyCombination(Qt::Key key = Qt::Key_unknown) noexcept
Constructs a QKeyCombination object that represents the key \a key
and no modifiers.
\sa key()
*/
/*!
\fn QKeyCombination::QKeyCombination(Qt::Modifiers modifiers, Qt::Key key = Qt::Key_unknown) noexcept
Constructs a QKeyCombination object that represents the combination
of \a key with the modifiers \a modifiers.
\sa key(), keyboardModifiers()
*/
/*!
\fn QKeyCombination::QKeyCombination(Qt::KeyboardModifiers modifiers, Qt::Key key = Qt::Key_unknown) noexcept
Constructs a QKeyCombination object that represents the combination
of \a key with the modifiers \a modifiers.
\sa key(), keyboardModifiers()
*/
/*!
\fn Qt::KeyboardModifiers QKeyCombination::keyboardModifiers() const noexcept
Returns the keyboard modifiers represented by this QKeyCombination object.
\sa key()
*/
/*!
\fn Qt::Key QKeyCombination::key() const noexcept
Returns the key represented by this QKeyCombination object.
\sa keyboardModifiers()
*/
/*!
\fn QKeyCombination QKeyCombination::fromCombined(int combined)
Constructs a QKeyCombination object by extracting the key and the
modifiers out of \a combined, which must be the result of a bitwise
OR between a value of type Qt::Key and value of type
Qt::KeyboardModifiers. toCombined() can be used in order to produce
valid values for \a combined.
\sa toCombined()
*/
/*!
\fn int QKeyCombination::toCombined() const noexcept
Returns an integer value obtained by applying a bitwise OR between
the values of key() and keyboardModifiers() represented
by this object. A QKeyCombination object can be created from the
returned integer value by using fromCombined().
\sa fromCombined(), key(), keyboardModifiers()
*/
#if QT_DEPRECATED_SINCE(6, 0)
/*!
\fn QKeyCombination::operator int() const noexcept
\obsolete
Use toCombined() instead.
*/
#endif
/*!
\fn bool operator==(QKeyCombination lhs, QKeyCombination rhs) noexcept
\relates QKeyCombination
Returns \c true if \a lhs and \a rhs have the same combination
of key and modifiers, and \c false otherwise.
*/
/*!
\fn bool operator!=(QKeyCombination lhs, QKeyCombination rhs) noexcept
\relates QKeyCombination
Returns \c true if \a lhs and \a rhs have different combinations
of key and modifiers, otherwise \c false.
*/
/*!
\fn QKeyCombination operator|(Qt::Modifier modifier, Qt::Key key) noexcept
\fn QKeyCombination operator|(Qt::KeyboardModifier modifier, Qt::Key key) noexcept
\fn QKeyCombination operator|(Qt::Key key, Qt::Modifier modifier) noexcept
\fn QKeyCombination operator|(Qt::Key key, Qt::KeyboardModifier modifier) noexcept
\relates QKeyCombination
Returns a QKeyCombination object that represents the combination
of \a key with the modifier \a modifier.
*/
/*!
\fn QKeyCombination operator|(Qt::Modifiers modifiers, Qt::Key key) noexcept
\fn QKeyCombination operator|(Qt::KeyboardModifiers modifiers, Qt::Key key) noexcept
\fn QKeyCombination operator|(Qt::Key key, Qt::Modifiers modifiers) noexcept
\fn QKeyCombination operator|(Qt::Key key, Qt::KeyboardModifiers modifiers) noexcept
\relates QKeyCombination
Returns a QKeyCombination object that represents the combination
of \a key with the modifiers \a modifiers.
*/
/*!
\fn QKeyCombination operator+(Qt::Modifier modifier, Qt::Key key) noexcept
\fn QKeyCombination operator+(Qt::KeyboardModifier modifier, Qt::Key key) noexcept
\fn QKeyCombination operator+(Qt::Key key, Qt::Modifier modifier) noexcept
\fn QKeyCombination operator+(Qt::Key key, Qt::KeyboardModifier modifier) noexcept
\relates QKeyCombination
\obsolete
Use operator| instead.
Returns a QKeyCombination object that represents the combination
of \a key with the modifier \a modifier.
*/
/*!
\fn QKeyCombination operator+(Qt::Modifiers modifiers, Qt::Key key) noexcept
\fn QKeyCombination operator+(Qt::KeyboardModifiers modifiers, Qt::Key key) noexcept
\fn QKeyCombination operator+(Qt::Key key, Qt::Modifiers modifiers) noexcept
\fn QKeyCombination operator+(Qt::Key key, Qt::KeyboardModifiers modifiers) noexcept
\relates QKeyCombination
\obsolete
Use operator| instead.
Returns a QKeyCombination object that represents the combination
of \a key with the modifiers \a modifiers.
*/
/*!
\fn size_t qHash(QKeyCombination key, size_t seed = 0) noexcept
\relates QKeyCombination
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
#ifndef QT_NO_DEBUG_STREAM
/*!
\fn QDebug operator<<(QDebug debug, QKeyCombination combination)
\relates QKeyCombination
Writes the combination \a combination into the debug object \a debug for
debugging purposes.
\sa {Debugging Techniques}
*/
#endif
#ifndef QT_NO_DATASTREAM
/*!
\fn QDataStream &operator<<(QDataStream &out, QKeyCombination combination)
\relates QKeyCombination
Writes the combination \a combination into the stream \a out.
Returns \a out.
\sa {Serializing Qt Data Types}
*/
/*!
\fn QDataStream &operator>>(QDataStream &in, QKeyCombination &combination)
\relates QKeyCombination
Reads the combination \a combination from the stream \a in.
Returns \a in.
\sa {Serializing Qt Data Types}
*/
#endif

View File

@ -446,6 +446,17 @@ inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
return qt_QMetaEnum_flagDebugOperator_helper(debug, flags); return qt_QMetaEnum_flagDebugOperator_helper(debug, flags);
} }
inline QDebug operator<<(QDebug debug, QKeyCombination combination)
{
QDebugStateSaver saver(debug);
debug.nospace() << "QKeyCombination("
<< combination.keyboardModifiers()
<< ", "
<< combination.key()
<< ")";
return debug;
}
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
// We provide QDebug stream operators for commonly used Core Foundation // We provide QDebug stream operators for commonly used Core Foundation

View File

@ -43,6 +43,7 @@
#include <QtCore/qscopedpointer.h> #include <QtCore/qscopedpointer.h>
#include <QtCore/qiodevicebase.h> #include <QtCore/qiodevicebase.h>
#include <QtCore/qcontainerfwd.h> #include <QtCore/qcontainerfwd.h>
#include <QtCore/qnamespace.h>
#ifdef Status #ifdef Status
#error qdatastream.h must be included before any header file that defines Status #error qdatastream.h must be included before any header file that defines Status
@ -510,6 +511,19 @@ inline QDataStreamIfHasOStreamOperators<T1, T2> operator<<(QDataStream& s, const
} }
#endif #endif
inline QDataStream &operator>>(QDataStream &s, QKeyCombination &combination)
{
int combined;
s >> combined;
combination = QKeyCombination::fromCombined(combined);
return s;
}
inline QDataStream &operator<<(QDataStream &s, QKeyCombination combination)
{
return s << combination.toCombined();
}
#endif // QT_NO_DATASTREAM #endif // QT_NO_DATASTREAM
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -162,6 +162,8 @@ inline Q_DECL_PURE_FUNCTION size_t qHash(const QString &key, size_t seed = 0) no
#endif #endif
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QBitArray &key, size_t seed = 0) noexcept; Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QBitArray &key, size_t seed = 0) noexcept;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QLatin1String key, size_t seed = 0) noexcept; Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QLatin1String key, size_t seed = 0) noexcept;
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(QKeyCombination key, size_t seed = 0) noexcept
{ return qHash(key.toCombined(), seed); }
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(QStringView key, uint chained = 0) noexcept; Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(QStringView key, uint chained = 0) noexcept;
template<typename T> inline size_t qHash(const T &t, size_t seed) template<typename T> inline size_t qHash(const T &t, size_t seed)

View File

@ -62,13 +62,15 @@ struct Wrapper : public QWidget
QKeySequence(QKeySequence::Print); QKeySequence(QKeySequence::Print);
QKeySequence(tr("Ctrl+P")); QKeySequence(tr("Ctrl+P"));
QKeySequence(tr("Ctrl+p")); QKeySequence(tr("Ctrl+p"));
QKeySequence(Qt::CTRL + Qt::Key_P); QKeySequence(Qt::CTRL | Qt::Key_P);
QKeySequence(Qt::CTRL + Qt::Key_P); // deprecated
//! [0] //! [0]
//! [1] //! [1]
QKeySequence(tr("Ctrl+X, Ctrl+C")); QKeySequence(tr("Ctrl+X, Ctrl+C"));
QKeySequence(Qt::CTRL + Qt::Key_X, Qt::CTRL + Qt::Key_C); QKeySequence(Qt::CTRL | Qt::Key_X, Qt::CTRL | Qt::Key_C);
QKeySequence(Qt::CTRL + Qt::Key_X, Qt::CTRL + Qt::Key_C); // deprecated
//! [1] //! [1]
*/ // Wrap non-compilable code snippet */ // Wrap non-compilable code snippet

View File

@ -60,6 +60,6 @@ setKey(QKeySequence()); // no signal emitted
setKey(0x3b1); // Greek letter alpha setKey(0x3b1); // Greek letter alpha
setKey(Qt::Key_D); // 'd', e.g. to delete setKey(Qt::Key_D); // 'd', e.g. to delete
setKey('q'); // 'q', e.g. to quit setKey('q'); // 'q', e.g. to quit
setKey(Qt::CTRL + Qt::Key_P); // Ctrl+P, e.g. to print document setKey(Qt::CTRL | Qt::Key_P); // Ctrl+P, e.g. to print document
setKey("Ctrl+P"); // Ctrl+P, e.g. to print document setKey("Ctrl+P"); // Ctrl+P, e.g. to print document
//! [1] //! [1]

View File

@ -1285,6 +1285,15 @@ Qt::KeyboardModifiers QKeyEvent::modifiers() const
return QInputEvent::modifiers(); return QInputEvent::modifiers();
} }
/*!
\fn QKeyCombination QKeyEvent::keyCombination() const
Returns a QKeyCombination object containing both the key() and
the modifiers() carried by this event.
\since 6.0
*/
#if QT_CONFIG(shortcut) #if QT_CONFIG(shortcut)
/*! /*!
\fn bool QKeyEvent::matches(QKeySequence::StandardKey key) const \fn bool QKeyEvent::matches(QKeySequence::StandardKey key) const

View File

@ -480,6 +480,10 @@ public:
bool matches(QKeySequence::StandardKey key) const; bool matches(QKeySequence::StandardKey key) const;
#endif #endif
Qt::KeyboardModifiers modifiers() const; Qt::KeyboardModifiers modifiers() const;
QKeyCombination keyCombination() const
{
return QKeyCombination(modifiers(), Qt::Key(m_key));
}
inline QString text() const { return m_text; } inline QString text() const { return m_text; }
inline bool isAutoRepeat() const { return m_autoRepeat; } inline bool isAutoRepeat() const { return m_autoRepeat; }
inline int count() const { return int(m_count); } inline int count() const { return int(m_count); }

View File

@ -99,7 +99,6 @@ struct GuiTypesFilter {
}; };
}; };
static const struct : QMetaTypeModuleHelper static const struct : QMetaTypeModuleHelper
{ {
#define QT_IMPL_METATYPEINTERFACE_GUI_TYPES(MetaTypeName, MetaTypeId, RealName) \ #define QT_IMPL_METATYPEINTERFACE_GUI_TYPES(MetaTypeName, MetaTypeId, RealName) \
@ -146,7 +145,7 @@ static const struct : QMetaTypeModuleHelper
); );
QMETATYPE_CONVERTER(QKeySequence, QString, result = source; return true;); QMETATYPE_CONVERTER(QKeySequence, QString, result = source; return true;);
QMETATYPE_CONVERTER(Int, QKeySequence, QMETATYPE_CONVERTER(Int, QKeySequence,
result = source.isEmpty() ? 0 : source[0]; result = source.isEmpty() ? 0 : source[0].toCombined();
return true; return true;
); );
QMETATYPE_CONVERTER(QKeySequence, Int, result = source; return true;); QMETATYPE_CONVERTER(QKeySequence, Int, result = source; return true;);

View File

@ -71,17 +71,20 @@ QKeyMapper::~QKeyMapper()
{ {
} }
QList<int> QKeyMapper::possibleKeys(QKeyEvent *e) static QList<int> extractKeyFromEvent(QKeyEvent *e)
{ {
QList<int> result; QList<int> result;
if (e->key() && (e->key() != Qt::Key_unknown))
result << e->keyCombination().toCombined();
else if (!e->text().isEmpty())
result << int(e->text().at(0).unicode() + (int)e->modifiers());
return result;
}
if (!e->nativeScanCode()) { QList<int> QKeyMapper::possibleKeys(QKeyEvent *e)
if (e->key() && (e->key() != Qt::Key_unknown)) {
result << int(e->key() + e->modifiers()); if (!e->nativeScanCode())
else if (!e->text().isEmpty()) return extractKeyFromEvent(e);
result << int(e->text().at(0).unicode() + e->modifiers());
return result;
}
return instance()->d_func()->possibleKeys(e); return instance()->d_func()->possibleKeys(e);
} }
@ -132,11 +135,7 @@ QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *e)
if (!result.isEmpty()) if (!result.isEmpty())
return result; return result;
if (e->key() && (e->key() != Qt::Key_unknown)) return extractKeyFromEvent(e);
result << int(e->key() + e->modifiers());
else if (!e->text().isEmpty())
result << int(e->text().at(0).unicode() + e->modifiers());
return result;
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -869,6 +869,17 @@ QKeySequence::QKeySequence(int k1, int k2, int k3, int k4)
d->key[3] = k4; d->key[3] = k4;
} }
/*!
Constructs a key sequence with up to 4 keys \a k1, \a k2,
\a k3 and \a k4.
\sa QKeyCombination
*/
QKeySequence::QKeySequence(QKeyCombination k1, QKeyCombination k2, QKeyCombination k3, QKeyCombination k4)
: QKeySequence(k1.toCombined(), k2.toCombined(), k3.toCombined(), k4.toCombined())
{
}
/*! /*!
Copy constructor. Makes a copy of \a keysequence. Copy constructor. Makes a copy of \a keysequence.
*/ */
@ -908,11 +919,11 @@ QKeySequence::~QKeySequence()
delivery. delivery.
*/ */
void QKeySequence::setKey(int key, int index) void QKeySequence::setKey(QKeyCombination key, int index)
{ {
Q_ASSERT_X(index >= 0 && index < QKeySequencePrivate::MaxKeyCount, "QKeySequence::setKey", "index out of range"); Q_ASSERT_X(index >= 0 && index < QKeySequencePrivate::MaxKeyCount, "QKeySequence::setKey", "index out of range");
qAtomicDetach(d); qAtomicDetach(d);
d->key[index] = key; d->key[index] = key.toCombined();
} }
static_assert(QKeySequencePrivate::MaxKeyCount == 4, "Change docs below"); static_assert(QKeySequencePrivate::MaxKeyCount == 4, "Change docs below");
@ -967,7 +978,7 @@ QKeySequence QKeySequence::mnemonic(const QString &text)
if (c.isPrint()) { if (c.isPrint()) {
if (!found) { if (!found) {
c = c.toUpper(); c = c.toUpper();
ret = QKeySequence(c.unicode() + Qt::ALT); ret = QKeySequence(QKeyCombination(Qt::ALT, Qt::Key(c.unicode())));
#ifdef QT_NO_DEBUG #ifdef QT_NO_DEBUG
return ret; return ret;
#else #else
@ -1377,8 +1388,8 @@ QKeySequence::SequenceMatch QKeySequence::matches(const QKeySequence &seq) const
SequenceMatch match = (userN == seqN ? ExactMatch : PartialMatch); SequenceMatch match = (userN == seqN ? ExactMatch : PartialMatch);
for (uint i = 0; i < userN; ++i) { for (uint i = 0; i < userN; ++i) {
int userKey = (*this)[i], QKeyCombination userKey = (*this)[i],
sequenceKey = seq[i]; sequenceKey = seq[i];
if (userKey != sequenceKey) if (userKey != sequenceKey)
return NoMatch; return NoMatch;
} }
@ -1397,10 +1408,10 @@ QKeySequence::operator QVariant() const
Returns a reference to the element at position \a index in the key Returns a reference to the element at position \a index in the key
sequence. This can only be used to read an element. sequence. This can only be used to read an element.
*/ */
int QKeySequence::operator[](uint index) const QKeyCombination QKeySequence::operator[](uint index) const
{ {
Q_ASSERT_X(index < QKeySequencePrivate::MaxKeyCount, "QKeySequence::operator[]", "index out of range"); Q_ASSERT_X(index < QKeySequencePrivate::MaxKeyCount, "QKeySequence::operator[]", "index out of range");
return d->key[index]; return QKeyCombination::fromCombined(d->key[index]);
} }

View File

@ -155,6 +155,10 @@ public:
QKeySequence(); QKeySequence();
QKeySequence(const QString &key, SequenceFormat format = NativeText); QKeySequence(const QString &key, SequenceFormat format = NativeText);
QKeySequence(int k1, int k2 = 0, int k3 = 0, int k4 = 0); QKeySequence(int k1, int k2 = 0, int k3 = 0, int k4 = 0);
QKeySequence(QKeyCombination k1,
QKeyCombination k2 = QKeyCombination::fromCombined(0),
QKeyCombination k3 = QKeyCombination::fromCombined(0),
QKeyCombination k4 = QKeyCombination::fromCombined(0));
QKeySequence(const QKeySequence &ks); QKeySequence(const QKeySequence &ks);
QKeySequence(StandardKey key); QKeySequence(StandardKey key);
~QKeySequence(); ~QKeySequence();
@ -179,7 +183,7 @@ public:
static QList<QKeySequence> keyBindings(StandardKey key); static QList<QKeySequence> keyBindings(StandardKey key);
operator QVariant() const; operator QVariant() const;
int operator[](uint i) const; QKeyCombination operator[](uint i) const;
QKeySequence &operator=(const QKeySequence &other); QKeySequence &operator=(const QKeySequence &other);
QKeySequence &operator=(QKeySequence &&other) noexcept { swap(other); return *this; } QKeySequence &operator=(QKeySequence &&other) noexcept { swap(other); return *this; }
void swap(QKeySequence &other) noexcept { qSwap(d, other.d); } void swap(QKeySequence &other) noexcept { qSwap(d, other.d); }
@ -201,7 +205,7 @@ private:
static QString encodeString(int key); static QString encodeString(int key);
int assign(const QString &str); int assign(const QString &str);
int assign(const QString &str, SequenceFormat format); int assign(const QString &str, SequenceFormat format);
void setKey(int key, int index); void setKey(QKeyCombination key, int index);
QKeySequencePrivate *d; QKeySequencePrivate *d;

View File

@ -64,7 +64,7 @@ struct QKeyBinding
{ {
QKeySequence::StandardKey standardKey; QKeySequence::StandardKey standardKey;
uchar priority; uchar priority;
uint shortcut; QKeyCombination shortcut;
uint platform; uint platform;
}; };

View File

@ -645,7 +645,7 @@ QList<QKeySequence> QPlatformTheme::keyBindings(QKeySequence::StandardKey key) c
if (!(it->platform & platform)) if (!(it->platform & platform))
continue; continue;
uint shortcut = it->shortcut; uint shortcut = it->shortcut.toCombined();
if (it->priority > 0) if (it->priority > 0)
list.prepend(QKeySequence(shortcut)); list.prepend(QKeySequence(shortcut));

View File

@ -543,12 +543,12 @@ void QShortcutMap::createNewSequences(QKeyEvent *e, QList<QKeySequence> &ksl, in
curKsl.setKey(curSeq[2], 2); curKsl.setKey(curSeq[2], 2);
curKsl.setKey(curSeq[3], 3); curKsl.setKey(curSeq[3], 3);
} else { } else {
curKsl.setKey(0, 0); curKsl.setKey(QKeyCombination::fromCombined(0), 0);
curKsl.setKey(0, 1); curKsl.setKey(QKeyCombination::fromCombined(0), 1);
curKsl.setKey(0, 2); curKsl.setKey(QKeyCombination::fromCombined(0), 2);
curKsl.setKey(0, 3); curKsl.setKey(QKeyCombination::fromCombined(0), 3);
} }
curKsl.setKey(possibleKeys.at(pkNum) & ~ignoredModifiers, index); curKsl.setKey(QKeyCombination::fromCombined(possibleKeys.at(pkNum) & ~ignoredModifiers), index);
} }
} }
} }
@ -574,8 +574,8 @@ QKeySequence::SequenceMatch QShortcutMap::matches(const QKeySequence &seq1,
: QKeySequence::PartialMatch); : QKeySequence::PartialMatch);
for (uint i = 0; i < userN; ++i) { for (uint i = 0; i < userN; ++i) {
int userKey = seq1[i], int userKey = seq1[i].toCombined(),
sequenceKey = seq2[i]; sequenceKey = seq2[i].toCombined();
if ((userKey & Qt::Key_unknown) == Qt::Key_hyphen) if ((userKey & Qt::Key_unknown) == Qt::Key_hyphen)
userKey = (userKey & Qt::KeyboardModifierMask) | Qt::Key_Minus; userKey = (userKey & Qt::KeyboardModifierMask) | Qt::Key_Minus;
if ((sequenceKey & Qt::Key_unknown) == Qt::Key_hyphen) if ((sequenceKey & Qt::Key_unknown) == Qt::Key_hyphen)

View File

@ -241,7 +241,7 @@ QDBusMenuShortcut QDBusMenuItem::convertKeySequence(const QKeySequence &sequence
QDBusMenuShortcut shortcut; QDBusMenuShortcut shortcut;
for (int i = 0; i < sequence.count(); ++i) { for (int i = 0; i < sequence.count(); ++i) {
QStringList tokens; QStringList tokens;
int key = sequence[i]; int key = sequence[i].toCombined();
if (key & Qt::MetaModifier) if (key & Qt::MetaModifier)
tokens << QStringLiteral("Super"); tokens << QStringLiteral("Super");
if (key & Qt::ControlModifier) if (key & Qt::ControlModifier)

View File

@ -656,7 +656,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
int baseQtKey = keysymToQtKey_internal(sym, modifiers, queryState, keycode, superAsMeta, hyperAsMeta); int baseQtKey = keysymToQtKey_internal(sym, modifiers, queryState, keycode, superAsMeta, hyperAsMeta);
if (baseQtKey) if (baseQtKey)
result += (baseQtKey + modifiers); result += (baseQtKey + int(modifiers));
xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(keymap, "Shift"); xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(keymap, "Shift");
xkb_mod_index_t altMod = xkb_keymap_mod_get_index(keymap, "Alt"); xkb_mod_index_t altMod = xkb_keymap_mod_get_index(keymap, "Alt");
@ -711,7 +711,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
if (ambiguous) if (ambiguous)
continue; continue;
result += (qtKey + mods); result += (qtKey + int(mods));
} }
} }

View File

@ -172,8 +172,8 @@ namespace QTest
Q_DECL_UNUSED inline static void keySequence(QWindow *window, const QKeySequence &keySequence) Q_DECL_UNUSED inline static void keySequence(QWindow *window, const QKeySequence &keySequence)
{ {
for (int i = 0; i < keySequence.count(); ++i) { for (int i = 0; i < keySequence.count(); ++i) {
const Qt::Key key = Qt::Key(keySequence[i] & ~Qt::KeyboardModifierMask); const Qt::Key key = keySequence[i].key();
const Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(keySequence[i] & Qt::KeyboardModifierMask); const Qt::KeyboardModifiers modifiers = keySequence[i].keyboardModifiers();
keyClick(window, key, modifiers); keyClick(window, key, modifiers);
} }
} }
@ -313,8 +313,8 @@ namespace QTest
inline static void keySequence(QWidget *widget, const QKeySequence &keySequence) inline static void keySequence(QWidget *widget, const QKeySequence &keySequence)
{ {
for (int i = 0; i < keySequence.count(); ++i) { for (int i = 0; i < keySequence.count(); ++i) {
const Qt::Key key = Qt::Key(keySequence[i] & ~Qt::KeyboardModifierMask); const Qt::Key key = keySequence[i].key();
const Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(keySequence[i] & Qt::KeyboardModifierMask); const Qt::KeyboardModifiers modifiers = keySequence[i].keyboardModifiers();
keyClick(widget, key, modifiers); keyClick(widget, key, modifiers);
} }
} }

View File

@ -3287,7 +3287,7 @@ void QFileDialogPrivate::createMenuActions()
QAction *goHomeAction = new QAction(q); QAction *goHomeAction = new QAction(q);
#ifndef QT_NO_SHORTCUT #ifndef QT_NO_SHORTCUT
goHomeAction->setShortcut(Qt::CTRL + Qt::Key_H + Qt::SHIFT); goHomeAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_H);
#endif #endif
QObject::connect(goHomeAction, SIGNAL(triggered()), q, SLOT(_q_goHome())); QObject::connect(goHomeAction, SIGNAL(triggered()), q, SLOT(_q_goHome()));
q->addAction(goHomeAction); q->addAction(goHomeAction);

View File

@ -1522,7 +1522,7 @@ void QMessageBox::keyPressEvent(QKeyEvent *e)
const QList<QAbstractButton *> buttons = d->buttonBox->buttons(); const QList<QAbstractButton *> buttons = d->buttonBox->buttons();
for (auto *pb : buttons) { for (auto *pb : buttons) {
QKeySequence shortcut = pb->shortcut(); QKeySequence shortcut = pb->shortcut();
if (!shortcut.isEmpty() && key == int(shortcut[0] & ~Qt::MODIFIER_MASK)) { if (!shortcut.isEmpty() && key == shortcut[0].key()) {
pb->animateClick(); pb->animateClick();
return; return;
} }

View File

@ -510,7 +510,7 @@ QWhatsThisAction::QWhatsThisAction(QObject *parent) : QAction(tr("What's This?")
setCheckable(true); setCheckable(true);
connect(this, SIGNAL(triggered()), this, SLOT(actionTriggered())); connect(this, SIGNAL(triggered()), this, SLOT(actionTriggered()));
#ifndef QT_NO_SHORTCUT #ifndef QT_NO_SHORTCUT
setShortcut(Qt::ShiftModifier + Qt::Key_F1); setShortcut(Qt::ShiftModifier | Qt::Key_F1);
#endif #endif
} }

View File

@ -63,7 +63,7 @@ void QKeySequenceEditPrivate::init()
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(lineEdit); layout->addWidget(lineEdit);
key[0] = key[1] = key[2] = key[3] = 0; std::fill_n(key, QKeySequencePrivate::MaxKeyCount, QKeyCombination::fromCombined(0));
lineEdit->setFocusProxy(q); lineEdit->setFocusProxy(q);
lineEdit->installEventFilter(q); lineEdit->installEventFilter(q);
@ -186,7 +186,7 @@ void QKeySequenceEdit::setKeySequence(const QKeySequence &keySequence)
d->keySequence = keySequence; d->keySequence = keySequence;
d->key[0] = d->key[1] = d->key[2] = d->key[3] = 0; d->key[0] = d->key[1] = d->key[2] = d->key[3] = QKeyCombination::fromCombined(0);
d->keyNum = keySequence.count(); d->keyNum = keySequence.count();
for (int i = 0; i < d->keyNum; ++i) for (int i = 0; i < d->keyNum; ++i)
d->key[i] = keySequence[i]; d->key[i] = keySequence[i];
@ -286,7 +286,7 @@ void QKeySequenceEdit::keyPressEvent(QKeyEvent *e)
} }
d->key[d->keyNum] = nextKey; d->key[d->keyNum] = QKeyCombination::fromCombined(nextKey);
d->keyNum++; d->keyNum++;
QKeySequence key(d->key[0], d->key[1], d->key[2], d->key[3]); QKeySequence key(d->key[0], d->key[1], d->key[2], d->key[3]);

View File

@ -76,7 +76,7 @@ public:
QLineEdit *lineEdit; QLineEdit *lineEdit;
QKeySequence keySequence; QKeySequence keySequence;
int keyNum; int keyNum;
int key[QKeySequencePrivate::MaxKeyCount]; QKeyCombination key[QKeySequencePrivate::MaxKeyCount];
int prevKey; int prevKey;
int releaseTimer; int releaseTimer;
}; };

View File

@ -3406,7 +3406,7 @@ void QMenu::keyPressEvent(QKeyEvent *e)
continue; continue;
QAction *act = d->actions.at(i); QAction *act = d->actions.at(i);
QKeySequence sequence = QKeySequence::mnemonic(act->text()); QKeySequence sequence = QKeySequence::mnemonic(act->text());
int key = sequence[0] & 0xffff; int key = sequence[0].toCombined() & 0xffff; // suspicious
if (key == c.unicode()) { if (key == c.unicode()) {
clashCount++; clashCount++;
if (!first) if (!first)

View File

@ -11,6 +11,7 @@ add_subdirectory(qlogging)
add_subdirectory(qtendian) add_subdirectory(qtendian)
add_subdirectory(qglobalstatic) add_subdirectory(qglobalstatic)
add_subdirectory(qhooks) add_subdirectory(qhooks)
add_subdirectory(qkeycombination)
if(WIN32) if(WIN32)
add_subdirectory(qwinregistry) add_subdirectory(qwinregistry)
endif() endif()

View File

@ -6,6 +6,7 @@ SUBDIRS=\
qglobal \ qglobal \
qnumeric \ qnumeric \
qfloat16 \ qfloat16 \
qkeycombination \
qrandomgenerator \ qrandomgenerator \
qlogging \ qlogging \
qtendian \ qtendian \

View File

@ -0,0 +1 @@
tst_qkeycombination

View File

@ -0,0 +1,10 @@
# Generated from qkeycombination.pro.
#####################################################################
## tst_qkeycombination Test:
#####################################################################
qt_add_test(tst_qkeycombination
SOURCES
tst_qkeycombination.cpp
)

View File

@ -0,0 +1,5 @@
CONFIG += testcase
TARGET = tst_qkeycombination
QT = core testlib
SOURCES = tst_qkeycombination.cpp

View File

@ -0,0 +1,317 @@
/****************************************************************************
**
** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QObject>
#include <QTest>
class tst_QKeyCombination : public QObject
{
Q_OBJECT
private slots:
void construction();
void operator_eq();
void operator_or();
};
constexpr int bitwiseOr()
{
return 0;
}
template <typename ...T>
constexpr auto bitwiseOr(T ... args)
{
return (... | ((int)args));
}
void tst_QKeyCombination::construction()
{
{
QKeyCombination combination;
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers{});
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::Key_unknown));
}
{
QKeyCombination combination(Qt::CTRL); // explicit
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::ControlModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::ControlModifier, Qt::Key_unknown));
}
{
QKeyCombination combination(Qt::SHIFT); // explicit
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::ShiftModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::ShiftModifier, Qt::Key_unknown));
}
{
QKeyCombination combination(Qt::AltModifier); // explicit
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::AltModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::AltModifier, Qt::Key_unknown));
}
{
QKeyCombination combination(Qt::AltModifier | Qt::ControlModifier); // explicit
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::AltModifier | Qt::ControlModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::AltModifier, Qt::ControlModifier, Qt::Key_unknown));
}
{
QKeyCombination combination = Qt::Key_A; // implicit
QCOMPARE(combination.key(), Qt::Key_A);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers{});
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::Key_A));
}
{
QKeyCombination combination = Qt::Key_F1; // implicit
QCOMPARE(combination.key(), Qt::Key_F1);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers{});
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::Key_F1));
}
{
QKeyCombination combination(Qt::SHIFT, Qt::Key_F1);
QCOMPARE(combination.key(), Qt::Key_F1);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::ShiftModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::SHIFT, Qt::Key_F1));
}
{
QKeyCombination combination(Qt::SHIFT | Qt::CTRL, Qt::Key_F1);
QCOMPARE(combination.key(), Qt::Key_F1);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::ShiftModifier | Qt::ControlModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::SHIFT, Qt::CTRL, Qt::Key_F1));
}
{
QKeyCombination combination(Qt::AltModifier, Qt::Key_F1);
QCOMPARE(combination.key(), Qt::Key_F1);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::AltModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::AltModifier, Qt::Key_F1));
}
// corner cases
{
QKeyCombination combination = Qt::Key_Alt;
QCOMPARE(combination.key(), Qt::Key_Alt);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers{});
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::Key_Alt));
}
{
QKeyCombination combination(Qt::ALT, Qt::Key_Alt);
QCOMPARE(combination.key(), Qt::Key_Alt);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::AltModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::ALT, Qt::Key_Alt));
}
{
QKeyCombination combination(Qt::Key_unknown);
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers{});
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::Key_unknown));
}
{
QKeyCombination combination(Qt::CTRL | Qt::SHIFT, Qt::Key_unknown);
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::ControlModifier | Qt::ShiftModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::CTRL, Qt::SHIFT, Qt::Key_unknown));
}
}
void tst_QKeyCombination::operator_eq()
{
// default
{
QKeyCombination a, b;
QVERIFY(a == b);
QVERIFY(!(a != b));
}
// key only
{
QKeyCombination a;
QKeyCombination b(Qt::Key_X);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::Key_Y);
QKeyCombination b;
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::Key_Y);
QKeyCombination b(Qt::Key_X);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::Key_F1);
QKeyCombination b(Qt::Key_F1);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
// modifier only
{
QKeyCombination a;
QKeyCombination b(Qt::CTRL);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::CTRL);
QKeyCombination b;
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::CTRL);
QKeyCombination b(Qt::SHIFT);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::CTRL);
QKeyCombination b(Qt::CTRL);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
QKeyCombination a(Qt::CTRL);
QKeyCombination b(Qt::ControlModifier);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
QKeyCombination a(Qt::ControlModifier);
QKeyCombination b(Qt::CTRL);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
QKeyCombination a(Qt::ControlModifier);
QKeyCombination b(Qt::ControlModifier);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
// key and modifier
{
QKeyCombination a(Qt::Key_A);
QKeyCombination b(Qt::SHIFT, Qt::Key_A);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::CTRL, Qt::Key_A);
QKeyCombination b(Qt::SHIFT, Qt::Key_A);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::SHIFT, Qt::Key_A);
QKeyCombination b(Qt::SHIFT, Qt::Key_A);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
QKeyCombination a(Qt::SHIFT, Qt::Key_A);
QKeyCombination b(Qt::SHIFT, Qt::Key_Escape);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::SHIFT, Qt::Key_A);
QKeyCombination b(Qt::ShiftModifier, Qt::Key_A);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
QKeyCombination a(Qt::SHIFT | Qt::CTRL, Qt::Key_A);
QKeyCombination b(Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_A);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
// corner cases
{
QKeyCombination a(Qt::CTRL);
QKeyCombination b(Qt::Key_Control);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::ALT);
QKeyCombination b(Qt::Key_Alt);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
}
void tst_QKeyCombination::operator_or()
{
// note tha operator+ between enumerators of the same enumeration
// yields int, so one can't do
// Qt::SHIFT + Qt::CTRL + Qt::Key_A
// but one can do
// Qt::SHIFT | Qt::CTRL | Qt::Key_A
QCOMPARE(Qt::SHIFT | Qt::Key_A, QKeyCombination(Qt::SHIFT, Qt::Key_A));
QCOMPARE(Qt::AltModifier | Qt::Key_F1, QKeyCombination(Qt::AltModifier, Qt::Key_F1));
QCOMPARE(Qt::SHIFT | Qt::ALT | Qt::Key_F1, QKeyCombination(Qt::SHIFT | Qt::ALT, Qt::Key_F1));
QCOMPARE(Qt::ControlModifier | Qt::Key_Escape, QKeyCombination(Qt::ControlModifier, Qt::Key_Escape));
}
QTEST_APPLESS_MAIN(tst_QKeyCombination)
#include "tst_qkeycombination.moc"

View File

@ -181,8 +181,9 @@ void tst_QKeySequence::swap()
QKeySequence ks1(Qt::CTRL+Qt::Key_O); QKeySequence ks1(Qt::CTRL+Qt::Key_O);
QKeySequence ks2(Qt::CTRL+Qt::Key_L); QKeySequence ks2(Qt::CTRL+Qt::Key_L);
ks1.swap(ks2); ks1.swap(ks2);
QCOMPARE(ks1[0], int(Qt::CTRL+Qt::Key_L));
QCOMPARE(ks2[0], int(Qt::CTRL+Qt::Key_O)); QCOMPARE(ks1[0], Qt::CTRL+Qt::Key_L);
QCOMPARE(ks2[0], Qt::CTRL+Qt::Key_O);
} }
void tst_QKeySequence::operatorQString_data() void tst_QKeySequence::operatorQString_data()