6#include "QskShortcutMap.h"
7#include "QskMetaInvokable.h"
9#include "QskInternalMacros.h"
11#include <qkeysequence.h>
12#include <qquickitem.h>
15#include <QtGui/private/qguiapplication_p.h>
20static inline QShortcutMap* qskShortcutMap()
22 return qGuiApp ? &QGuiApplicationPrivate::instance()->shortcutMap :
nullptr;
25class QskShortcutHandler final :
public QObject
30 int insert( QQuickItem*,
const QKeySequence&,
bool autoRepeat,
33 void remove(
int id );
35 void setEnabled(
int id,
bool );
36 void setEnabled(
const QKeySequence&,
bool on );
37 void setAutoRepeat(
int id,
bool repeat );
39 bool eventFilter( QObject*, QEvent* )
override;
40 bool invoke( QQuickItem*,
const QKeySequence& );
43 void cleanUp( QObject* );
56 auto that =
const_cast< InvokeData*
>( this );
57 auto object =
const_cast< QObject*
>( receiver );
59 void* args[] = {
nullptr };
60 that->invokable.invoke(
object, args, Qt::AutoConnection );
63 QKeySequence sequence;
65 const QObject* receiver;
69 std::map< int, InvokeData > m_invokeDataMap;
72Q_GLOBAL_STATIC( QskShortcutHandler, qskShortcutHandler )
74static bool qskContextMatcher( QObject*
object, Qt::ShortcutContext context )
76 if ( context == Qt::ApplicationShortcut )
79 auto item = qobject_cast< QQuickItem* >(
object );
80 if ( item && context == Qt::WindowShortcut )
82 if ( QskShortcutMap::contextMatcher( item, context ) )
91 item->installEventFilter( qskShortcutHandler );
99QskShortcutHandler::QskShortcutHandler()
102 installEventFilter(
this );
105int QskShortcutHandler::insert(
106 QQuickItem* item,
const QKeySequence& sequence,
bool autoRepeat,
109 if ( sequence.isEmpty() )
111 qDebug() <<
"QskShortcutMap: invalid shortcut key sequence";
115 if ( invokable.parameterCount() > 0 )
117 qDebug() <<
"QskShortcutMap: invalid slot parameter count";
123 connect( receiver, &QObject::destroyed,
124 this, &QskShortcutHandler::cleanUp, Qt::UniqueConnection );
129 auto map = qskShortcutMap();
133 if ( item != receiver )
135 connect( item, &QObject::destroyed,
136 this, &QskShortcutHandler::cleanUp, Qt::UniqueConnection );
139 id = map->addShortcut( item, sequence, Qt::WindowShortcut, qskContextMatcher );
143 id = map->addShortcut(
this, sequence, Qt::ApplicationShortcut, qskContextMatcher );
146 auto& data = m_invokeDataMap[ id ];
148 data.sequence = sequence;
150 data.receiver = receiver;
151 data.invokable = invokable;
154 setAutoRepeat(
id,
false );
159void QskShortcutHandler::remove(
int id )
161 auto it = m_invokeDataMap.find(
id );
162 if ( it == m_invokeDataMap.end() )
165 auto map = qskShortcutMap();
166 map->removeShortcut(
id,
nullptr );
168 const QQuickItem* item = it->second.item;
169 const QObject* receiver = it->second.receiver;
171 m_invokeDataMap.erase( it );
177 for (
const auto& entry : std::as_const( m_invokeDataMap ) )
179 if ( item ==
nullptr && receiver ==
nullptr )
182 if ( entry.second.item == item )
185 if ( entry.second.receiver == receiver )
190 item->disconnect(
this );
192 if ( receiver && receiver != item )
193 receiver->disconnect(
this );
196void QskShortcutHandler::cleanUp( QObject*
object )
202 auto map = qskShortcutMap();
204 for (
auto it = m_invokeDataMap.begin(); it != m_invokeDataMap.end(); )
206 const auto& data = it->second;
208 if ( data.item ==
object || data.receiver ==
object )
211 map->removeShortcut( it->first,
nullptr );
213 it = m_invokeDataMap.erase( it );
222void QskShortcutHandler::setEnabled(
const QKeySequence& sequence,
bool on )
224 for (
auto it = m_invokeDataMap.begin();
225 it != m_invokeDataMap.end(); ++it )
227 if ( it->second.sequence == sequence )
228 setEnabled( it->first, on );
232void QskShortcutHandler::setEnabled(
int id,
bool enabled )
234 auto map = qskShortcutMap();
235 map->setShortcutEnabled( enabled,
id,
this );
238void QskShortcutHandler::setAutoRepeat(
int id,
bool repeat )
240 auto map = qskShortcutMap();
241 map->setShortcutAutoRepeat( repeat,
id,
this );
244bool QskShortcutHandler::eventFilter( QObject*
object, QEvent* event )
246 if ( event->type() != QEvent::Shortcut )
249 if (
object !=
this )
250 object->removeEventFilter(
this );
252 const QShortcutEvent* se =
static_cast< const QShortcutEvent*
>( event );
256 if ( se->isAmbiguous() )
260 const auto it = m_invokeDataMap.find( se->shortcutId() );
261 if ( it != m_invokeDataMap.end() )
263 auto& data = it->second;
265 Q_ASSERT( data.item ==
nullptr || data.item ==
object );
276bool QskShortcutHandler::invoke( QQuickItem* item,
const QKeySequence& sequence )
280 for (
const auto& entry : std::as_const( m_invokeDataMap ) )
282 auto& data = entry.second;
284 if ( ( data.item == item ) && ( data.sequence == sequence ) )
294int QskShortcutMap::addMethod( QQuickItem* item,
const QKeySequence& sequence,
295 bool autoRepeat,
const QObject* receiver,
const char* method )
297 if ( receiver ==
nullptr )
299 qDebug() <<
"QskShortcutMap: bad receiver for shortcut:" << sequence;
303 return qskShortcutHandler->insert(
304 item, sequence, autoRepeat, receiver, qskMetaMethod( receiver, method ) );
307int QskShortcutMap::addFunction( QQuickItem* item,
const QKeySequence& sequence,
308 bool autoRepeat,
const QObject* receiver,
const QskMetaFunction& function )
310 if ( ( receiver ==
nullptr ) &&
311 ( function.functionType() == QskMetaFunction::MemberFunction ) )
313 qDebug() <<
"QskShortcutMap: bad receiver for shortcut:" << sequence;
317 return qskShortcutHandler->insert(
318 item, sequence, autoRepeat, receiver, function );
321bool QskShortcutMap::invokeCallback(
const QKeySequence& sequence )
323 QQuickItem* item =
nullptr;
324 return qskShortcutHandler->invoke( item, sequence );
327bool QskShortcutMap::invokeCallback( QQuickWindow* window,
const QKeySequence& sequence )
329 auto item = window ? window->contentItem() :
nullptr;
330 return qskShortcutHandler->invoke( item, sequence );
333bool QskShortcutMap::invokeCallback( QQuickItem* item,
const QKeySequence& sequence )
335 return qskShortcutHandler->invoke( item, sequence );
338void QskShortcutMap::setAutoRepeat(
int id,
bool on )
340 qskShortcutHandler->setAutoRepeat(
id, on );
343void QskShortcutMap::setEnabled(
const QKeySequence& sequence,
bool on )
345 qskShortcutHandler->setEnabled( sequence, on );
348void QskShortcutMap::setEnabled(
int id,
bool on )
350 qskShortcutHandler->setEnabled(
id, on );
353void QskShortcutMap::removeShortcut(
int id )
355 qskShortcutHandler->remove(
id );
358bool QskShortcutMap::contextMatcher(
359 const QQuickItem* item, Qt::ShortcutContext context )
361 if ( context == Qt::ApplicationShortcut )
364 if ( item && context == Qt::WindowShortcut )
366 const auto focusWindow = QGuiApplication::focusWindow();
368 const auto window = item->window();
369 if ( window ==
nullptr || window != focusWindow )
380 if ( qskIsShortcutScope( item ) )
382 if ( !item->hasFocus() )
386 item = item->parentItem();