blob: 8e135b4624a06927f186ad92dd4c6c38b62a6b01 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qquickshortcut_p.h"
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickwindow.h>
#include <QtQuick/qquickrendercontrol.h>
#include <QtQuick/private/qtquickglobal_p.h>
#include <QtGui/private/qguiapplication_p.h>
/*!
\qmltype Shortcut
\instantiates QQuickShortcut
\inqmlmodule QtQuick
\since 5.5
\ingroup qtquick-input
\brief Provides keyboard shortcuts.
The Shortcut type provides a way of handling keyboard shortcuts. The shortcut can
be set to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts},
or it can be described with a string containing a sequence of up to four key
presses that are needed to \l{Shortcut::activated}{activate} the shortcut.
\qml
Item {
id: view
property int currentIndex
Shortcut {
sequence: StandardKey.NextChild
onActivated: view.currentIndex++
}
}
\endqml
It is also possible to set multiple shortcut \l sequences, so that the shortcut
can be \l activated via several different sequences of key presses.
\sa Keys, {Keys::}{shortcutOverride()}
*/
/*! \qmlsignal QtQuick::Shortcut::activated()
This signal is emitted when the shortcut is activated.
*/
/*! \qmlsignal QtQuick::Shortcut::activatedAmbiguously()
This signal is emitted when the shortcut is activated ambigously,
meaning that it matches the start of more than one shortcut.
*/
static bool qQuickShortcutContextMatcher(QObject *obj, Qt::ShortcutContext context)
{
switch (context) {
case Qt::ApplicationShortcut:
return true;
case Qt::WindowShortcut:
while (obj && !obj->isWindowType()) {
obj = obj->parent();
if (QQuickItem *item = qobject_cast<QQuickItem *>(obj))
obj = item->window();
}
if (QWindow *renderWindow = QQuickRenderControl::renderWindowFor(qobject_cast<QQuickWindow *>(obj)))
obj = renderWindow;
return obj && obj == QGuiApplication::focusWindow();
default:
return false;
}
}
typedef bool (*ContextMatcher)(QObject *, Qt::ShortcutContext);
Q_GLOBAL_STATIC_WITH_ARGS(ContextMatcher, ctxMatcher, (qQuickShortcutContextMatcher))
Q_QUICK_PRIVATE_EXPORT ContextMatcher qt_quick_shortcut_context_matcher()
{
return *ctxMatcher();
}
Q_QUICK_PRIVATE_EXPORT void qt_quick_set_shortcut_context_matcher(ContextMatcher matcher)
{
if (!ctxMatcher.isDestroyed())
*ctxMatcher() = matcher;
}
QT_BEGIN_NAMESPACE
static QKeySequence valueToKeySequence(const QVariant &value)
{
if (value.userType() == QMetaType::Int)
return QKeySequence(static_cast<QKeySequence::StandardKey>(value.toInt()));
return QKeySequence::fromString(value.toString());
}
QQuickShortcut::QQuickShortcut(QObject *parent) : QObject(parent),
m_enabled(true), m_completed(false), m_autorepeat(true), m_context(Qt::WindowShortcut)
{
}
QQuickShortcut::~QQuickShortcut()
{
ungrabShortcut(m_shortcut);
for (Shortcut &shortcut : m_shortcuts)
ungrabShortcut(shortcut);
}
/*!
\qmlproperty keysequence QtQuick::Shortcut::sequence
This property holds the shortcut's key sequence. The key sequence can be set
to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts}, or
it can be described with a string containing a sequence of up to four key
presses that are needed to \l{Shortcut::activated}{activate} the shortcut.
The default value is an empty key sequence.
\qml
Shortcut {
sequence: "Ctrl+E,Ctrl+W"
onActivated: edit.wrapMode = TextEdit.Wrap
}
\endqml
\sa sequences
*/
QVariant QQuickShortcut::sequence() const
{
return m_shortcut.userValue;
}
void QQuickShortcut::setSequence(const QVariant &value)
{
if (value == m_shortcut.userValue)
return;
QKeySequence keySequence = valueToKeySequence(value);
ungrabShortcut(m_shortcut);
m_shortcut.userValue = value;
m_shortcut.keySequence = keySequence;
grabShortcut(m_shortcut, m_context);
emit sequenceChanged();
}
/*!
\qmlproperty list<keysequence> QtQuick::Shortcut::sequences
\since 5.9
This property holds multiple key sequences for the shortcut. The key sequences
can be set to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts},
or they can be described with strings containing sequences of up to four key
presses that are needed to \l{Shortcut::activated}{activate} the shortcut.
\qml
Shortcut {
sequences: [StandardKey.Cut, "Ctrl+X", "Shift+Del"]
onActivated: edit.cut()
}
\endqml
*/
QVariantList QQuickShortcut::sequences() const
{
QVariantList values;
for (const Shortcut &shortcut : m_shortcuts)
values += shortcut.userValue;
return values;
}
void QQuickShortcut::setSequences(const QVariantList &values)
{
QVector<Shortcut> remainder = m_shortcuts.mid(values.count());
m_shortcuts.resize(values.count());
bool changed = !remainder.isEmpty();
for (int i = 0; i < values.count(); ++i) {
const QVariant &value = values.at(i);
Shortcut& shortcut = m_shortcuts[i];
if (value == shortcut.userValue)
continue;
QKeySequence keySequence = valueToKeySequence(value);
ungrabShortcut(shortcut);
shortcut.userValue = value;
shortcut.keySequence = keySequence;
grabShortcut(shortcut, m_context);
changed = true;
}
if (changed)
emit sequencesChanged();
}
/*!
\qmlproperty string QtQuick::Shortcut::nativeText
\since 5.6
This property provides the shortcut's key sequence as a platform specific
string. This means that it will be shown translated, and on \macos it will
resemble a key sequence from the menu bar. It is best to display this text
to the user (for example, on a tooltip).
\sa sequence, portableText
*/
QString QQuickShortcut::nativeText() const
{
return m_shortcut.keySequence.toString(QKeySequence::NativeText);
}
/*!
\qmlproperty string QtQuick::Shortcut::portableText
\since 5.6
This property provides the shortcut's key sequence as a string in a
"portable" format, suitable for reading and writing to a file. In many
cases, it will look similar to the native text on Windows and X11.
\sa sequence, nativeText
*/
QString QQuickShortcut::portableText() const
{
return m_shortcut.keySequence.toString(QKeySequence::PortableText);
}
/*!
\qmlproperty bool QtQuick::Shortcut::enabled
This property holds whether the shortcut is enabled.
The default value is \c true.
*/
bool QQuickShortcut::isEnabled() const
{
return m_enabled;
}
void QQuickShortcut::setEnabled(bool enabled)
{
if (enabled == m_enabled)
return;
setEnabled(m_shortcut, enabled);
for (Shortcut &shortcut : m_shortcuts)
setEnabled(shortcut, enabled);
m_enabled = enabled;
emit enabledChanged();
}
/*!
\qmlproperty bool QtQuick::Shortcut::autoRepeat
This property holds whether the shortcut can auto repeat.
The default value is \c true.
*/
bool QQuickShortcut::autoRepeat() const
{
return m_autorepeat;
}
void QQuickShortcut::setAutoRepeat(bool repeat)
{
if (repeat == m_autorepeat)
return;
setAutoRepeat(m_shortcut, repeat);
for (Shortcut &shortcut : m_shortcuts)
setAutoRepeat(shortcut, repeat);
m_autorepeat = repeat;
emit autoRepeatChanged();
}
/*!
\qmlproperty enumeration QtQuick::Shortcut::context
This property holds the \l{Qt::ShortcutContext}{shortcut context}.
Supported values are:
\list
\li \c Qt.WindowShortcut (default) - The shortcut is active when its parent item is in an active top-level window.
\li \c Qt.ApplicationShortcut - The shortcut is active when one of the application's windows are active.
\endlist
\qml
Shortcut {
sequence: StandardKey.Quit
context: Qt.ApplicationShortcut
onActivated: Qt.quit()
}
\endqml
*/
Qt::ShortcutContext QQuickShortcut::context() const
{
return m_context;
}
void QQuickShortcut::setContext(Qt::ShortcutContext context)
{
if (context == m_context)
return;
ungrabShortcut(m_shortcut);
m_context = context;
grabShortcut(m_shortcut, context);
emit contextChanged();
}
void QQuickShortcut::classBegin()
{
}
void QQuickShortcut::componentComplete()
{
m_completed = true;
grabShortcut(m_shortcut, m_context);
for (Shortcut &shortcut : m_shortcuts)
grabShortcut(shortcut, m_context);
}
bool QQuickShortcut::event(QEvent *event)
{
if (m_enabled && event->type() == QEvent::Shortcut) {
QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
bool match = m_shortcut.matches(se);
int i = 0;
while (!match && i < m_shortcuts.count())
match |= m_shortcuts.at(i++).matches(se);
if (match) {
if (se->isAmbiguous())
emit activatedAmbiguously();
else
emit activated();
return true;
}
}
return false;
}
bool QQuickShortcut::Shortcut::matches(QShortcutEvent *event) const
{
return event->shortcutId() == id && event->key() == keySequence;
}
void QQuickShortcut::setEnabled(QQuickShortcut::Shortcut &shortcut, bool enabled)
{
if (shortcut.id)
QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enabled, shortcut.id, this);
}
void QQuickShortcut::setAutoRepeat(QQuickShortcut::Shortcut &shortcut, bool repeat)
{
if (shortcut.id)
QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(repeat, shortcut.id, this);
}
void QQuickShortcut::grabShortcut(Shortcut &shortcut, Qt::ShortcutContext context)
{
if (m_completed && !shortcut.keySequence.isEmpty()) {
QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
shortcut.id = pApp->shortcutMap.addShortcut(this, shortcut.keySequence, context, *ctxMatcher());
if (!m_enabled)
pApp->shortcutMap.setShortcutEnabled(false, shortcut.id, this);
if (!m_autorepeat)
pApp->shortcutMap.setShortcutAutoRepeat(false, shortcut.id, this);
}
}
void QQuickShortcut::ungrabShortcut(Shortcut &shortcut)
{
if (shortcut.id) {
QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(shortcut.id, this);
shortcut.id = 0;
}
}
QT_END_NAMESPACE
#include "moc_qquickshortcut_p.cpp"