6#include "QskShortcutMap.h"
7#include "QskMetaInvokable.h"
10#include <qkeysequence.h>
11#include <qquickitem.h>
14#include <QtGui/private/qguiapplication_p.h>
19static inline QShortcutMap* qskShortcutMap()
21 return qGuiApp ? &QGuiApplicationPrivate::instance()->shortcutMap :
nullptr;
24class QskShortcutHandler final :
public QObject
29 int insert( QQuickItem*,
const QKeySequence&,
bool autoRepeat,
32 void remove(
int id );
34 void setEnabled(
int id,
bool );
35 void setEnabled(
const QKeySequence&,
bool on );
36 void setAutoRepeat(
int id,
bool repeat );
38 bool eventFilter( QObject*, QEvent* )
override;
39 bool invoke( QQuickItem*,
const QKeySequence& );
42 void cleanUp( QObject* );
55 auto that =
const_cast< InvokeData*
>( this );
56 auto object =
const_cast< QObject*
>( receiver );
58 void* args[] = {
nullptr };
59 that->invokable.invoke(
object, args, Qt::AutoConnection );
62 QKeySequence sequence;
64 const QObject* receiver;
68 std::map< int, InvokeData > m_invokeDataMap;
71Q_GLOBAL_STATIC( QskShortcutHandler, qskShortcutHandler )
73static bool qskContextMatcher( QObject*
object, Qt::ShortcutContext context )
75 if ( context == Qt::ApplicationShortcut )
78 auto item = qobject_cast< QQuickItem* >(
object );
79 if ( item && context == Qt::WindowShortcut )
81 if ( QskShortcutMap::contextMatcher( item, context ) )
90 item->installEventFilter( qskShortcutHandler );
98QskShortcutHandler::QskShortcutHandler()
101 installEventFilter(
this );
104int QskShortcutHandler::insert(
105 QQuickItem* item,
const QKeySequence& sequence,
bool autoRepeat,
108 if ( sequence.isEmpty() )
110 qDebug() <<
"QskShortcutMap: invalid shortcut key sequence";
114 if ( invokable.parameterCount() > 0 )
116 qDebug() <<
"QskShortcutMap: invalid slot parameter count";
122 connect( receiver, &QObject::destroyed,
123 this, &QskShortcutHandler::cleanUp, Qt::UniqueConnection );
128 auto map = qskShortcutMap();
132 if ( item != receiver )
134 connect( item, &QObject::destroyed,
135 this, &QskShortcutHandler::cleanUp, Qt::UniqueConnection );
138 id = map->addShortcut( item, sequence, Qt::WindowShortcut, qskContextMatcher );
142 id = map->addShortcut(
this, sequence, Qt::ApplicationShortcut, qskContextMatcher );
145 auto& data = m_invokeDataMap[ id ];
147 data.sequence = sequence;
149 data.receiver = receiver;
150 data.invokable = invokable;
153 setAutoRepeat(
id,
false );
158void QskShortcutHandler::remove(
int id )
160 auto it = m_invokeDataMap.find(
id );
161 if ( it == m_invokeDataMap.end() )
164 auto map = qskShortcutMap();
165 map->removeShortcut(
id,
nullptr );
167 const QQuickItem* item = it->second.item;
168 const QObject* receiver = it->second.receiver;
170 m_invokeDataMap.erase( it );
176 for (
const auto& entry : std::as_const( m_invokeDataMap ) )
178 if ( item ==
nullptr && receiver ==
nullptr )
181 if ( entry.second.item == item )
184 if ( entry.second.receiver == receiver )
189 item->disconnect(
this );
191 if ( receiver && receiver != item )
192 receiver->disconnect(
this );
195void QskShortcutHandler::cleanUp( QObject*
object )
201 auto map = qskShortcutMap();
203 for (
auto it = m_invokeDataMap.begin(); it != m_invokeDataMap.end(); )
205 const auto& data = it->second;
207 if ( data.item ==
object || data.receiver ==
object )
210 map->removeShortcut( it->first,
nullptr );
212 it = m_invokeDataMap.erase( it );
221void QskShortcutHandler::setEnabled(
const QKeySequence& sequence,
bool on )
223 for (
auto it = m_invokeDataMap.begin();
224 it != m_invokeDataMap.end(); ++it )
226 if ( it->second.sequence == sequence )
227 setEnabled( it->first, on );
231void QskShortcutHandler::setEnabled(
int id,
bool enabled )
233 auto map = qskShortcutMap();
234 map->setShortcutEnabled( enabled,
id,
this );
237void QskShortcutHandler::setAutoRepeat(
int id,
bool repeat )
239 auto map = qskShortcutMap();
240 map->setShortcutAutoRepeat( repeat,
id,
this );
243bool QskShortcutHandler::eventFilter( QObject*
object, QEvent* event )
245 if ( event->type() != QEvent::Shortcut )
248 if (
object !=
this )
249 object->removeEventFilter(
this );
251 const QShortcutEvent* se =
static_cast< const QShortcutEvent*
>( event );
255 if ( se->isAmbiguous() )
259 const auto it = m_invokeDataMap.find( se->shortcutId() );
260 if ( it != m_invokeDataMap.end() )
262 auto& data = it->second;
264 Q_ASSERT( data.item ==
nullptr || data.item ==
object );
275bool QskShortcutHandler::invoke( QQuickItem* item,
const QKeySequence& sequence )
279 for (
const auto& entry : std::as_const( m_invokeDataMap ) )
281 auto& data = entry.second;
283 if ( ( data.item == item ) && ( data.sequence == sequence ) )
293int QskShortcutMap::addMethod( QQuickItem* item,
const QKeySequence& sequence,
294 bool autoRepeat,
const QObject* receiver,
const char* method )
296 if ( receiver ==
nullptr )
298 qDebug() <<
"QskShortcutMap: bad receiver for shortcut:" << sequence;
302 return qskShortcutHandler->insert(
303 item, sequence, autoRepeat, receiver, qskMetaMethod( receiver, method ) );
306int QskShortcutMap::addFunction( QQuickItem* item,
const QKeySequence& sequence,
307 bool autoRepeat,
const QObject* receiver,
const QskMetaFunction& function )
309 if ( ( receiver ==
nullptr ) &&
310 ( function.functionType() == QskMetaFunction::MemberFunction ) )
312 qDebug() <<
"QskShortcutMap: bad receiver for shortcut:" << sequence;
316 return qskShortcutHandler->insert(
317 item, sequence, autoRepeat, receiver, function );
320bool QskShortcutMap::invokeCallback(
const QKeySequence& sequence )
322 QQuickItem* item =
nullptr;
323 return qskShortcutHandler->invoke( item, sequence );
326bool QskShortcutMap::invokeCallback( QQuickWindow* window,
const QKeySequence& sequence )
328 auto item = window ? window->contentItem() :
nullptr;
329 return qskShortcutHandler->invoke( item, sequence );
332bool QskShortcutMap::invokeCallback( QQuickItem* item,
const QKeySequence& sequence )
334 return qskShortcutHandler->invoke( item, sequence );
337void QskShortcutMap::setAutoRepeat(
int id,
bool on )
339 qskShortcutHandler->setAutoRepeat(
id, on );
342void QskShortcutMap::setEnabled(
const QKeySequence& sequence,
bool on )
344 qskShortcutHandler->setEnabled( sequence, on );
347void QskShortcutMap::setEnabled(
int id,
bool on )
349 qskShortcutHandler->setEnabled(
id, on );
352void QskShortcutMap::removeShortcut(
int id )
354 qskShortcutHandler->remove(
id );
357bool QskShortcutMap::contextMatcher(
358 const QQuickItem* item, Qt::ShortcutContext context )
360 if ( context == Qt::ApplicationShortcut )
363 if ( item && context == Qt::WindowShortcut )
365 const auto focusWindow = QGuiApplication::focusWindow();
367 const auto window = item->window();
368 if ( window ==
nullptr || window != focusWindow )
379 if ( qskIsShortcutScope( item ) )
381 if ( !item->hasFocus() )
385 item = item->parentItem();