Support global shortcut to switch to specific layout

Summary:
Our keyboard layout kcm allows to set a global shortcut to switch to a
specific keyboard layout. So far KWin/Wayland did not support those
shortcuts, only the switch to next layout shortcut was supported.

This change introduces support for custom layout shortcuts. For that
we iterate over all available layouts and check whether a shortcut is
registered. If that is the case a QAction is created and passed to
KGlobalAccel.

As the triggering code is similar to the menu, the switchLayout lambda
is split out into a dedicated method and translating the layouts is
extracted into a method.

Reviewers: #kwin, #plasma_on_wayland

Subscribers: plasma-devel, kwin

Tags: #plasma_on_wayland, #kwin

Differential Revision: https://phabricator.kde.org/D4256
This commit is contained in:
Martin Gräßlin 2017-01-23 20:06:53 +01:00
parent 997af81ea9
commit 6b0b4cf468
2 changed files with 43 additions and 7 deletions

View file

@ -46,6 +46,11 @@ KeyboardLayout::KeyboardLayout(Xkb *xkb)
KeyboardLayout::~KeyboardLayout() = default;
static QString translatedLayout(const QString &layout)
{
return i18nd("xkeyboard-config", layout.toUtf8().constData());
}
void KeyboardLayout::init()
{
QAction *switchKeyboardAction = new QAction(this);
@ -127,6 +132,12 @@ void KeyboardLayout::switchToPreviousLayout()
checkLayoutChange();
}
void KeyboardLayout::switchToLayout(xkb_layout_index_t index)
{
m_xkb->switchToLayout(index);
checkLayoutChange();
}
void KeyboardLayout::reconfigure()
{
m_xkb->reconfigure();
@ -142,6 +153,30 @@ void KeyboardLayout::resetLayout()
initNotifierItem();
updateNotifier();
reinitNotifierMenu();
loadShortcuts();
}
void KeyboardLayout::loadShortcuts()
{
qDeleteAll(m_layoutShortcuts);
m_layoutShortcuts.clear();
const auto layouts = m_xkb->layoutNames();
const QString componentName = QStringLiteral("KDE Keyboard Layout Switcher");
for (auto it = layouts.begin(); it != layouts.end(); it++) {
// layout name is translated in the action name in keyboard kcm!
const QString action = QStringLiteral("Switch keyboard layout to %1").arg(translatedLayout(it.value()));
const auto shortcuts = KGlobalAccel::self()->globalShortcut(componentName, action);
if (shortcuts.isEmpty()) {
continue;
}
QAction *a = new QAction(this);
a->setObjectName(action);
a->setProperty("componentName", componentName);
connect(a, &QAction::triggered, this,
std::bind(&KeyboardLayout::switchToLayout, this, it.key()));
KGlobalAccel::self()->setShortcut(a, shortcuts, KGlobalAccel::Autoloading);
m_layoutShortcuts << a;
}
}
void KeyboardLayout::keyEvent(KeyEvent *event)
@ -171,7 +206,7 @@ void KeyboardLayout::notifyLayoutChange()
QStringLiteral("org.kde.osdService"),
QStringLiteral("kbdLayoutChanged"));
msg << i18nd("xkeyboard-config", m_xkb->layoutName().toUtf8().constData());
msg << translatedLayout(m_xkb->layoutName());
QDBusConnection::sessionBus().asyncCall(msg);
}
@ -181,7 +216,7 @@ void KeyboardLayout::updateNotifier()
if (!m_notifierItem) {
return;
}
m_notifierItem->setToolTipSubTitle(i18nd("xkeyboard-config", m_xkb->layoutName().toUtf8().constData()));
m_notifierItem->setToolTipSubTitle(translatedLayout(m_xkb->layoutName()));
// TODO: update icon
}
@ -193,12 +228,8 @@ void KeyboardLayout::reinitNotifierMenu()
const auto layouts = m_xkb->layoutNames();
QMenu *menu = new QMenu;
auto switchLayout = [this] (xkb_layout_index_t index) {
m_xkb->switchToLayout(index);
checkLayoutChange();
};
for (auto it = layouts.begin(); it != layouts.end(); it++) {
menu->addAction(i18nd("xkeyboard-config", it.value().toUtf8().constData()), std::bind(switchLayout, it.key()));
menu->addAction(translatedLayout(it.value()), std::bind(&KeyboardLayout::switchToLayout, this, it.key()));
}
menu->addSeparator();

View file

@ -22,11 +22,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "input_event_spy.h"
#include <QObject>
#include <QVector>
#include <KSharedConfig>
typedef uint32_t xkb_layout_index_t;
class KStatusNotifierItem;
class QAction;
namespace KWin
{
@ -58,12 +60,15 @@ private:
void initNotifierItem();
void switchToNextLayout();
void switchToPreviousLayout();
void switchToLayout(xkb_layout_index_t index);
void updateNotifier();
void reinitNotifierMenu();
void loadShortcuts();
Xkb *m_xkb;
xkb_layout_index_t m_layout = 0;
KStatusNotifierItem *m_notifierItem;
KSharedConfigPtr m_config;
QVector<QAction*> m_layoutShortcuts;
};
}