Skip to content

Commit

Permalink
LWJGL IME support
Browse files Browse the repository at this point in the history
  • Loading branch information
daipom authored and Spasi committed Jan 15, 2025
1 parent e7ea71b commit eb9046f
Show file tree
Hide file tree
Showing 30 changed files with 4,483 additions and 98 deletions.
4 changes: 4 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ video tutorials.
- Jason Francis
- Gerald Franz
- Mário Freitas
- Daijiro Fukuda
- GeO4d
- Marcus Geelnard
- Gegy
Expand Down Expand Up @@ -105,6 +106,7 @@ video tutorials.
- Charles Huber
- Brent Huisman
- Florian Hülsmann
- Ryo Ichinose
- illustris
- InKryption
- IntellectualKitty
Expand All @@ -123,6 +125,7 @@ video tutorials.
- Cameron King
- Peter Knut
- Christoph Kubisch
- Yasutaka Kumei
- Yuri Kunde Schlesner
- Rokas Kupstys
- Konstantin Käfer
Expand Down Expand Up @@ -286,6 +289,7 @@ video tutorials.
- Andy Williams
- Joel Winarske
- Richard A. Wilkes
- xfangfang
- Tatsuya Yatagawa
- Ryogo Yoshimura
- Lukas Zanner
Expand Down
385 changes: 385 additions & 0 deletions deps/wayland/text-input-unstable-v1.xml

Large diffs are not rendered by default.

457 changes: 457 additions & 0 deletions deps/wayland/text-input-unstable-v3.xml

Large diffs are not rendered by default.

253 changes: 253 additions & 0 deletions docs/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,259 @@ specified key is `GLFW_KEY_UNKNOWN` then the scancode is used, otherwise it is
ignored. This matches the behavior of the key callback, meaning the callback
arguments can always be passed unmodified to this function.
## 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.
### IME styles {#ime_style}
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.
### Preedit input {#input_preedit}
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.
```c
glfwSetPreeditCallback(window, preedit_callback);
```

The callback receives the following information.

```c
void preedit_callback(GLFWwindow* window,
int preedit_count,
unsigned int* preedit_string,
int block_count,
int* block_sizes,
int focused_block,
int caret)
{
}
```
"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)
### 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.
```c
glfwSetPreeditCursorRectangle(window, x, y, w, h);
glfwGetPreeditCursorRectangle(window, &x, &y, &w, &h);
```


### 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:

```c
glfwSetIMEStatusCallback(window, imestatus_callback);
```
The callback has a simple signature like this:
```c
void imestatus_callback(GLFWwindow* window)
{
}
```

@anchor GLFW_IME
You can get the current IME status by the following function:

```c
glfwGetInputMode(window, GLFW_IME);
```
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:
```c
glfwSetInputMode(window, GLFW_IME, GLFW_TRUE);
glfwSetInputMode(window, GLFW_IME, GLFW_FALSE);
```

You can use the following function to clear the current preedit.

```c
glfwResetPreeditText(window);
```
@### Full screen with IME {#ime_full_screen}
To use IME in the full screen, you can use the
[GLFW_SOFT_FULLSCREEN](@ref GLFW_SOFT_FULLSCREEN_hint) window hint.
The default full screen of GLFW is exclusive and is not suitable for IME.
Setting this window hint enables IME to display properly on the full screen.
```c
glfwWindowHint(GLFW_SOFT_FULLSCREEN, GLFW_TRUE);
```


### Manage preedit candidate {#manage_preedit_candidate}

By default, the IME manages the drawing of the preedit candidates, but
sometimes you need to do that on the application side for some reason. In such
a case, you can use
[GLFW_MANAGE_PREEDIT_CANDIDATE](@ref GLFW_MANAGE_PREEDIT_CANDIDATE_hint) init hint.
By setting this to `GLFW_TRUE`, the IME stops managing the drawing of the
candidates and the application needs to manage it by using the following
functions.

@note
@win32 Only the OS currently supports this hint.

You can register the candidate callback as follows.

```c
glfwSetPreeditCandidateCallback(window, candidate_callback);
```
The callback receives the following information.
```c
void candidate_callback(GLFWwindow* window,
int candidates_count,
int selected_index,
int page_start,
int page_size)
{
}
```

`candidates_count` is the number of total candidates. `selected_index` is the
index of the currently selected candidate. Normally all candidates should not
be displayed at once, but divided into pages. You can use `page_start` and
`page_size` to manage the pages. `page_start` is the index of the first
candidate on the current page. `page_size` is the number of the candidates on
the current page.

You can get the text of the candidate on the specific index as follows. Each
character of the returned text is a native endian UTF-32.

```c
int text_count;
unsigned int* text = glfwGetPreeditCandidate(window, index, &text_count);
```

A sample code to get all candidate texts on the current page is as follows.

```c
void candidate_callback(GLFWwindow* window, int candidates_count,
int selected_index, int page_start, int page_size)
{
int i, j;
for (i = 0; i < page_size; ++i)
{
int index = i + page_start;
int text_count;
unsigned int* text = glfwGetPreeditCandidate(window, index, &text_count);
if (index == selected_index)
printf("> ");
for (j = 0; j < text_count; ++j)
{
char encoded[5] = "";
encode_utf8(encoded, text[j]); // Some kind of encoding process
printf("%s", encoded);
}
printf("\n");
}
}

glfwSetPreeditCandidateCallback(window, candidate_callback);
```
## Mouse input {#input_mouse}
Expand Down
38 changes: 29 additions & 9 deletions docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ The ANGLE platform type is specified via the `EGL_ANGLE_platform_angle`
extension. This extension is not used if this hint is
`GLFW_ANGLE_PLATFORM_TYPE_NONE`, which is the default value.
@anchor GLFW_MANAGE_PREEDIT_CANDIDATE_hint
__GLFW_MANAGE_PREEDIT_CANDIDATE__ specifies whether to manage the preedit
candidates on the application side. Possible values are `GLFW_TRUE` and
`GLFW_FALSE`. The default is `GLFW_FALSE` and there is no need to manage
the candidates on the application side. When you need to do that on the
application side for some reason, you can enable this hint. Please see
@ref ime_support for more information about IME support.
@win32 Only the OS currently supports this hint.
#### macOS specific init hints {#init_hints_osx}
Expand Down Expand Up @@ -152,18 +162,28 @@ __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}
Initialization hint | Default value | Supported values
-------------------------------- | ------------------------------- | ----------------
@ref GLFW_PLATFORM | `GLFW_ANY_PLATFORM` | `GLFW_ANY_PLATFORM`, `GLFW_PLATFORM_WIN32`, `GLFW_PLATFORM_COCOA`, `GLFW_PLATFORM_WAYLAND`, `GLFW_PLATFORM_X11` or `GLFW_PLATFORM_NULL`
@ref GLFW_JOYSTICK_HAT_BUTTONS | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_ANGLE_PLATFORM_TYPE | `GLFW_ANGLE_PLATFORM_TYPE_NONE` | `GLFW_ANGLE_PLATFORM_TYPE_NONE`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGL`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGLES`, `GLFW_ANGLE_PLATFORM_TYPE_D3D9`, `GLFW_ANGLE_PLATFORM_TYPE_D3D11`, `GLFW_ANGLE_PLATFORM_TYPE_VULKAN` or `GLFW_ANGLE_PLATFORM_TYPE_METAL`
@ref GLFW_COCOA_CHDIR_RESOURCES | `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_X11_XCB_VULKAN_SURFACE | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
Initialization hint | Default value | Supported values
---------------------------------- | ------------------------------- | ----------------
@ref GLFW_PLATFORM | `GLFW_ANY_PLATFORM` | `GLFW_ANY_PLATFORM`, `GLFW_PLATFORM_WIN32`, `GLFW_PLATFORM_COCOA`, `GLFW_PLATFORM_WAYLAND`, `GLFW_PLATFORM_X11` or `GLFW_PLATFORM_NULL`
@ref GLFW_JOYSTICK_HAT_BUTTONS | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_ANGLE_PLATFORM_TYPE | `GLFW_ANGLE_PLATFORM_TYPE_NONE` | `GLFW_ANGLE_PLATFORM_TYPE_NONE`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGL`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGLES`, `GLFW_ANGLE_PLATFORM_TYPE_D3D9`, `GLFW_ANGLE_PLATFORM_TYPE_D3D11`, `GLFW_ANGLE_PLATFORM_TYPE_VULKAN` or `GLFW_ANGLE_PLATFORM_TYPE_METAL`
@ref GLFW_MANAGE_PREEDIT_CANDIDATE | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_COCOA_CHDIR_RESOURCES | `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_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}
Expand Down
14 changes: 14 additions & 0 deletions docs/window.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,19 @@ __GLFW_FOCUS_ON_SHOW__ specifies whether the window will be given input
focus when @ref glfwShowWindow is called. Possible values are `GLFW_TRUE` and
`GLFW_FALSE`.
@anchor GLFW_SOFT_FULLSCREEN_hint
__GLFW_SOFT_FULLSCREEN__ specifies whether the full screen window will be
_soft full screen_ or _hard full screen_. Possible values are `GLFW_TRUE` and
`GLFW_FALSE`. The default is `GLFW_FALSE` and the full screen window will be
_hard full screen_.
_Hard full screen_ is exclusive screen and it is suitable for applications
such as games.
_Soft full screen_ is not exclusive screen and it is suitable for applications
such as text-editors using Input Method Editor(Engine).
See [Full screen with IME](@ref ime_full_screen) for details.
@anchor GLFW_SCALE_TO_MONITOR
__GLFW_SCALE_TO_MONITOR__ specified whether the window content area should be
resized based on [content scale](@ref window_scale) changes. This can be
Expand Down Expand Up @@ -564,6 +577,7 @@ GLFW_REFRESH_RATE | `GLFW_DONT_CARE` | 0 to `INT_MAX` or
GLFW_STEREO | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
GLFW_SRGB_CAPABLE | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
GLFW_DOUBLEBUFFER | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
GLFW_SOFT_FULLSCREEN | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
GLFW_CLIENT_API | `GLFW_OPENGL_API` | `GLFW_OPENGL_API`, `GLFW_OPENGL_ES_API` or `GLFW_NO_API`
GLFW_CONTEXT_CREATION_API | `GLFW_NATIVE_CONTEXT_API` | `GLFW_NATIVE_CONTEXT_API`, `GLFW_EGL_CONTEXT_API` or `GLFW_OSMESA_CONTEXT_API`
GLFW_CONTEXT_VERSION_MAJOR | 1 | Any valid major version number of the chosen client API
Expand Down
Loading

0 comments on commit eb9046f

Please sign in to comment.