Wayland: Fix text input v3 preedit cursor offsets

Convert text-input-v3 preedit cursor byte offsets to GLFW's
codepoint-based caret index before reporting preedit state.

The protocol reports cursor_begin and cursor_end as UTF-8 byte offsets,
while the GLFW preedit callback exposes caret and block sizes in
codepoint units. Keep the reported preedit block as the full preedit
string because text-input-v3 does not provide styling blocks.

Also clear the current preedit state before delivering committed text,
matching the v1 path.
This commit is contained in:
Takuro Ashie 2026-07-14 18:42:54 +09:00
parent 300b3207e0
commit 068858eece

View file

@ -2452,6 +2452,25 @@ static void textInputV3Leave(void* data,
textInputV3Reset(window);
}
static int utf8OffsetToCodepointIndex(const char* text, int32_t offset)
{
const char* cur = text;
const char* end;
int index = 0;
if (!text || offset <= 0)
return 0;
end = text + offset;
while (*cur && cur < end)
{
_glfwDecodeUTF8(&cur);
index++;
}
return index;
}
static void textInputV3PreeditString(void* data,
struct zwp_text_input_v3* textInputV3,
const char* text,
@ -2461,7 +2480,7 @@ static void textInputV3PreeditString(void* data,
_GLFWwindow* window = (_GLFWwindow*) data;
_GLFWpreedit* preedit = &window->preedit;
const char* cur = text;
unsigned int cursorLength = 0;
int cursorPos = 0;
if (textInputFocusDisabled(window))
return;
@ -2471,6 +2490,8 @@ static void textInputV3PreeditString(void* data,
preedit->focusedBlockIndex = 0;
preedit->caretIndex = 0;
cursorPos = utf8OffsetToCodepointIndex(text, cursorBegin);
// Store preedit text
while (cur && *cur)
{
@ -2478,11 +2499,6 @@ static void textInputV3PreeditString(void* data,
++preedit->textCount;
if (cur == text + cursorBegin)
preedit->caretIndex = preedit->textCount;
if (cursorBegin != cursorEnd && cur == text + cursorEnd)
cursorLength = preedit->textCount - cursorBegin;
if (preedit->textBufferCount < preedit->textCount + 1)
{
int bufSize = preedit->textBufferCount;
@ -2500,12 +2516,14 @@ static void textInputV3PreeditString(void* data,
if (preedit->text)
preedit->text[preedit->textCount] = 0;
if (cursorPos > preedit->textCount)
cursorPos = preedit->textCount;
preedit->caretIndex = cursorPos;
// Store preedit blocks
if (preedit->textCount)
{
int* blocks = preedit->blockSizes;
int blockCount = preedit->blockSizesCount;
int cursorPos = preedit->caretIndex;
int textCount = preedit->textCount;
if (!preedit->blockSizes)
@ -2519,16 +2537,9 @@ static void textInputV3PreeditString(void* data,
blocks = preedit->blockSizes;
}
if (cursorLength && cursorPos)
blocks[blockCount++] = cursorPos;
preedit->focusedBlockIndex = blockCount;
blocks[blockCount++] = cursorLength ? cursorLength : textCount;
if (cursorLength && cursorPos + cursorLength != textCount)
blocks[blockCount++] = textCount - cursorPos - cursorLength;
preedit->blockSizesCount = blockCount;
blocks[0] = textCount;
preedit->focusedBlockIndex = 0;
preedit->blockSizesCount = 1;
}
}
@ -2542,6 +2553,8 @@ static void textInputV3CommitString(void* data,
if (textInputFocusDisabled(window))
return;
textInputV3Reset(window);
if (!window->callbacks.character)
return;