ShortcutOverride: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
h1. Shortcut Override Events (QKeyEvent)
h1. Shortcut Override Events (QKeyEvent)


shortcut: a key combination that triggers an action<br />override: prevent the shortcut action under some circumstances
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).<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.
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: A media player uses space for pause/play. This should work everywhere except when searching for music in a line edit.
Line 9: Line 11:
== Example uses of ShortcutOverride in Qt: ==
== Example uses of ShortcutOverride in Qt: ==


QWidgetWindow::handleKeyEvent<br />QComboBoxPrivateContainer::eventFilter<br /> - for enter etc, bad implementation
QWidgetWindow::handleKeyEvent
QComboBoxPrivateContainer::eventFilter
- for enter etc, bad implementation


QWidgetLineControl::processShortcutOverrideEvent(QKeyEvent '''ke)<br /> - arrow keys, copy paste, …
QWidgetLineControl::processShortcutOverrideEvent(QKeyEvent '''ke)
<br />QMainWindow::event<br /> - to show drag and drop cursor, doesn’t handle event otherwise
- arrow keys, copy paste, …
<br />QMenu::event<br /> - override arrow and enter keys
<br />QMenuBar::eventFilter<br /> - installs a global event filter (no, really[[Image:?|?]]) temporarily until next key press
<br />h2. Behavior:
<br />In widgets the event is sent to the focus object and then to all it's parent objects. Done by QGuiApplication::notify.
<br />h2. Implementation:


<br />QWindowSystemInterface::tryHandleShortcutEvent<br /> return QGuiApplicationPrivate::instance()<s>&gt;shortcutMap.tryShortcutEvent(w, &amp;qevent);<br /> only used on mac?
QMainWindow::event
- to show drag and drop cursor, doesn’t handle event otherwise


<br />QShortcutMap::tryShortcutEvent(QObject *o, QKeyEvent '''e)<br /> creates actual shortcut events<br /> returns true when shortcut should be overridden (not delivered and not trigger action), even before shortcut is complete<br /> results in QCoreApplication::sendEvent( shortcut overrid event)
QMenu::event
<br />Who may call try'''*'''ShortcutEvent?<br /> -  
- override arrow and enter keys
<br />currently:<br /> QNSView: - (void)handleKeyEvent:(NSEvent''')nsevent eventType:(int)eventType<br /> m_sendKeyEvent = !QWindowSystemInterface::tryHandleShortcutEvent(focusWindow, timestamp, keyCode, modifiers, text);<br /> is the only user of the QWindowSystem one and thus the duplicate


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


h2. Behavior:


<br />QGuiApplication:<br /><code><br />QGuiApplicationPrivate::instance()</s>&gt;shortcutMap.tryShortcutEvent(focus, static_cast&amp;lt;QKeyEvent'''&gt;(event))<br /></code>
In widgets the event is sent to the focus object and then to all it's parent objects. Done by QGuiApplication::notify.


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


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


note that we don't have to reset pw while<br /> propagating (because the original receiver will<br /> be destroyed if one of its ancestors is)<br /> '''/<br /> || !pr<br /> || (isWidget &amp;&amp; (w-&gt;isWindow() || !w-&gt;parentWidget()))<br />#ifndef QT_NO_GRAPHICSVIEW<br /> || (isGraphicsWidget &amp;&amp; (gw-&gt;isWindow() || !gw-&gt;parentWidget()))<br />#endif<br /> ) {<br /> break;<br /> }
QWindowSystemInterface::tryHandleShortcutEvent
<br />#ifndef QT_NO_GRAPHICSVIEW<br /> receiver = w ? (QObject''')w-&gt;parentWidget() : (QObject *)gw-&gt;parentWidget();<br />#else<br /> receiver = w-&gt;parentWidget();<br />#endif<br /> }<br /> qt_in_tab_key_event = false;<br /> }<br /> break;
return QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(w, &amp;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:
<code>
QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(focus, static_cast<QKeyEvent'''>(event))
</code>
 
QApplication:
<code>
case QEvent::ShortcutOverride:
case QEvent::KeyPress:
case QEvent::KeyRelease:
{
bool isWidget = receiver->isWidgetType();
bool isGraphicsWidget = false;
#ifndef QT_NO_GRAPHICSVIEW
isGraphicsWidget = !isWidget &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; (w->isWindow() || !w->parentWidget()))
#ifndef QT_NO_GRAPHICSVIEW
|| (isGraphicsWidget &amp;&amp; (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;

Revision as of 10:37, 25 February 2015

h1. 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 (no, really?) temporarily until next key press

h2. Behavior:

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

h2. 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;
  1. ifndef QT_NO_GRAPHICSVIEW
isGraphicsWidget = !isWidget && qobject_cast<QGraphicsWidget >(receiver);
  1. 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;
  1. ifndef QT_NO_GRAPHICSVIEW
QGraphicsWidget gw = isGraphicsWidget ? static_cast<QGraphicsWidget>(receiver) : 0;
  1. 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()))
  1. ifndef QT_NO_GRAPHICSVIEW
|| (isGraphicsWidget && (gw->isWindow() || !gw->parentWidget()))
  1. endif
) {
break;
}
  1. ifndef QT_NO_GRAPHICSVIEW
receiver = w ? (QObject)w->parentWidget() : (QObject *)gw->parentWidget();
  1. else
receiver = w->parentWidget();
  1. endif
}
qt_in_tab_key_event = false;
}
break;