Add support for modifier only shortcuts on Wayland

On popular demand!

This change tracks how modifiers are used and detects a modifier only
key press/release. That is:
* no other key is pressed when the modifier gets pressed
* no other key gets pressed before the modifier gets released

If such a press/release is detected, we call a configurable dbus call.
The possible shortcuts can be configured in kwinrc, group
"ModifierOnlyShortcuts". The following keys are supported:
* Shift
* Control
* Alt
* Meta

As value it takes a QStringList (comma seperated string) with
service,path,interface,method,additionalargs

E.g. to invoke Desktop Grid effect on Meta key:

[ModifierOnlyShortcuts]
Meta=org.kde.kglobalaccel,/component/kwin/,org.kde.kglobalaccel.Component,invokeShortcut,ShowDesktopGrid

I do not intend to add a config interface for it. Let's keep it a hidden
way.

REVIEW: 124954
This commit is contained in:
Martin Gräßlin 2015-08-27 17:56:28 +02:00
parent f6f555d688
commit 07414e88a5
4 changed files with 57 additions and 0 deletions

View file

@ -42,6 +42,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <decorations/decoratedclient.h>
#include <KDecoration2/Decoration>
// Qt
#include <QDBusMessage>
#include <QDBusPendingCall>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QTemporaryFile>
@ -183,6 +185,32 @@ void Xkb::updateKey(uint32_t key, InputRedirection::KeyboardKeyState state)
}
xkb_state_update_key(m_state, key + 8, static_cast<xkb_key_direction>(state));
updateModifiers();
if (state == InputRedirection::KeyboardKeyPressed) {
m_modOnlyShortcut.pressCount++;
if (m_modOnlyShortcut.pressCount == 1) {
m_modOnlyShortcut.modifier = Qt::KeyboardModifier(int(m_modifiers));
} else {
m_modOnlyShortcut.modifier = Qt::NoModifier;
}
} else {
m_modOnlyShortcut.pressCount--;
// TODO: ignore on lock screen
if (m_modOnlyShortcut.pressCount == 0) {
if (m_modOnlyShortcut.modifier != Qt::NoModifier) {
const auto list = options->modifierOnlyDBusShortcut(m_modOnlyShortcut.modifier);
if (list.size() >= 4) {
auto call = QDBusMessage::createMethodCall(list.at(0), list.at(1), list.at(2), list.at(3));
QVariantList args;
for (int i = 4; i < list.size(); ++i) {
args << list.at(i);
}
call.setArguments(args);
QDBusConnection::sessionBus().asyncCall(call);
}
}
}
m_modOnlyShortcut.modifier = Qt::NoModifier;
}
}
void Xkb::updateModifiers()

View file

@ -262,6 +262,10 @@ private:
xkb_mod_index_t m_altModifier;
xkb_mod_index_t m_metaModifier;
Qt::KeyboardModifiers m_modifiers;
struct {
uint pressCount = 0;
Qt::KeyboardModifier modifier = Qt::NoModifier;
} m_modOnlyShortcut;
};
inline

View file

@ -838,6 +838,22 @@ void Options::loadConfig()
setMaxFpsInterval(1 * 1000 * 1000 * 1000 / config.readEntry("MaxFPS", Options::defaultMaxFps()));
setRefreshRate(config.readEntry("RefreshRate", Options::defaultRefreshRate()));
setVBlankTime(config.readEntry("VBlankTime", Options::defaultVBlankTime()) * 1000); // config in micro, value in nano resolution
// Modifier Only Shortcuts
config = KConfigGroup(m_settings->config(), "ModifierOnlyShortcuts");
m_modifierOnlyShortcuts.clear();
if (config.hasKey("Shift")) {
m_modifierOnlyShortcuts.insert(Qt::ShiftModifier, config.readEntry("Shift", QStringList()));
}
if (config.hasKey("Control")) {
m_modifierOnlyShortcuts.insert(Qt::ControlModifier, config.readEntry("Control", QStringList()));
}
if (config.hasKey("Alt")) {
m_modifierOnlyShortcuts.insert(Qt::AltModifier, config.readEntry("Alt", QStringList()));
}
if (config.hasKey("Meta")) {
m_modifierOnlyShortcuts.insert(Qt::MetaModifier, config.readEntry("Meta", QStringList()));
}
}
void Options::syncFromKcfgc()
@ -1124,4 +1140,9 @@ Options::WindowOperation Options::operationMaxButtonClick(Qt::MouseButtons butto
opMaxButtonLeftClick;
}
QStringList Options::modifierOnlyDBusShortcut(Qt::KeyboardModifier mod) const
{
return m_modifierOnlyShortcuts.value(mod);
}
} // namespace

View file

@ -589,6 +589,8 @@ public:
return m_glPreferBufferSwap;
}
QStringList modifierOnlyDBusShortcut(Qt::KeyboardModifier mod) const;
// setters
void setFocusPolicy(FocusPolicy focusPolicy);
void setNextFocusPrefersMouse(bool nextFocusPrefersMouse);
@ -929,6 +931,8 @@ private:
bool condensed_title;
int animationSpeed; // 0 - instant, 5 - very slow
QHash<Qt::KeyboardModifier, QStringList> m_modifierOnlyShortcuts;
MouseCommand wheelToMouseCommand(MouseWheelCommand com, int delta) const;
};