How to synthesize key press events?

8.5k Views Asked by At

I am able to get key value's from HAL through a call back function in Qt. Created event for that key by

QKeyEvent *event = new QKeyEvent (QEvent::KeyPress, 
                                  inputKey.keyValue, 
                                  Qt::NoModifier);

Note: inputKey.keyValue Key value received from HAL Layer.

Now I need to Register This key event in Qt, So that if any key press happened in IR Remote then in respective form, keyPressEvent(e) or event(e) will get invoke. and based on the key press, specific action will get execute.

Note: More than one form is there, where key press event will trigger And more than one keys are there "Page_Up, Page_Down, Ok Key etc....."

tried to invoke Postevent() and connect(.......) but nothing helped me. KeyPressEvent() is not getting executed.

2

There are 2 best solutions below

3
On

E.g. like this:

// receiver is a pointer to QObject
QCoreApplication::postEvent (receiver, event);

You can find more info here.

You can reimplement QObject::event() or QWidget::keyPressEvent in your widget to receive key events. Visit this link or link for more information. See the example code below which consists of two buttons and a label. Clicking pushButton sends 'enter pressed' and pushButton_2 sends 'letter A pressed'. Key events are received in the event() function and label is updated accordingly.

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(sendKeyEvent()));
    connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(sendKeyEvent()));
}

void MainWindow::sendKeyEvent()
{
    QObject* button = QObject::sender();
    if (button == ui->pushButton)
    {
        QKeyEvent *event = new QKeyEvent (QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
        QCoreApplication::postEvent (this, event);
    }
    else if (button == ui->pushButton_2)
    {
        QKeyEvent *event = new QKeyEvent (QEvent::KeyPress, Qt::Key_A, Qt::NoModifier);
        QCoreApplication::postEvent (this, event);
    }
}

bool MainWindow::event(QEvent *event)
{
    if (event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if (keyEvent->key() == Qt::Key_Enter) {
            ui->label->setText("Enter received");
            return true;
        }
        else if (keyEvent->key() == Qt::Key_A)
        {
            ui->label->setText("A received");
            return true;
        }
    }

    return QWidget::event(event);
}
0
On

You can create the event on the stack. Then use QCoreApplication::sendEvent to have the event immediately delivered:

QWidget w1, w2;
QKeyEvent event(QEvent::KeyPress, inputKey.keyValue, Qt::NoModifier);
QApplication::sendEvent(&w1, &ev);
QApplication::sendEvent(&w2, &ev);

Each sendEvent will call the widget's event method, that will then invoke the xxxxEvent protected methods as applicable. But don't do it yourself, as you then bypass the application-global event filters and depend on implementation details.

// WRONG!
w1.event(&ev);
// WRONG and won't compile since keyPressEvent is protected
w2.keyPressEvent(&ev);

Or, you can create it on the heap. Qt is managing the event's lifetime as soon as you post it. After you post, the event is not yours anymore and you can't reuse it. You must create multiple events for each post. The simplest way to avoid repetition is to create a local function that produces the events on demand.

QWidget w1, w2;
auto ev = [=]{ return new QKeyEvent(QEvent::KeyPress, inputKey.keyValue, Qt::NoModifier); };
QApplication::postEvent(&w1, ev());
QApplication::postEvent(&w2, ev());

The events will be added to the main thread's event queue. Once the control returns to QApplication::exec, they will be delivered to the widgets one-by-one. The widgets' event method will be called from QApplication::exec, not from postEvent.

The QWidget::event implementation decodes the event types and invokes the protected convenience handlers, such as keyPressEvent, enterEvent, etc. Its implementation follows the following pattern:

bool QWidget::event(QEvent * ev) {
  switch (ev->type()) {
  case QEvent::KeyPress:
    keyPressEvent(static_cast<QKeyEvent*>(ev));
    return true;
  case QEvent::Enter:
    enterEvent(static_cast<QEnterEvent*>(ev));
    return true;
  ...
  }
  return QObject::event(ev);
}

When implementing handlers for event types that have such xxxxEvent convenience virtual methods, you should reimplement the virtual method, and not the event() itself. Thus your MainWindow should reimplement keyPressEvent:

void MainWindow::keyPressEvent(QKeyEvent * event) {
  if (event->key() == Qt::Key_Enter)
    ui->label->setText("Enter received");
  else if (event->key() == Qt::Key_A)
    ui->label->setText("A received");
  QMainWindow::keyPressEvent(event);
}

If you wish your key events to be delivered to your window immediately, and that seems to be a reasonable approach, your sendKeyEvent method becomes much simpler:

void MainWindow::sendKeyEvent()
{
  if (sender() == ui->pushButton) {
    QKeyEvent event(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
    QApplication::sendEvent(this, &event);
  }
  else if (sender() == ui->pushButton_2) {
    QKeyEvent event(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier);
    QApplication::sendEvent(this, &event);
  }
}

There is a way to simplify things further, though. Recall that the QObject supports dynamic properties. You can thus easily assign the keys as a property of the buttons, and automatically send the event whenever a button with a key property has been pressed:

static const char keyPropKey[] = "key";

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::sendKeyEvent);
  connect(ui->pushButton_2, &QPushButton::clicked, this, &MainWindow::sendKeyEvent);
  ui->pushButton.setProperty(keyPropKey, (int)Qt::Key_Enter);
  ui->pushButton.setProperty(keyPropKey, (int)Qt::Key_A);
}

void MainWindow::sendKeyEvent()
{
  auto key = sender().property(KeyPropKey);
  if (key.isValid()) {
    QKeyEvent event(QEvent::KeyPress, key.toInt(), Qt::NoModifier);
    QApplication::sendEvent(this, &event);
  }
}

Finally, as a stylistic nitpick: there's no reason to have the ui member be a pointer. You'll avoid one heap allocation, and plenty of indirections, by using it as a direct member.