diff options
author | Michael Weghorn <m.weghorn@posteo.de> | 2022-05-28 10:51:53 +0200 |
---|---|---|
committer | Michael Weghorn <m.weghorn@posteo.de> | 2022-05-28 16:09:00 +0200 |
commit | 217ca9c79d75912df3fb735def4b64b0a7284e30 (patch) | |
tree | 89b5a7cbfc23fb6a74d8d0e9b1412f5a6564ebbb | |
parent | 54f6599a4de738dfe3a26e8229e5588d26dd8165 (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.hxx | 2 | ||||
-rw-r--r-- | vcl/qt5/QtWidget.cxx | 39 |
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; |