inputmethod: Use touch events to decide if the panel is shown not the state

Prefer hiding/showing the panel (i.e. the window) when not a touch event
than stopping to make the inputmethod active.
This way we remain compatible with non-virtualkeyboard inputmethods.
This commit is contained in:
Aleix Pol 2021-10-13 18:24:59 +02:00 committed by Aleix Pol Gonzalez
parent 5b9deafa14
commit 3e77907d21
4 changed files with 33 additions and 14 deletions

View file

@ -86,7 +86,6 @@ void InputMethod::init()
new TextInputManagerV2Interface(waylandServer()->display()); new TextInputManagerV2Interface(waylandServer()->display());
new TextInputManagerV3Interface(waylandServer()->display()); new TextInputManagerV3Interface(waylandServer()->display());
connect(workspace(), &Workspace::clientAdded, this, &InputMethod::clientAdded);
connect(waylandServer()->seat(), &SeatInterface::focusedTextInputSurfaceChanged, this, &InputMethod::handleFocusedSurfaceChanged); connect(waylandServer()->seat(), &SeatInterface::focusedTextInputSurfaceChanged, this, &InputMethod::handleFocusedSurfaceChanged);
TextInputV2Interface *textInputV2 = waylandServer()->seat()->textInputV2(); TextInputV2Interface *textInputV2 = waylandServer()->seat()->textInputV2();
@ -118,11 +117,15 @@ void InputMethod::hide()
setActive(false); setActive(false);
} }
void InputMethod::setActive(bool active) bool InputMethod::touchEventTriggered() const
{ {
active &= input()->touch() return input()->touch()
&& input()->touch()->lastEventTime() > input()->keyboard()->lastEventTime() && input()->touch()->lastEventTime() > input()->keyboard()->lastEventTime()
&& input()->touch()->lastEventTime() > input()->pointer()->lastEventTime(); && input()->touch()->lastEventTime() > input()->pointer()->lastEventTime();
}
void InputMethod::setActive(bool active)
{
const bool wasActive = waylandServer()->inputMethod()->context(); const bool wasActive = waylandServer()->inputMethod()->context();
if (wasActive && !active) { if (wasActive && !active) {
waylandServer()->inputMethod()->sendDeactivate(); waylandServer()->inputMethod()->sendDeactivate();
@ -148,18 +151,14 @@ void InputMethod::setActive(bool active)
} }
} }
void InputMethod::clientAdded(AbstractClient *_client) void InputMethod::setPanel(InputPanelV1Client *client)
{ {
if (!_client->isInputMethod()) { Q_ASSERT(client->isInputMethod());
return;
}
if (m_inputClient) { if (m_inputClient) {
qCWarning(KWIN_VIRTUALKEYBOARD) << "Replacing input client" << m_inputClient << "with" << _client; qCWarning(KWIN_VIRTUALKEYBOARD) << "Replacing input client" << m_inputClient << "with" << client;
disconnect(m_inputClient, nullptr, this, nullptr); disconnect(m_inputClient, nullptr, this, nullptr);
} }
const auto client = dynamic_cast<InputPanelV1Client *>(_client);
m_inputClient = client; m_inputClient = client;
connect(client->surface(), &SurfaceInterface::inputChanged, this, &InputMethod::updateInputPanelState); connect(client->surface(), &SurfaceInterface::inputChanged, this, &InputMethod::updateInputPanelState);
connect(client, &QObject::destroyed, this, [this] { connect(client, &QObject::destroyed, this, [this] {
@ -253,6 +252,9 @@ void InputMethod::textInputInterfaceV2StateUpdated(quint32 serial, KWaylandServe
if (!t2 || !t2->isEnabled()) { if (!t2 || !t2->isEnabled()) {
return; return;
} }
if (m_inputClient && touchEventTriggered()) {
m_inputClient->allow();
}
switch (reason) { switch (reason) {
case KWaylandServer::TextInputV2Interface::UpdateReason::StateChange: case KWaylandServer::TextInputV2Interface::UpdateReason::StateChange:
break; break;
@ -526,6 +528,10 @@ void InputMethod::updateInputPanelState()
return; return;
} }
if (m_inputClient && touchEventTriggered()) {
m_inputClient->allow();
}
QRect overlap = QRect(0, 0, 0, 0); QRect overlap = QRect(0, 0, 0, 0);
if (m_trackedClient) { if (m_trackedClient) {
const bool bottomKeyboard = m_inputClient && m_inputClient->mode() != InputPanelV1Client::Overlay && m_inputClient->isShown(false); const bool bottomKeyboard = m_inputClient && m_inputClient->mode() != InputPanelV1Client::Overlay && m_inputClient->isShown(false);

View file

@ -54,6 +54,7 @@ public:
bool isVisible() const; bool isVisible() const;
bool isAvailable() const; bool isAvailable() const;
void setPanel(InputPanelV1Client* client);
void setInputMethodCommand(const QString &path); void setInputMethodCommand(const QString &path);
Q_SIGNALS: Q_SIGNALS:
@ -63,8 +64,6 @@ Q_SIGNALS:
void availableChanged(); void availableChanged();
private Q_SLOTS: private Q_SLOTS:
void clientAdded(AbstractClient* client);
// textinput interface slots // textinput interface slots
void handleFocusedSurfaceChanged(); void handleFocusedSurfaceChanged();
void surroundingTextChanged(); void surroundingTextChanged();
@ -94,6 +93,8 @@ private:
void setTrackedClient(AbstractClient *trackedClient); void setTrackedClient(AbstractClient *trackedClient);
void installKeyboardGrab(KWaylandServer::InputMethodGrabV1 *keyboardGrab); void installKeyboardGrab(KWaylandServer::InputMethodGrabV1 *keyboardGrab);
bool touchEventTriggered() const;
struct { struct {
QString text = QString(); QString text = QString();
quint32 begin = 0; quint32 begin = 0;

View file

@ -13,6 +13,7 @@
#include "workspace.h" #include "workspace.h"
#include "abstract_wayland_output.h" #include "abstract_wayland_output.h"
#include "platform.h" #include "platform.h"
#include "inputmethod.h"
#include <KWaylandServer/output_interface.h> #include <KWaylandServer/output_interface.h>
#include <KWaylandServer/seat_interface.h> #include <KWaylandServer/seat_interface.h>
#include <KWaylandServer/surface_interface.h> #include <KWaylandServer/surface_interface.h>
@ -38,6 +39,8 @@ InputPanelV1Client::InputPanelV1Client(InputPanelSurfaceV1Interface *panelSurfac
connect(panelSurface, &InputPanelSurfaceV1Interface::topLevel, this, &InputPanelV1Client::showTopLevel); connect(panelSurface, &InputPanelSurfaceV1Interface::topLevel, this, &InputPanelV1Client::showTopLevel);
connect(panelSurface, &InputPanelSurfaceV1Interface::overlayPanel, this, &InputPanelV1Client::showOverlayPanel); connect(panelSurface, &InputPanelSurfaceV1Interface::overlayPanel, this, &InputPanelV1Client::showOverlayPanel);
connect(panelSurface, &InputPanelSurfaceV1Interface::destroyed, this, &InputPanelV1Client::destroyClient); connect(panelSurface, &InputPanelSurfaceV1Interface::destroyed, this, &InputPanelV1Client::destroyClient);
InputMethod::self()->setPanel(this);
} }
void InputPanelV1Client::showOverlayPanel() void InputPanelV1Client::showOverlayPanel()
@ -53,12 +56,20 @@ void InputPanelV1Client::showTopLevel(OutputInterface *output, InputPanelSurface
Q_UNUSED(position); Q_UNUSED(position);
m_mode = Toplevel; m_mode = Toplevel;
setOutput(output); setOutput(output);
reposition(); }
void InputPanelV1Client::allow()
{
setReadyForPainting(); setReadyForPainting();
reposition();
} }
void KWin::InputPanelV1Client::reposition() void KWin::InputPanelV1Client::reposition()
{ {
if (!readyForPainting()) {
return;
}
switch (m_mode) { switch (m_mode) {
case Toplevel: { case Toplevel: {
if (m_output) { if (m_output) {
@ -109,7 +120,7 @@ NET::WindowType InputPanelV1Client::windowType(bool, int) const
QRect InputPanelV1Client::inputGeometry() const QRect InputPanelV1Client::inputGeometry() const
{ {
return surface()->input().boundingRect().translated(pos()); return readyForPainting() ? surface()->input().boundingRect().translated(pos()) : QRect();
} }
void InputPanelV1Client::setOutput(OutputInterface *outputIface) void InputPanelV1Client::setOutput(OutputInterface *outputIface)

View file

@ -47,6 +47,7 @@ public:
{ {
return m_mode; return m_mode;
} }
void allow();
protected: protected:
void moveResizeInternal(const QRect &rect, MoveResizeMode mode) override; void moveResizeInternal(const QRect &rect, MoveResizeMode mode) override;