PDA

View Full Version : Global key press handling: best practice?



ghorwin
13th March 2021, 16:57
Hi all,

got a small design problem here. My app consists of a typical widget hierarchy, with a centered main widget and around it several widgets with editable properties. I now want to react on some special keys (including normal characters like xyz 01234567890.,- ) that affect the center-widget's functionality. Some of the property widgets contain line edits.

Requirements:

When the user has a line edit focused and types in a line edit, all typed characters should go there. When the focus is anywhere else (pushbutton, ...), the center widget should get these keyPress and keyRelease events and handle them accordingly.

Implementation-wise this appears to be not so trivial: for one, the center widget does not always have focus and thus does not even receive keyPress/keyRelease-events.
Also, there are really quite a lot of property widgets, and installing an eventfilter on each of them feels kind of too complicated (for Qt based code, anyway).

Adding top-level actions and treating the special characters as shortcuts would probably work, but again feels like a hack.

So, how would you implement this?

Thanks,
Andreas

d_stranz
13th March 2021, 17:18
You might look at deriving your own application class from somewhere in the QCoreApplication hierarchy and overriding the QCoreApplication::notify() method, or using the standard application class and installing an event filter on it. All events application wide go through either the notify() function or the event filter if installed.

Whichever you choose, you can examine the object and event types and choose to let the event get handled as normal or to redirect it to the central widget. (Although I am not sure how redirecting a key press on a button could be reinterpreted in a widget of a different type).

You don't need to install an event filter on every widget; doing it at the application level (through notify() or an app-level filter) means you'll get to see every event before any other QObject does.

ghorwin
13th March 2021, 18:32
Thanks! I had also thought of doing this application wide - I still need to check the focusedWidget() type - if it is indeed a line edit, I'll let the keys pass through.

ghorwin
26th June 2021, 15:35
Btw, just to close this topic off. What I successfully did was:

- subclass QApplication and re-implement notify
- in there check for keypress event
- if received, check if sender was a line edit -> if so, ignore it
- otherwise handle as global key press



bool SVDebugApplication::notify( QObject *recv, QEvent *e ) {
try {
if (e->type() == QEvent::KeyPress) {
// got a keypress event
QWidget * w = focusWidget();
// was it sent from a line edit?
if (qobject_cast<QLineEdit*>(w) == nullptr) {
// no, handle as global key press
QKeyEvent * ke = dynamic_cast<QKeyEvent *>(e);
if (SVViewStateHandler::instance().m_geometryView->handleGlobalKeyPress(ke))
return true;
}
}
}
return QApplication::notify( recv, e );
}
catch (Vic3D::Exception &ex) {
ex.writeMsgStackToError();
IBK::IBK_Message("Vic3D::Exception caught.", IBK::MSG_ERROR, FUNC_ID);
}

return false;
}