commit 8064dbeb66f85a59e75e6b06e3d734f74a3b5f15
Author: Koji Yokota <[email protected]>
Date: Tue Aug 19 12:44:41 2025 +0900
Respond correct pos and surrounding texts in QInputMethodQueryEvent
This fix makes it work the re-conversion feature of IM after string
commitment.
---
src/frontends/qt/GuiInputMethod.cpp | 77 ++++++++++++++++++++++---------------
src/frontends/qt/GuiInputMethod.h | 4 ++
2 files changed, 50 insertions(+), 31 deletions(-)
diff --git a/src/frontends/qt/GuiInputMethod.cpp
b/src/frontends/qt/GuiInputMethod.cpp
index 4b0c4cb34d..8e91f1bdb9 100644
--- a/src/frontends/qt/GuiInputMethod.cpp
+++ b/src/frontends/qt/GuiInputMethod.cpp
@@ -74,11 +74,11 @@ struct GuiInputMethod::Private
Rows::iterator rows_;
size_type rows_size_;
- pos_type * cur_pos_ptr_ = nullptr;
+ pos_type cur_pos_ = 0;
pos_type cur_row_idx_;
pos_type caret_pos_;
- pos_type anchor_pos_;
+ pos_type anchor_pos_ = 0;
pos_type abs_pos_;
bool real_boundary_ = false;
@@ -109,6 +109,8 @@ GuiInputMethod::GuiInputMethod(GuiWorkArea *parent)
d->sys_im_, &QInputMethod::update);
connect(d->sys_im_, &QInputMethod::localeChanged,
this, &GuiInputMethod::onLocaleChanged);
+ connect(this, &GuiInputMethod::cursorPositionChanged,
+ this, &GuiInputMethod::onCursorPositionChanged);
}
GuiInputMethod::~GuiInputMethod()
@@ -256,14 +258,6 @@ void GuiInputMethod::processPreedit(QInputMethodEvent* ev)
d->init_point_.y + d->caret_offset_[1] +
d->cur_dim_.height());
d->im_state_.anchor_rect_ = d->im_state_.cursor_rect_;
- /*
- * Get surrounding text
- */
- // take this opportunity to obtain the surrounding text to report back
to
- // the input method
- // FIXME: is there a benefit to cache this?
- setSurroundingText(*d->cur_);
-
// if preedit string is not empty, we are still working on it
d->im_state_.preediting_ = d->preedit_str_.empty() ? false : true;
@@ -273,6 +267,14 @@ void GuiInputMethod::processPreedit(QInputMethodEvent* ev)
}
+void GuiInputMethod::onCursorPositionChanged()
+{
+ d->cur_pos_ = d->cur_->top().pos();
+ d->anchor_pos_ = d->cur_->realAnchor().pos();
+ setSurroundingText(*d->cur_);
+}
+
+
void GuiInputMethod::setPreeditStyle(
const QList<QInputMethodEvent::Attribute> & attr)
{
@@ -675,15 +677,15 @@ std::array<int,2> GuiInputMethod::setCaretOffset(pos_type
caret_pos){
#if defined(Q_OS_MACOS) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (d->im_state_.composing_mode_)
str_before_caret =
- toqstr(d->preedit_str_.substr(0, caret_pos -
*d->cur_pos_ptr_));
+ toqstr(d->preedit_str_.substr(0, caret_pos - d->cur_pos_));
else
// adjust for the reported caret position in the completion
mode in Qt5
str_before_caret = toqstr(
- d->preedit_str_.substr(0, caret_pos -
*d->cur_pos_ptr_ -
+ d->preedit_str_.substr(0, caret_pos - d->cur_pos_ -
shiftFromCaretToSegmentHead()));
#else
str_before_caret =
- toqstr(d->preedit_str_.substr(0, caret_pos - *d->cur_pos_ptr_));
+ toqstr(d->preedit_str_.substr(0, caret_pos - d->cur_pos_));
#endif
// process line wrapping
@@ -707,12 +709,12 @@ std::array<int,2> GuiInputMethod::setCaretOffset(pos_type
caret_pos){
else
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
lastline_str = str_before_caret.sliced(
- caret_row.pos - *d->cur_pos_ptr_,
- *d->cur_pos_ptr_ + str_before_caret.length() -
caret_row.pos);
+ caret_row.pos - d->cur_pos_,
+ d->cur_pos_ + str_before_caret.length() -
caret_row.pos);
#else
lastline_str = str_before_caret.mid(
- caret_row.pos - *d->cur_pos_ptr_,
- *d->cur_pos_ptr_ + str_before_caret.length() -
caret_row.pos);
+ caret_row.pos - d->cur_pos_,
+ d->cur_pos_ + str_before_caret.length() -
caret_row.pos);
#endif
//
// calculate left margin
@@ -904,6 +906,7 @@ void GuiInputMethod::processQuery(Qt::InputMethodQuery
query)
}
// plain text before the cursor
case Qt::ImTextBeforeCursor: {
+ updatePosAndSurroundingText();
if (d->im_state_.text_before_.empty())
LYXERR(Debug::DEBUG, msg << "\"\"");
else
@@ -914,6 +917,7 @@ void GuiInputMethod::processQuery(Qt::InputMethodQuery
query)
}
// plain text after the cursor
case Qt::ImTextAfterCursor: {
+ updatePosAndSurroundingText();
if (d->im_state_.text_after_.empty())
LYXERR(Debug::DEBUG, msg << "\"\"");
else
@@ -924,12 +928,14 @@ void GuiInputMethod::processQuery(Qt::InputMethodQuery
query)
}
// logical position of the cursor within the text surrounding the input
area
case Qt::ImCursorPosition: {
+ updatePosAndSurroundingText();
LYXERR(Debug::DEBUG, msg << std::dec << d->cur_->pos());
Q_EMIT queryProcessed((qlonglong)d->cur_->pos());
break;
}
// position of the selection anchor
case Qt::ImAnchorPosition: {
+ updatePosAndSurroundingText();
LYXERR(Debug::DEBUG, msg << std::dec << (unsigned
int)d->anchor_pos_);
Q_EMIT queryProcessed(QVariant((unsigned int)d->anchor_pos_));
break;
@@ -1016,21 +1022,22 @@ docstring
GuiInputMethod::inputMethodQueryFlagsAsString(unsigned long int query)
pos_type GuiInputMethod::initializePositions(Cursor * cur) {
// the function sets the following variables:
- // d->cur_pos_ptr_ = pointer to the starting pos of preedits
+ // d->cur_pos_ = the starting pos of preedits
// d->real_boundary_ = if the starting point is boundary
// d->virtual_boundary_ = if the preedits hit the boundary
// and returns the row index of the starting point of preedits
// position of the real cursor (also the start of the preedit)
- d->cur_pos_ptr_ = &cur->top().pos();
+ if (cur->top().pos() != d->cur_pos_)
+ Q_EMIT cursorPositionChanged();
+
d->pm_ptr_ = resetParagraphMetrics(cur);
- d->anchor_pos_ = *d->cur_pos_ptr_;
// Note that getRowIndex(., false) gives the row index *after* preedit
// strings since they are virtual, so it increases as preedit strings go
// over multiple rows. To fix it at the starting point, getRowIndex(.,
true)
// is used here. As a result, cur_row_idx points the row before the
boundary
// in the case it is true.
- pos_type cur_row_idx = d->pm_ptr_->getRowIndex(*d->cur_pos_ptr_, true);
+ pos_type cur_row_idx = d->pm_ptr_->getRowIndex(d->cur_pos_, true);
//
// boundary check
@@ -1086,7 +1093,7 @@ pos_type GuiInputMethod::initializePositions(Cursor *
cur) {
// cursor is at the head of the next row after boundary
post_real_boundary =
cur_row_idx + 1 < (pos_type)d->rows_size_ ?
- *d->cur_pos_ptr_ == d->rows_[cur_row_idx+1].pos() &&
+ d->cur_pos_ == d->rows_[cur_row_idx+1].pos() &&
!has_room_to_insert : false;
// Preedit string and the caret starts from the new line when either
@@ -1187,8 +1194,8 @@ GuiInputMethod::PreeditRow GuiInputMethod::getCaretInfo(
// the length of str is used since preedits has zero widths (pos ==
endpos)
// second_row_pos is only useful when preedit string goes over two rows
Row::const_iterator begin =
- d->rows_[d->cur_row_idx_].findElement(*d->cur_pos_ptr_, false);
- pos_type second_row_pos = *d->cur_pos_ptr_;
+ d->rows_[d->cur_row_idx_].findElement(d->cur_pos_, false);
+ pos_type second_row_pos = d->cur_pos_;
for (Row::const_iterator eit = begin;
eit < d->rows_[d->cur_row_idx_].end(); ++eit)
second_row_pos += eit->str.length();
@@ -1199,7 +1206,7 @@ GuiInputMethod::PreeditRow GuiInputMethod::getCaretInfo(
// new line, while the caret on screen stays at the end of one line
above
// below is the starting point to calculate caret_row.pos
caret_row.pos = (real_boundary && !d->im_state_.composing_mode_) ?
- *d->cur_pos_ptr_ : second_row_pos;
+ d->cur_pos_ : second_row_pos;
// if the preedit caret is on the second row or later, count the second
row
caret_row.index = d->caret_pos_ > second_row_pos ?
@@ -1223,10 +1230,10 @@ GuiInputMethod::PreeditRow GuiInputMethod::getCaretInfo(
}
}
} else
- caret_row.pos = *d->cur_pos_ptr_;
+ caret_row.pos = d->cur_pos_;
LYXERR(Debug::DEBUG, "============= BEGIN: getCaretInfo
===============");
- LYXERR(Debug::DEBUG, "*d->cur_pos_ptr = " << *d->cur_pos_ptr_);
+ LYXERR(Debug::DEBUG, "*d->cur_pos_ptr = " << d->cur_pos_);
LYXERR(Debug::DEBUG, "second_row_pos = " << second_row_pos);
LYXERR(Debug::DEBUG, "d->caret_pos_ = " << std::dec <<
d->caret_pos_ <<
"\tcaret_row.index = " << std::dec << caret_row.index);
@@ -1251,15 +1258,15 @@ void GuiInputMethod::setSurroundingText(const Cursor &
cur) {
InsetList const & inset_list = cur.paragraph().insetList();
pos_type insets_before_cur = 0;
for (const auto & inset : inset_list) {
- if (inset.pos < *d->cur_pos_ptr_)
+ if (inset.pos < d->cur_pos_)
++insets_before_cur;
}
- if (*d->cur_pos_ptr_ >= insets_before_cur) {
+ if (d->cur_pos_ >= insets_before_cur) {
d->im_state_.text_before_ =
- partext.substr(0, *d->cur_pos_ptr_ -
insets_before_cur);
+ partext.substr(0, d->cur_pos_ -
insets_before_cur);
d->im_state_.text_after_ =
- partext.substr(*d->cur_pos_ptr_ -
insets_before_cur);
+ partext.substr(d->cur_pos_ - insets_before_cur);
d->im_state_.surrounding_text_ =
d->im_state_.text_before_ + d->im_state_.text_after_;
} else {
@@ -1285,6 +1292,14 @@ void GuiInputMethod::setSurroundingText(const Cursor &
cur) {
return;
}
+void GuiInputMethod::updatePosAndSurroundingText()
+{
+ if (d->cur_->top().pos() == d->cur_pos_)
+ return;
+ Q_EMIT cursorPositionChanged();
+}
+
+
docstring & GuiInputMethod::preeditString() const
{
return d->preedit_str_;
diff --git a/src/frontends/qt/GuiInputMethod.h
b/src/frontends/qt/GuiInputMethod.h
index 9baa2ae8b2..637e8adf0a 100644
--- a/src/frontends/qt/GuiInputMethod.h
+++ b/src/frontends/qt/GuiInputMethod.h
@@ -118,6 +118,7 @@ Q_SIGNALS:
void preeditProcessed(QInputMethodEvent* ev);
void queryProcessed(QVariant response);
void inputMethodStateChanged(Qt::InputMethodQueries);
+ void cursorPositionChanged();
public Q_SLOT:
/// Process incoming preedit string
@@ -127,6 +128,7 @@ public Q_SLOT:
/// Turn off IM in math mode and command phase and turn it on otherwise
void toggleInputMethodAcceptance() override;
void onLocaleChanged();
+ void onCursorPositionChanged();
#ifdef Q_DEBUG
///
void setHint(InputMethod::Hint hint) override;
@@ -166,6 +168,8 @@ private:
pos_type registerSegment(pos_type start, size_type length,
QTextCharFormat char_format);
/// Returns enum Qt::InputMethodQuery constant from its value
docstring inputMethodQueryFlagsAsString(unsigned long int query) const;
+ /// update cursor position and surrounding text
+ void updatePosAndSurroundingText();
struct Private;
Private * const d;
--
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs