mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-01-31 07:12:18 +00:00
d2ebfd0519
Screw the description like that inbred T3Q
281 lines
10 KiB
C++
281 lines
10 KiB
C++
/*
|
|
SPDX-FileCopyrightText: 2000 Matthias Hölzer-Klüpfel <hoelzer@kde.org>
|
|
SPDX-FileCopyrightText: 2014 Frederik Gladhorn <gladhorn@kde.org>
|
|
|
|
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
|
*/
|
|
|
|
#include "kcmaccess.h"
|
|
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <QFileDialog>
|
|
#include <QProcess>
|
|
#include <QQuickItem>
|
|
#include <QQuickRenderControl>
|
|
#include <QStandardPaths>
|
|
#include <QWindow>
|
|
#include <QX11Info>
|
|
|
|
#include <KConfigGroup>
|
|
#include <KKeyServer>
|
|
#include <KLocalizedString>
|
|
#include <KNotifyConfigWidget>
|
|
#include <KPluginFactory>
|
|
#include <KSharedConfig>
|
|
#include <X11/XKBlib.h>
|
|
#include <X11/Xlib.h>
|
|
|
|
#define XK_MISCELLANY
|
|
#define XK_XKB_KEYS
|
|
#include <X11/keysymdef.h>
|
|
|
|
#include "kcmaccessibilitybell.h"
|
|
#include "kcmaccessibilitydata.h"
|
|
#include "kcmaccessibilitykeyboard.h"
|
|
#include "kcmaccessibilitykeyboardfilters.h"
|
|
#include "kcmaccessibilitymouse.h"
|
|
#include "kcmaccessibilityscreenreader.h"
|
|
|
|
K_PLUGIN_FACTORY_WITH_JSON(KCMAccessFactory, "kcm_access.json", registerPlugin<KAccessConfig>(); registerPlugin<AccessibilityData>();)
|
|
|
|
QString mouseKeysShortcut(Display *display)
|
|
{
|
|
// Calculate the keycode
|
|
KeySym sym = XK_MouseKeys_Enable;
|
|
KeyCode code = XKeysymToKeycode(display, sym);
|
|
if (code == 0) {
|
|
sym = XK_Pointer_EnableKeys;
|
|
code = XKeysymToKeycode(display, sym);
|
|
if (code == 0)
|
|
return QString(); // No shortcut available?
|
|
}
|
|
|
|
// Calculate the modifiers by searching the keysym in the X keyboard mapping
|
|
XkbDescPtr xkbdesc = XkbGetMap(display, XkbKeyTypesMask | XkbKeySymsMask, XkbUseCoreKbd);
|
|
if (!xkbdesc)
|
|
return QString(); // Failed to obtain the mapping from server
|
|
|
|
bool found = false;
|
|
unsigned char modifiers = 0;
|
|
int groups = XkbKeyNumGroups(xkbdesc, code);
|
|
for (int grp = 0; grp < groups && !found; grp++) {
|
|
int levels = XkbKeyGroupWidth(xkbdesc, code, grp);
|
|
for (int level = 0; level < levels && !found; level++) {
|
|
if (sym == XkbKeySymEntry(xkbdesc, code, level, grp)) {
|
|
// keysym found => determine modifiers
|
|
int typeIdx = xkbdesc->map->key_sym_map[code].kt_index[grp];
|
|
XkbKeyTypePtr type = &(xkbdesc->map->types[typeIdx]);
|
|
for (int i = 0; i < type->map_count && !found; i++) {
|
|
if (type->map[i].active && (type->map[i].level == level)) {
|
|
modifiers = type->map[i].mods.mask;
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
XkbFreeClientMap(xkbdesc, 0, true);
|
|
|
|
if (!found)
|
|
return QString(); // Somehow the keycode -> keysym mapping is flawed
|
|
|
|
XEvent ev;
|
|
ev.type = KeyPress;
|
|
ev.xkey.display = display;
|
|
ev.xkey.keycode = code;
|
|
ev.xkey.state = 0;
|
|
int key;
|
|
KKeyServer::xEventToQt(&ev, &key);
|
|
QString keyname = QKeySequence(key).toString();
|
|
|
|
unsigned int AltMask = KKeyServer::modXAlt();
|
|
unsigned int WinMask = KKeyServer::modXMeta();
|
|
unsigned int NumMask = KKeyServer::modXNumLock();
|
|
unsigned int ScrollMask = KKeyServer::modXScrollLock();
|
|
|
|
unsigned int MetaMask = XkbKeysymToModifiers(display, XK_Meta_L);
|
|
unsigned int SuperMask = XkbKeysymToModifiers(display, XK_Super_L);
|
|
unsigned int HyperMask = XkbKeysymToModifiers(display, XK_Hyper_L);
|
|
unsigned int AltGrMask = XkbKeysymToModifiers(display, XK_Mode_switch) | XkbKeysymToModifiers(display, XK_ISO_Level3_Shift)
|
|
| XkbKeysymToModifiers(display, XK_ISO_Level3_Latch) | XkbKeysymToModifiers(display, XK_ISO_Level3_Lock);
|
|
|
|
unsigned int mods = ShiftMask | ControlMask | AltMask | WinMask | LockMask | NumMask | ScrollMask;
|
|
|
|
AltGrMask &= ~mods;
|
|
MetaMask &= ~(mods | AltGrMask);
|
|
SuperMask &= ~(mods | AltGrMask | MetaMask);
|
|
HyperMask &= ~(mods | AltGrMask | MetaMask | SuperMask);
|
|
|
|
if ((modifiers & AltGrMask) != 0)
|
|
keyname = i18n("AltGraph") + QLatin1Char('+') + keyname;
|
|
if ((modifiers & HyperMask) != 0)
|
|
keyname = i18n("Hyper") + QLatin1Char('+') + keyname;
|
|
if ((modifiers & SuperMask) != 0)
|
|
keyname = i18n("Super") + QLatin1Char('+') + keyname;
|
|
if ((modifiers & WinMask) != 0)
|
|
keyname = QKeySequence(Qt::META).toString() + QLatin1Char('+') + keyname;
|
|
if ((modifiers & AltMask) != 0)
|
|
keyname = QKeySequence(Qt::ALT).toString() + QLatin1Char('+') + keyname;
|
|
if ((modifiers & ControlMask) != 0)
|
|
keyname = QKeySequence(Qt::CTRL).toString() + QLatin1Char('+') + keyname;
|
|
if ((modifiers & ShiftMask) != 0)
|
|
keyname = QKeySequence(Qt::SHIFT).toString() + QLatin1Char('+') + keyname;
|
|
|
|
return modifiers & ScrollMask & LockMask & NumMask ? i18n("Press %1 while NumLock, CapsLock and ScrollLock are active", keyname)
|
|
: modifiers & ScrollMask & LockMask ? i18n("Press %1 while CapsLock and ScrollLock are active", keyname)
|
|
: modifiers & ScrollMask & NumMask ? i18n("Press %1 while NumLock and ScrollLock are active", keyname)
|
|
: modifiers & ScrollMask ? i18n("Press %1 while ScrollLock is active", keyname)
|
|
: modifiers & LockMask & NumMask ? i18n("Press %1 while NumLock and CapsLock are active", keyname)
|
|
: modifiers & LockMask ? i18n("Press %1 while CapsLock is active", keyname)
|
|
: modifiers & NumMask ? i18n("Press %1 while NumLock is active", keyname)
|
|
: i18n("Press %1", keyname);
|
|
}
|
|
|
|
KAccessConfig::KAccessConfig(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args)
|
|
: KQuickAddons::ManagedConfigModule(parent, metaData, args)
|
|
, m_data(new AccessibilityData(this))
|
|
, m_desktopShortcutInfo(QX11Info::isPlatformX11() ? mouseKeysShortcut(QX11Info::display()) : QString())
|
|
{
|
|
qmlRegisterType<MouseSettings>();
|
|
qmlRegisterType<BellSettings>();
|
|
qmlRegisterType<KeyboardSettings>();
|
|
qmlRegisterType<KeyboardFiltersSettings>();
|
|
qmlRegisterType<ScreenReaderSettings>();
|
|
|
|
int tryOrcaRun = QProcess::execute(QStringLiteral("orca"), {QStringLiteral("--version")});
|
|
m_screenReaderInstalled = tryOrcaRun != -2;
|
|
|
|
setButtons(ConfigModule::Apply | ConfigModule::Default | ConfigModule::Help);
|
|
|
|
connect(m_data->bellSettings(), &BellSettings::configChanged, this, &KAccessConfig::bellIsDefaultsChanged);
|
|
connect(m_data->mouseSettings(), &MouseSettings::configChanged, this, &KAccessConfig::mouseIsDefaultsChanged);
|
|
connect(m_data->keyboardFiltersSettings(), &ScreenReaderSettings::configChanged, this, &KAccessConfig::keyboardFiltersIsDefaultsChanged);
|
|
connect(m_data->keyboardSettings(), &ScreenReaderSettings::configChanged, this, &KAccessConfig::keyboardModifiersIsDefaultsChanged);
|
|
connect(m_data->screenReaderSettings(), &ScreenReaderSettings::configChanged, this, &KAccessConfig::screenReaderIsDefaultsChanged);
|
|
}
|
|
|
|
KAccessConfig::~KAccessConfig()
|
|
{
|
|
}
|
|
|
|
void KAccessConfig::configureKNotify(QQuickItem *parent)
|
|
{
|
|
auto dialog = KNotifyConfigWidget::configure(nullptr, QStringLiteral("kaccess"));
|
|
if (parent && parent->window()) {
|
|
dialog->winId();
|
|
dialog->windowHandle()->setTransientParent(QQuickRenderControl::renderWindowFor(parent->window()));
|
|
}
|
|
}
|
|
|
|
void KAccessConfig::launchOrcaConfiguration()
|
|
{
|
|
const QStringList gsettingArgs = {QStringLiteral("set"),
|
|
QStringLiteral("org.gnome.desktop.a11y.applications"),
|
|
QStringLiteral("screen-reader-enabled"),
|
|
QStringLiteral("true")};
|
|
|
|
int ret = QProcess::execute(QStringLiteral("gsettings"), gsettingArgs);
|
|
if (ret) {
|
|
const QString errorStr = QLatin1String("gsettings ") + gsettingArgs.join(QLatin1Char(' '));
|
|
setOrcaLaunchFeedback(i18n("Could not set gsettings for Orca: \"%1\" failed", errorStr));
|
|
return;
|
|
}
|
|
|
|
qint64 pid = 0;
|
|
bool started = QProcess::startDetached(QStringLiteral("orca"), {QStringLiteral("--setup")}, QString(), &pid);
|
|
if (!started) {
|
|
setOrcaLaunchFeedback(i18n("Error: Could not launch \"orca --setup\""));
|
|
}
|
|
}
|
|
|
|
void KAccessConfig::save()
|
|
{
|
|
ManagedConfigModule::save();
|
|
|
|
if (bellSettings()->systemBell() || bellSettings()->customBell() || bellSettings()->visibleBell()) {
|
|
KConfig _cfg(QStringLiteral("kdeglobals"), KConfig::NoGlobals);
|
|
KConfigGroup cfg(&_cfg, "General");
|
|
cfg.writeEntry("UseSystemBell", true);
|
|
cfg.sync();
|
|
}
|
|
|
|
// make kaccess reread the configuration
|
|
// turning a11y features off needs to be done by kaccess
|
|
// so run it to clear any enabled features and it will exit if it should
|
|
QProcess::startDetached(QStringLiteral("kaccess"), {});
|
|
}
|
|
|
|
QString KAccessConfig::orcaLaunchFeedback() const
|
|
{
|
|
return m_orcaLaunchFeedback;
|
|
}
|
|
|
|
void KAccessConfig::setOrcaLaunchFeedback(const QString &value)
|
|
{
|
|
if (m_orcaLaunchFeedback != value) {
|
|
m_orcaLaunchFeedback = value;
|
|
Q_EMIT orcaLaunchFeedbackChanged();
|
|
}
|
|
}
|
|
|
|
bool KAccessConfig::orcaInstalled()
|
|
{
|
|
int tryOrcaRun = QProcess::execute(QStringLiteral("orca"), {QStringLiteral("--version")});
|
|
// If the process cannot be started, -2 is returned.
|
|
return tryOrcaRun != -2;
|
|
}
|
|
|
|
MouseSettings *KAccessConfig::mouseSettings() const
|
|
{
|
|
return m_data->mouseSettings();
|
|
}
|
|
|
|
BellSettings *KAccessConfig::bellSettings() const
|
|
{
|
|
return m_data->bellSettings();
|
|
}
|
|
|
|
KeyboardSettings *KAccessConfig::keyboardSettings() const
|
|
{
|
|
return m_data->keyboardSettings();
|
|
}
|
|
|
|
KeyboardFiltersSettings *KAccessConfig::keyboardFiltersSettings() const
|
|
{
|
|
return m_data->keyboardFiltersSettings();
|
|
}
|
|
|
|
ScreenReaderSettings *KAccessConfig::screenReaderSettings() const
|
|
{
|
|
return m_data->screenReaderSettings();
|
|
}
|
|
|
|
bool KAccessConfig::bellIsDefaults() const
|
|
{
|
|
return bellSettings()->isDefaults();
|
|
}
|
|
|
|
bool KAccessConfig::mouseIsDefaults() const
|
|
{
|
|
return mouseSettings()->isDefaults();
|
|
}
|
|
|
|
bool KAccessConfig::keyboardFiltersIsDefaults() const
|
|
{
|
|
return keyboardFiltersSettings()->isDefaults();
|
|
}
|
|
|
|
bool KAccessConfig::keyboardModifiersIsDefaults() const
|
|
{
|
|
return keyboardSettings()->isDefaults();
|
|
}
|
|
|
|
bool KAccessConfig::screenReaderIsDefaults() const
|
|
{
|
|
return screenReaderSettings()->isDefaults();
|
|
}
|
|
|
|
#include "kcmaccess.moc"
|