I'm using PyQt5. When I write a keyPressEvent handler, I would like to be able to print, for debugging purposes, a human-readable description of what keys were pressed. I want to be able to print such a thing no matter what, regardless of how many keys were pressed in the event, or whether they were modifiers or "regular" keys.
I have seen this previous question in which the accepted answer (using C++) suggests creating a QKeySequence and using its .toString
method. I can do this like this:
def keyPressEvent(self, event):
print("got a key event of ", QKeySequence(event.key()).toString())
However, this does not always work. For instance, if I press the Shift key, it will result in an encoding error when I try to output (or if I try to encode it to UTF-8). This seems to be because QKeySequence does not work on isolated modifier keys:
>>> QKeySequence(Qt.Key_Shift).toString().encode('unicode-escape')
b'\\u17c0\\udc20'
It gives gibberish instead of what I would expect, namely "Shift". It works if I use Qt.SHIFT
(sort of, in that it gives "Shift+"), but that is of no use, because Qt.SHIFT
is not what I get in event.key()
if I press the Shift key.
How can I get Qt to give me a printable representation of anything that might ever be the value of event.key()
, where event
is a QKeyEvent?
To deal with the specific question:
How can I get Qt to give me a printable representation of anything that might ever be the value of event.key(), where event is a QKeyEvent?
The first things to note is that event.key()
returns an int
, rather than a Qt.Key
. This is simply because the key can be any unicode value whatsoever. As a consequnce of this, it is not really feasible to give a printable representation of literally anything, since not every unicode key is printable, and it is impractical to enumerate them all.
The only API Qt provides for this is the QKeySequnce
class. However, as you have found, it does not handle all inputs in the way you want. So you will have to roll your own solution.
It might be tempting to use QMetaEnum
to convert key values to their names wherever possible. However, this won't work here, because there is no staticMetaObject
for the Qt
object, and PyQt does not provide anything like qt_getQtMetaObject
. It also doesn't currently implement QMetaEnum.fromType
(although this is likely to change in future versions).
So the only available solution is to use normal python introspection to build a mapping, and build up a printable representation from that.
Here is a basic demo (only tested on Linux):
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget
keymap = {}
for key, value in vars(Qt).items():
if isinstance(value, Qt.Key):
keymap[value] = key.partition('_')[2]
modmap = {
Qt.ControlModifier: keymap[Qt.Key_Control],
Qt.AltModifier: keymap[Qt.Key_Alt],
Qt.ShiftModifier: keymap[Qt.Key_Shift],
Qt.MetaModifier: keymap[Qt.Key_Meta],
Qt.GroupSwitchModifier: keymap[Qt.Key_AltGr],
Qt.KeypadModifier: keymap[Qt.Key_NumLock],
}
def keyevent_to_string(event):
sequence = []
for modifier, text in modmap.items():
if event.modifiers() & modifier:
sequence.append(text)
key = keymap.get(event.key(), event.text())
if key not in sequence:
sequence.append(key)
return '+'.join(sequence)
class Window(QWidget):
def keyPressEvent(self, event):
print(keyevent_to_string(event))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With