summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Weghorn <m.weghorn@posteo.de>2022-05-28 10:51:53 +0200
committerMichael Weghorn <m.weghorn@posteo.de>2022-05-28 16:09:00 +0200
commit217ca9c79d75912df3fb735def4b64b0a7284e30 (patch)
tree89b5a7cbfc23fb6a74d8d0e9b1412f5a6564ebbb
parent54f6599a4de738dfe3a26e8229e5588d26dd8165 (diff)
tdf#149255 qt: Implement deletion/"swallowing" for IM replacement
This implements deletion of the text specified by the `replacementStart()` and `replacementLength()` of the `QInputMethodEvent*` received in `QtWidget::inputMethodEvent`. Quoting from the `QInputMethodEvent` doc [1]: > When receiving an input method event, the text widget has to performs > the following steps: > > 1. If the widget has selected text, the selected text should > get removed. > 2. Remove the text starting at replacementStart() with length > replacementLength() and replace it by the commitString(). > [...] This implementation is sufficient for the scenario described in tdf#149255, but I didn't test any more complex scenarios, like one where text is selected. (My current knowledge of input methods is too limited to be able to do more extensive testing without first spending time to get deeper into the topic.) The gtk3 implementation in `GtkSalFrame::IMHandler::signalIMDeleteSurrounding` was very helpful to get an impression of what needs to be done. Since the documentation for `QInputMethodEvent::replacementLength()` talks about "number of characters", I suspect that conversion to UTF-16 code units is needed just the same way as it is for the gtk3 case and this therefore calls `SalFrame::CalcDeleteSurroundingSelection` the same way. However, this part is untested, since it is not relevant for the tested scenario (where each of the characters is represented in a single UTF-16 code unit). [1] https://doc.qt.io/qt-5/qinputmethodevent.html Change-Id: I2a34e58067e253c39dbd87905943134bdfa4ea27 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134855 Tested-by: Jenkins Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de> Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
-rw-r--r--vcl/inc/qt5/QtWidget.hxx2
-rw-r--r--vcl/qt5/QtWidget.cxx39
2 files changed, 39 insertions, 2 deletions
diff --git a/vcl/inc/qt5/QtWidget.hxx b/vcl/inc/qt5/QtWidget.hxx
index 8f7f6cc319e1..e644e7f70cd9 100644
--- a/vcl/inc/qt5/QtWidget.hxx
+++ b/vcl/inc/qt5/QtWidget.hxx
@@ -49,6 +49,8 @@ class QtWidget : public QWidget
};
static void commitText(QtFrame&, const QString& aText);
+ static void deleteReplacementText(QtFrame& rFrame, int nReplacementStart,
+ int nReplacementLength);
static bool handleKeyEvent(QtFrame&, const QWidget&, QKeyEvent*, const ButtonKeyState);
static void handleMouseButtonEvent(const QtFrame&, const QMouseEvent*, const ButtonKeyState);
static void handleMouseEnterLeaveEvents(const QtFrame&, QEvent*);
diff --git a/vcl/qt5/QtWidget.cxx b/vcl/qt5/QtWidget.cxx
index a9484f0b2531..74adcc4e974c 100644
--- a/vcl/qt5/QtWidget.cxx
+++ b/vcl/qt5/QtWidget.cxx
@@ -493,6 +493,33 @@ void QtWidget::commitText(QtFrame& rFrame, const QString& aText)
rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr);
}
+void QtWidget::deleteReplacementText(QtFrame& rFrame, int nReplacementStart, int nReplacementLength)
+{
+ // get the surrounding text
+ SolarMutexGuard aGuard;
+ SalSurroundingTextRequestEvent aSurroundingTextEvt;
+ aSurroundingTextEvt.maText.clear();
+ aSurroundingTextEvt.mnStart = aSurroundingTextEvt.mnEnd = 0;
+ rFrame.CallCallback(SalEvent::SurroundingTextRequest, &aSurroundingTextEvt);
+
+ // Turn nReplacementStart, nReplacementLength into a UTF-16 selection
+ const Selection aSelection = SalFrame::CalcDeleteSurroundingSelection(
+ aSurroundingTextEvt.maText, aSurroundingTextEvt.mnStart, nReplacementStart,
+ nReplacementLength);
+
+ const Selection aInvalid(SAL_MAX_UINT32, SAL_MAX_UINT32);
+ if (aSelection == aInvalid)
+ {
+ SAL_WARN("vcl.qt", "Invalid selection when deleting IM replacement text");
+ return;
+ }
+
+ SalSurroundingTextSelectionChangeEvent aEvt;
+ aEvt.mnStart = aSelection.Min();
+ aEvt.mnEnd = aSelection.Max();
+ rFrame.CallCallback(SalEvent::DeleteSurroundingTextRequest, &aEvt);
+}
+
bool QtWidget::handleKeyEvent(QtFrame& rFrame, const QWidget& rWidget, QKeyEvent* pEvent,
const ButtonKeyState eState)
{
@@ -724,8 +751,16 @@ static ExtTextInputAttr lcl_MapUnderlineStyle(QTextCharFormat::UnderlineStyle us
void QtWidget::inputMethodEvent(QInputMethodEvent* pEvent)
{
- if (!pEvent->commitString().isEmpty())
- commitText(m_rFrame, pEvent->commitString());
+ const bool bHasCommitText = !pEvent->commitString().isEmpty();
+ const int nReplacementLength = pEvent->replacementLength();
+
+ if (nReplacementLength > 0 || bHasCommitText)
+ {
+ if (nReplacementLength > 0)
+ deleteReplacementText(m_rFrame, pEvent->replacementStart(), nReplacementLength);
+ if (bHasCommitText)
+ commitText(m_rFrame, pEvent->commitString());
+ }
else
{
SalExtTextInputEvent aInputEvent;