ShortcutOverride: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
(Add "cleanup" tag)
m (Fixed line breaks)
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{Cleanup | reason=Auto-imported from ExpressionEngine.}}
= Shortcut Override Events (QKeyEvent) =
 
shortcut: a key combination that triggers an action<br />
h1. Shortcut Override Events (QKeyEvent)
 
shortcut: a key combination that triggers an action
override: prevent the shortcut action under some circumstances
override: prevent the shortcut action under some circumstances


When the shortcut is about to trigger send shortcut override to the focus item instead. the focus item now has the option to override the shortcut (by accepting the shortcut override event).
When the shortcut is about to trigger send shortcut override to the focus item instead. the focus item now has the option to override the shortcut (by accepting the shortcut override event).<br />
If the shortcut override is accepted it will be delivered as normal key press to the focus widget. otherwise it will trigger the shortcut action.
If the shortcut override is accepted it will be delivered as normal key press to the focus widget. otherwise it will trigger the shortcut action.


Example: A media player uses space for pause/play. This should work everywhere except when searching for music in a line edit.
Example: A media player uses space for pause/play. This should work everywhere except when searching for music in a line edit.


== Example uses of ShortcutOverride in Qt: ==
== Example uses of ShortcutOverride in Qt ==


QWidgetWindow::handleKeyEvent
QWidgetWindow::handleKeyEvent
QComboBoxPrivateContainer::eventFilter
QComboBoxPrivateContainer::eventFilter
- for enter etc, bad implementation
* for enter etc, bad implementation


QWidgetLineControl::processShortcutOverrideEvent(QKeyEvent '''ke)
QWidgetLineControl::processShortcutOverrideEvent(QKeyEvent *ke)
- arrow keys, copy paste,
* arrow keys, copy paste, ...


QMainWindow::event
QMainWindow::event
- to show drag and drop cursor, doesn’t handle event otherwise
* to show drag and drop cursor, doesn’t handle event otherwise


QMenu::event
QMenu::event
- override arrow and enter keys
* override arrow and enter keys


QMenuBar::eventFilter
QMenuBar::eventFilter
- installs a global event filter (no, really[[Image:?|?]]) temporarily until next key press
* installs a global event filter temporarily until next key press
 
h2. Behavior:


== Behavior ==
In widgets the event is sent to the focus object and then to all it's parent objects. Done by QGuiApplication::notify.
In widgets the event is sent to the focus object and then to all it's parent objects. Done by QGuiApplication::notify.


h2. Implementation:
== Implementation ==
 
<code>
 
QWindowSystemInterface::tryHandleShortcutEvent
QWindowSystemInterface::tryHandleShortcutEvent
return QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(w, &amp;qevent);
return QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(w, &qevent);
only used on mac?
</code>
* only used on mac?




QShortcutMap::tryShortcutEvent(QObject *o, QKeyEvent '''e)
QShortcutMap::tryShortcutEvent(QObject *o, QKeyEvent *e)
creates actual shortcut events
* creates actual shortcut events
returns true when shortcut should be overridden (not delivered and not trigger action), even before shortcut is complete
* returns true when shortcut should be overridden (not delivered and not trigger action), even before shortcut is complete
results in QCoreApplication::sendEvent( shortcut overrid event)
* results in QCoreApplication::sendEvent( shortcut overrid event)


Who may call try'''*'''ShortcutEvent?
Who may call try ShortcutEvent?
-


currently:
currently:
QNSView: - (void)handleKeyEvent:(NSEvent''')nsevent eventType:(int)eventType
<code>
m_sendKeyEvent = !QWindowSystemInterface::tryHandleShortcutEvent(focusWindow, timestamp, keyCode, modifiers, text);
QNSView: (void)handleKeyEvent:(NSEvent*)nsevent eventType:(int)eventType
is the only user of the QWindowSystem one and thus the duplicate
m_sendKeyEvent = !QWindowSystemInterface::tryHandleShortcutEvent(focusWindow, timestamp, keyCode, modifiers, text);
 
</code>
 
is the only user of the QWindowSystem one and thus the duplicate
 


QGuiApplication:
QGuiApplication:
<code>
<code>
QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(focus, static_cast<QKeyEvent'''>(event))
QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(focus, static_cast<QKeyEvent*>(event))
</code>
</code>


Line 71: Line 65:
  bool isGraphicsWidget = false;
  bool isGraphicsWidget = false;
#ifndef QT_NO_GRAPHICSVIEW
#ifndef QT_NO_GRAPHICSVIEW
  isGraphicsWidget = !isWidget &amp;&amp; qobject_cast<QGraphicsWidget '''>(receiver);
  isGraphicsWidget = !isWidget && qobject_cast<QGraphicsWidget*>(receiver);
#endif
#endif
  QKeyEvent''' key = static_cast<QKeyEvent*>(e);
  QKeyEvent *key = static_cast<QKeyEvent*>(e);
  bool def = key->isAccepted();
  bool def = key->isAccepted();
  QPointer<QObject> pr = receiver;
  QPointer<QObject> pr = receiver;
Line 82: Line 76:
  key->ignore();
  key->ignore();
  res = d->notify_helper(receiver, e);
  res = d->notify_helper(receiver, e);
  QWidget '''w = isWidget ? static_cast<QWidget'''>(receiver) : 0;
  QWidget *w = isWidget ? static_cast<QWidget*>(receiver) : 0;
#ifndef QT_NO_GRAPHICSVIEW
#ifndef QT_NO_GRAPHICSVIEW
  QGraphicsWidget '''gw = isGraphicsWidget ? static_cast<QGraphicsWidget'''>(receiver) : 0;
  QGraphicsWidget *gw = isGraphicsWidget ? static_cast<QGraphicsWidget*>(receiver) : 0;
#endif
#endif


if ((res &amp;&amp; key->isAccepted())
if ((res && key->isAccepted())
  /*
  /*
  QLineEdit will emit a signal on Key_Return, but
  QLineEdit will emit a signal on Key_Return, but
Line 101: Line 95:
  */
  */
  || !pr
  || !pr
  || (isWidget &amp;&amp; (w->isWindow() || !w->parentWidget()))
  || (isWidget && (w->isWindow() || !w->parentWidget()))
#ifndef QT_NO_GRAPHICSVIEW
#ifndef QT_NO_GRAPHICSVIEW
  || (isGraphicsWidget &amp;&amp; (gw->isWindow() || !gw->parentWidget()))
  || (isGraphicsWidget && (gw->isWindow() || !gw->parentWidget()))
#endif
#endif
  ) {
  ) {
Line 110: Line 104:


#ifndef QT_NO_GRAPHICSVIEW
#ifndef QT_NO_GRAPHICSVIEW
  receiver = w ? (QObject''')w->parentWidget() : (QObject *)gw->parentWidget();
  receiver = w ? (QObject*)w->parentWidget() : (QObject *)gw->parentWidget();
#else
#else
  receiver = w->parentWidget();
  receiver = w->parentWidget();
Line 118: Line 112:
  }
  }
  break;
  break;
</code>

Latest revision as of 14:47, 24 February 2018

Shortcut Override Events (QKeyEvent)

shortcut: a key combination that triggers an action
override: prevent the shortcut action under some circumstances

When the shortcut is about to trigger send shortcut override to the focus item instead. the focus item now has the option to override the shortcut (by accepting the shortcut override event).
If the shortcut override is accepted it will be delivered as normal key press to the focus widget. otherwise it will trigger the shortcut action.

Example: A media player uses space for pause/play. This should work everywhere except when searching for music in a line edit.

Example uses of ShortcutOverride in Qt

QWidgetWindow::handleKeyEvent QComboBoxPrivateContainer::eventFilter

  • for enter etc, bad implementation

QWidgetLineControl::processShortcutOverrideEvent(QKeyEvent *ke)

  • arrow keys, copy paste, ...

QMainWindow::event

  • to show drag and drop cursor, doesn’t handle event otherwise

QMenu::event

  • override arrow and enter keys

QMenuBar::eventFilter

  • installs a global event filter temporarily until next key press

Behavior

In widgets the event is sent to the focus object and then to all it's parent objects. Done by QGuiApplication::notify.

Implementation

QWindowSystemInterface::tryHandleShortcutEvent
return QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(w, &qevent);
  • only used on mac?


QShortcutMap::tryShortcutEvent(QObject *o, QKeyEvent *e)

  • creates actual shortcut events
  • returns true when shortcut should be overridden (not delivered and not trigger action), even before shortcut is complete
  • results in QCoreApplication::sendEvent( shortcut overrid event)

Who may call try ShortcutEvent?

currently:

QNSView: (void)handleKeyEvent:(NSEvent*)nsevent eventType:(int)eventType
m_sendKeyEvent = !QWindowSystemInterface::tryHandleShortcutEvent(focusWindow, timestamp, keyCode, modifiers, text);

is the only user of the QWindowSystem one and thus the duplicate

QGuiApplication:

QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(focus, static_cast<QKeyEvent*>(event))

QApplication:

 case QEvent::ShortcutOverride:
 case QEvent::KeyPress:
 case QEvent::KeyRelease:
 {
 bool isWidget = receiver->isWidgetType();
 bool isGraphicsWidget = false;
#ifndef QT_NO_GRAPHICSVIEW
 isGraphicsWidget = !isWidget && qobject_cast<QGraphicsWidget*>(receiver);
#endif
 QKeyEvent *key = static_cast<QKeyEvent*>(e);
 bool def = key->isAccepted();
 QPointer<QObject> pr = receiver;
 while (receiver) {
 if (def)
 key->accept();
 else
 key->ignore();
 res = d->notify_helper(receiver, e);
 QWidget *w = isWidget ? static_cast<QWidget*>(receiver) : 0;
#ifndef QT_NO_GRAPHICSVIEW
 QGraphicsWidget *gw = isGraphicsWidget ? static_cast<QGraphicsWidget*>(receiver) : 0;
#endif

if ((res && key->isAccepted())
 /*
 QLineEdit will emit a signal on Key_Return, but
 ignore the event, and sometimes the connected
 slot deletes the QLineEdit (common in itemview
 delegates), so we have to check if the widget
 was destroyed even if the event was ignored (to
 prevent a crash)

note that we don't have to reset pw while
 propagating (because the original receiver will
 be destroyed if one of its ancestors is)
 */
 || !pr
 || (isWidget && (w->isWindow() || !w->parentWidget()))
#ifndef QT_NO_GRAPHICSVIEW
 || (isGraphicsWidget && (gw->isWindow() || !gw->parentWidget()))
#endif
 ) {
 break;
 }

#ifndef QT_NO_GRAPHICSVIEW
 receiver = w ? (QObject*)w->parentWidget() : (QObject *)gw->parentWidget();
#else
 receiver = w->parentWidget();
#endif
 }
 qt_in_tab_key_event = false;
 }
 break;