From: Byeongsik Jeon bsjeon@hanmail.net
If CompStrAttr and CompStrClause are properly configured, Japanese input will be more comfortable.
Inspired by cursor_begin and cursor_end from Wayland zwp_text_input_v3 preedit_string, I extended the cursor_pos concept as follows:
cursor_pos = MAKELONG( cursor_begin, cursor_end );
ime_to_tascii_ex() uses this to construct CompStrAttr, CompStrClause. MS Windows native CompStrAttr, CompStrClause is a bit more complicated than this, but the concept is useful enough.
It requires additional implementation in the Wine ime_ui_window proc and richedit control. However, it is useful for applications that inline ime composition string.
This can be tested with MS Office Word, Excel. LANG=ja_JP.UTF-8 wine EXCEL.EXE
Test key sequences: - “n-i-h-o-n-g-o-n-o-m-o-j-i-d-e-s-u-.-SPACE”. - And, RIGHT, LEFT, Shift+LEFT, Shift+RIGHT, SPACE, UP, DOWN, ESC, etc. --- dlls/win32u/imm.c | 57 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-)
diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index c0ed670e779..13a66f3f2b4 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -445,8 +445,8 @@ static void post_ime_update( HWND hwnd, UINT cursor_pos, WCHAR *comp_str, WCHAR WCHAR *prev_result_str, *tmp; struct ime_update *update;
- TRACE( "hwnd %p, cursor_pos %u, comp_str %s, result_str %s\n", hwnd, cursor_pos, - debugstr_w(comp_str), debugstr_w(result_str) ); + TRACE( "hwnd %p, cursor_pos %u - %u, comp_str %s, result_str %s\n", hwnd, LOWORD(cursor_pos), + HIWORD(cursor_pos), debugstr_w(comp_str), debugstr_w(result_str) );
comp_len = comp_str ? wcslen( comp_str ) + 1 : 0; result_len = result_str ? wcslen( result_str ) + 1 : 0; @@ -495,6 +495,16 @@ static void post_ime_update( HWND hwnd, UINT cursor_pos, WCHAR *comp_str, WCHAR free( tmp ); }
+static UINT get_comp_clause_count( INT cursor_begin, INT cursor_end, UINT comp_len ) +{ + if (cursor_begin == cursor_end || (cursor_begin == 0 && cursor_end == comp_len)) + return 2; + else if (cursor_begin == 0 || cursor_end == comp_len) + return 3; + else + return 4; +} + static struct ime_update *find_ime_update( WORD vkey, WORD scan ) { struct ime_update *update; @@ -508,7 +518,8 @@ static struct ime_update *find_ime_update( WORD vkey, WORD scan ) static UINT ime_to_tascii_ex( UINT vkey, UINT lparam, const BYTE *state, COMPOSITIONSTRING *compstr, BOOL *key_consumed, HIMC himc ) { - UINT needed = sizeof(COMPOSITIONSTRING), comp_len, result_len; + UINT needed = sizeof(COMPOSITIONSTRING), comp_len, result_len, comp_clause_count = 0; + INT cursor_begin = -1, cursor_end = -1; struct ime_update *update; void *dst;
@@ -528,9 +539,19 @@ static UINT ime_to_tascii_ex( UINT vkey, UINT lparam, const BYTE *state, COMPOSI else { comp_len = wcslen( update->comp_str ); + cursor_begin = LOWORD(update->cursor_pos); + cursor_end = HIWORD(update->cursor_pos); + + if (cursor_begin > comp_len) cursor_begin = comp_len; + if (cursor_end > comp_len) cursor_end = comp_len; + if (cursor_end < cursor_begin) cursor_end = cursor_begin; + if (cursor_begin < 0 || cursor_end < 0) cursor_begin = cursor_end = -1; /* no cursor */ + + comp_clause_count = get_comp_clause_count( cursor_begin, cursor_end, comp_len ); + needed += comp_len * sizeof(WCHAR); /* GCS_COMPSTR */ needed += comp_len; /* GCS_COMPATTR */ - needed += 2 * sizeof(DWORD); /* GCS_COMPCLAUSE */ + needed += comp_clause_count * sizeof(DWORD); /* GCS_COMPCLAUSE */ }
if (!update->result_str) result_len = 0; @@ -556,7 +577,7 @@ static UINT ime_to_tascii_ex( UINT vkey, UINT lparam, const BYTE *state, COMPOSI
if (update->comp_str) { - compstr->dwCursorPos = update->cursor_pos; + compstr->dwCursorPos = cursor_begin;
compstr->dwCompStrLen = comp_len; compstr->dwCompStrOffset = compstr->dwSize; @@ -564,17 +585,37 @@ static UINT ime_to_tascii_ex( UINT vkey, UINT lparam, const BYTE *state, COMPOSI memcpy( dst, update->comp_str, compstr->dwCompStrLen * sizeof(WCHAR) ); compstr->dwSize += compstr->dwCompStrLen * sizeof(WCHAR);
- compstr->dwCompClauseLen = 2 * sizeof(DWORD); + compstr->dwCompClauseLen = comp_clause_count * sizeof(DWORD); compstr->dwCompClauseOffset = compstr->dwSize; dst = (BYTE *)compstr + compstr->dwCompClauseOffset; *((DWORD *)dst + 0) = 0; - *((DWORD *)dst + 1) = compstr->dwCompStrLen; + switch (comp_clause_count) + { + case 2: + *((DWORD *)dst + 1) = compstr->dwCompStrLen; + break; + case 3: + *((DWORD *)dst + 1) = cursor_begin == 0 ? cursor_end : cursor_begin; + *((DWORD *)dst + 2) = compstr->dwCompStrLen; + break; + case 4: + *((DWORD *)dst + 1) = cursor_begin; + *((DWORD *)dst + 2) = cursor_end; + *((DWORD *)dst + 3) = compstr->dwCompStrLen; + break; + } compstr->dwSize += compstr->dwCompClauseLen;
compstr->dwCompAttrLen = compstr->dwCompStrLen; compstr->dwCompAttrOffset = compstr->dwSize; dst = (BYTE *)compstr + compstr->dwCompAttrOffset; - memset( dst, ATTR_INPUT, compstr->dwCompAttrLen ); + if (cursor_begin == cursor_end) + memset( dst, ATTR_INPUT, compstr->dwCompAttrLen ); + else + { + memset( dst, ATTR_CONVERTED, compstr->dwCompAttrLen ); + memset( (BYTE *)dst + cursor_begin, ATTR_TARGET_CONVERTED, cursor_end - cursor_begin ); + } compstr->dwSize += compstr->dwCompAttrLen; }