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();