From 0ba4b3655707cce780e47679798f9e4d7023cc1a Mon Sep 17 00:00:00 2001 From: Daijiro Fukuda Date: Mon, 30 May 2022 14:41:10 +0900 Subject: [PATCH] Add caret position to preedit-callback - Win32: This works fine. - macOS: The caret is always at the last of the preedit text. - X11: - over-the-spot: The callback is not used. - on-the-spot: In IBus, the caret is always at the last of the preedit text, although the actual position can be changed. On-the-spot on X11 has many other unstable behaviors, so allow this problem for now. --- docs/input.dox | 15 +++++++++++++-- include/GLFW/glfw3.h | 7 +++++-- src/cocoa_window.m | 5 +++-- src/input.c | 5 +++-- src/internal.h | 2 +- src/win32_window.c | 5 +++-- src/x11_window.c | 14 +++++++------- tests/events.c | 6 +++++- tests/input_text.c | 12 +++++++++++- 9 files changed, 51 insertions(+), 20 deletions(-) diff --git a/docs/input.dox b/docs/input.dox index 65f41090..136fbe4d 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -255,7 +255,8 @@ void preedit_callback(GLFWwindow* window, unsigned int* preedit_string, int block_count, int* block_sizes, - int focused_block) + int focused_block, + int caret) { } @endcode @@ -273,7 +274,7 @@ times like the following sequence: -# key event: s -# preedit: [preedit_string: "すs", block_sizes: [2], focused_block: 0] -# key event: h --# preedit: [preedit_string: "すsh", block_sizes: [2], focused_block: 0] +-# preedit: [preedit_string: "すsh", block_sizes: [3], focused_block: 0] -# key event: i -# preedit: [preedit_string: "すし", block_sizes: [2], focused_block: 0] -# key event: ' ' @@ -296,6 +297,16 @@ blocks and the second block is focused. The application side should draw a focused block and unfocused blocks in different styles. +You can use the "caret" parameter to draw the caret of the preedit text. +The specification of this parameter depends on the specification of the input method. +The following is an example on Win32. + +- "あいうえお|" (caret: 5) +- key event: arrow-left +- "あいうえ|お" (caret: 4) +- ... +- "|あいうえお" (caret: 0) + GLFW provides helper functions to teach the suitable position of the candidate window to the window system. The window system decides the best position from text cursor geometry (x, y coords and height). diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 7e3f488c..b8bb475b 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1893,6 +1893,7 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int * @param[in] block_count Attributed block count. * @param[in] block_sizes List of attributed block size. * @param[in] focused_block Focused block index. + * @param[in] caret Caret position. * * @sa @ref preedit * @sa glfwSetPreeditCallback @@ -1904,7 +1905,8 @@ typedef void (* GLFWpreeditfun)(GLFWwindow* window, unsigned int* preedit_string, int block_count, int* block_sizes, - int focused_block); + int focused_block, + int caret); /*! @brief The function pointer type for IME status change callbacks. * @@ -5277,7 +5279,8 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods unsigned int* preedit_string, int block_count, int* block_sizes, - int focused_block) + int focused_block, + int caret) * @endcode * For more information about the callback parameters, see the * [function pointer type](@ref GLFWpreeditfun). diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 43f81177..fb9f0e9d 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -763,7 +763,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; focusedBlock = window->nblocks; window->nblocks++; } - _glfwInputPreedit(window, focusedBlock); + // The caret is always at the last of preedit in macOS. + _glfwInputPreedit(window, focusedBlock, window->ntext); } - (void)unmarkText @@ -771,7 +772,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; [[markedText mutableString] setString:@""]; window->nblocks = 0; window->ntext = 0; - _glfwInputPreedit(window, 0); + _glfwInputPreedit(window, 0, 0); } - (NSArray*)validAttributesForMarkedText diff --git a/src/input.c b/src/input.c index 75614a01..b43c44c8 100644 --- a/src/input.c +++ b/src/input.c @@ -315,7 +315,7 @@ void _glfwInputChar(_GLFWwindow* window, uint32_t codepoint, int mods, GLFWbool // Notifies shrared code of a preedit event // -void _glfwInputPreedit(_GLFWwindow* window, int focusedBlock) +void _glfwInputPreedit(_GLFWwindow* window, int focusedBlock, int caret) { if (window->callbacks.preedit) { @@ -324,7 +324,8 @@ void _glfwInputPreedit(_GLFWwindow* window, int focusedBlock) window->preeditText, window->nblocks, window->preeditAttributeBlocks, - focusedBlock); + focusedBlock, + caret); } } diff --git a/src/internal.h b/src/internal.h index ff4c4f78..69f3ce89 100644 --- a/src/internal.h +++ b/src/internal.h @@ -936,7 +936,7 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods); void _glfwInputChar(_GLFWwindow* window, uint32_t codepoint, int mods, GLFWbool plain); -void _glfwInputPreedit(_GLFWwindow* window, int focusedBlock); +void _glfwInputPreedit(_GLFWwindow* window, int focusedBlock, int caret); void _glfwInputIMEStatus(_GLFWwindow* window); void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset); void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); diff --git a/src/win32_window.c b/src/win32_window.c index f6983edf..37639e04 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -577,6 +577,7 @@ static GLFWbool getImmPreedit(_GLFWwindow* window) LONG preeditBytes = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0); LONG attrBytes = ImmGetCompositionStringW(hIMC, GCS_COMPATTR, NULL, 0); LONG clauseBytes = ImmGetCompositionStringW(hIMC, GCS_COMPCLAUSE, NULL, 0); + LONG cursorPos = ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, NULL, 0); if (preeditBytes > 0) { @@ -663,7 +664,7 @@ static GLFWbool getImmPreedit(_GLFWwindow* window) _glfw_free(attributes); _glfw_free(clauses); - _glfwInputPreedit(window, focusedBlock); + _glfwInputPreedit(window, focusedBlock, cursorPos); } ImmReleaseContext(window->win32.handle, hIMC); @@ -994,7 +995,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l { window->nblocks = 0; window->ntext = 0; - _glfwInputPreedit(window, 0); + _glfwInputPreedit(window, 0, 0); commitImmResultStr(window); return TRUE; } diff --git a/src/x11_window.c b/src/x11_window.c index 543e0458..b0ddcd78 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -574,7 +574,7 @@ static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDraw // preedit text is empty window->ntext = 0; window->nblocks = 0; - _glfwInputPreedit(window, 0); + _glfwInputPreedit(window, 0, 0); return; } else @@ -634,7 +634,7 @@ static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDraw window->nblocks = 1; window->preeditAttributeBlocks[0] = length; window->preeditAttributeBlocks[1] = 0; - _glfwInputPreedit(window, 0); + _glfwInputPreedit(window, 0, callData->caret); } else if (rstart == 0) { @@ -643,7 +643,7 @@ static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDraw window->nblocks = 1; window->preeditAttributeBlocks[0] = length; window->preeditAttributeBlocks[1] = 0; - _glfwInputPreedit(window, 0); + _glfwInputPreedit(window, 0, callData->caret); } else { @@ -651,7 +651,7 @@ static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDraw window->preeditAttributeBlocks[0] = rend + 1; window->preeditAttributeBlocks[1] = length - rend - 1; window->preeditAttributeBlocks[2] = 0; - _glfwInputPreedit(window, 0); + _glfwInputPreedit(window, 0, callData->caret); } } else if (rend == length - 1) @@ -660,7 +660,7 @@ static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDraw window->preeditAttributeBlocks[0] = rstart; window->preeditAttributeBlocks[1] = length - rstart; window->preeditAttributeBlocks[2] = 0; - _glfwInputPreedit(window, 1); + _glfwInputPreedit(window, 1, callData->caret); } else { @@ -669,7 +669,7 @@ static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDraw window->preeditAttributeBlocks[1] = rend - rstart + 1; window->preeditAttributeBlocks[2] = length - rend - 1; window->preeditAttributeBlocks[3] = 0; - _glfwInputPreedit(window, 1); + _glfwInputPreedit(window, 1, callData->caret); } } } @@ -3298,7 +3298,7 @@ void _glfwResetPreeditTextX11(_GLFWwindow* window) window->ntext = 0; window->nblocks = 0; - _glfwInputPreedit(window, 0); + _glfwInputPreedit(window, 0, 0); XFree (result); } diff --git a/tests/events.c b/tests/events.c index 18a12389..aedd8e4f 100644 --- a/tests/events.c +++ b/tests/events.c @@ -456,7 +456,7 @@ static void char_callback(GLFWwindow* window, unsigned int codepoint) static void preedit_callback(GLFWwindow* window, int strLength, unsigned int* string, int blockLength, - int* blocks, int focusedBlock) + int* blocks, int focusedBlock, int caret) { Slot* slot = glfwGetWindowUserPointer(window); int i, blockIndex = -1, blockCount = 0; @@ -482,12 +482,16 @@ static void preedit_callback(GLFWwindow* window, int strLength, if (blockIndex == focusedBlock) printf("["); } + if (i == caret) + printf("|"); encode_utf8(encoded, string[i]); printf("%s", encoded); blockCount--; } if (blockIndex == focusedBlock) printf("]"); + if (caret == strLength) + printf("|"); printf("\n"); glfwGetWindowSize(window, &width, &height); glfwSetPreeditCursorPos(window, width/2, height/2, 20); diff --git a/tests/input_text.c b/tests/input_text.c index 685a8282..48d82d30 100644 --- a/tests/input_text.c +++ b/tests/input_text.c @@ -516,7 +516,7 @@ static void ime_callback(GLFWwindow* window) static void preedit_callback(GLFWwindow* window, int strLength, unsigned int* string, int blockLength, - int* blocks, int focusedBlock) + int* blocks, int focusedBlock, int caret) { int blockIndex = -1, blockCount = 0; if (strLength == 0 || blockLength == 0) @@ -531,6 +531,11 @@ static void preedit_callback(GLFWwindow* window, int strLength, { char encoded[5] = ""; + if (i == caret) + { + if (strlen(preeditBuf) + strlen("|") < MAX_PREDIT_LEN) + strcat(preeditBuf, "|"); + } if (blockCount == 0) { if (blockIndex == focusedBlock) @@ -556,6 +561,11 @@ static void preedit_callback(GLFWwindow* window, int strLength, if (strlen(preeditBuf) + strlen("]") < MAX_PREDIT_LEN) strcat(preeditBuf, "]"); } + if (caret == strLength) + { + if (strlen(preeditBuf) + strlen("|") < MAX_PREDIT_LEN) + strcat(preeditBuf, "|"); + } } int main(int argc, char** argv)