diff --git a/docs/input.md b/docs/input.md index a18e3d75..3e881e84 100644 --- a/docs/input.md +++ b/docs/input.md @@ -229,96 +229,6 @@ void character_callback(GLFWwindow* window, unsigned int codepoint) } ``` -@subsection preedit IME Support - -All desktop operating systems support IME (Input Method Editor) to input characters -that are not mapped with physical keys. IME have been popular among Eeastern Asian people. -And some operating systems start supporting voice input via IME mechanism. - -GLFW provides IME support functions to help -you implement better text input features. You should add suitable visualization code for -preedit text. - -IME works in front of actual character input events (@ref input_char). -If your application uses text input and you want to support IME, -you should register preedit callback to receive preedit text before committed. - -@code -glfwSetPreeditCallback(window, preedit_callback); -@endcode - -The callback function receives chunk of text and focused block information. - -@code -static void preedit_callback(GLFWwindow* window, int strLength, unsigned int* string, int blockLength, int* blocks, int focusedBlock) { -} -@endcode - -strLength and string parameter reprsent whole preedit text. Each character of the preedit string is a codepoint like @ref input_char. - -If you want to type the text "寿司(sushi)", Usually the callback is called several times like the following sequence: - --# key event: s --# preedit: [string: "s", block: [1], focusedBlock: 0] --# key event: u --# preedit: [string: "す", block: [1], focusedBlock: 0] --# key event: s --# preedit: [string: "すs", block: [2], focusedBlock: 0] --# key event: h --# preedit: [string: "すsh", block: [2], focusedBlock: 0] --# key event: i --# preedit: [string: "すし", block: [2], focusedBlock: 0] --# key event: ' ' --# preedit: [string: "寿司", block: [2], focusedBlock: 0] --# char: '寿' --# char: '司' --# preedit: [string: "", block: [], focusedBlock: 0] - -If preedit text includes several semantic blocks, preedit callbacks returns several blocks after a space key pressed: - --# preedit: [string: "わたしはすしをたべます", block: [11], focusedBlock: 0] --# preedit: [string: "私は寿司を食べます", block: [2, 7], focusedBlock: 1] - -"blocks" is a list of block length. The above case, it contains the following blocks and second block is focused. - -- 私は -- [寿司を食べます] - -commited text(passed via regular @ref input_char event), unfocused block, focused block should have different text style. - - -GLFW provides helper function to teach suitable position of the candidate window to window system. -Window system decides the best position from text cursor geometry (x, y coords and height). You should call this function -in the above preedit text callback function. - -@code -glfwSetPreeditCursorPos(window, x, y, h); -glfwGetPreeditCursorPos(window, &x, &y, &h); -@endcode - -Sometimes IME task is interrupted by user or application. There are several functions to support these situation. -You can receive notification about IME status change(on/off) by using the following function: - -@code -glfwSetIMEStatusCallback(window, imestatus_callback); -@endcode - -imestatus_callback has simple sigunature like this: - -@code -static void imestatus_callback(GLFWwindow* window) { -} -@endcode - -You can implement the code that resets or commits preedit text when IME status is changed and preedit text is not empty. - -When the focus is gone from text box, you can use the following functions to reset IME status: - -@code -void glfwResetPreeditText(GLFWwindow* window); -void glfwSetIMEStatus(GLFWwindow* window, int active) -int glfwGetIMEStatus(GLFWwindow* window) -@endcode ### Key names {#input_key_name} @@ -336,6 +246,174 @@ ignored. This matches the behavior of the key callback, meaning the callback arguments can always be passed unmodified to this function. +@section ime_support IME support + +IME (Input Method Editor/Engine) is used to input characters not mapped with +physical keys. It is popular among East Asian people. + + +@subsection ime_style IME styles + +GLFW supports the following two styles of IME. + + - On-the-spot + - Over-the-spot + +On-the-spot style is supported on Windows, macOS and Wayland. On these platforms, +applications need to draw preedit text directly in their UI by using the preedit +callback (See [Preedit input](@ref input_preedit)). + +Over-the-spot style is supported on X11. On this platform, the IME displays preedit +text, and applications don't need to draw it. So the preedit callback doesn't work +on X11. + +In both styles, applications should manage the position of the candidate window. +See [Candidate window](@ref candidate_window) for details. + +@note +@x11 You can use on-the-spot style also on X11 by using @ref GLFW_X11_ONTHESPOT_hint. +In this case, the preedit callback also works on X11. However, on-the-spot style on +X11 is unstable, so it is not recommended. + + +@subsection input_preedit Preedit input + +When inputting text with IME, the text is temporarily inputted, then conversion +and other processing are performed and finally committed. The committed text is +inputted in the same way as input without IME (See [Text input](@ref input_char)). + +This temporary input is called "preedit" or "pre-edit". + +On Windows, macOS and Wayland, that use on-the-spot sytle, applications need to +take preedit information and draw it in their UI. + +You can register the preedit callback as follows. + +@code +glfwSetPreeditCallback(window, preedit_callback); +@endcode + +The callback receives the following information. + +@code +void preedit_callback(GLFWwindow* window, + int preedit_count, + unsigned int* preedit_string, + int block_count, + int* block_sizes, + int focused_block, + int caret) +{ +} +@endcode + +"preedit_count" and "preedit_string" parameter represent the whole preedit text. +Each character of the preedit string is a native endian UTF-32 like @ref input_char. + +If you want to type the text "寿司(sushi)", Usually the callback is called several +times like the following sequence: + +-# key event: s +-# preedit: [preedit_string: "s", block_sizes: [1], focused_block: 0] +-# key event: u +-# preedit: [preedit_string: "す", block_sizes: [1], focused_block: 0] +-# key event: s +-# preedit: [preedit_string: "すs", block_sizes: [2], focused_block: 0] +-# key event: h +-# preedit: [preedit_string: "すsh", block_sizes: [3], focused_block: 0] +-# key event: i +-# preedit: [preedit_string: "すし", block_sizes: [2], focused_block: 0] +-# key event: ' ' +-# preedit: [preedit_string: "寿司", block_sizes: [2], focused_block: 0] +-# char: '寿' +-# char: '司' +-# preedit: [preedit_string: "", block_sizes: [], focused_block: 0] + +If preedit text includes several semantic blocks, the callback returns several blocks: + +-# preedit: [preedit_string: "わたしはすしをたべます", block_sizes: [11], focused_block: 0] +-# preedit: [preedit_string: "私は寿司を食べます", block_sizes: [2, 7], focused_block: 1] + +"block_sizes" is a list of the sizes of each block. The above case, it contains the following +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) + + +@subsection candidate_window Candidate window + +The application has to manage the position of the candidate window that shows +the preedit candidate list. To do this, the application has to manage the area +of the preedit text cursor by the following functions. The IME displays the +candidate window in the appropriate position based on the area of the preedit +text cursor. + +@code +glfwSetPreeditCursorRectangle(window, x, y, w, h); +glfwGetPreeditCursorRectangle(window, &x, &y, &w, &h); +@endcode + + +@subsection ime_status IME status + +Sometimes, IME task needs to be interrupted by a user or an application. There +are several functions to support these situations. + +@note +@x11 @wayland This feature is not supported. + +You can receive notification about IME status change(on/off) by using the following +function: + +@code +glfwSetIMEStatusCallback(window, imestatus_callback); +@endcode + +The callback has a simple signature like this: + +@code +void imestatus_callback(GLFWwindow* window) +{ +} +@endcode + +@anchor GLFW_IME +You can get the current IME status by the following function: + +@code +glfwGetInputMode(window, GLFW_IME); +@endcode + +If you get GLFW_TRUE, it means the IME is on, and GLFW_FALSE means the IME is off. + +You can also change the IME status by the following function: + +@code +glfwSetInputMode(window, GLFW_IME, GLFW_TRUE); +glfwSetInputMode(window, GLFW_IME, GLFW_FALSE); +@endcode + +You can use the following function to clear the current preedit. + +@code +glfwResetPreeditText(window); +@endcode + + ## Mouse input {#input_mouse} Mouse input comes in many forms, including mouse motion, button presses and diff --git a/docs/intro.md b/docs/intro.md index 7aa75e31..486b9856 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -152,6 +152,15 @@ __GLFW_X11_XCB_VULKAN_SURFACE__ specifies whether to prefer the the `VK_KHR_xlib_surface` extension. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. This is ignored on other platforms. +@anchor GLFW_X11_ONTHESPOT_hint +__GLFW_X11_ONTHESPOT__ specifies whether to use on-the-spot input method style. +On X11 platform, over-the-spot style is used if this hint is `GLFW_FALSE`, +which is the default value. You can set `GLFW_TRUE` to use on-the-spot style +as with other platforms. However, on-the-spot style on X11 is unstable, so +it is recommended not to use this hint in normal cases. Possible values are +`GLFW_TRUE` and `GLFW_FALSE`. This is ignored on other platforms. Please see +@ref ime_support for more information about IME support. + #### Supported and default values {#init_hints_values} @@ -164,6 +173,7 @@ Initialization hint | Default value | Supported v @ref GLFW_COCOA_MENUBAR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @ref GLFW_WAYLAND_LIBDECOR | `GLFW_WAYLAND_PREFER_LIBDECOR` | `GLFW_WAYLAND_PREFER_LIBDECOR` or `GLFW_WAYLAND_DISABLE_LIBDECOR` @ref GLFW_X11_XCB_VULKAN_SURFACE | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` +@ref GLFW_X11_ONTHESPOT | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` ### Runtime platform selection {#platform} diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 3c4879ac..5b4df635 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1963,7 +1963,7 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int * @param[in] focused_block Focused block index. * @param[in] caret Caret position. * - * @sa @ref preedit + * @sa @ref ime_support * @sa glfwSetPreeditCallback * * @ingroup input @@ -1982,7 +1982,7 @@ typedef void (* GLFWpreeditfun)(GLFWwindow* window, * * @param[in] window The window that received the event. * - * @sa @ref preedit + * @sa @ref ime_support * @sa glfwSetIMEStatusCallback * * @ingroup monitor @@ -5218,7 +5218,7 @@ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); * @par Thread Safety * This function may only be called from the main thread. * - * @sa @ref input_char + * @sa @ref ime_support * * @since Added in GLFW 3.X. * @@ -5240,7 +5240,7 @@ GLFWAPI void glfwGetPreeditCursorRectangle(GLFWwindow* window, int* x, int* y, i * @par Thread Safety * This function may only be called from the main thread. * - * @sa @ref input_char + * @sa @ref ime_support * * @since Added in GLFW 3.X. * @@ -5262,7 +5262,7 @@ GLFWAPI void glfwSetPreeditCursorRectangle(GLFWwindow* window, int x, int y, int * @par Thread Safety * This function may only be called from the main thread. * - * @sa @ref preedit + * @sa @ref ime_support * * @since Added in GLFW 3.X. * @@ -5439,7 +5439,7 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods * @par Thread Safety * This function may only be called from the main thread. * - * @sa @ref input_char + * @sa @ref ime_support * * @since Added in GLFW 3.X * @@ -5470,7 +5470,7 @@ GLFWAPI GLFWpreeditfun glfwSetPreeditCallback(GLFWwindow* window, GLFWpreeditfun * @par Thread Safety * This function may only be called from the main thread. * - * @sa @ref input_char + * @sa @ref ime_support * * @since Added in GLFW 3.X *