Add Plasma task group shortcuts
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "keyboardlayout.h"
|
||||
|
||||
#include <QDBusArgument>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusMetaType>
|
||||
#include <QDBusReply>
|
||||
#include <QDebug>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
namespace KeyboardLayoutDbus
|
||||
{
|
||||
struct Layout
|
||||
{
|
||||
QString name;
|
||||
QString variant;
|
||||
QString displayName;
|
||||
};
|
||||
|
||||
using Layouts = QList<Layout>;
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const Layout &layout)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << layout.name << layout.variant << layout.displayName;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, Layout &layout)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> layout.name >> layout.variant >> layout.displayName;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KeyboardLayoutDbus::Layout)
|
||||
Q_DECLARE_METATYPE(KeyboardLayoutDbus::Layouts)
|
||||
|
||||
namespace
|
||||
{
|
||||
KeyboardLayoutDbus::Layouts configuredLayouts()
|
||||
{
|
||||
qDBusRegisterMetaType<KeyboardLayoutDbus::Layout>();
|
||||
qDBusRegisterMetaType<KeyboardLayoutDbus::Layouts>();
|
||||
|
||||
QDBusInterface layouts(QStringLiteral("org.kde.KWin"), QStringLiteral("/Layouts"),
|
||||
QStringLiteral("org.kde.KeyboardLayouts"));
|
||||
const QDBusReply<KeyboardLayoutDbus::Layouts> reply = layouts.call(QStringLiteral("getLayoutsList"));
|
||||
if (!reply.isValid()) {
|
||||
qWarning() << "Could not read KWin keyboard layouts:" << reply.error().message();
|
||||
return {};
|
||||
}
|
||||
return reply.value();
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Qt::Key> numberRowKey(QStringView layout, QStringView variant, int number, bool shifted)
|
||||
{
|
||||
if (number < 1 || number > 9) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
using Context = std::unique_ptr<xkb_context, decltype(&xkb_context_unref)>;
|
||||
using Keymap = std::unique_ptr<xkb_keymap, decltype(&xkb_keymap_unref)>;
|
||||
using State = std::unique_ptr<xkb_state, decltype(&xkb_state_unref)>;
|
||||
|
||||
const Context context(xkb_context_new(XKB_CONTEXT_NO_FLAGS), xkb_context_unref);
|
||||
if (!context) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const QByteArray layoutName = layout.toLatin1();
|
||||
const QByteArray variantName = variant.toLatin1();
|
||||
const xkb_rule_names names{
|
||||
.layout = layoutName.constData(),
|
||||
.variant = variantName.isEmpty() ? nullptr : variantName.constData(),
|
||||
};
|
||||
const Keymap keymap(xkb_keymap_new_from_names(context.get(), &names, XKB_KEYMAP_COMPILE_NO_FLAGS),
|
||||
xkb_keymap_unref);
|
||||
if (!keymap) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const State state(xkb_state_new(keymap.get()), xkb_state_unref);
|
||||
if (!state) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (shifted) {
|
||||
const xkb_mod_index_t shift = xkb_keymap_mod_get_index(keymap.get(), XKB_MOD_NAME_SHIFT);
|
||||
if (shift == XKB_MOD_INVALID) {
|
||||
return std::nullopt;
|
||||
}
|
||||
xkb_state_update_mask(state.get(), xkb_mod_mask_t{1} << shift, 0, 0, 0, 0, 0);
|
||||
}
|
||||
const QByteArray keyName = QByteArrayLiteral("AE0") + QByteArray::number(number);
|
||||
const xkb_keycode_t keycode = xkb_keymap_key_by_name(keymap.get(), keyName.constData());
|
||||
if (keycode == XKB_KEYCODE_INVALID) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const uint32_t codePoint = xkb_keysym_to_utf32(xkb_state_key_get_one_sym(state.get(), keycode));
|
||||
if (codePoint == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return static_cast<Qt::Key>(codePoint);
|
||||
}
|
||||
|
||||
QList<QKeySequence> numberRowShortcuts(int number)
|
||||
{
|
||||
QList<QKeySequence> shortcuts;
|
||||
for (const auto &layout : configuredLayouts()) {
|
||||
for (const bool shifted : {false, true}) {
|
||||
const auto key = numberRowKey(layout.name, layout.variant, number, shifted);
|
||||
if (!key) {
|
||||
qWarning() << "Could not map number-row key" << number << "for keyboard layout" << layout.name;
|
||||
continue;
|
||||
}
|
||||
|
||||
const QKeySequence sequence(Qt::META | *key);
|
||||
if (!shortcuts.contains(sequence)) {
|
||||
shortcuts.append(sequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
return shortcuts;
|
||||
}
|
||||
Reference in New Issue
Block a user