#include "KWinInputMethod.h" #include "KWinInputContext.h" #include 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(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(); }