[PATCH v5 0/4] MR9992: Introduce ImeToAsciiEx() user driver function for use in winemac
-- v5: winemac: Implement and use macdrv_ImeToAsciiEx(). win32u: Generate a WM_KEYDOWN message for unconsumed keys. https://gitlab.winehq.org/wine/wine/-/merge_requests/9992
From: Marc-Aurel Zent <mzent@codeweavers.com> --- dlls/imm32/ime.c | 1 + dlls/win32u/driver.c | 12 ++++++++++++ dlls/win32u/imm.c | 1 + include/ntuser.h | 1 + include/wine/gdi_driver.h | 1 + 5 files changed, 16 insertions(+) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 65f46f20550..ed3f262c47a 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -551,6 +551,7 @@ UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, params.compstr = compstr; params.key_consumed = &key_consumed; + params.msgs = msgs; status = NtUserMessageCall( ctx->hWnd, WINE_IME_TO_ASCII_EX, vkey, vsc, ¶ms, NtUserImeDriverCall, FALSE ); size = compstr->dwSize; diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 60aba702d1a..9664c355fc2 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -676,6 +676,11 @@ static UINT nulldrv_ImeProcessKey( HIMC himc, UINT wparam, UINT lparam, const BY return 0; } +static UINT nulldrv_ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, UINT flags, HIMC himc ) +{ + return 0; +} + static void nulldrv_NotifyIMEStatus( HWND hwnd, UINT status ) { } @@ -1103,6 +1108,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, BYTE *state, TRANSMSGLIST *msgs, UINT flags, HIMC himc ) +{ + return load_driver()->pImeToAsciiEx( vkey, vsc, state, msgs, flags, himc ); +} + static void loaderdrv_NotifyIMEStatus( HWND hwnd, UINT status ) { return load_driver()->pNotifyIMEStatus( hwnd, status ); @@ -1256,6 +1266,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 */ @@ -1360,6 +1371,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/dlls/win32u/imm.c b/dlls/win32u/imm.c index 3337f66e291..0d225f23e37 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -687,6 +687,7 @@ LRESULT ime_driver_call( HWND hwnd, enum wine_ime_call call, WPARAM wparam, LPAR return res; } case WINE_IME_TO_ASCII_EX: + user_driver->pImeToAsciiEx( wparam, lparam, (BYTE *)params->state, params->msgs, 0, params->himc ); return ime_to_tascii_ex( wparam, lparam, params->state, params->compstr, params->key_consumed, params->himc ); case WINE_IME_POST_UPDATE: post_ime_update( hwnd, wparam, (WCHAR *)lparam, (WCHAR *)params ); diff --git a/include/ntuser.h b/include/ntuser.h index ce1b18fdfd9..54a4949e407 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -682,6 +682,7 @@ struct ime_driver_call_params const BYTE *state; COMPOSITIONSTRING *compstr; BOOL *key_consumed; + TRANSMSGLIST *msgs; }; /* NtUserSystemTrayCall calls */ diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index f6390bce878..7e2a6005deb 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,BYTE*,TRANSMSGLIST*,UINT,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 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index ed3f262c47a..8369fa7bed9 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -361,12 +361,14 @@ static UINT ime_set_comp_string( HIMC himc, LPARAM lparam ) TRANSMSG *msgs; HIMCC himcc; UINT count; + BYTE state[256]; TRACE( "himc %p\n", himc ); if (!(ctx = ImmLockIMC( himc ))) return 0; - count = ImeToAsciiEx( VK_PROCESSKEY, lparam, NULL, &buffer.list, 0, himc ); + GetKeyboardState( state ); + count = ImeToAsciiEx( VK_PROCESSKEY, lparam, state, &buffer.list, 0, himc ); if (!count) TRACE( "ImeToAsciiEx returned no messages\n" ); else if (count >= buffer.uMsgCount) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9992
From: Marc-Aurel Zent <mzent@codeweavers.com> --- dlls/win32u/imm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index 0d225f23e37..1bfb6e58320 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -687,7 +687,14 @@ LRESULT ime_driver_call( HWND hwnd, enum wine_ime_call call, WPARAM wparam, LPAR return res; } case WINE_IME_TO_ASCII_EX: - user_driver->pImeToAsciiEx( wparam, lparam, (BYTE *)params->state, params->msgs, 0, params->himc ); + res = user_driver->pImeToAsciiEx( wparam, lparam, (BYTE *)params->state, params->msgs, 0, params->himc ); + + if (res) + { + NtUserPostMessage( hwnd, WM_KEYDOWN, wparam, lparam ); + return res; + } + return ime_to_tascii_ex( wparam, lparam, params->state, params->compstr, params->key_consumed, params->himc ); case WINE_IME_POST_UPDATE: post_ime_update( hwnd, wparam, (WCHAR *)lparam, (WCHAR *)params ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9992
From: Marc-Aurel Zent <mzent@codeweavers.com> --- dlls/winemac.drv/gdi.c | 1 + dlls/winemac.drv/keyboard.c | 38 ++++++++++++++++++++++++++----------- dlls/winemac.drv/macdrv.h | 2 ++ 3 files changed, 30 insertions(+), 11 deletions(-) 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..0b6a81938e5 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -1086,15 +1086,13 @@ 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); + WORD vkey = LOWORD(wparam); BOOL repeat = !!(lparam >> 30), pressed = !(lparam >> 31); - unsigned int flags; - int keyc; - UINT ret; - TRACE("himc %p, scan %#x, vkey %#x, repeat %u, pressed %u\n", - himc, scan, vkey, repeat, pressed); + TRACE("himc %p, vkey %#x, repeat %u, pressed %u\n", + himc, vkey, repeat, pressed); + thread_data->repeat = repeat; if (!macdrv_using_input_method()) return 0; if (!pressed) @@ -1111,23 +1109,41 @@ 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, BYTE *state, TRANSMSGLIST *msgs, UINT flags, HIMC himc) +{ + struct macdrv_thread_data *thread_data = macdrv_thread_data(); + int keyc; + UINT ret; + + TRACE("himc %p, vkey %#x state %p\n", + himc, vkey, state); + 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,7 +1155,7 @@ 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 = !(UINT)macdrv_ime_process_key(keyc, flags, thread_data->repeat, himc); NtUserMsgWaitForMultipleObjectsEx(0, NULL, 0, QS_POSTMESSAGE | QS_SENDMESSAGE, 0); TRACE("returning %u\n", ret); return ret; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index ac2a7853652..c415509c270 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -107,6 +107,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect) CFDataRef keyboard_layout_uchr; CGEventSourceKeyboardType keyboard_type; bool iso_keyboard; + bool repeat; CGEventFlags last_modifiers; UInt32 dead_key_state; HKL active_keyboard_layout; @@ -160,6 +161,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, BYTE *state, TRANSMSGLIST *msgs, UINT flags, 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); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9992
Rémi Bernon (@rbernon) commented about dlls/imm32/ime.c:
TRANSMSG *msgs; HIMCC himcc; UINT count; + BYTE state[256];
TRACE( "himc %p\n", himc );
if (!(ctx = ImmLockIMC( himc ))) return 0;
- count = ImeToAsciiEx( VK_PROCESSKEY, lparam, NULL, &buffer.list, 0, himc ); + GetKeyboardState( state ); + count = ImeToAsciiEx( VK_PROCESSKEY, lparam, state, &buffer.list, 0, himc ); if (!count)
This call is only meant to gather the queued updates and generate composition messages out of it, it shouldn't cause a key event to be fed back into the host IME and thus doesn't need the keyboard state. The IMN_WINE_SET_COMP_STRING already comes from an asynchronous IME input from the host IME itself. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9992#note_129866
Rémi Bernon (@rbernon) commented about dlls/win32u/imm.c:
return res; } case WINE_IME_TO_ASCII_EX: + user_driver->pImeToAsciiEx( wparam, lparam, (BYTE *)params->state, params->msgs, 0, params->himc ); return ime_to_tascii_ex( wparam, lparam, params->state, params->compstr, params->key_consumed, params->himc );
IMO instead of adding another driver entry, we should move things from ImeProcessKey to ImeToAsciiEx. Whether host input is an IME, and whether builtin IME be called at all, should be done using the dedicated bit in the HKL (IME HKL have 0xe000 high word bits set). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9992#note_129869
Rémi Bernon (@rbernon) commented about dlls/win32u/imm.c:
return res; } case WINE_IME_TO_ASCII_EX: - user_driver->pImeToAsciiEx( wparam, lparam, (BYTE *)params->state, params->msgs, 0, params->himc ); + res = user_driver->pImeToAsciiEx( wparam, lparam, (BYTE *)params->state, params->msgs, 0, params->himc ); + + if (res) + { + NtUserPostMessage( hwnd, WM_KEYDOWN, wparam, lparam ); + return res;
This could probably be done directly in ImeToAsciiEx by appending a TRANSMSG. We could use a specific return status for that, like STATUS_NOT_IMPLEMENTED. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9992#note_129867
Rémi Bernon (@rbernon) commented about dlls/winemac.drv/keyboard.c:
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); + WORD vkey = LOWORD(wparam); BOOL repeat = !!(lparam >> 30), pressed = !(lparam >> 31); - unsigned int flags; - int keyc; - UINT ret;
- TRACE("himc %p, scan %#x, vkey %#x, repeat %u, pressed %u\n", - himc, scan, vkey, repeat, pressed); + TRACE("himc %p, vkey %#x, repeat %u, pressed %u\n", + himc, vkey, repeat, pressed);
+ thread_data->repeat = repeat; You should be able to get the repeat (resp. pressed) bits from ImeToAsciiEx vsc bit 14 (resp. 15), I think?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9992#note_129868
v2: Slightly simplified version that does not use the `key_consumed` mechanism (and leaves the existing logic there unchanged).
Edit: Now also properly rebased and fixed a typo in a commit.
As you mentioned in your previous comment, I had misunderstood the intended direction of the MR. However, since I still believed that separating the functionality of macdrv_ImeProcessKey was necessary, I went ahead and worked on it independently. I initially started this because a memory leak occurs when ImeToAsciiEx is not invoked. In the end, this turned out to be a waste of time, but I am attaching it here for reference, as it feels somewhat unfortunate to discard it entirely. It appears that the regression introduced in v2 no longer occurs, although the changes still need further cleanup. [fix_macdrv_ime_process_key.patch](/uploads/414c1f64da4aba9acedc55196ecdab8e/fix_macdrv_ime_process_key.patch) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9992#note_129873
participants (4)
-
Byeongsik Jeon (@bsjeon) -
Marc-Aurel Zent -
Marc-Aurel Zent (@mzent) -
Rémi Bernon (@rbernon)