Home > Software design >  Store all keyboard keys currently being pressed in PyQt5
Store all keyboard keys currently being pressed in PyQt5

Time:01-10

I'm trying to write a PyQt5 GUI that captures all keyboard keys that are currently being pressed. Based on this answer, I've tried the following minimal code:

import sys

from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QEvent

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        QApplication.instance().installEventFilter(self)

        self.pressedKeys = []

    def eventFilter(self, source, event):
        if event.type() == QEvent.KeyPress:
            if int(event.key()) not in self.pressedKeys:
                self.pressedKeys.append(int(event.key()))
                print(self.pressedKeys)
        elif event.type() == QEvent.KeyRelease:
            if int(event.key()) in self.pressedKeys:
                self.pressedKeys.remove(int(event.key()))
                print(self.pressedKeys)

        return super().eventFilter(source, event)


if __name__ == "__main__":
    app = QApplication(sys.argv)

    demo = MainWindow()
    demo.show()

    sys.exit(app.exec_())

When I run this, if I hold down a key the output list keeps flipping back and forth between one containing the key value and being empty. Similarly, holding down multiple keys adds the keys to the list, but alternates back and forth between containing and removing the final key that I have pressed. It seems that if I hold down keys the KeyRelease event still keeps getting triggered for the last key I pressed.

Is there are way to hold all current key presses in PyQt5, or should I use a different package (e.g., using one or other of the packages suggested in this question)?

Note, I've also tried:

import sys

from PyQt5.QtWidgets import QApplication, QWidget

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.pressedKeys = []

    def keyPressEvent(self, event):
        if int(event.key()) not in self.pressedKeys:
            self.pressedKeys.append(int(event.key()))
            print(self.pressedKeys)

    def keyReleaseEvent(self, event):
        if int(event.key()) in self.pressedKeys:
            self.pressedKeys.remove(int(event.key()))
            print(self.pressedKeys)

if __name__ == "__main__":
    app = QApplication(sys.argv)

    demo = MainWindow()
    demo.show()

    sys.exit(app.exec_())

which results in pretty much the same behaviour.

CodePudding user response:

Physical keyboards have the "autorepeat" feature, which allows simulating multiple pressure of a key while keeping it pressed.

This results in having multiple press/release events while a standard key (usually, not modifiers) is down and until it's physically released, with a rate normally set for the system.

You can check if the event is actually a physical press/release or if it isAutoRepeat():

    def eventFilter(self, source, event):
        if event.type() == QEvent.KeyPress:
            if not event.isAutoRepeat() and int(event.key()) not in self.pressedKeys:
                self.pressedKeys.append(int(event.key()))
                print(self.pressedKeys)
        elif event.type() == QEvent.KeyRelease:
            if not event.isAutoRepeat() and int(event.key()) in self.pressedKeys:
                self.pressedKeys.remove(int(event.key()))
                print(self.pressedKeys)

        return super().eventFilter(source, event)
  • Related