Anti Earth
Anti Earth

Reputation: 4806

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

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?

Upvotes: 5

Views: 4309

Answers (1)

eqzx
eqzx

Reputation: 5609

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()

Upvotes: 7

Related Questions