Diagnostics collects what this session doesn't allow, logs it, and lists it in the settings panel (with a dot on the gear): KWin not launching sloposk as its keyboard (detected by WAYLAND_SOCKET, since KWin offers the input-method global to every client), fake input missing or too old, org.kde.keyboard unreachable, and the D-Bus control name taken. Modifier combos go through fake input even in text fields: KWin drops the input method's modifier mask for most clients, so Ctrl+A typed "a". The desktop file is generated with an absolute Exec, which KWin needs to match it: one for the installed binary, one for the build's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
110 lines
3.1 KiB
C++
110 lines
3.1 KiB
C++
#include "KWinInputMethod.h"
|
|
#include "KWinInputContext.h"
|
|
|
|
#include <xkbcommon/xkbcommon-keysyms.h>
|
|
|
|
KWinInputMethodGlobal::KWinInputMethodGlobal()
|
|
: QWaylandClientExtensionTemplate(1)
|
|
{
|
|
initialize();
|
|
}
|
|
|
|
void KWinInputMethodGlobal::zwp_input_method_v1_activate(::zwp_input_method_context_v1 *context)
|
|
{
|
|
Q_EMIT activated(context);
|
|
}
|
|
|
|
void KWinInputMethodGlobal::zwp_input_method_v1_deactivate(::zwp_input_method_context_v1 *context)
|
|
{
|
|
Q_EMIT deactivated(context);
|
|
}
|
|
|
|
KWinInputMethod::KWinInputMethod(QObject *parent)
|
|
: TextBackend(parent)
|
|
{
|
|
connect(&m_global, &KWinInputMethodGlobal::activated, this, &KWinInputMethod::activate);
|
|
connect(&m_global, &KWinInputMethodGlobal::deactivated, this, &KWinInputMethod::deactivate);
|
|
connect(&m_global, &QWaylandClientExtension::activeChanged, this, &KWinInputMethod::availableChanged);
|
|
}
|
|
|
|
KWinInputMethod::~KWinInputMethod() = default;
|
|
|
|
bool KWinInputMethod::isAvailable() const
|
|
{
|
|
return m_global.isActive();
|
|
}
|
|
|
|
bool KWinInputMethod::isActive() const
|
|
{
|
|
return m_context != nullptr;
|
|
}
|
|
|
|
TextContext KWinInputMethod::context() const
|
|
{
|
|
return m_context ? m_context->context() : TextContext();
|
|
}
|
|
|
|
void KWinInputMethod::commitText(const QString &text)
|
|
{
|
|
if (m_context)
|
|
m_context->commit(text);
|
|
else
|
|
m_fakeInput.typeText(text);
|
|
}
|
|
|
|
void KWinInputMethod::replaceBeforeCursor(const QString &before, const QString &text)
|
|
{
|
|
if (m_context) {
|
|
m_context->replaceBeforeCursor(before, text);
|
|
return;
|
|
}
|
|
// Key events are one ordered stream, so plain Backspaces are safe here.
|
|
for (qsizetype i = 0; i < before.toUcs4().size(); ++i)
|
|
m_fakeInput.sendKeysym(XKB_KEY_BackSpace);
|
|
m_fakeInput.typeText(text);
|
|
}
|
|
|
|
void KWinInputMethod::setPreedit(const QString &text)
|
|
{
|
|
if (m_context)
|
|
m_context->preedit(text);
|
|
}
|
|
|
|
// KWin drops the input method's modifier mask for most clients (it forwards
|
|
// only the key), so Ctrl+A would type "a": combos hold real modifier keys.
|
|
void KWinInputMethod::sendKeysym(quint32 keysym, Qt::KeyboardModifiers modifiers)
|
|
{
|
|
if (m_context && (modifiers == Qt::NoModifier || !m_fakeInput.canSendKeysyms()))
|
|
m_context->sendKeysym(keysym, modifiers);
|
|
else
|
|
m_fakeInput.sendKeysym(keysym, modifiers);
|
|
}
|
|
|
|
// Always fake input, even in a text field: held keys are key events, and the
|
|
// input method's keysyms can't hold a modifier across keys.
|
|
void KWinInputMethod::setKeyPressed(quint32 keysym, bool pressed)
|
|
{
|
|
m_fakeInput.setKeyPressed(keysym, pressed);
|
|
}
|
|
|
|
void KWinInputMethod::activate(::zwp_input_method_context_v1 *context)
|
|
{
|
|
m_previous = std::move(m_context);
|
|
m_context = std::make_unique<KWinInputContext>(context);
|
|
connect(m_context.get(), &KWinInputContext::contextChanged, this, &TextBackend::contextChanged);
|
|
Q_EMIT activeChanged();
|
|
}
|
|
|
|
void KWinInputMethod::deactivate(::zwp_input_method_context_v1 *context)
|
|
{
|
|
if (m_previous && m_previous->object() == context) {
|
|
m_previous.reset();
|
|
return;
|
|
}
|
|
if (!m_context || m_context->object() != context)
|
|
return;
|
|
m_context.reset();
|
|
Q_EMIT activeChanged();
|
|
Q_EMIT contextChanged();
|
|
}
|