Get the “name” of a key from QKeyEvent in Qt

2019-06-15 14:37发布

问题:

Is there an easy way of getting the name of a key (so something like "uparrow" from a key event instead of just getting the key code "16777235")? Do I have to make a list of key names myself?

回答1:

Using human-readable names in your code

You can use the Qt::Key enum, or get the key as a string with QKeyEvent::text().

From QKeyEvent documentation:

int QKeyEvent::key () const

Returns the code of the key that was pressed or released.

See Qt::Key for the list of keyboard codes. These codes are independent of the underlying window system. Note that this function does not distinguish between capital and non-capital letters, use the text() function (returning the Unicode text the key generated) for this purpose.

...

Qt::Key is an enum that maps numeric key IDs (like the return value of QKeyEvent::key()) to programmer-readable names like Qt::Key_Up.

If you only care about alphanumeric keys, you can also use QKeyEvent::text() to get the value:

QString QKeyEvent::text () const

Returns the Unicode text that this key generated. The text returned can be an empty string in cases where modifier keys, such as Shift, Control, Alt, and Meta, are being pressed or released. In such cases key() will contain a valid value.

See also Qt::WA_KeyCompression.

Displaying human-readable names to the user

Use QKeySequence::toString() or build your own table of "nice" names.

The easiest way to get human-readable key names to show to the user is to use QKeySequence::toString().

Here's an example:

Qt::Key key = Qt::Key_Up;
qDebug() << QKeySequence(key).toString(); // prints "Up"

If you don't like the names that QKeySequence uses (e.g. you want to use "Up Arrow" instead of "Up"), you'll need to make your data table to remap the enum values to your preferred names.



回答2:

Another approach leverages the Qt metaobject system and the introspection into most enumerations in the Qt namespace. This works in both Qt 4 and Qt 5.

// https://github.com/KubaO/stackoverflown/tree/master/questions/keyname-21764138
#include <QMetaEnum>

namespace SO {
enum KeyNameOption { KeyNameNone = 0, AppendArrow = 1 };
Q_DECLARE_FLAGS(KeyNameOptions, KeyNameOption)
}
QString keyName(int index, SO::KeyNameOptions opt = {}) {
   constexpr static auto const getEnum = [](const char *name) {
      int enumIndex = qt_getQtMetaObject()->indexOfEnumerator(name);
      return qt_getQtMetaObject()->enumerator(enumIndex);
   };
   static const auto keyEnum = getEnum("Key");
   static const auto modifierEnum = getEnum("KeyboardModifiers");

   auto name = modifierEnum.valueToKeys(index & Qt::KeyboardModifierMask);
   index &= ~Qt::KeyboardModifierMask;

   if (name == "NoModifier")
      name.clear();
   else {
      name.replace('|', '+');
      name.replace("Modifier", "");
      name.append('+');
   }

   auto keyName = keyEnum.valueToKey(index);
   if (keyName)
      name.append(keyName + 4);
   if ((opt & SO::AppendArrow) && index >= Qt::Key_Left && index <= Qt::Key_Down)
      name.append(" Arrow");
   return QLatin1String(name);
}

int main() {
   Q_ASSERT(keyName(Qt::Key_Tab) == "Tab");
   Q_ASSERT(keyName(Qt::ShiftModifier | Qt::Key_Up, SO::AppendArrow) == "Shift+Up Arrow");
   Q_ASSERT(keyName(Qt::AltModifier | Qt::Key_Down) == "Alt+Down");
}

You'd then use it in, say, keyPressEvent, as follows:

void MyWidget::keyPressEvent(QKeyEvent * ev) {
  qDebug() << keyName(ev->key());
}