diff --git a/virtualkeyboard.h b/virtualkeyboard.h --- a/virtualkeyboard.h +++ b/virtualkeyboard.h @@ -45,16 +45,38 @@ QWindow *inputPanel() const; + /** + * Enum describing the modes the keyboard can be in + **/ + enum class Mode { + /** + * Keyboard disabled + **/ + Disabled, + /** + * Keyboard enabled on touch events, disabled on other events + **/ + Dynamic, + /** + * Keyboard enabled + **/ + Enabled + }; + + void setDynamicEnabled(bool set); + Q_SIGNALS: - void enabledChanged(bool enabled); + void modeChanged(); private: void show(); void hide(); - void setEnabled(bool enable); + void setMode(Mode mode); void updateSni(); + bool isEnabled() const; - bool m_enabled = false; + Mode m_mode = Mode::Disabled; + bool m_dynamicEnabled = false; KStatusNotifierItem *m_sni = nullptr; QScopedPointer m_inputWindow; QMetaObject::Connection m_waylandShowConnection; diff --git a/virtualkeyboard.cpp b/virtualkeyboard.cpp --- a/virtualkeyboard.cpp +++ b/virtualkeyboard.cpp @@ -20,6 +20,7 @@ #include "virtualkeyboard.h" #include "virtualkeyboard_dbus.h" #include "input.h" +#include "input_event_spy.h" #include "keyboard_input.h" #include "utils.h" #include "screens.h" @@ -52,6 +53,77 @@ namespace KWin { +class VirtualKeyboardSpy : public InputEventSpy +{ +public: + VirtualKeyboardSpy(VirtualKeyboard *vk); + + void keyEvent(KeyEvent *event) override; + void pinchGestureBegin(int fingerCount, quint32 time) override; + void swipeGestureBegin(int fingerCount, quint32 time) override; + void pointerEvent(MouseEvent *event) override; + void wheelEvent(WheelEvent *event) override; + void touchDown(quint32 id, const QPointF &pos, quint32 time) override; + +private: + void enable(bool set); + QPointer m_keyboard; +}; + +VirtualKeyboardSpy::VirtualKeyboardSpy(VirtualKeyboard *vk) + : m_keyboard(vk) +{ +} + +void VirtualKeyboardSpy::keyEvent(KeyEvent *event) +{ + Q_UNUSED(event) + enable(false); +} + +void VirtualKeyboardSpy::pinchGestureBegin(int fingerCount, quint32 time) +{ + Q_UNUSED(fingerCount) + Q_UNUSED(time) + enable(false); +} + +void VirtualKeyboardSpy::swipeGestureBegin(int fingerCount, quint32 time) +{ + Q_UNUSED(fingerCount) + Q_UNUSED(time) + enable(false); +} + +void VirtualKeyboardSpy::pointerEvent(MouseEvent *event) +{ + Q_UNUSED(event) + enable(false); +} + +void VirtualKeyboardSpy::wheelEvent(WheelEvent *event) +{ + Q_UNUSED(event) + enable(false); +} + +void VirtualKeyboardSpy::touchDown(quint32 id, const QPointF &pos, quint32 time) +{ + Q_UNUSED(id) + Q_UNUSED(pos) + Q_UNUSED(time) + enable(true); +} + +void VirtualKeyboardSpy::enable(bool set) +{ + if (!m_keyboard) { + return; + } + m_keyboard->setDynamicEnabled(set); +} + + KWIN_SINGLETON_FACTORY(VirtualKeyboard) VirtualKeyboard::VirtualKeyboard(QObject *parent) @@ -82,12 +154,12 @@ m_inputWindow->setProperty("__kwin_input_method", true); if (waylandServer()) { - m_enabled = !input()->hasAlphaNumericKeyboard(); - qCDebug(KWIN_VIRTUALKEYBOARD) << "enabled by default: " << m_enabled; + setMode(input()->hasAlphaNumericKeyboard() ? Mode::Dynamic : Mode::Enabled); + qCDebug(KWIN_VIRTUALKEYBOARD) << "enabled by default: " << int(m_mode); connect(input(), &InputRedirection::hasAlphaNumericKeyboardChanged, this, [this] (bool set) { qCDebug(KWIN_VIRTUALKEYBOARD) << "AlphaNumeric Keyboard changed:" << set << "toggling VirtualKeyboard."; - setEnabled(!set); + setMode(set ? Mode::Dynamic : Mode::Enabled); } ); } @@ -101,16 +173,27 @@ updateSni(); connect(m_sni, &KStatusNotifierItem::activateRequested, this, [this] { - setEnabled(!m_enabled); + switch (m_mode) { + case Mode::Disabled: + setMode(Mode::Dynamic); + break; + case Mode::Dynamic: + setMode(Mode::Enabled); + break; + case Mode::Enabled: + setMode(Mode::Disabled); + break; + } } ); - connect(this, &VirtualKeyboard::enabledChanged, this, &VirtualKeyboard::updateSni); + connect(this, &VirtualKeyboard::modeChanged, this, &VirtualKeyboard::updateSni); + // TODO: a new dbus interface supporting mode? auto dbus = new VirtualKeyboardDBus(this); qCDebug(KWIN_VIRTUALKEYBOARD) << "Registering the DBus interface"; - dbus->setEnabled(m_enabled); - connect(dbus, &VirtualKeyboardDBus::activateRequested, this, &VirtualKeyboard::setEnabled); - connect(this, &VirtualKeyboard::enabledChanged, dbus, &VirtualKeyboardDBus::setEnabled); + dbus->setEnabled(m_mode != Mode::Disabled); + connect(dbus, &VirtualKeyboardDBus::activateRequested, this, [this] (bool active) { setMode(active ? Mode::Enabled : Mode::Disabled); }); + connect(this, &VirtualKeyboard::modeChanged, dbus, [this, dbus] { dbus->setEnabled(m_mode != Mode::Disabled); }); if (waylandServer()) { // we can announce support for the text input interface @@ -190,45 +273,55 @@ } } ); + + input()->installInputEventSpy(new VirtualKeyboardSpy{this}); } -void VirtualKeyboard::setEnabled(bool enabled) +void VirtualKeyboard::setMode(Mode mode) { - if (m_enabled == enabled) { + if (m_mode == mode) { return; } - m_enabled = enabled; + m_mode = mode; qApp->inputMethod()->update(Qt::ImQueryAll); - emit enabledChanged(m_enabled); + emit modeChanged(); // send OSD message QDBusMessage msg = QDBusMessage::createMethodCall( QStringLiteral("org.kde.plasmashell"), QStringLiteral("/org/kde/osdService"), QStringLiteral("org.kde.osdService"), QStringLiteral("virtualKeyboardEnabledChanged") ); - msg.setArguments({enabled}); + // TODO: new call for dynamic mode + msg.setArguments({m_mode != Mode::Disabled}); QDBusConnection::sessionBus().asyncCall(msg); } void VirtualKeyboard::updateSni() { if (!m_sni) { return; } - if (m_enabled) { - m_sni->setIconByName(QStringLiteral("input-keyboard-virtual-on")); - m_sni->setToolTipTitle(i18n("Virtual Keyboard is enabled.")); - } else { + switch (m_mode) { + case Mode::Disabled: m_sni->setIconByName(QStringLiteral("input-keyboard-virtual-off")); m_sni->setToolTipTitle(i18n("Virtual Keyboard is disabled.")); + break; + case Mode::Enabled: + m_sni->setIconByName(QStringLiteral("input-keyboard-virtual-on")); + m_sni->setToolTipTitle(i18n("Virtual Keyboard is enabled.")); + break; + case Mode::Dynamic: + m_sni->setIconByName(QStringLiteral("input-keyboard-virtual-on")); + m_sni->setToolTipTitle(i18n("Virtual Keyboard is enabled for touch input.")); + break; } } void VirtualKeyboard::show() { - if (m_inputWindow.isNull() || !m_enabled) { + if (m_inputWindow.isNull() || !isEnabled()) { return; } m_inputWindow->setGeometry(screens()->geometry(screens()->current())); @@ -247,7 +340,7 @@ { if (e->type() == QEvent::InputMethod) { QInputMethodEvent *event = static_cast(e); - if (m_enabled && waylandServer()) { + if (isEnabled() && waylandServer()) { bool isPreedit = false; for (auto attribute : event->attributes()) { switch (attribute.type) { @@ -274,7 +367,7 @@ if (e->type() == QEvent::InputMethodQuery) { auto event = static_cast(e); TextInputInterface *ti = nullptr; - if (waylandServer() && m_enabled) { + if (waylandServer() && isEnabled()) { ti = waylandServer()->seat()->focusedTextInput(); } if (event->queries().testFlag(Qt::ImEnabled)) { @@ -446,4 +539,29 @@ return m_inputWindow.data(); } +bool VirtualKeyboard::isEnabled() const +{ + switch (m_mode) { + case Mode::Disabled: + return false; + case Mode::Enabled: + return true; + case Mode::Dynamic: + return m_dynamicEnabled; + default: + Q_UNREACHABLE(); + } +} + +void VirtualKeyboard::setDynamicEnabled(bool set) +{ + if (m_dynamicEnabled == set) { + return; + } + m_dynamicEnabled = set; + if (m_mode == Mode::Dynamic) { + qApp->inputMethod()->update(Qt::ImQueryAll); + } +} + }