PyQt4 - Holding down a key detected as frequent press and release?
Asked Answered
S

1

5

I've noticed some unusual behavior when the QApplication processes key events, which jeopardizes a small game I'd hoped to make.

Holding down a key causes the keyPressEvent and then keyReleaseEvent methods to be repeatedly (and very frequently) called, rather than triggering keyPressEvent once and waiting for the key to be released to trigger the other (which is the desired and admittedly expected behavior).

This causes huge performance issues, to the extent where holding down multiple keys causes some to be completely ignored by the program, presumably because the event queue is suffering.

This program demonstrates the repeated calling:

from PyQt4 import QtGui
import sys

class Window(QtGui.QWidget):

    def __init__(self):
        super(Window, self).__init__()

    def keyPressEvent(self, event):
        print 'PRESSED'
        event.accept()

    def keyReleaseEvent(self, event):
        print 'RELEASED'
        event.accept()

app = QtGui.QApplication(sys.argv)
Window().show()
sys.exit(app.exec_())

This program (a silly graphical thing I was using to test the gaming potential of Qt) demonstrates the ignoring of new pressed keys when holding existing keys.

from PyQt4 import QtGui
import sys


class Window(QtGui.QWidget):

    def __init__(self):
        super(Window, self).__init__()
        self.resize(100,300)
        self.lower, self.upper = 10, -10
        self.keys = [81, 65, 90, 87, 83, 88, 69, 68, 67, 82, 70, 86, 84, 71,
        66, 89, 72, 78, 85, 74, 77, 73, 75, 44, 79, 76, 46, 80, 59, 47]
        self.dots = [self.lower] * len(self.keys)

    def keyPressEvent(self, event):
        pressed = event.key()
        if (pressed in self.keys):
            index = self.keys.index(pressed)
            self.dots[index] = self.height()+self.upper
            self.repaint()
        event.accept()

    def keyReleaseEvent(self, event):
        pressed = event.key()
        if (pressed in self.keys):
            index = self.keys.index(pressed)
            self.dots[index] = self.lower
            self.repaint()
        event.accept()

    def paintEvent(self, event):
        step = self.width() / (len(self.dots) + 1)
        painter = QtGui.QPainter()
        painter.begin(self)
        x, y = 0, 0
        for w in self.dots:
            i, j = x + step, w
            painter.drawLine(x, self.height() - y, i, self.height() - j)
            x, y = i, j
        painter.end()


app = QtGui.QApplication(sys.argv)
Window().show()
sys.exit(app.exec_())

As you can observe by running the above program, holding down more than 3 or 4 keys will result in no new spikes being established, until the currently held keys are released.

How can I prevent this behaviour, such that keyPressEvent is only triggered once for a key that hasn't been physically released?

Saintsimonianism answered 4/1, 2013 at 14:48 Comment(2)
I've deduced it's relevant to this: #877352 How do I combat this?Saintsimonianism
This might be more than a bit late, but many keyboards don't support more than 3 or 4 simultaneous key presses anyway.Cleodal
F
7

using event.isAutoRepeat() might help

e.g.

def keyPressEvent(self, event):
    if event.isAutoRepeat():
        return
    pressed = event.key()
    if (pressed in self.keys):
        index = self.keys.index(pressed)
        self.dots[index] = self.height()+self.upper
        self.repaint()
    event.accept()
Forswear answered 5/1, 2013 at 6:6 Comment(1)
This stops repeated repainting, but not the events taking up precious space in the event-queue, and so new key presses are still being ignored.Saintsimonianism

© 2022 - 2024 — McMap. All rights reserved.