[PATCH v7 0/3] MR9992: Introduce ImeToAsciiEx() user driver function for use in winemac
-- v7: winemac: Implement and use macdrv_ImeToAsciiEx(). win32u: Move IME processing to ImeToAsciiEx. win32u: Introduce new ImeToAsciiEx user driver call. https://gitlab.winehq.org/wine/wine/-/merge_requests/9992
From: Marc-Aurel Zent <mzent@codeweavers.com> --- dlls/win32u/driver.c | 12 ++++++++++++ include/wine/gdi_driver.h | 1 + 2 files changed, 13 insertions(+) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index c9e81016ee8..36f0205b8b3 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -675,6 +675,11 @@ static UINT nulldrv_ImeProcessKey( HIMC himc, UINT wparam, UINT lparam, const BY return 0; } +static UINT nulldrv_ImeToAsciiEx( UINT vkey, UINT vsc, const BYTE *state, HIMC himc ) +{ + return STATUS_NOT_IMPLEMENTED; +} + static void nulldrv_NotifyIMEStatus( HWND hwnd, UINT status ) { } @@ -1102,6 +1107,11 @@ static UINT loaderdrv_ImeProcessKey( HIMC himc, UINT wparam, UINT lparam, const return load_driver()->pImeProcessKey( himc, wparam, lparam, state ); } +static UINT loaderdrv_ImeToAsciiEx( UINT vkey, UINT vsc,const BYTE *state, HIMC himc ) +{ + return load_driver()->pImeToAsciiEx( vkey, vsc, state, himc ); +} + static void loaderdrv_NotifyIMEStatus( HWND hwnd, UINT status ) { return load_driver()->pNotifyIMEStatus( hwnd, status ); @@ -1255,6 +1265,7 @@ static const struct user_driver_funcs lazy_load_driver = loaderdrv_KbdLayerDescriptor, loaderdrv_ReleaseKbdTables, loaderdrv_ImeProcessKey, + loaderdrv_ImeToAsciiEx, loaderdrv_NotifyIMEStatus, loaderdrv_SetIMECompositionRect, /* cursor/icon functions */ @@ -1359,6 +1370,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(KbdLayerDescriptor); SET_USER_FUNC(ReleaseKbdTables); SET_USER_FUNC(ImeProcessKey); + SET_USER_FUNC(ImeToAsciiEx); SET_USER_FUNC(NotifyIMEStatus); SET_USER_FUNC(SetIMECompositionRect); SET_USER_FUNC(DestroyCursorIcon); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index f6390bce878..c5b200fb935 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -373,6 +373,7 @@ struct user_driver_funcs void (*pReleaseKbdTables)(const KBDTABLES *); /* IME functions */ UINT (*pImeProcessKey)(HIMC,UINT,UINT,const BYTE*); + UINT (*pImeToAsciiEx)(UINT,UINT,const BYTE*,HIMC); void (*pNotifyIMEStatus)(HWND,UINT); BOOL (*pSetIMECompositionRect)(HWND,RECT); /* cursor/icon functions */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9992
From: Marc-Aurel Zent <mzent@codeweavers.com> --- dlls/imm32/ime.c | 13 ++++++++++++- dlls/win32u/driver.c | 2 +- dlls/win32u/imm.c | 14 +++++++++----- include/ntuser.h | 1 + 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 65f46f20550..9d1e48da673 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -532,6 +532,7 @@ UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, INPUTCONTEXT *ctx; NTSTATUS status; BOOL key_consumed = TRUE; + struct ime_driver_call_params params = {.himc = himc, .state = state}; TRACE( "vkey %#x, vsc %#x, state %p, msgs %p, flags %#x, himc %p\n", vkey, vsc, state, msgs, flags, himc ); @@ -540,9 +541,19 @@ UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) goto done; size = max( compstr->dwSize, sizeof(COMPOSITIONSTRING) ); + status = NtUserMessageCall( ctx->hWnd, WINE_IME_TO_ASCII_EX_USER, vkey, vsc, ¶ms, + NtUserImeDriverCall, FALSE ); + + if (!NT_SUCCESS(status)) + { + TRANSMSG msg = {.message = WM_KEYDOWN, .wParam = vkey, .lParam = vsc}; + msgs->TransMsg[count++] = msg; + ImmUnlockIMCC( ctx->hCompStr ); + goto done; + } + do { - struct ime_driver_call_params params = {.himc = himc, .state = state}; HIMCC himcc; ImmUnlockIMCC( ctx->hCompStr ); diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 36f0205b8b3..40ccdefc6e0 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -672,7 +672,7 @@ static void nulldrv_ReleaseKbdTables( const KBDTABLES *tables ) static UINT nulldrv_ImeProcessKey( HIMC himc, UINT wparam, UINT lparam, const BYTE *state ) { - return 0; + return 1; } static UINT nulldrv_ImeToAsciiEx( UINT vkey, UINT vsc, const BYTE *state, HIMC himc ) diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index f585b80a383..3c650a9c5f9 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -664,25 +664,29 @@ LRESULT ime_driver_call( HWND hwnd, enum wine_ime_call call, WPARAM wparam, LPAR switch (call) { case WINE_IME_PROCESS_KEY: + res = user_driver->pImeProcessKey( params->himc, wparam, lparam, params->state ); + TRACE( "ImeProcessKey vkey %#x, scan %#x -> %lu\n", LOWORD(wparam), HIWORD(lparam), res ); + return res; + case WINE_IME_TO_ASCII_EX_USER: { struct imm_thread_data *data = get_imm_thread_data(); - data->ime_process_scan = HIWORD(lparam); + data->ime_process_scan = LOWORD(lparam); data->ime_process_vkey = LOWORD(wparam); - res = user_driver->pImeProcessKey( params->himc, wparam, lparam, params->state ); + res = user_driver->pImeToAsciiEx( wparam, lparam, (BYTE *)params->state, params->himc ); data->ime_process_vkey = data->ime_process_scan = 0; if (data->update) { - data->update->key_consumed = res; + data->update->key_consumed = NT_SUCCESS(res); pthread_mutex_lock( &imm_mutex ); list_add_tail( &ime_updates, &data->update->entry ); pthread_mutex_unlock( &imm_mutex ); data->update = NULL; - res = TRUE; + res = STATUS_SUCCESS; } - TRACE( "processing vkey %#x, scan %#x -> %lu\n", LOWORD(wparam), HIWORD(lparam), res ); + TRACE( "processing vkey %#x, scan %#x -> %lu\n", LOWORD(wparam), LOWORD(lparam), res ); return res; } case WINE_IME_TO_ASCII_EX: diff --git a/include/ntuser.h b/include/ntuser.h index 939771c9121..3ff7fd574e6 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -679,6 +679,7 @@ enum wine_ime_call WINE_IME_PROCESS_KEY, WINE_IME_TO_ASCII_EX, WINE_IME_POST_UPDATE, /* for the user drivers */ + WINE_IME_TO_ASCII_EX_USER, }; /* NtUserImeDriverCall params */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9992
From: Marc-Aurel Zent <mzent@codeweavers.com> Also renames back macdrv_ime_process_key to macdrv_send_keydown_to_input_source, which is a more accurate name for the function. --- dlls/winemac.drv/cocoa_window.m | 4 +-- dlls/winemac.drv/gdi.c | 1 + dlls/winemac.drv/keyboard.c | 47 ++++++++++++++++++++++----------- dlls/winemac.drv/macdrv.h | 1 + dlls/winemac.drv/macdrv_cocoa.h | 2 +- 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 7d6d704436c..4c1ac93524f 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -4034,13 +4034,13 @@ uint32_t macdrv_window_background_color(void) } /*********************************************************************** - * macdrv_ime_process_key + * macdrv_send_keydown_to_input_source * * Sends a key down event to the active window's inputContext so that it can be * processed by input sources (AKA IMEs). This is only called when there is an * active non-keyboard input source. */ -bool macdrv_ime_process_key(int keyc, unsigned int flags, int repeat, void *himc) +bool macdrv_send_keydown_to_input_source(int keyc, unsigned int flags, int repeat, void *himc) { __block bool ret; diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index 2ef941aedb4..1bf703459f5 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -278,6 +278,7 @@ static const struct user_driver_funcs macdrv_funcs = .pUpdateLayeredWindow = macdrv_UpdateLayeredWindow, .pVkKeyScanEx = macdrv_VkKeyScanEx, .pImeProcessKey = macdrv_ImeProcessKey, + .pImeToAsciiEx = macdrv_ImeToAsciiEx, .pNotifyIMEStatus = macdrv_NotifyIMEStatus, .pSetIMECompositionRect = macdrv_SetIMECompositionRect, .pWindowMessage = macdrv_WindowMessage, diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c index 7c49be7849f..e173e19d96d 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -1085,15 +1085,11 @@ void macdrv_hotkey_press(const macdrv_event *event) */ UINT macdrv_ImeProcessKey(HIMC himc, UINT wparam, UINT lparam, const BYTE *key_state) { - struct macdrv_thread_data *thread_data = macdrv_thread_data(); - WORD scan = HIWORD(lparam) & 0x1ff, vkey = LOWORD(wparam); - BOOL repeat = !!(lparam >> 30), pressed = !(lparam >> 31); - unsigned int flags; - int keyc; - UINT ret; + WORD vkey = LOWORD(wparam); + BOOL pressed = !(lparam >> 31); - TRACE("himc %p, scan %#x, vkey %#x, repeat %u, pressed %u\n", - himc, scan, vkey, repeat, pressed); + TRACE("himc %p, vkey %#x, pressed %u\n", + himc, vkey, pressed); if (!macdrv_using_input_method()) return 0; @@ -1111,23 +1107,45 @@ UINT macdrv_ImeProcessKey(HIMC himc, UINT wparam, UINT lparam, const BYTE *key_s case VK_CONTROL: case VK_CAPITAL: case VK_MENU: + case VK_KANA: + case VK_KANJI: + TRACE("Skipping metakey\n"); return 0; } + return 1; +} + +/*********************************************************************** + * ImeToAsciiEx (MACDRV.@) + */ +UINT macdrv_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, HIMC himc) +{ + struct macdrv_thread_data *thread_data = macdrv_thread_data(); + unsigned int flags; + int keyc; + bool ret; + BOOL repeat = !!(vsc & 0x4000); + + TRACE("himc %p, vkey %#x state %p repeat %u\n", + himc, vkey, state, repeat); + + if (!state) return 0; + flags = thread_data->last_modifiers; - if (key_state[VK_SHIFT] & 0x80) + if (state[VK_SHIFT] & 0x80) flags |= NX_SHIFTMASK; else flags &= ~(NX_SHIFTMASK | NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK); - if (key_state[VK_CAPITAL] & 0x01) + if (state[VK_CAPITAL] & 0x01) flags |= NX_ALPHASHIFTMASK; else flags &= ~NX_ALPHASHIFTMASK; - if (key_state[VK_CONTROL] & 0x80) + if (state[VK_CONTROL] & 0x80) flags |= NX_CONTROLMASK; else flags &= ~(NX_CONTROLMASK | NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK); - if (key_state[VK_MENU] & 0x80) + if (state[VK_MENU] & 0x80) flags |= NX_COMMANDMASK; else flags &= ~(NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK); @@ -1139,10 +1157,9 @@ UINT macdrv_ImeProcessKey(HIMC himc, UINT wparam, UINT lparam, const BYTE *key_s if (keyc >= ARRAY_SIZE(thread_data->keyc2vkey)) return 0; TRACE("flags 0x%08x keyc 0x%04x\n", flags, keyc); - ret = (UINT)macdrv_ime_process_key(keyc, flags, repeat, himc); + ret = macdrv_send_keydown_to_input_source(keyc, flags, repeat, himc); NtUserMsgWaitForMultipleObjectsEx(0, NULL, 0, QS_POSTMESSAGE | QS_SENDMESSAGE, 0); - TRACE("returning %u\n", ret); - return ret; + return ret ? STATUS_SUCCESS : STATUS_NOT_IMPLEMENTED; } diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 0ef7a706d91..e5c922296bf 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -159,6 +159,7 @@ extern void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hin extern void macdrv_UnregisterHotKey(HWND hwnd, UINT modifiers, UINT vkey); extern SHORT macdrv_VkKeyScanEx(WCHAR wChar, HKL hkl); extern UINT macdrv_ImeProcessKey(HIMC himc, UINT wparam, UINT lparam, const BYTE *state); +extern UINT macdrv_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, HIMC himc); extern UINT macdrv_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl); extern INT macdrv_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState, LPWSTR bufW, int bufW_size, UINT flags, HKL hkl); diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 6a6b6975f55..381808479ce 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -530,7 +530,7 @@ extern void macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev, extern bool macdrv_get_view_backing_size(macdrv_view v, int backing_size[2]); extern void macdrv_set_view_backing_size(macdrv_view v, const int backing_size[2]); extern uint32_t macdrv_window_background_color(void); -extern bool macdrv_ime_process_key(int keyc, unsigned int flags, int repeat, void *data); +extern bool macdrv_send_keydown_to_input_source(int keyc, unsigned int flags, int repeat, void *data); extern bool macdrv_is_any_wine_window_visible(void); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9992
The imm_thread_data, ime_update related code in WINE_IME_PROCESS_KEY should be moved into WINE_IME_TO_ASCII_EX.
Indeed it should, and the latest version does so now.
When STATUS_BUFFER_TOO_SMALL is returned, macdrv_ImeToAsciiEx should not be executed again.
This is fixed by having a separate WINE_IME_TO_ASCII_EX_USER call to interact with the user driver. I believe the other issues you noted are also fixed by this redesign, but feel free to correct me if I am wrong. This does have have the side-effect of always first processing input as IME and then backtracking for user drivers that do not implement ImeProcessKey for non-IME layouts, until something like https://gitlab.winehq.org/wine/wine/-/merge_requests/10138 is merged (and I think doing them is this order would also be better). After that the user driver ImeProcessKey, should be able to be removed... There are some technicalities left, like whether key up events should be processed in general to create the equivalent logic in win32u that is currently sitting in macdrv_ImeProcessKey. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9992#note_133864
Am marking this as draft, as a lot of tests expect not `VK_PROCESSKEY` initially, so https://gitlab.winehq.org/wine/wine/-/merge_requests/10138 is a prerequisite for the last iteration. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9992#note_133876
On Fri Mar 27 12:38:44 2026 +0000, Marc-Aurel Zent wrote:
Am marking this as draft, as a lot of tests expect not `VK_PROCESSKEY` initially, so https://gitlab.winehq.org/wine/wine/-/merge_requests/10138 is a prerequisite for the last iteration. The test failure appears to be caused by nulldrv_ImeProcessKey returning 1.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9992#note_134028
On Fri Mar 27 12:38:44 2026 +0000, Byeongsik Jeon wrote:
The test failure appears to be caused by nulldrv_ImeProcessKey returning 1. Yes, which was an intentional choice to get the correct messages for IME processing on platforms that do not implement ImeProcessKey (which is only in macdrv currently).
After the above-mentioned MR and some refactoring, ImeProcessKey (the user driver version that is) can be removed completely. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9992#note_134055
participants (3)
-
Byeongsik Jeon (@bsjeon) -
Marc-Aurel Zent -
Marc-Aurel Zent (@mzent)