From: Attila Fidan dev@print0.net
--- dlls/winewayland.drv/wayland_text_input.c | 101 +++++++++++++++++++--- dlls/winewayland.drv/waylanddrv.h | 3 + 2 files changed, 92 insertions(+), 12 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_text_input.c b/dlls/winewayland.drv/wayland_text_input.c index 3ba2622fed6..ba11e1f0917 100644 --- a/dlls/winewayland.drv/wayland_text_input.c +++ b/dlls/winewayland.drv/wayland_text_input.c @@ -38,6 +38,20 @@ static void post_ime_update(HWND hwnd, UINT cursor_pos, WCHAR *comp_str, WCHAR * NtUserImeDriverCall, FALSE); }
+static WCHAR *get_wide_string(const char *str) +{ + WCHAR *output; + DWORD output_len; + size_t str_len = strlen(str); + + if (!(output = malloc((str_len + 1) * sizeof(WCHAR)))) + return NULL; + + output_len = ntdll_umbstowcs(str, str_len, output, str_len); + output[output_len] = 0; + return output; +} + static void text_input_enter(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, struct wl_surface *surface) { @@ -60,12 +74,21 @@ static void text_input_leave(void *data, struct zwp_text_input_v3 *zwp_text_inpu struct wl_surface *surface) { struct wayland_text_input *text_input = data; + HWND hwnd; TRACE("data %p, text_input %p, surface %p.\n", data, zwp_text_input_v3, surface);
pthread_mutex_lock(&text_input->mutex); zwp_text_input_v3_disable(text_input->zwp_text_input_v3); zwp_text_input_v3_commit(text_input->zwp_text_input_v3); text_input->serial++; + if (text_input->preedit_started) + { + assert(text_input->wl_surface); + hwnd = wl_surface_get_user_data(text_input->wl_surface); + post_ime_update(hwnd, 0, NULL, NULL); + NtUserPostMessage(hwnd, WM_WINE_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, FALSE); + text_input->preedit_started = FALSE; + } text_input->wl_surface = NULL; pthread_mutex_unlock(&text_input->mutex); } @@ -73,6 +96,21 @@ static void text_input_leave(void *data, struct zwp_text_input_v3 *zwp_text_inpu static void text_input_preedit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, const char *text, int32_t cursor_begin, int32_t cursor_end) { + struct wayland_text_input *text_input = data; + TRACE("data %p, text_input %p, text %s, cursor_begin %d.\n", data, zwp_text_input_v3, + debugstr_a(text), cursor_begin); + + pthread_mutex_lock(&text_input->mutex); + text_input->preedit_string = malloc(strlen(text) + 1); + if (!text_input->preedit_string) + { + ERR("Failed to allocate memory for IME preedit string.\n"); + pthread_mutex_unlock(&text_input->mutex); + return; + } + strcpy(text_input->preedit_string, text); + text_input->cursor_begin = cursor_begin; + pthread_mutex_unlock(&text_input->mutex); }
static void text_input_commit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, @@ -102,9 +140,9 @@ static void text_input_done(void *data, struct zwp_text_input_v3 *zwp_text_input uint32_t serial) { struct wayland_text_input *text_input = data; - size_t commit_len; - WCHAR *output; - DWORD len; + int preedit_cursor_pos = 0; + WCHAR *wide_preedit = NULL; + WCHAR *wide_commit = NULL; HWND hwnd; TRACE("data %p, text_input %p, serial %u.\n", data, zwp_text_input_v3, serial);
@@ -112,19 +150,58 @@ static void text_input_done(void *data, struct zwp_text_input_v3 *zwp_text_input assert(text_input->wl_surface); hwnd = wl_surface_get_user_data(text_input->wl_surface);
- commit_len = strlen(text_input->commit_string); - if (!(output = malloc((commit_len + 1) * sizeof(WCHAR)))) + if (text_input->preedit_string && !text_input->preedit_started) { - ERR("Failed to allocate memory for wide IME commit string.\n"); - goto done; + NtUserPostMessage(hwnd, WM_WINE_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, TRUE); + text_input->preedit_started = TRUE; }
- len = ntdll_umbstowcs(text_input->commit_string, commit_len, output, commit_len); - output[len] = 0; - post_ime_update(hwnd, 0, NULL, output); - free(output); + if (text_input->commit_string) + { + if (!(wide_commit = get_wide_string(text_input->commit_string))) + ERR("Failed to allocate memory for wide IME commit string.\n"); + }
-done: + if (text_input->preedit_string) + { + /* the preedit_string event tells the cursor position in bytes */ + if (text_input->cursor_begin > 0) + { + size_t preedit_len = strlen(text_input->preedit_string); + assert(text_input->cursor_begin <= preedit_len); + + mblen(NULL, 0); + for (size_t byte_idx = 0; byte_idx < text_input->cursor_begin; preedit_cursor_pos++) + { + int bytes_parsed = mblen(text_input->preedit_string + byte_idx, + preedit_len - byte_idx); + + if (bytes_parsed <= 0) + break; + + byte_idx += bytes_parsed; + } + } + + if (!(wide_preedit = get_wide_string(text_input->preedit_string))) + { + ERR("Failed to allocate memory for wide IME preedit string.\n"); + preedit_cursor_pos = 0; + } + } + + post_ime_update(hwnd, preedit_cursor_pos, wide_preedit, wide_commit); + + if (!text_input->preedit_string && text_input->preedit_started) + { + NtUserPostMessage(hwnd, WM_WINE_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, FALSE); + text_input->preedit_started = FALSE; + } + free(wide_preedit); + free(wide_commit); + text_input->cursor_begin = 0; + free(text_input->preedit_string); + text_input->preedit_string = NULL; free(text_input->commit_string); text_input->commit_string = NULL; pthread_mutex_unlock(&text_input->mutex); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 97f82d9d770..2e7cce15904 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -116,6 +116,9 @@ struct wayland_text_input { struct zwp_text_input_v3 *zwp_text_input_v3; uint32_t serial; + BOOL preedit_started; + char *preedit_string; + int32_t cursor_begin; char *commit_string; struct wl_surface *wl_surface; pthread_mutex_t mutex;