Files
sloposk/src/backend/KWinInputMethod.cpp
T
ericek111andClaude Opus 5.5 499e5ee76e Report unavailable protocols and services; send combos as real keys
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>
2026-10-15 11:36:56 +02:00

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();
}