win32u: Move ImeToAsciiEx implementation from winex11.

Using a new WINE_IME_POST_UPDATE NtUserMessageCall call for the drivers.
This commit is contained in:
Rémi Bernon 2024-01-12 12:30:18 +01:00 committed by Alexandre Julliard
parent 59820f0efb
commit 5f313c0fdb
7 changed files with 149 additions and 151 deletions

View file

@ -731,7 +731,7 @@ static UINT nulldrv_ImeProcessKey( HIMC himc, UINT wparam, UINT lparam, const BY
static UINT nulldrv_ImeToAsciiEx( UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc )
{
return 0;
return STATUS_NOT_IMPLEMENTED;
}
static void nulldrv_NotifyIMEStatus( HWND hwnd, UINT status )

View file

@ -34,6 +34,15 @@
WINE_DEFAULT_DEBUG_CHANNEL(imm);
struct ime_update
{
struct list entry;
DWORD id;
DWORD cursor_pos;
WCHAR *comp_str;
WCHAR *result_str;
WCHAR buffer[];
};
struct imc
{
@ -53,6 +62,7 @@ struct imm_thread_data
static struct list thread_data_list = LIST_INIT( thread_data_list );
static pthread_mutex_t imm_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct list ime_updates = LIST_INIT( ime_updates );
static BOOL disable_ime;
static struct imc *get_imc_ptr( HIMC handle )
@ -421,15 +431,147 @@ NTSTATUS WINAPI NtUserBuildHimcList( UINT thread_id, UINT count, HIMC *buffer, U
return STATUS_SUCCESS;
}
static void post_ime_update( HWND hwnd, UINT cursor_pos, WCHAR *comp_str, WCHAR *result_str )
{
static UINT ime_update_count;
UINT id, comp_len, result_len;
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) );
comp_len = comp_str ? wcslen( comp_str ) + 1 : 0;
result_len = result_str ? wcslen( result_str ) + 1 : 0;
if (!(update = malloc( offsetof(struct ime_update, buffer[comp_len + result_len]) ))) return;
update->cursor_pos = cursor_pos;
update->comp_str = comp_str ? memcpy( update->buffer, comp_str, comp_len * sizeof(WCHAR) ) : NULL;
update->result_str = result_str ? memcpy( update->buffer + comp_len, result_str, result_len * sizeof(WCHAR) ) : NULL;
pthread_mutex_lock( &imm_mutex );
id = update->id = ++ime_update_count;
list_add_tail( &ime_updates, &update->entry );
pthread_mutex_unlock( &imm_mutex );
NtUserPostMessage( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_COMP_STRING, id );
}
static struct ime_update *find_ime_update( UINT id )
{
struct ime_update *update;
LIST_FOR_EACH_ENTRY( update, &ime_updates, struct ime_update, entry )
if (update->id == id) return update;
return NULL;
}
UINT ime_to_tascii_ex( UINT vkey, UINT lparam, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc )
{
UINT needed = sizeof(COMPOSITIONSTRING), comp_len, result_len;
struct ime_update *update;
void *dst;
TRACE( "vkey %#x, lparam %#x, state %p, compstr %p, himc %p\n", vkey, lparam, state, compstr, himc );
pthread_mutex_lock( &imm_mutex );
if (!(update = find_ime_update( lparam )))
{
pthread_mutex_unlock( &imm_mutex );
return STATUS_NOT_FOUND;
}
if (!update->comp_str) comp_len = 0;
else
{
comp_len = wcslen( update->comp_str );
needed += comp_len * sizeof(WCHAR); /* GCS_COMPSTR */
needed += comp_len; /* GCS_COMPATTR */
needed += 2 * sizeof(DWORD); /* GCS_COMPCLAUSE */
}
if (!update->result_str) result_len = 0;
else
{
result_len = wcslen( update->result_str );
needed += result_len * sizeof(WCHAR); /* GCS_RESULTSTR */
needed += 2 * sizeof(DWORD); /* GCS_RESULTCLAUSE */
}
if (compstr->dwSize < needed)
{
compstr->dwSize = needed;
pthread_mutex_unlock( &imm_mutex );
return STATUS_BUFFER_TOO_SMALL;
}
list_remove( &update->entry );
pthread_mutex_unlock( &imm_mutex );
memset( compstr, 0, sizeof(*compstr) );
compstr->dwSize = sizeof(*compstr);
if (update->comp_str)
{
compstr->dwCursorPos = update->cursor_pos;
compstr->dwCompStrLen = comp_len;
compstr->dwCompStrOffset = compstr->dwSize;
dst = (BYTE *)compstr + compstr->dwCompStrOffset;
memcpy( dst, update->comp_str, compstr->dwCompStrLen * sizeof(WCHAR) );
compstr->dwSize += compstr->dwCompStrLen * sizeof(WCHAR);
compstr->dwCompClauseLen = 2 * sizeof(DWORD);
compstr->dwCompClauseOffset = compstr->dwSize;
dst = (BYTE *)compstr + compstr->dwCompClauseOffset;
*((DWORD *)dst + 0) = 0;
*((DWORD *)dst + 1) = compstr->dwCompStrLen;
compstr->dwSize += compstr->dwCompClauseLen;
compstr->dwCompAttrLen = compstr->dwCompStrLen;
compstr->dwCompAttrOffset = compstr->dwSize;
dst = (BYTE *)compstr + compstr->dwCompAttrOffset;
memset( dst, ATTR_INPUT, compstr->dwCompAttrLen );
compstr->dwSize += compstr->dwCompAttrLen;
}
if (update->result_str)
{
compstr->dwResultStrLen = result_len;
compstr->dwResultStrOffset = compstr->dwSize;
dst = (BYTE *)compstr + compstr->dwResultStrOffset;
memcpy( dst, update->result_str, compstr->dwResultStrLen * sizeof(WCHAR) );
compstr->dwSize += compstr->dwResultStrLen * sizeof(WCHAR);
compstr->dwResultClauseLen = 2 * sizeof(DWORD);
compstr->dwResultClauseOffset = compstr->dwSize;
dst = (BYTE *)compstr + compstr->dwResultClauseOffset;
*((DWORD *)dst + 0) = 0;
*((DWORD *)dst + 1) = compstr->dwResultStrLen;
compstr->dwSize += compstr->dwResultClauseLen;
}
free( update );
return 0;
}
LRESULT ime_driver_call( HWND hwnd, enum wine_ime_call call, WPARAM wparam, LPARAM lparam,
struct ime_driver_call_params *params )
{
LRESULT res;
switch (call)
{
case WINE_IME_PROCESS_KEY:
return user_driver->pImeProcessKey( params->himc, wparam, lparam, params->state );
case WINE_IME_TO_ASCII_EX:
return user_driver->pImeToAsciiEx( wparam, lparam, params->state, params->compstr, params->himc );
res = user_driver->pImeToAsciiEx( wparam, lparam, params->state, params->compstr, params->himc );
if ((NTSTATUS)res != STATUS_NOT_IMPLEMENTED) return res;
return ime_to_tascii_ex( wparam, lparam, params->state, params->compstr, params->himc );
case WINE_IME_POST_UPDATE:
post_ime_update( hwnd, wparam, (WCHAR *)lparam, (WCHAR *)params );
return 0;
default:
ERR( "Unknown IME driver call %#x\n", call );
return 0;

View file

@ -397,7 +397,6 @@ static const struct user_driver_funcs x11drv_funcs =
.pMapVirtualKeyEx = X11DRV_MapVirtualKeyEx,
.pToUnicodeEx = X11DRV_ToUnicodeEx,
.pVkKeyScanEx = X11DRV_VkKeyScanEx,
.pImeToAsciiEx = X11DRV_ImeToAsciiEx,
.pNotifyIMEStatus = X11DRV_NotifyIMEStatus,
.pDestroyCursorIcon = X11DRV_DestroyCursorIcon,
.pSetCursor = X11DRV_SetCursor,

View file

@ -208,8 +208,6 @@ extern INT X11DRV_GetKeyNameText( LONG lparam, LPWSTR buffer, INT size );
extern UINT X11DRV_MapVirtualKeyEx( UINT code, UINT map_type, HKL hkl );
extern INT X11DRV_ToUnicodeEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
LPWSTR bufW, int bufW_size, UINT flags, HKL hkl );
extern UINT X11DRV_ImeToAsciiEx( UINT vkey, UINT vsc, const BYTE *state,
COMPOSITIONSTRING *compstr, HIMC himc );
extern SHORT X11DRV_VkKeyScanEx( WCHAR wChar, HKL hkl );
extern void X11DRV_NotifyIMEStatus( HWND hwnd, UINT status );
extern void X11DRV_DestroyCursorIcon( HCURSOR handle );

View file

@ -44,19 +44,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(xim);
#define XICProc XIMProc
#endif
struct ime_update
{
struct list entry;
DWORD id;
DWORD cursor_pos;
WCHAR *comp_str;
WCHAR *result_str;
WCHAR buffer[];
};
static pthread_mutex_t ime_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct list ime_updates = LIST_INIT(ime_updates);
static DWORD ime_update_count;
static WCHAR *ime_comp_buf;
static XIMStyle input_style = 0;
@ -89,23 +76,8 @@ BOOL xim_in_compose_mode(void)
static void post_ime_update( HWND hwnd, UINT cursor_pos, WCHAR *comp_str, WCHAR *result_str )
{
UINT id, comp_len, result_len;
struct ime_update *update;
comp_len = comp_str ? wcslen( comp_str ) + 1 : 0;
result_len = result_str ? wcslen( result_str ) + 1 : 0;
if (!(update = malloc( offsetof(struct ime_update, buffer[comp_len + result_len]) ))) return;
update->cursor_pos = cursor_pos;
update->comp_str = comp_str ? memcpy( update->buffer, comp_str, comp_len * sizeof(WCHAR) ) : NULL;
update->result_str = result_str ? memcpy( update->buffer + comp_len, result_str, result_len * sizeof(WCHAR) ) : NULL;
pthread_mutex_lock( &ime_mutex );
id = update->id = ++ime_update_count;
list_add_tail( &ime_updates, &update->entry );
pthread_mutex_unlock( &ime_mutex );
NtUserPostMessage( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_COMP_STRING, id );
NtUserMessageCall( hwnd, WINE_IME_POST_UPDATE, cursor_pos, (LPARAM)comp_str,
result_str, NtUserImeDriverCall, FALSE );
}
static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text, UINT new_len )
@ -511,123 +483,8 @@ XIC X11DRV_get_ic( HWND hwnd )
void xim_set_focus( HWND hwnd, BOOL focus )
{
struct list updates = LIST_INIT(updates);
struct ime_update *update, *next;
XIC xic;
if (!(xic = X11DRV_get_ic( hwnd ))) return;
if ((xic = X11DRV_get_ic( hwnd ))) return;
if (focus) XSetICFocus( xic );
else XUnsetICFocus( xic );
pthread_mutex_lock( &ime_mutex );
list_move_tail( &updates, &ime_updates );
pthread_mutex_unlock( &ime_mutex );
LIST_FOR_EACH_ENTRY_SAFE( update, next, &updates, struct ime_update, entry ) free( update );
}
static struct ime_update *find_ime_update( UINT id )
{
struct ime_update *update;
LIST_FOR_EACH_ENTRY( update, &ime_updates, struct ime_update, entry )
if (update->id == id) return update;
return NULL;
}
/***********************************************************************
* ImeToAsciiEx (X11DRV.@)
*
* As XIM filters key events upfront, we don't use ImeProcessKey and ImeToAsciiEx is instead called
* back from the IME UI window procedure when WM_IME_NOTIFY / IMN_WINE_SET_COMP_STRING messages are
* sent to it, to retrieve composition string updates and generate WM_IME messages.
*/
UINT X11DRV_ImeToAsciiEx( UINT vkey, UINT lparam, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc )
{
UINT needed = sizeof(COMPOSITIONSTRING), comp_len, result_len;
struct ime_update *update;
void *dst;
TRACE( "vkey %#x, lparam %#x, state %p, compstr %p, himc %p\n", vkey, lparam, state, compstr, himc );
pthread_mutex_lock( &ime_mutex );
if (!(update = find_ime_update( lparam )))
{
pthread_mutex_unlock( &ime_mutex );
return STATUS_NOT_FOUND;
}
if (!update->comp_str) comp_len = 0;
else
{
comp_len = wcslen( update->comp_str );
needed += comp_len * sizeof(WCHAR); /* GCS_COMPSTR */
needed += comp_len; /* GCS_COMPATTR */
needed += 2 * sizeof(DWORD); /* GCS_COMPCLAUSE */
}
if (!update->result_str) result_len = 0;
else
{
result_len = wcslen( update->result_str );
needed += result_len * sizeof(WCHAR); /* GCS_RESULTSTR */
needed += 2 * sizeof(DWORD); /* GCS_RESULTCLAUSE */
}
if (compstr->dwSize < needed)
{
compstr->dwSize = needed;
pthread_mutex_unlock( &ime_mutex );
return STATUS_BUFFER_TOO_SMALL;
}
list_remove( &update->entry );
pthread_mutex_unlock( &ime_mutex );
memset( compstr, 0, sizeof(*compstr) );
compstr->dwSize = sizeof(*compstr);
if (update->comp_str)
{
compstr->dwCursorPos = update->cursor_pos;
compstr->dwCompStrLen = comp_len;
compstr->dwCompStrOffset = compstr->dwSize;
dst = (BYTE *)compstr + compstr->dwCompStrOffset;
memcpy( dst, update->comp_str, compstr->dwCompStrLen * sizeof(WCHAR) );
compstr->dwSize += compstr->dwCompStrLen * sizeof(WCHAR);
compstr->dwCompClauseLen = 2 * sizeof(DWORD);
compstr->dwCompClauseOffset = compstr->dwSize;
dst = (BYTE *)compstr + compstr->dwCompClauseOffset;
*((DWORD *)dst + 0) = 0;
*((DWORD *)dst + 1) = compstr->dwCompStrLen;
compstr->dwSize += compstr->dwCompClauseLen;
compstr->dwCompAttrLen = compstr->dwCompStrLen;
compstr->dwCompAttrOffset = compstr->dwSize;
dst = (BYTE *)compstr + compstr->dwCompAttrOffset;
memset( dst, ATTR_INPUT, compstr->dwCompAttrLen );
compstr->dwSize += compstr->dwCompAttrLen;
}
if (update->result_str)
{
compstr->dwResultStrLen = result_len;
compstr->dwResultStrOffset = compstr->dwSize;
dst = (BYTE *)compstr + compstr->dwResultStrOffset;
memcpy( dst, update->result_str, compstr->dwResultStrLen * sizeof(WCHAR) );
compstr->dwSize += compstr->dwResultStrLen * sizeof(WCHAR);
compstr->dwResultClauseLen = 2 * sizeof(DWORD);
compstr->dwResultClauseOffset = compstr->dwSize;
dst = (BYTE *)compstr + compstr->dwResultClauseOffset;
*((DWORD *)dst + 0) = 0;
*((DWORD *)dst + 1) = compstr->dwResultStrLen;
compstr->dwSize += compstr->dwResultClauseLen;
}
free( update );
return 0;
}

View file

@ -3597,6 +3597,7 @@ NTSTATUS WINAPI wow64_NtUserMessageCall( UINT *args )
ULONG compstr;
} *params32 = result_info;
struct ime_driver_call_params params;
if (msg == WINE_IME_POST_UPDATE) ERR( "Unexpected WINE_IME_POST_UPDATE message\n" );
params.himc = UlongToPtr( params32->himc );
params.state = UlongToPtr( params32->state );
params.compstr = UlongToPtr( params32->compstr );

View file

@ -511,6 +511,7 @@ enum wine_ime_call
{
WINE_IME_PROCESS_KEY,
WINE_IME_TO_ASCII_EX,
WINE_IME_POST_UPDATE, /* for the user drivers */
};
/* NtUserImeDriverCall params */