3
votes

I am writing a Qt program to simulate a piece of hardware and I would like to simulate button press, hold, and release events. In my application, I'd like to handle input from both the keyboard and mouse clicks to make things convenient to the user (i.e. me). I've noticed some odd behavior and I don't understand it.

The application uses QPushButton with autoRepeat enabled and a 100 ms autoRepeatDelay and autoRepeatInterval. If I mouse click on a button, I receive alternating "pressed" and "released" events. I would have expected to see 1 to N-1 "pressed" events followed by a "released" event. Why is Qt behaving that way?

I've also implemented the following code to handle button presses from the keyboard:

void MyApp::keyPressEvent(QKeyEvent *event)
{
    QString s = QString("My PRESS key is %1. The counter is %2").arg(event->text(), QString::number(keyCounter));
    qDebug() << s;
    keyCounter++;
}

void MyApp::keyReleaseEvent(QKeyEvent *event)
{
    QString s = QString("My RELEASE key is %1. The counter is %2").arg(event->text(), QString::number(keyCounter));
    qDebug() << s;
    keyCounter = 0;
}

bool MyApp::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress)
    {
        this->keyPressEvent(dynamic_cast<QKeyEvent*>(event));
        return true;
    }
    else if (event->type() == QEvent::KeyRelease)
    {
        this->keyReleaseEvent(dynamic_cast<QKeyEvent*>(event));
        return  true;
    }
    else
    {
        return QObject::eventFilter(obj, event);
    }
}

Here I see two types of behavior. For alphanumeric keys, I see the alternating "pressed" and "released" events. For arrow keys, I only see the "released" events. Again, I would have expected to see 1 to N-1 "pressed" events followed by a "released" event. Why do the arrow keys behave differently than the alphanumeric keys?

Is what I'm trying to do possible in Qt?

2
"If autoRepeat is enabled, then the pressed(), released(), and clicked() signals are emitted at regular intervals when the button is down." I didn't fully grok this at first - looks like this is the source of the repeated events. I'll have to generate my own solution.GrandAdmiral
behaviour you expected seem in par with windows API... but X11 Gui works diferently... dunno about Wayland. My guess is that qt emulated uniform behaviourSwift - Friday Pie

2 Answers

3
votes

Here was my solution: First I disabled autoRepeat and stopped handling keyPressEvents because I found that the arrow keys weren't generating them. Instead I registered shortcuts for the keyboard buttons I wanted to use:

QShortcut *shortcutUp = new QShortcut(QKeySequence("Up"), this);
QObject::connect(shortcutUp, SIGNAL(activated()), this, SLOT(on_upButton_pressed()));
shortcutUp->setAutoRepeat(false);

Then in the on_upButton_pressed() function (for example) I set a flag indicating the button was pressed. This flag is cleared in the on_upButton_released() function. That flag is checked on a 100 ms interval (using a QTimer). If the flag is true, I call on_upButton_pressed() again. This means:

  • Each mouse click or keyboard button press generates one "Press" event
  • The "Press" event sets a flag that is checked by a QTimer
  • If the flag is true, another "Press" event is generated
  • When the mouse or keyboard button is released, the "Release" event is generated and the flag is cleared.

It's working now.

0
votes

This is caused by some keys in QT generate auto-repeat event:

Here I see two types of behavior. For alphanumeric keys, I see the alternating "pressed" and "released" events. For arrow keys, I only see the "released" events. Again, I would have expected to see 1 to N-1 "pressed" events followed by a "released" event. Why do the arrow keys behave differently than the alphanumeric keys?

In QT5 you can detect key held down by function isAutoRepeat() of QKeyEvent object. If the key is held down then isAutoRepeat() will return true. for example:

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    if (event->isAutoRepeat())
    {
        return;
    }

    if (!event->isAutoRepeat())
    {
        qDebug() << "[MainWindow::keyPressEvent()] " << event->key() << "; " << event->isAutoRepeat();
    }
}

void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
    if (event->isAutoRepeat())
    {
        return;
    }
    qDebug() << "[MainWindow::keyReleaseEvent()] " << event->key() << "; " << event->isAutoRepeat();
}