Doc: Improve document about IME features

This commit is contained in:
Daijiro Fukuda 2023-04-07 17:50:26 +09:00 committed by Takuro Ashie
parent d5795ba0a5
commit 1ba8267f20
3 changed files with 185 additions and 97 deletions

View File

@ -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: "", 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} ### 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. 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: "", 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 {#input_mouse}
Mouse input comes in many forms, including mouse motion, button presses and Mouse input comes in many forms, including mouse motion, button presses and

View File

@ -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 the `VK_KHR_xlib_surface` extension. Possible values are `GLFW_TRUE` and
`GLFW_FALSE`. This is ignored on other platforms. `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} #### 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_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_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_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} ### Runtime platform selection {#platform}

View File

@ -1963,7 +1963,7 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int
* @param[in] focused_block Focused block index. * @param[in] focused_block Focused block index.
* @param[in] caret Caret position. * @param[in] caret Caret position.
* *
* @sa @ref preedit * @sa @ref ime_support
* @sa glfwSetPreeditCallback * @sa glfwSetPreeditCallback
* *
* @ingroup input * @ingroup input
@ -1982,7 +1982,7 @@ typedef void (* GLFWpreeditfun)(GLFWwindow* window,
* *
* @param[in] window The window that received the event. * @param[in] window The window that received the event.
* *
* @sa @ref preedit * @sa @ref ime_support
* @sa glfwSetIMEStatusCallback * @sa glfwSetIMEStatusCallback
* *
* @ingroup monitor * @ingroup monitor
@ -5218,7 +5218,7 @@ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor);
* @par Thread Safety * @par Thread Safety
* This function may only be called from the main thread. * This function may only be called from the main thread.
* *
* @sa @ref input_char * @sa @ref ime_support
* *
* @since Added in GLFW 3.X. * @since Added in GLFW 3.X.
* *
@ -5240,7 +5240,7 @@ GLFWAPI void glfwGetPreeditCursorRectangle(GLFWwindow* window, int* x, int* y, i
* @par Thread Safety * @par Thread Safety
* This function may only be called from the main thread. * This function may only be called from the main thread.
* *
* @sa @ref input_char * @sa @ref ime_support
* *
* @since Added in GLFW 3.X. * @since Added in GLFW 3.X.
* *
@ -5262,7 +5262,7 @@ GLFWAPI void glfwSetPreeditCursorRectangle(GLFWwindow* window, int x, int y, int
* @par Thread Safety * @par Thread Safety
* This function may only be called from the main thread. * This function may only be called from the main thread.
* *
* @sa @ref preedit * @sa @ref ime_support
* *
* @since Added in GLFW 3.X. * @since Added in GLFW 3.X.
* *
@ -5439,7 +5439,7 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods
* @par Thread Safety * @par Thread Safety
* This function may only be called from the main thread. * This function may only be called from the main thread.
* *
* @sa @ref input_char * @sa @ref ime_support
* *
* @since Added in GLFW 3.X * @since Added in GLFW 3.X
* *
@ -5470,7 +5470,7 @@ GLFWAPI GLFWpreeditfun glfwSetPreeditCallback(GLFWwindow* window, GLFWpreeditfun
* @par Thread Safety * @par Thread Safety
* This function may only be called from the main thread. * This function may only be called from the main thread.
* *
* @sa @ref input_char * @sa @ref ime_support
* *
* @since Added in GLFW 3.X * @since Added in GLFW 3.X
* *