Split implementation of keyboard layout handling into a dedicated class
Summary: So far the implementation of keyboard layout handling was split between KeyboardInputRedirection and Xkb. KeyboardInputRedirection registered the global shortcut and did the handling for layout switch and config changes. Xkb did the notification on layout change. Layout changes can nowadays be detected through an InputEventSpy. It can only happen after a key change or an explicit layout switch. Thus it does not need to be in Xkb anymore which allows to reduce Xkb to only care about the Xkb keymap and state tracking. This change introduces a new class KeyboardLayout which is an InputEventSpy and takes over the task of the layout change notification from Xkb and the layout management from KeyboardInputRedirection. Thus everything related to management of keyboard layout is together in one class. This allows in future to add unit test to it (requires further cleanup of Xkb to be able to use it and drop the InputRedirection dependency) and opens the possibility to also take over keyboard layout management on X11 for the Plasma desktop. Test Plan: Manual testing Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D4135
This commit is contained in:
parent
437edb45ca
commit
d6c0a5414e
5 changed files with 186 additions and 43 deletions
|
@ -370,6 +370,7 @@ set(kwin_KDEINIT_SRCS
|
|||
input_event.cpp
|
||||
input_event_spy.cpp
|
||||
keyboard_input.cpp
|
||||
keyboard_layout.cpp
|
||||
pointer_input.cpp
|
||||
touch_input.cpp
|
||||
netinfo.cpp
|
||||
|
|
|
@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "keyboard_input.h"
|
||||
#include "input_event.h"
|
||||
#include "input_event_spy.h"
|
||||
#include "keyboard_layout.h"
|
||||
#include "abstract_client.h"
|
||||
#include "options.h"
|
||||
#include "utils.h"
|
||||
|
@ -377,19 +378,6 @@ void Xkb::updateModifiers()
|
|||
const xkb_layout_index_t layout = xkb_state_serialize_layout(m_state, XKB_STATE_LAYOUT_EFFECTIVE);
|
||||
if (layout != m_currentLayout) {
|
||||
m_currentLayout = layout;
|
||||
// notify OSD service about the new layout
|
||||
if (kwinApp()->usesLibinput()) {
|
||||
// only if kwin is in charge of keyboard input
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(
|
||||
QStringLiteral("org.kde.plasmashell"),
|
||||
QStringLiteral("/org/kde/osdService"),
|
||||
QStringLiteral("org.kde.osdService"),
|
||||
QStringLiteral("kbdLayoutChanged"));
|
||||
|
||||
msg << QString::fromLocal8Bit(xkb_keymap_layout_get_name(m_keymap, layout));
|
||||
|
||||
QDBusConnection::sessionBus().asyncCall(msg);
|
||||
}
|
||||
}
|
||||
if (waylandServer()) {
|
||||
waylandServer()->seat()->updateKeyboardModifiers(xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_DEPRESSED)),
|
||||
|
@ -399,6 +387,11 @@ void Xkb::updateModifiers()
|
|||
}
|
||||
}
|
||||
|
||||
QString Xkb::layoutName() const
|
||||
{
|
||||
return QString::fromLocal8Bit(xkb_keymap_layout_get_name(m_keymap, m_currentLayout));
|
||||
}
|
||||
|
||||
void Xkb::updateConsumedModifiers(uint32_t key)
|
||||
{
|
||||
Qt::KeyboardModifiers mods = Qt::NoModifier;
|
||||
|
@ -564,6 +557,9 @@ void KeyboardInputRedirection::init()
|
|||
m_input->installInputEventSpy(new KeyStateChangedSpy(m_input));
|
||||
m_modifiersChangedSpy = new ModifiersChangedSpy(m_input);
|
||||
m_input->installInputEventSpy(m_modifiersChangedSpy);
|
||||
m_keyboardLayout = new KeyboardLayout(m_xkb.data());
|
||||
m_keyboardLayout->init();
|
||||
m_input->installInputEventSpy(m_keyboardLayout);
|
||||
|
||||
// setup key repeat
|
||||
m_keyRepeat.timer = new QTimer(this);
|
||||
|
@ -593,33 +589,6 @@ void KeyboardInputRedirection::init()
|
|||
if (waylandServer()->hasScreenLockerIntegration()) {
|
||||
connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &KeyboardInputRedirection::update);
|
||||
}
|
||||
|
||||
QAction *switchKeyboardAction = new QAction(this);
|
||||
switchKeyboardAction->setObjectName(QStringLiteral("Switch to Next Keyboard Layout"));
|
||||
switchKeyboardAction->setProperty("componentName", QStringLiteral("KDE Keyboard Layout Switcher"));
|
||||
const QKeySequence sequence = QKeySequence(Qt::ALT+Qt::CTRL+Qt::Key_K);
|
||||
KGlobalAccel::self()->setDefaultShortcut(switchKeyboardAction, QList<QKeySequence>({sequence}));
|
||||
KGlobalAccel::self()->setShortcut(switchKeyboardAction, QList<QKeySequence>({sequence}));
|
||||
m_input->registerShortcut(sequence, switchKeyboardAction);
|
||||
connect(switchKeyboardAction, &QAction::triggered, this,
|
||||
[this] {
|
||||
m_xkb->switchToNextLayout();
|
||||
}
|
||||
);
|
||||
|
||||
QDBusConnection::sessionBus().connect(QString(),
|
||||
QStringLiteral("/Layouts"),
|
||||
QStringLiteral("org.kde.keyboard"),
|
||||
QStringLiteral("reloadConfig"),
|
||||
this,
|
||||
SLOT(reconfigure()));
|
||||
|
||||
m_xkb->reconfigure();
|
||||
}
|
||||
|
||||
void KeyboardInputRedirection::reconfigure()
|
||||
{
|
||||
m_xkb->reconfigure();
|
||||
}
|
||||
|
||||
void KeyboardInputRedirection::update()
|
||||
|
@ -737,6 +706,7 @@ void KeyboardInputRedirection::processModifiers(uint32_t modsDepressed, uint32_t
|
|||
// TODO: send to proper Client and also send when active Client changes
|
||||
m_xkb->updateModifiers(modsDepressed, modsLatched, modsLocked, group);
|
||||
m_modifiersChangedSpy->updateModifiers(modifiers());
|
||||
m_keyboardLayout->checkLayoutChange();
|
||||
}
|
||||
|
||||
void KeyboardInputRedirection::processKeymapChange(int fd, uint32_t size)
|
||||
|
@ -746,6 +716,7 @@ void KeyboardInputRedirection::processKeymapChange(int fd, uint32_t size)
|
|||
}
|
||||
// TODO: should we pass the keymap to our Clients? Or only to the currently active one and update
|
||||
m_xkb->installKeymap(fd, size);
|
||||
m_keyboardLayout->resetLayout();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace KWin
|
|||
{
|
||||
|
||||
class InputRedirection;
|
||||
class KeyboardLayout;
|
||||
class ModifiersChangedSpy;
|
||||
class Toplevel;
|
||||
|
||||
|
@ -94,6 +95,7 @@ public:
|
|||
quint32 currentLayout() const {
|
||||
return m_currentLayout;
|
||||
}
|
||||
QString layoutName() const;
|
||||
|
||||
private:
|
||||
xkb_keymap *loadKeymapFromConfig();
|
||||
|
@ -167,9 +169,6 @@ public:
|
|||
Q_SIGNALS:
|
||||
void ledsChanged(KWin::Xkb::LEDs);
|
||||
|
||||
private Q_SLOTS:
|
||||
void reconfigure();
|
||||
|
||||
private:
|
||||
InputRedirection *m_input;
|
||||
bool m_inited = false;
|
||||
|
@ -181,6 +180,7 @@ private:
|
|||
QTimer *timer = nullptr;
|
||||
} m_keyRepeat;
|
||||
ModifiersChangedSpy *m_modifiersChangedSpy = nullptr;
|
||||
KeyboardLayout *m_keyboardLayout = nullptr;
|
||||
};
|
||||
|
||||
inline
|
||||
|
|
115
keyboard_layout.cpp
Normal file
115
keyboard_layout.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2016, 2017 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "keyboard_layout.h"
|
||||
#include "keyboard_input.h"
|
||||
#include "input_event.h"
|
||||
#include "main.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include <KGlobalAccel>
|
||||
#include <QAction>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusPendingCall>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
KeyboardLayout::KeyboardLayout(Xkb *xkb)
|
||||
: QObject()
|
||||
, m_xkb(xkb)
|
||||
{
|
||||
}
|
||||
|
||||
KeyboardLayout::~KeyboardLayout() = default;
|
||||
|
||||
void KeyboardLayout::init()
|
||||
{
|
||||
QAction *switchKeyboardAction = new QAction(this);
|
||||
switchKeyboardAction->setObjectName(QStringLiteral("Switch to Next Keyboard Layout"));
|
||||
switchKeyboardAction->setProperty("componentName", QStringLiteral("KDE Keyboard Layout Switcher"));
|
||||
const QKeySequence sequence = QKeySequence(Qt::ALT+Qt::CTRL+Qt::Key_K);
|
||||
KGlobalAccel::self()->setDefaultShortcut(switchKeyboardAction, QList<QKeySequence>({sequence}));
|
||||
KGlobalAccel::self()->setShortcut(switchKeyboardAction, QList<QKeySequence>({sequence}));
|
||||
kwinApp()->platform()->setupActionForGlobalAccel(switchKeyboardAction);
|
||||
connect(switchKeyboardAction, &QAction::triggered, this,
|
||||
[this] {
|
||||
m_xkb->switchToNextLayout();
|
||||
checkLayoutChange();
|
||||
}
|
||||
);
|
||||
|
||||
QDBusConnection::sessionBus().connect(QString(),
|
||||
QStringLiteral("/Layouts"),
|
||||
QStringLiteral("org.kde.keyboard"),
|
||||
QStringLiteral("reloadConfig"),
|
||||
this,
|
||||
SLOT(reconfigure()));
|
||||
|
||||
reconfigure();
|
||||
}
|
||||
|
||||
void KeyboardLayout::reconfigure()
|
||||
{
|
||||
m_xkb->reconfigure();
|
||||
resetLayout();
|
||||
}
|
||||
|
||||
void KeyboardLayout::resetLayout()
|
||||
{
|
||||
m_layout = m_xkb->currentLayout();
|
||||
}
|
||||
|
||||
void KeyboardLayout::keyEvent(KeyEvent *event)
|
||||
{
|
||||
if (!event->isAutoRepeat()) {
|
||||
checkLayoutChange();
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardLayout::checkLayoutChange()
|
||||
{
|
||||
const auto layout = m_xkb->currentLayout();
|
||||
if (m_layout == layout) {
|
||||
return;
|
||||
}
|
||||
m_layout = layout;
|
||||
notifyLayoutChange();
|
||||
}
|
||||
|
||||
void KeyboardLayout::notifyLayoutChange()
|
||||
{
|
||||
// notify OSD service about the new layout
|
||||
if (!kwinApp()->usesLibinput()) {
|
||||
return;
|
||||
}
|
||||
// only if kwin is in charge of keyboard input
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(
|
||||
QStringLiteral("org.kde.plasmashell"),
|
||||
QStringLiteral("/org/kde/osdService"),
|
||||
QStringLiteral("org.kde.osdService"),
|
||||
QStringLiteral("kbdLayoutChanged"));
|
||||
|
||||
msg << m_xkb->layoutName();
|
||||
|
||||
QDBusConnection::sessionBus().asyncCall(msg);
|
||||
}
|
||||
|
||||
}
|
56
keyboard_layout.h
Normal file
56
keyboard_layout.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2016, 2017 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#ifndef KWIN_KEYBOARD_LAYOUT_H
|
||||
#define KWIN_KEYBOARD_LAYOUT_H
|
||||
|
||||
#include "input_event_spy.h"
|
||||
#include <QObject>
|
||||
typedef uint32_t xkb_layout_index_t;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
class Xkb;
|
||||
|
||||
class KeyboardLayout : public QObject, public InputEventSpy
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit KeyboardLayout(Xkb *xkb);
|
||||
~KeyboardLayout() override;
|
||||
|
||||
void init();
|
||||
|
||||
void checkLayoutChange();
|
||||
void resetLayout();
|
||||
|
||||
void keyEvent(KeyEvent *event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void reconfigure();
|
||||
|
||||
private:
|
||||
void notifyLayoutChange();
|
||||
Xkb *m_xkb;
|
||||
xkb_layout_index_t m_layout = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue