Show notification when modifier keys are used

If the relevant accessibility setting is enabled

BUG: 395559
This commit is contained in:
Nicolas Fella 2024-07-08 17:29:14 +02:00 committed by Nicolas Fella
parent 0419c9a3b1
commit de9eb16527
6 changed files with 209 additions and 0 deletions

View file

@ -113,6 +113,10 @@ add_subdirectory(windowview)
add_subdirectory(wobblywindows)
add_subdirectory(zoom)
if (KWIN_BUILD_NOTIFICATIONS)
add_subdirectory(keynotification)
endif()
if (KWIN_BUILD_DECORATIONS)
add_subdirectory(kdecorations)
endif()

View file

@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: 2024 Nicolas Fella <nicolas.fella@kdab.com>
# SPDX-License-Identifier: BSD-3-Clause
kcoreaddons_add_plugin(KeyNotificationPlugin INSTALL_NAMESPACE "kwin/plugins")
target_compile_definitions(KeyNotificationPlugin PRIVATE
-DTRANSLATION_DOMAIN=\"kwin\"
)
target_sources(KeyNotificationPlugin PRIVATE
main.cpp
keynotification.cpp
)
target_link_libraries(KeyNotificationPlugin PRIVATE kwin KF6::Notifications KF6::I18n XKB::XKB)

View file

@ -0,0 +1,119 @@
/*
SPDX-FileCopyrightText: 2024 Nicolas Fella <nicolas.fella@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "keynotification.h"
#include "keyboard_input.h"
#include "xkb.h"
#include <KLocalizedString>
#include <KNotification>
namespace KWin
{
KeyNotificationPlugin::KeyNotificationPlugin()
: m_configWatcher(KConfigWatcher::create(KSharedConfig::openConfig("kaccessrc")))
{
const QLatin1String groupName("Keyboard");
connect(m_configWatcher.get(), &KConfigWatcher::configChanged, this, [this, groupName](const KConfigGroup &group) {
if (group.name() == groupName) {
loadConfig(group);
}
});
loadConfig(m_configWatcher->config()->group(groupName));
connect(input()->keyboard(), &KeyboardInputRedirection::ledsChanged, this,
&KeyNotificationPlugin::ledsChanged);
connect(input()->keyboard()->xkb(), &Xkb::modifierStateChanged, this, &KeyNotificationPlugin::modifiersChanged);
}
void KeyNotificationPlugin::ledsChanged(LEDs leds)
{
if (m_enabled) {
if (!m_currentLEDs.testFlag(LED::CapsLock) && leds.testFlag(LED::CapsLock)) {
sendNotification("lockkey-locked", i18n("The Caps Lock key has been activated"));
}
if (m_currentLEDs.testFlag(LED::CapsLock) && !leds.testFlag(LED::CapsLock)) {
sendNotification("lockkey-unlocked", i18n("The Caps Lock key is now inactive"));
}
if (!m_currentLEDs.testFlag(LED::NumLock) && leds.testFlag(LED::NumLock)) {
sendNotification("lockkey-locked", i18n("The Num Lock key has been activated"));
}
if (m_currentLEDs.testFlag(LED::NumLock) && !leds.testFlag(LED::NumLock)) {
sendNotification("lockkey-unlocked", i18n("The Num Lock key is now inactive"));
}
if (!m_currentLEDs.testFlag(LED::ScrollLock) && leds.testFlag(LED::ScrollLock)) {
sendNotification("lockkey-locked", i18n("The Scroll Lock key has been activated"));
}
if (m_currentLEDs.testFlag(LED::ScrollLock) && !leds.testFlag(LED::ScrollLock)) {
sendNotification("lockkey-unlocked", i18n("The Scroll Lock key is now inactive"));
}
}
m_currentLEDs = leds;
}
void KeyNotificationPlugin::modifiersChanged()
{
Qt::KeyboardModifiers mods = input()->keyboard()->xkb()->modifiers();
if (m_enabled) {
if (!m_currentModifiers.testFlag(Qt::ShiftModifier) && mods.testFlag(Qt::ShiftModifier)) {
sendNotification("modifierkey-latched", i18n("The Shift key is now active."));
}
if (m_currentModifiers.testFlag(Qt::ShiftModifier) && !mods.testFlag(Qt::ShiftModifier)) {
sendNotification("modifierkey-unlatched", i18n("The Shift key is now inactive."));
}
if (!m_currentModifiers.testFlag(Qt::ControlModifier) && mods.testFlag(Qt::ControlModifier)) {
sendNotification("modifierkey-latched", i18n("The Control key is now active."));
}
if (m_currentModifiers.testFlag(Qt::ControlModifier) && !mods.testFlag(Qt::ControlModifier)) {
sendNotification("modifierkey-unlatched", i18n("The Control key is now inactive."));
}
if (!m_currentModifiers.testFlag(Qt::AltModifier) && mods.testFlag(Qt::AltModifier)) {
sendNotification("modifierkey-latched", i18n("The Alt key is now active."));
}
if (m_currentModifiers.testFlag(Qt::AltModifier) && !mods.testFlag(Qt::AltModifier)) {
sendNotification("modifierkey-unlatched", i18n("The Alt key is now inactive."));
}
if (!m_currentModifiers.testFlag(Qt::MetaModifier) && mods.testFlag(Qt::MetaModifier)) {
sendNotification("modifierkey-latched", i18n("The Meta key is now active."));
}
if (m_currentModifiers.testFlag(Qt::MetaModifier) && !mods.testFlag(Qt::AltModifier)) {
sendNotification("modifierkey-unlatched", i18n("The Meta key is now inactive."));
}
}
m_currentModifiers = input()->keyboard()->xkb()->modifiers();
}
void KeyNotificationPlugin::sendNotification(const QString &eventId, const QString &text)
{
KNotification *notification = new KNotification(QStringLiteral("modifierkey-locked"));
notification->setComponentName(QStringLiteral("kaccess"));
notification->setText(text);
notification->sendEvent();
}
void KeyNotificationPlugin::loadConfig(const KConfigGroup &group)
{
m_enabled = group.readEntry("kNotifyModifiers", false);
}
}
#include "moc_keynotification.cpp"

View file

@ -0,0 +1,34 @@
/*
SPDX-FileCopyrightText: 2024 Nicolas Fella <nicolas.fella@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include "effect/globals.h"
#include "plugin.h"
#include <KConfigGroup>
#include <KConfigWatcher>
namespace KWin
{
class KeyNotificationPlugin : public KWin::Plugin
{
Q_OBJECT
public:
explicit KeyNotificationPlugin();
private:
void loadConfig(const KConfigGroup &group);
void ledsChanged(KWin::LEDs leds);
void modifiersChanged();
void sendNotification(const QString &eventId, const QString &text);
KConfigWatcher::Ptr m_configWatcher;
bool m_enabled = false;
KWin::LEDs m_currentLEDs;
Qt::KeyboardModifiers m_currentModifiers;
};
}

View file

@ -0,0 +1,32 @@
/*
SPDX-FileCopyrightText: 2024 Nicolas Fella <nicolas.fella@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "main.h"
#include "plugin.h"
#include "keynotification.h"
class KWIN_EXPORT KeyNotificationFactory : public KWin::PluginFactory
{
Q_OBJECT
Q_PLUGIN_METADATA(IID PluginFactory_iid FILE "metadata.json")
Q_INTERFACES(KWin::PluginFactory)
public:
std::unique_ptr<KWin::Plugin> create() const override
{
switch (KWin::kwinApp()->operationMode()) {
case KWin::Application::OperationModeXwayland:
case KWin::Application::OperationModeWaylandOnly:
return std::make_unique<KWin::KeyNotificationPlugin>();
case KWin::Application::OperationModeX11:
default:
return nullptr;
}
}
};
#include "main.moc"

View file

@ -0,0 +1,5 @@
{
"KPlugin": {
"EnabledByDefault": true
}
}