-- v2: imm32: Post messages to the target window in ImmTranslateMessage. imm32: Clear vkey before calling ToAsciiEx in ImmTranslateMessage. imm32: Ignore some messages in ImmTranslateMessage. imm32: Increase the ImmTranslateMessage buffer size. imm32/tests: Test ImmTranslateMessage / ImeToAsciiEx calls. imm32/tests: Add more ImmProcessKey and ImmGetVirtualKey tests. imm32: Use INPUTCONTEXT directly in ImmRequestMessage(W|A). imm32/tests: Test cross-thread ImmRequestMessage(W|A) calls. imm32/tests: Move IME calls test helpers around.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 738 +++++++++++++++++++-------------------- 1 file changed, 369 insertions(+), 369 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 093b79ff86b..d06ad1fae3d 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -263,6 +263,299 @@ static void process_messages(void) } }
+#define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ ) + +static BOOL ImeSelect_init_status; +static BOOL todo_ImeInquire; +DEFINE_EXPECT( ImeInquire ); +static BOOL todo_ImeDestroy; +DEFINE_EXPECT( ImeDestroy ); +DEFINE_EXPECT( ImeEscape ); +DEFINE_EXPECT( ImeEnumRegisterWord ); +DEFINE_EXPECT( ImeRegisterWord ); +DEFINE_EXPECT( ImeGetRegisterWordStyle ); +DEFINE_EXPECT( ImeUnregisterWord ); +static BOOL todo_ImeSetCompositionString; +DEFINE_EXPECT( ImeSetCompositionString ); +static BOOL todo_IME_DLL_PROCESS_ATTACH; +DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); +static BOOL todo_IME_DLL_PROCESS_DETACH; +DEFINE_EXPECT( IME_DLL_PROCESS_DETACH ); + +static IMEINFO ime_info; +static UINT ime_count; +static WCHAR ime_path[MAX_PATH]; +static HIMC default_himc; +static HKL default_hkl, wineime_hkl; +static HKL expect_ime = (HKL)(int)0xe020047f; + +enum ime_function +{ + IME_SELECT = 1, + IME_NOTIFY, + IME_PROCESS_KEY, + IME_SET_ACTIVE_CONTEXT, + MSG_IME_UI, + MSG_TEST_WIN, +}; + +struct ime_call +{ + HKL hkl; + HIMC himc; + enum ime_function func; + + union + { + int select; + struct + { + int action; + int index; + int value; + } notify; + struct + { + WORD vkey; + LPARAM lparam; + } process_key; + struct + { + int flag; + } set_active_context; + struct + { + UINT msg; + WPARAM wparam; + LPARAM lparam; + } message; + }; + + BOOL todo; + BOOL broken; + BOOL flaky_himc; +}; + +struct ime_call empty_sequence[] = {{0}}; +static struct ime_call ime_calls[1024]; +static ULONG ime_call_count; + +#define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b ) +static int ok_call_( const char *file, int line, const struct ime_call *expected, const struct ime_call *received ) +{ + int ret; + + if ((ret = expected->func - received->func)) goto done; + /* Wine doesn't allocate HIMC in a deterministic order, ignore them when they are enumerated */ + if (expected->flaky_himc && (ret = !!(UINT_PTR)expected->himc - !!(UINT_PTR)received->himc)) goto done; + if (!expected->flaky_himc && (ret = (UINT_PTR)expected->himc - (UINT_PTR)received->himc)) goto done; + if ((ret = (UINT)(UINT_PTR)expected->hkl - (UINT)(UINT_PTR)received->hkl)) goto done; + switch (expected->func) + { + case IME_SELECT: + if ((ret = expected->select - received->select)) goto done; + break; + case IME_NOTIFY: + if ((ret = expected->notify.action - received->notify.action)) goto done; + if ((ret = expected->notify.index - received->notify.index)) goto done; + if ((ret = expected->notify.value - received->notify.value)) goto done; + break; + case IME_PROCESS_KEY: + if ((ret = expected->process_key.vkey - received->process_key.vkey)) goto done; + if ((ret = expected->process_key.lparam - received->process_key.lparam)) goto done; + break; + case IME_SET_ACTIVE_CONTEXT: + if ((ret = expected->set_active_context.flag - received->set_active_context.flag)) goto done; + break; + case MSG_IME_UI: + case MSG_TEST_WIN: + if ((ret = expected->message.msg - received->message.msg)) goto done; + if ((ret = (expected->message.wparam - received->message.wparam))) goto done; + if ((ret = (expected->message.lparam - received->message.lparam))) goto done; + break; + } + +done: + if (ret && broken( expected->broken )) return ret; + + switch (received->func) + { + case IME_SELECT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SELECT select %u\n", received->hkl, received->himc, received->select ); + return ret; + case IME_NOTIFY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", + received->hkl, received->himc, received->notify.action, received->notify.index, + received->notify.value ); + return ret; + case IME_PROCESS_KEY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n", + received->hkl, received->himc, received->process_key.vkey, received->process_key.lparam ); + return ret; + case IME_SET_ACTIVE_CONTEXT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", received->hkl, received->himc, + received->set_active_context.flag ); + return ret; + case MSG_IME_UI: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, + received->himc, received->message.msg, received->message.wparam, received->message.lparam ); + return ret; + case MSG_TEST_WIN: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, + received->himc, received->message.msg, received->message.wparam, received->message.lparam ); + return ret; + } + + switch (expected->func) + { + case IME_SELECT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_SELECT select %u\n", expected->hkl, expected->himc, expected->select ); + break; + case IME_NOTIFY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", + expected->hkl, expected->himc, expected->notify.action, expected->notify.index, + expected->notify.value ); + break; + case IME_PROCESS_KEY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n", + expected->hkl, expected->himc, expected->process_key.vkey, expected->process_key.lparam ); + break; + case IME_SET_ACTIVE_CONTEXT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", expected->hkl, expected->himc, + expected->set_active_context.flag ); + break; + case MSG_IME_UI: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, + expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); + break; + case MSG_TEST_WIN: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, + expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); + break; + } + + return 0; +} + +#define ok_seq( a ) ok_seq_( __FILE__, __LINE__, a, #a ) +static void ok_seq_( const char *file, int line, const struct ime_call *expected, const char *context ) +{ + const struct ime_call *received = ime_calls; + UINT i = 0, ret; + + while (expected->func || received->func) + { + winetest_push_context( "%u%s%s", i++, !expected->func ? " (spurious)" : "", + !received->func ? " (missing)" : "" ); + ret = ok_call_( file, line, expected, received ); + if (ret && expected->todo && expected->func && + !strcmp( winetest_platform, "wine" )) + expected++; + else if (ret && broken(expected->broken)) + expected++; + else + { + if (expected->func) expected++; + if (received->func) received++; + } + winetest_pop_context(); + } + + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + +static BOOL check_WM_SHOWWINDOW; + +static BOOL ignore_message( UINT msg ) +{ + switch (msg) + { + case WM_IME_STARTCOMPOSITION: + case WM_IME_ENDCOMPOSITION: + case WM_IME_COMPOSITION: + case WM_IME_SETCONTEXT: + case WM_IME_NOTIFY: + case WM_IME_CONTROL: + case WM_IME_COMPOSITIONFULL: + case WM_IME_SELECT: + case WM_IME_CHAR: + case 0x287: + case WM_IME_REQUEST: + case WM_IME_KEYDOWN: + case WM_IME_KEYUP: + return FALSE; + case WM_SHOWWINDOW: + return !check_WM_SHOWWINDOW; + default: + return TRUE; + } +} + +static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ), + .func = MSG_IME_UI, .message = {.msg = msg, .wparam = wparam, .lparam = lparam} + }; + LONG_PTR ptr; + + ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + + ptr = GetWindowLongPtrW( hwnd, IMMGWL_PRIVATE ); + ok( !ptr, "got IMMGWL_PRIVATE %#Ix\n", ptr ); + + ime_calls[ime_call_count++] = call; + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static LRESULT CALLBACK test_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = ImmGetContext( hwnd ), + .func = MSG_TEST_WIN, .message = {.msg = msg, .wparam = wparam, .lparam = lparam} + }; + + ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + + ime_calls[ime_call_count++] = call; + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static WNDCLASSEXW ime_ui_class = +{ + .cbSize = sizeof(WNDCLASSEXW), + .style = CS_IME, + .lpfnWndProc = ime_ui_window_proc, + .cbWndExtra = 2 * sizeof(LONG_PTR), + .lpszClassName = L"WineTestIME", +}; + +static WNDCLASSEXW test_class = +{ + .cbSize = sizeof(WNDCLASSEXW), + .lpfnWndProc = test_window_proc, + .lpszClassName = L"WineTest", +}; + /* * msgspy - record and analyse message traces sent to a certain window */ @@ -2595,397 +2888,104 @@ static void test_com_initialization(void) test_apttype(hr == S_OK ? APTTYPE_MTA : APTTYPE_MAINSTA); DestroyWindow(wnd); test_apttype(-1); -} - -static DWORD WINAPI disable_ime_thread(void *arg) -{ - HWND h, def; - MSG msg; - BOOL r; - - h = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); - ok(h != NULL, "CreateWindow failed\n"); - def = ImmGetDefaultIMEWnd(h); - ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n"); - - r = ImmDisableIME(arg ? GetCurrentThreadId() : 0); - ok(r, "ImmDisableIME failed\n"); - - if (arg) - { - def = ImmGetDefaultIMEWnd(h); - todo_wine ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n"); - while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) - DispatchMessageA(&msg); - } - def = ImmGetDefaultIMEWnd(h); - ok(!def, "ImmGetDefaultIMEWnd returned %p\n", def); - return 0; -} - -static DWORD WINAPI check_not_disabled_ime_thread(void *arg) -{ - HWND def, hwnd; - - WaitForSingleObject(arg, INFINITE); - hwnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); - ok(hwnd != NULL, "CreateWindow failed\n"); - def = ImmGetDefaultIMEWnd(hwnd); - ok(def != NULL, "ImmGetDefaultIMEWnd returned %p\n", def); - return 0; -} - -static DWORD WINAPI disable_ime_process(void *arg) -{ - BOOL r = ImmDisableIME(-1); - ok(r, "ImmDisableIME failed\n"); - return 0; -} - -static void test_ImmDisableIME(void) -{ - HANDLE thread, event; - DWORD tid; - HWND def, def2; - BOOL r; - - def = ImmGetDefaultIMEWnd(hwnd); - ok(def != NULL, "ImmGetDefaultIMEWnd(hwnd) returned NULL\n"); - - event = CreateEventW(NULL, TRUE, FALSE, FALSE); - thread = CreateThread(NULL, 0, check_not_disabled_ime_thread, event, 0, &tid); - ok(thread != NULL, "CreateThread failed\n"); - r = ImmDisableIME(tid); - ok(!r, "ImmDisableIME(tid) succeeded\n"); - SetEvent(event); - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - CloseHandle(event); - - thread = CreateThread(NULL, 0, disable_ime_thread, 0, 0, NULL); - ok(thread != NULL, "CreateThread failed\n"); - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - - thread = CreateThread(NULL, 0, disable_ime_thread, (void*)1, 0, NULL); - ok(thread != NULL, "CreateThread failed\n"); - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - - msg_spy_pump_msg_queue(); - thread = CreateThread(NULL, 0, disable_ime_process, 0, 0, NULL); - ok(thread != NULL, "CreateThread failed\n"); - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - - ok(IsWindow(def), "not a window\n"); - def2 = ImmGetDefaultIMEWnd(hwnd); - ok(def2 == def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def2); - ok(IsWindow(def), "not a window\n"); - msg_spy_pump_msg_queue(); - ok(!IsWindow(def), "window is still valid\n"); - def = ImmGetDefaultIMEWnd(hwnd); - ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); - - r = ImmDisableIME(-1); - ok(r, "ImmDisableIME(-1) failed\n"); - def = ImmGetDefaultIMEWnd(hwnd); - ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); -} - -#define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ ) - -static BOOL ImeSelect_init_status; -static BOOL todo_ImeInquire; -DEFINE_EXPECT( ImeInquire ); -static BOOL todo_ImeDestroy; -DEFINE_EXPECT( ImeDestroy ); -DEFINE_EXPECT( ImeEscape ); -DEFINE_EXPECT( ImeEnumRegisterWord ); -DEFINE_EXPECT( ImeRegisterWord ); -DEFINE_EXPECT( ImeGetRegisterWordStyle ); -DEFINE_EXPECT( ImeUnregisterWord ); -static BOOL todo_ImeSetCompositionString; -DEFINE_EXPECT( ImeSetCompositionString ); -static BOOL todo_IME_DLL_PROCESS_ATTACH; -DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); -static BOOL todo_IME_DLL_PROCESS_DETACH; -DEFINE_EXPECT( IME_DLL_PROCESS_DETACH ); - -static IMEINFO ime_info; -static UINT ime_count; -static WCHAR ime_path[MAX_PATH]; -static HIMC default_himc; -static HKL default_hkl, wineime_hkl; -static HKL expect_ime = (HKL)(int)0xe020047f; - -enum ime_function -{ - IME_SELECT = 1, - IME_NOTIFY, - IME_PROCESS_KEY, - IME_SET_ACTIVE_CONTEXT, - MSG_IME_UI, - MSG_TEST_WIN, -}; - -struct ime_call -{ - HKL hkl; - HIMC himc; - enum ime_function func; - - union - { - int select; - struct - { - int action; - int index; - int value; - } notify; - struct - { - WORD vkey; - LPARAM key_data; - } process_key; - struct - { - int flag; - } set_active_context; - struct - { - UINT msg; - WPARAM wparam; - LPARAM lparam; - } message; - }; - - BOOL todo; - BOOL broken; - BOOL flaky_himc; -}; - -struct ime_call empty_sequence[] = {{0}}; -static struct ime_call ime_calls[1024]; -static ULONG ime_call_count; +}
-#define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b ) -static int ok_call_( const char *file, int line, const struct ime_call *expected, const struct ime_call *received ) +static DWORD WINAPI disable_ime_thread(void *arg) { - int ret; - - if ((ret = expected->func - received->func)) goto done; - /* Wine doesn't allocate HIMC in a deterministic order, ignore them when they are enumerated */ - if (expected->flaky_himc && (ret = !!(UINT_PTR)expected->himc - !!(UINT_PTR)received->himc)) goto done; - if (!expected->flaky_himc && (ret = (UINT_PTR)expected->himc - (UINT_PTR)received->himc)) goto done; - if ((ret = (UINT)(UINT_PTR)expected->hkl - (UINT)(UINT_PTR)received->hkl)) goto done; - switch (expected->func) - { - case IME_SELECT: - if ((ret = expected->select - received->select)) goto done; - break; - case IME_NOTIFY: - if ((ret = expected->notify.action - received->notify.action)) goto done; - if ((ret = expected->notify.index - received->notify.index)) goto done; - if ((ret = expected->notify.value - received->notify.value)) goto done; - break; - case IME_PROCESS_KEY: - if ((ret = expected->process_key.vkey - received->process_key.vkey)) goto done; - if ((ret = expected->process_key.key_data - received->process_key.key_data)) goto done; - break; - case IME_SET_ACTIVE_CONTEXT: - if ((ret = expected->set_active_context.flag - received->set_active_context.flag)) goto done; - break; - case MSG_IME_UI: - case MSG_TEST_WIN: - if ((ret = expected->message.msg - received->message.msg)) goto done; - if ((ret = (expected->message.wparam - received->message.wparam))) goto done; - if ((ret = (expected->message.lparam - received->message.lparam))) goto done; - break; - } + HWND h, def; + MSG msg; + BOOL r;
-done: - if (ret && broken( expected->broken )) return ret; + h = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); + ok(h != NULL, "CreateWindow failed\n"); + def = ImmGetDefaultIMEWnd(h); + ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n");
- switch (received->func) - { - case IME_SELECT: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SELECT select %u\n", received->hkl, received->himc, received->select ); - return ret; - case IME_NOTIFY: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", - received->hkl, received->himc, received->notify.action, received->notify.index, - received->notify.value ); - return ret; - case IME_PROCESS_KEY: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n", - received->hkl, received->himc, received->process_key.vkey, received->process_key.key_data ); - return ret; - case IME_SET_ACTIVE_CONTEXT: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", received->hkl, received->himc, - received->set_active_context.flag ); - return ret; - case MSG_IME_UI: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, - received->himc, received->message.msg, received->message.wparam, received->message.lparam ); - return ret; - case MSG_TEST_WIN: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, - received->himc, received->message.msg, received->message.wparam, received->message.lparam ); - return ret; - } + r = ImmDisableIME(arg ? GetCurrentThreadId() : 0); + ok(r, "ImmDisableIME failed\n");
- switch (expected->func) + if (arg) { - case IME_SELECT: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, IME_SELECT select %u\n", expected->hkl, expected->himc, expected->select ); - break; - case IME_NOTIFY: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", - expected->hkl, expected->himc, expected->notify.action, expected->notify.index, - expected->notify.value ); - break; - case IME_PROCESS_KEY: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n", - expected->hkl, expected->himc, expected->process_key.vkey, expected->process_key.key_data ); - break; - case IME_SET_ACTIVE_CONTEXT: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", expected->hkl, expected->himc, - expected->set_active_context.flag ); - break; - case MSG_IME_UI: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, - expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); - break; - case MSG_TEST_WIN: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, - expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); - break; + def = ImmGetDefaultIMEWnd(h); + todo_wine ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n"); + while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); } - + def = ImmGetDefaultIMEWnd(h); + ok(!def, "ImmGetDefaultIMEWnd returned %p\n", def); return 0; }
-#define ok_seq( a ) ok_seq_( __FILE__, __LINE__, a, #a ) -static void ok_seq_( const char *file, int line, const struct ime_call *expected, const char *context ) +static DWORD WINAPI check_not_disabled_ime_thread(void *arg) { - const struct ime_call *received = ime_calls; - UINT i = 0, ret; - - while (expected->func || received->func) - { - winetest_push_context( "%u%s%s", i++, !expected->func ? " (spurious)" : "", - !received->func ? " (missing)" : "" ); - ret = ok_call_( file, line, expected, received ); - if (ret && expected->todo && expected->func && - !strcmp( winetest_platform, "wine" )) - expected++; - else if (ret && broken(expected->broken)) - expected++; - else - { - if (expected->func) expected++; - if (received->func) received++; - } - winetest_pop_context(); - } + HWND def, hwnd;
- memset( ime_calls, 0, sizeof(ime_calls) ); - ime_call_count = 0; + WaitForSingleObject(arg, INFINITE); + hwnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); + ok(hwnd != NULL, "CreateWindow failed\n"); + def = ImmGetDefaultIMEWnd(hwnd); + ok(def != NULL, "ImmGetDefaultIMEWnd returned %p\n", def); + return 0; }
-static BOOL check_WM_SHOWWINDOW; - -static BOOL ignore_message( UINT msg ) +static DWORD WINAPI disable_ime_process(void *arg) { - switch (msg) - { - case WM_IME_STARTCOMPOSITION: - case WM_IME_ENDCOMPOSITION: - case WM_IME_COMPOSITION: - case WM_IME_SETCONTEXT: - case WM_IME_NOTIFY: - case WM_IME_CONTROL: - case WM_IME_COMPOSITIONFULL: - case WM_IME_SELECT: - case WM_IME_CHAR: - case 0x287: - case WM_IME_REQUEST: - case WM_IME_KEYDOWN: - case WM_IME_KEYUP: - return FALSE; - case WM_SHOWWINDOW: - return !check_WM_SHOWWINDOW; - default: - return TRUE; - } + BOOL r = ImmDisableIME(-1); + ok(r, "ImmDisableIME failed\n"); + return 0; }
-static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +static void test_ImmDisableIME(void) { - struct ime_call call = - { - .hkl = GetKeyboardLayout( 0 ), .himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ), - .func = MSG_IME_UI, .message = {.msg = msg, .wparam = wparam, .lparam = lparam} - }; - LONG_PTR ptr; - - ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + HANDLE thread, event; + DWORD tid; + HWND def, def2; + BOOL r;
- if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + def = ImmGetDefaultIMEWnd(hwnd); + ok(def != NULL, "ImmGetDefaultIMEWnd(hwnd) returned NULL\n");
- ptr = GetWindowLongPtrW( hwnd, IMMGWL_PRIVATE ); - ok( !ptr, "got IMMGWL_PRIVATE %#Ix\n", ptr ); + event = CreateEventW(NULL, TRUE, FALSE, FALSE); + thread = CreateThread(NULL, 0, check_not_disabled_ime_thread, event, 0, &tid); + ok(thread != NULL, "CreateThread failed\n"); + r = ImmDisableIME(tid); + ok(!r, "ImmDisableIME(tid) succeeded\n"); + SetEvent(event); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + CloseHandle(event);
- ime_calls[ime_call_count++] = call; - return DefWindowProcW( hwnd, msg, wparam, lparam ); -} + thread = CreateThread(NULL, 0, disable_ime_thread, 0, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread);
-static LRESULT CALLBACK test_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) -{ - struct ime_call call = - { - .hkl = GetKeyboardLayout( 0 ), .himc = ImmGetContext( hwnd ), - .func = MSG_TEST_WIN, .message = {.msg = msg, .wparam = wparam, .lparam = lparam} - }; + thread = CreateThread(NULL, 0, disable_ime_thread, (void*)1, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread);
- ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + msg_spy_pump_msg_queue(); + thread = CreateThread(NULL, 0, disable_ime_process, 0, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread);
- if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + ok(IsWindow(def), "not a window\n"); + def2 = ImmGetDefaultIMEWnd(hwnd); + ok(def2 == def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def2); + ok(IsWindow(def), "not a window\n"); + msg_spy_pump_msg_queue(); + ok(!IsWindow(def), "window is still valid\n"); + def = ImmGetDefaultIMEWnd(hwnd); + ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def);
- ime_calls[ime_call_count++] = call; - return DefWindowProcW( hwnd, msg, wparam, lparam ); + r = ImmDisableIME(-1); + ok(r, "ImmDisableIME(-1) failed\n"); + def = ImmGetDefaultIMEWnd(hwnd); + ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); }
-static WNDCLASSEXW ime_ui_class = -{ - .cbSize = sizeof(WNDCLASSEXW), - .style = CS_IME, - .lpfnWndProc = ime_ui_window_proc, - .cbWndExtra = 2 * sizeof(LONG_PTR), - .lpszClassName = L"WineTestIME", -}; - -static WNDCLASSEXW test_class = -{ - .cbSize = sizeof(WNDCLASSEXW), - .lpfnWndProc = test_window_proc, - .lpszClassName = L"WineTest", -}; - static BOOL WINAPI ime_ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data ) { ime_trace( "hkl %p, hwnd %p, mode %lu, data %p\n", hkl, hwnd, mode, data ); @@ -3136,15 +3136,15 @@ static BOOL WINAPI ime_ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) return TRUE; }
-static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYTE *key_state ) +static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE *state ) { struct ime_call call = { .hkl = GetKeyboardLayout( 0 ), .himc = himc, - .func = IME_PROCESS_KEY, .process_key = {.vkey = vkey, .key_data = key_data} + .func = IME_PROCESS_KEY, .process_key = {.vkey = vkey, .lparam = lparam} }; - ime_trace( "himc %p, vkey %u, key_data %#Ix, key_state %p\n", - himc, vkey, key_data, key_state ); + ime_trace( "himc %p, vkey %u, lparam %#Ix, state %p\n", + himc, vkey, lparam, state ); ime_calls[ime_call_count++] = call; return TRUE; } @@ -4644,7 +4644,7 @@ static void test_ImmProcessKey(void) { { .hkl = expect_ime, .himc = default_himc, - .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .key_data = 0}, + .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = 0}, }, {0}, };
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 102 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index d06ad1fae3d..9290c9c5d0b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -1351,13 +1351,14 @@ static DWORD WINAPI test_cross_thread_himc_thread( void *arg ) POINT pos = {0}; MSG msg;
- hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok_ne( NULL, hwnd, HWND, "%p" ); himc[0] = ImmGetContext( hwnd ); ok_ne( NULL, himc[0], HIMC, "%p" ); contexts[0] = ImmLockIMC( himc[0] ); ok_ne( NULL, contexts[0], INPUTCONTEXT *, "%p" ); + contexts[0]->hWnd = hwnd;
tmp_hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -1370,6 +1371,7 @@ static DWORD WINAPI test_cross_thread_himc_thread( void *arg ) ok_ne( NULL, himc[1], HIMC, "%p" ); contexts[1] = ImmLockIMC( himc[1] ); ok_ne( NULL, contexts[1], INPUTCONTEXT *, "%p" ); + contexts[1]->hWnd = hwnd;
ok_ret( 1, ImmSetOpenStatus( himc[0], 0xdeadbeef ) ); ok_ret( 1, ImmSetOpenStatus( himc[1], 0xfeedcafe ) ); @@ -1408,9 +1410,11 @@ static DWORD WINAPI test_cross_thread_himc_thread( void *arg ) static void test_cross_thread_himc(void) { static const WCHAR comp_string[] = L"CompString"; + RECONVERTSTRING reconv = {.dwSize = sizeof(RECONVERTSTRING)}; struct test_cross_thread_himc_params params; COMPOSITIONFORM composition = {0}; DWORD tid, conversion, sentence; + IMECHARPOSITION char_pos = {0}; CANDIDATEFORM candidate = {0}; COMPOSITIONSTRING *string; HIMC himc[2], tmp_himc; @@ -1434,6 +1438,9 @@ static void test_cross_thread_himc(void) ok_ne( NULL, thread, HANDLE, "%p" ); WaitForSingleObject( params.event, INFINITE );
+ memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + tmp_himc = ImmGetContext( params.hwnd ); ok_ne( himc[0], tmp_himc, HIMC, "%p" ); ok_eq( params.himc[0], tmp_himc, HIMC, "%p" ); @@ -1565,6 +1572,18 @@ static void test_cross_thread_himc(void) ok_ret( 1, ImmGetCompositionFontW( params.himc[0], &fontW ) ); ok_ret( 1, ImmGetCompositionFontW( params.himc[1], &fontW ) );
+ /* ImmRequestMessage(W|A) should fail with cross thread HIMC */ + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) ); + + todo_wine ok_seq( empty_sequence ); + /* ImmSetCompositionString(W|A) should fail with cross thread HIMC */
ok_ret( 10, ImmGetCompositionStringA( himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); @@ -1581,6 +1600,46 @@ static void test_cross_thread_himc(void) ok_ret( 20, ImmGetCompositionStringW( params.himc[0], GCS_COMPSTR, buffer, sizeof(buffer) ) ); ok_ret( 0, ImmGetCompositionStringW( params.himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) );
+ /* ImmRequestMessage(W|A) should fail with cross thread HIMC */ + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + + todo_wine ok_seq( empty_sequence ); + /* ImmSetCompositionWindow should fail with cross thread HIMC */
ok_ret( 1, ImmSetCompositionWindow( himc[1], &composition ) ); @@ -1591,6 +1650,18 @@ static void test_cross_thread_himc(void) ok_ret( 1, ImmGetCompositionWindow( params.himc[0], &composition ) ); ok_ret( 1, ImmGetCompositionWindow( params.himc[1], &composition ) );
+ /* ImmRequestMessage(W|A) should fail with cross thread HIMC */ + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + + todo_wine ok_seq( empty_sequence ); + /* ImmSetCandidateWindow should fail with cross thread HIMC */
ok_ret( 1, ImmSetCandidateWindow( himc[1], &candidate ) ); @@ -1601,6 +1672,23 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmSetCandidateWindow( params.himc[0], &candidate ) ); ok_ret( 0, ImmSetCandidateWindow( params.himc[1], &candidate ) );
+ /* ImmRequestMessage(W|A) should fail with cross thread HIMC */ + + candidate.dwIndex = -1; + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + + candidate.dwIndex = 0; + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + + todo_wine ok_seq( empty_sequence ); + /* ImmSetStatusWindowPos should fail with cross thread HIMC */
ok_ret( 1, ImmSetStatusWindowPos( himc[1], &pos ) ); @@ -1611,6 +1699,18 @@ static void test_cross_thread_himc(void) ok_ret( 1, ImmGetStatusWindowPos( params.himc[0], &pos ) ); ok_ret( 1, ImmGetStatusWindowPos( params.himc[1], &pos ) );
+ /* ImmRequestMessage(W|A) should fail with cross thread HIMC */ + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + + todo_wine ok_seq( empty_sequence ); + /* ImmGenerateMessage should fail with cross thread HIMC */
ok_ret( 1, ImmGenerateMessage( himc[1] ) );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 60 ++++++++++++++++++++++++++++++++-------- dlls/imm32/tests/imm32.c | 10 +++---- 2 files changed, 53 insertions(+), 17 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index dfe81ddaaf7..08af055275e 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2380,31 +2380,67 @@ BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC) /*********************************************************************** * ImmRequestMessageA(IMM32.@) */ -LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam) +LRESULT WINAPI ImmRequestMessageA( HIMC himc, WPARAM wparam, LPARAM lparam ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; + LRESULT res;
- TRACE("%p %Id %Id\n", hIMC, wParam, wParam); + TRACE( "himc %p, wparam %#Ix, lparam %#Ix\n", himc, wparam, lparam );
- if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
- SetLastError(ERROR_INVALID_HANDLE); - return 0; + switch (wparam) + { + case IMR_CANDIDATEWINDOW: + case IMR_COMPOSITIONFONT: + case IMR_COMPOSITIONWINDOW: + case IMR_CONFIRMRECONVERTSTRING: + case IMR_DOCUMENTFEED: + case IMR_QUERYCHARPOSITION: + case IMR_RECONVERTSTRING: + break; + default: + return FALSE; + } + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + res = SendMessageA( ctx->hWnd, WM_IME_REQUEST, wparam, lparam ); + ImmUnlockIMC( himc ); + + return res; }
/*********************************************************************** * ImmRequestMessageW(IMM32.@) */ -LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) +LRESULT WINAPI ImmRequestMessageW( HIMC himc, WPARAM wparam, LPARAM lparam ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; + LRESULT res;
- TRACE("%p %Id %Id\n", hIMC, wParam, wParam); + TRACE( "himc %p, wparam %#Ix, lparam %#Ix\n", himc, wparam, lparam );
- if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
- SetLastError(ERROR_INVALID_HANDLE); - return 0; + switch (wparam) + { + case IMR_CANDIDATEWINDOW: + case IMR_COMPOSITIONFONT: + case IMR_COMPOSITIONWINDOW: + case IMR_CONFIRMRECONVERTSTRING: + case IMR_DOCUMENTFEED: + case IMR_QUERYCHARPOSITION: + case IMR_RECONVERTSTRING: + break; + default: + return FALSE; + } + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + res = SendMessageW( ctx->hWnd, WM_IME_REQUEST, wparam, lparam ); + ImmUnlockIMC( himc ); + + return res; }
/*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 9290c9c5d0b..5593f2d391c 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -1582,7 +1582,7 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) ); ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) );
- todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence );
/* ImmSetCompositionString(W|A) should fail with cross thread HIMC */
@@ -1638,7 +1638,7 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) );
- todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence );
/* ImmSetCompositionWindow should fail with cross thread HIMC */
@@ -1660,7 +1660,7 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) );
- todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence );
/* ImmSetCandidateWindow should fail with cross thread HIMC */
@@ -1687,7 +1687,7 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) );
- todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence );
/* ImmSetStatusWindowPos should fail with cross thread HIMC */
@@ -1709,7 +1709,7 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) );
- todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence );
/* ImmGenerateMessage should fail with cross thread HIMC */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 49 +++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 5593f2d391c..7841fc179f6 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3246,7 +3246,7 @@ static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE ime_trace( "himc %p, vkey %u, lparam %#Ix, state %p\n", himc, vkey, lparam, state ); ime_calls[ime_call_count++] = call; - return TRUE; + return LOWORD(lparam); }
static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) @@ -4740,23 +4740,40 @@ cleanup:
static void test_ImmProcessKey(void) { - const struct ime_call process_key_seq[] = + const struct ime_call process_key_0[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = MAKELONG(0, 0x1e)}, + }, + {0}, + }; + const struct ime_call process_key_1[] = { { .hkl = expect_ime, .himc = default_himc, - .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = 0}, + .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = MAKELONG(1, 0x1e)}, + }, + {0}, + }; + const struct ime_call process_key_2[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = MAKELONG(2, 0x1e)}, }, {0}, }; HKL hkl; UINT_PTR ret; + HIMC himc;
hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); process_messages();
- ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', 0, 0 ) ); + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', MAKELONG(1, 0x1e), 0 ) ); ok_seq( empty_sequence );
ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -4769,19 +4786,35 @@ static void test_ImmProcessKey(void) memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0;
- ok_ret( 0, ImmProcessKey( 0, hkl, 'A', 0, 0 ) ); + ok_ret( 0, ImmProcessKey( 0, hkl, 'A', MAKELONG(1, 0x1e), 0 ) ); ok_seq( empty_sequence );
- ret = ImmProcessKey( hwnd, hkl, 'A', 0, 0 ); + ok_ret( 0, ImmProcessKey( hwnd, hkl, 'A', MAKELONG(0, 0x1e), 0 ) ); + ok_seq( process_key_0 ); + ret = ImmProcessKey( hwnd, hkl, 'A', MAKELONG(1, 0x1e), 0 ); todo_wine ok_ret( 2, ret ); - ok_seq( process_key_seq ); + ok_seq( process_key_1 ); + ok_ret( 2, ImmProcessKey( hwnd, hkl, 'A', MAKELONG(2, 0x1e), 0 ) ); + ok_seq( process_key_2 );
ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', 0, 0 ) ); + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', MAKELONG(1, 0x1e), 0 ) ); ok_seq( empty_sequence ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
+ himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ok_ret( 'A', ImmGetVirtualKey( hwnd ) ); + ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" ); + todo_wine ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + ok_eq( himc, ImmAssociateContext( hwnd, default_himc ), HIMC, "%p" ); + ok_ret( 'A', ImmGetVirtualKey( hwnd ) ); + ImmDestroyContext( himc ); + + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'A', 0 ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) );
ok_ret( 1, ImmFreeLayout( hkl ) );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 334 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 316 insertions(+), 18 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 7841fc179f6..622f209e36f 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -252,11 +252,12 @@ static void check_logfont_a_( int line, LOGFONTA *font, const LOGFONTA *expect ) DEFINE_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE); DEFINE_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
-static void process_messages(void) +#define process_messages() process_messages_(0) +static void process_messages_(HWND hwnd) { MSG msg;
- while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + while (PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE )) { TranslateMessage( &msg ); DispatchMessageA( &msg ); @@ -294,6 +295,7 @@ enum ime_function IME_SELECT = 1, IME_NOTIFY, IME_PROCESS_KEY, + IME_TO_ASCII_EX, IME_SET_ACTIVE_CONTEXT, MSG_IME_UI, MSG_TEST_WIN, @@ -320,6 +322,12 @@ struct ime_call LPARAM lparam; } process_key; struct + { + UINT vkey; + UINT vsc; + UINT flags; + } to_ascii_ex; + struct { int flag; } set_active_context; @@ -334,6 +342,7 @@ struct ime_call BOOL todo; BOOL broken; BOOL flaky_himc; + BOOL todo_value; };
struct ime_call empty_sequence[] = {{0}}; @@ -364,6 +373,11 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected if ((ret = expected->process_key.vkey - received->process_key.vkey)) goto done; if ((ret = expected->process_key.lparam - received->process_key.lparam)) goto done; break; + case IME_TO_ASCII_EX: + if ((ret = expected->to_ascii_ex.vkey - received->to_ascii_ex.vkey)) goto done; + if ((ret = expected->to_ascii_ex.vsc - received->to_ascii_ex.vsc)) goto done; + if ((ret = expected->to_ascii_ex.flags - received->to_ascii_ex.flags)) goto done; + break; case IME_SET_ACTIVE_CONTEXT: if ((ret = expected->set_active_context.flag - received->set_active_context.flag)) goto done; break; @@ -381,32 +395,38 @@ done: switch (received->func) { case IME_SELECT: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SELECT select %u\n", received->hkl, received->himc, received->select ); return ret; case IME_NOTIFY: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", received->hkl, received->himc, received->notify.action, received->notify.index, received->notify.value ); return ret; case IME_PROCESS_KEY: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n", received->hkl, received->himc, received->process_key.vkey, received->process_key.lparam ); return ret; + case IME_TO_ASCII_EX: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_TO_ASCII_EX vkey %#x, vsc %#x, flags %#x\n", + received->hkl, received->himc, received->to_ascii_ex.vkey, received->to_ascii_ex.vsc, + received->to_ascii_ex.flags ); + return ret; case IME_SET_ACTIVE_CONTEXT: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", received->hkl, received->himc, received->set_active_context.flag ); return ret; case MSG_IME_UI: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, received->himc, received->message.msg, received->message.wparam, received->message.lparam ); return ret; case MSG_TEST_WIN: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, received->himc, received->message.msg, received->message.wparam, received->message.lparam ); return ret; @@ -415,32 +435,38 @@ done: switch (expected->func) { case IME_SELECT: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, IME_SELECT select %u\n", expected->hkl, expected->himc, expected->select ); break; case IME_NOTIFY: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", expected->hkl, expected->himc, expected->notify.action, expected->notify.index, expected->notify.value ); break; case IME_PROCESS_KEY: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n", expected->hkl, expected->himc, expected->process_key.vkey, expected->process_key.lparam ); break; + case IME_TO_ASCII_EX: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_TO_ASCII_EX vkey %#x, vsc %#x, flags %#x\n", + expected->hkl, expected->himc, expected->to_ascii_ex.vkey, expected->to_ascii_ex.vsc, + expected->to_ascii_ex.flags ); + break; case IME_SET_ACTIVE_CONTEXT: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", expected->hkl, expected->himc, expected->set_active_context.flag ); break; case MSG_IME_UI: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); break; case MSG_TEST_WIN: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); break; @@ -3394,11 +3420,70 @@ static BOOL WINAPI ime_ImeSetCompositionString( HIMC himc, DWORD index, const vo return TRUE; }
-static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, TRANSMSGLIST *msgs, UINT state, HIMC himc ) +static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, UINT flags, HIMC himc ) { - ime_trace( "vkey %u, scan_code %u, key_state %p, msgs %p, state %u, himc %p\n", - vkey, scan_code, key_state, msgs, state, himc ); - return 0; + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = himc, + .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = vkey, .vsc = vsc, .flags = flags} + }; + INPUTCONTEXT *ctx; + UINT count = 0; + + ime_trace( "vkey %#x, vsc %#x, state %p, msgs %p, flags %#x, himc %p\n", + vkey, vsc, state, msgs, flags, himc ); + ime_calls[ime_call_count++] = call; + + ok_ne( NULL, msgs, TRANSMSGLIST *, "%p" ); + todo_wine ok_eq( 256, msgs->uMsgCount, UINT, "%u" ); + + ctx = ImmLockIMC( himc ); + todo_wine ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( ctx->hWnd ) ); + + if (vsc & 0x200) + { + msgs->TransMsg[0].message = WM_IME_STARTCOMPOSITION; + msgs->TransMsg[0].wParam = 1; + msgs->TransMsg[0].lParam = 0; + count++; + msgs->TransMsg[1].message = WM_IME_ENDCOMPOSITION; + msgs->TransMsg[1].wParam = 1; + msgs->TransMsg[1].lParam = 0; + count++; + } + + if (vsc & 0x400) + { + TRANSMSG *msgs; + + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + + ok_ne( NULL, ctx->hMsgBuf, HIMCC, "%p" ); + ok_eq( 0, ctx->dwNumMsgBuf, UINT, "%u" ); + + ctx->hMsgBuf = ImmReSizeIMCC( ctx->hMsgBuf, 64 * sizeof(*msgs) ); + ok_ne( NULL, ctx->hMsgBuf, HIMCC, "%p" ); + + msgs = ImmLockIMCC( ctx->hMsgBuf ); + ok_ne( NULL, msgs, TRANSMSG *, "%p" ); + + msgs[ctx->dwNumMsgBuf].message = WM_IME_STARTCOMPOSITION; + msgs[ctx->dwNumMsgBuf].wParam = 2; + msgs[ctx->dwNumMsgBuf].lParam = 0; + ctx->dwNumMsgBuf++; + msgs[ctx->dwNumMsgBuf].message = WM_IME_ENDCOMPOSITION; + msgs[ctx->dwNumMsgBuf].wParam = 2; + msgs[ctx->dwNumMsgBuf].lParam = 0; + ctx->dwNumMsgBuf++; + + ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); + } + + ok_ret( 1, ImmUnlockIMC( himc ) ); + + if (vsc & 0x800) count = ~0; + return count; }
static BOOL WINAPI ime_ImeUnregisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) @@ -6845,6 +6930,217 @@ static void test_ImmGenerateMessage(void) ime_call_count = 0; }
+static void test_ImmTranslateMessage( BOOL kbd_char_first ) +{ + const struct ime_call process_key_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0x10)}, + }, + { + .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc010)}, + }, + {.todo = TRUE}, + }; + const struct ime_call to_ascii_ex_0[] = + { + { + .hkl = expect_ime, .himc = default_himc, .func = IME_TO_ASCII_EX, + .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x10}, + }, + {0}, + }; + const struct ime_call to_ascii_ex_1[] = + { + { + .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc010)}, + }, + { + .hkl = expect_ime, .himc = default_himc, .func = IME_TO_ASCII_EX, + /* FIXME what happened to kbd_char_first here!? */ + .to_ascii_ex = {.vkey = 'Q', .vsc = 0xc010}, + .todo_value = TRUE, + }, + {0}, + }; + struct ime_call to_ascii_ex_2[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0x210)}, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, + .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x210}, + .todo_value = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0x410)}, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, + .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x410}, + .todo_value = TRUE, + }, + {0}, + }; + struct ime_call to_ascii_ex_3[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xa10)}, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, + .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0xa10}, + .todo_value = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc10)}, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, + .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0xc10}, + .todo_value = TRUE, + }, + {0}, + }; + struct ime_call post_messages[] = + { + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 1}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 1}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 1}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 1}}, + {0}, + }; + struct ime_call sent_messages[] = + { + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 2}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 2}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 2}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 2}}, + {0}, + }; + HWND hwnd, other_hwnd; + INPUTCONTEXT *ctx; + HIMC himc; + HKL hkl; + UINT i, ret; + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + if (kbd_char_first) ime_info.fdwProperty |= IME_PROP_KBD_CHAR_FIRST; + + winetest_push_context( kbd_char_first ? "kbd_char_first" : "default" ); + + if (!(hkl = wineime_hkl)) goto cleanup; + + other_hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!other_hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x10), 0 ) ); + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc010), 0 ) ); + + ok_ret( 0, ImmTranslateMessage( hwnd, 0, 0, 0 ) ); + todo_wine ok_ret( 'Q', ImmGetVirtualKey( hwnd ) ); + ok_seq( process_key_seq ); + + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'Q', MAKELONG(2, 0x10) ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + todo_wine ok_seq( to_ascii_ex_0 ); + + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc010) ) ); + ok_seq( empty_sequence ); + + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc010), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc010) ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + ok_seq( to_ascii_ex_1 ); + + ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" ); + ok_eq( default_himc, ImmAssociateContext( other_hwnd, himc ), HIMC, "%p" ); + for (i = 0; i < ARRAY_SIZE(to_ascii_ex_2); i++) to_ascii_ex_2[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(to_ascii_ex_3); i++) to_ascii_ex_3[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(post_messages); i++) post_messages[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(sent_messages); i++) sent_messages[i].himc = himc; + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ctx->hWnd = hwnd; + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x210), 0 ) ); + ret = ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ); + todo_wine ok_eq( 1, ret, UINT, "%u" ); + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x410), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x410) ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + ok_seq( to_ascii_ex_2 ); + process_messages(); + todo_wine ok_seq( post_messages ); + ok_ret( 1, ImmGenerateMessage( himc ) ); + todo_wine ok_seq( sent_messages ); + + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xa10), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xa10) ) ); + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc10), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc10) ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + ok_seq( to_ascii_ex_3 ); + process_messages(); + ok_seq( empty_sequence ); + ok_ret( 1, ImmGenerateMessage( himc ) ); + todo_wine ok_seq( sent_messages ); + + ctx->hWnd = 0; + ok_ret( 2, ImmProcessKey( other_hwnd, expect_ime, 'Q', MAKELONG(2, 0x210), 0 ) ); + ret = ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ); + todo_wine ok_eq( 1, ret, UINT, "%u" ); + ok_ret( 2, ImmProcessKey( other_hwnd, expect_ime, 'Q', MAKELONG(2, 0x410), 0 ) ); + ok_ret( 0, ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x410) ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( other_hwnd ) ); + ok_seq( to_ascii_ex_2 ); + process_messages_( hwnd ); + ok_seq( empty_sequence ); + process_messages_( other_hwnd ); + todo_wine ok_seq( post_messages ); + ok_ret( 1, ImmGenerateMessage( himc ) ); + ok_seq( empty_sequence ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( default_hkl ) ); + ok_ret( 1, DestroyWindow( other_hwnd ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ok_ret( 1, ImmFreeLayout( hkl ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + +cleanup: + winetest_pop_context(); +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -6908,6 +7204,8 @@ START_TEST(imm32) test_ImmSetCandidateWindow();
test_ImmGenerateMessage(); + test_ImmTranslateMessage( FALSE ); + test_ImmTranslateMessage( TRUE );
if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 2 +- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 08af055275e..34c2299035f 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3112,7 +3112,7 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar struct { UINT uMsgCount; - TRANSMSG TransMsg[10]; + TRANSMSG TransMsg[256]; }; TRANSMSGLIST list; } buffer = {.uMsgCount = ARRAY_SIZE(buffer.TransMsg)}; diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 622f209e36f..b76ff036020 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3435,7 +3435,7 @@ static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGL ime_calls[ime_call_count++] = call;
ok_ne( NULL, msgs, TRANSMSGLIST *, "%p" ); - todo_wine ok_eq( 256, msgs->uMsgCount, UINT, "%u" ); + ok_eq( 256, msgs->uMsgCount, UINT, "%u" );
ctx = ImmLockIMC( himc ); todo_wine ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( ctx->hWnd ) );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 1 + dlls/imm32/tests/imm32.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 34c2299035f..1d55eb49172 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3124,6 +3124,7 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar
TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam );
+ if (msg < WM_KEYDOWN || msg > WM_KEYUP) return FALSE; if (!(data = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; if (!(ime = imc_select_ime( data ))) return FALSE; if (data->lastVK == VK_PROCESSKEY) return FALSE; diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index b76ff036020..3c69c1632ac 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -7061,12 +7061,12 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc010), 0 ) );
ok_ret( 0, ImmTranslateMessage( hwnd, 0, 0, 0 ) ); - todo_wine ok_ret( 'Q', ImmGetVirtualKey( hwnd ) ); + ok_ret( 'Q', ImmGetVirtualKey( hwnd ) ); ok_seq( process_key_seq );
ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'Q', MAKELONG(2, 0x10) ) ); ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); - todo_wine ok_seq( to_ascii_ex_0 ); + ok_seq( to_ascii_ex_0 );
ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc010) ) ); ok_seq( empty_sequence );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 48 ++++++++++++++-------------------------- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 18 insertions(+), 32 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 1d55eb49172..291972574cd 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -85,8 +85,8 @@ struct imc DWORD dwLock; INPUTCONTEXT IMC;
- struct ime *ime; - UINT lastVK; + struct ime *ime; + UINT vkey;
HWND ui_hwnd; /* IME UI window, on the default input context */ }; @@ -2111,27 +2111,15 @@ BOOL WINAPI ImmGetStatusWindowPos( HIMC himc, POINT *pos ) /*********************************************************************** * ImmGetVirtualKey (IMM32.@) */ -UINT WINAPI ImmGetVirtualKey(HWND hWnd) -{ - OSVERSIONINFOA version; - struct imc *data = get_imc_data( ImmGetContext( hWnd ) ); - TRACE("%p\n", hWnd); - - if ( data ) - return data->lastVK; - - version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - GetVersionExA( &version ); - switch(version.dwPlatformId) - { - case VER_PLATFORM_WIN32_WINDOWS: - return VK_PROCESSKEY; - case VER_PLATFORM_WIN32_NT: - return 0; - default: - FIXME("%ld not supported\n",version.dwPlatformId); - return VK_PROCESSKEY; - } +UINT WINAPI ImmGetVirtualKey( HWND hwnd ) +{ + HIMC himc = ImmGetContext( hwnd ); + struct imc *imc; + + TRACE( "%p\n", hwnd ); + + if ((imc = get_imc_data( himc ))) return imc->vkey; + return VK_PROCESSKEY; }
/*********************************************************************** @@ -3127,17 +3115,17 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar if (msg < WM_KEYDOWN || msg > WM_KEYUP) return FALSE; if (!(data = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; if (!(ime = imc_select_ime( data ))) return FALSE; - if (data->lastVK == VK_PROCESSKEY) return FALSE;
+ if ((vkey = data->vkey) == VK_PROCESSKEY) return FALSE; + data->vkey = VK_PROCESSKEY; GetKeyboardState( state ); scan = lparam >> 0x10 & 0xff; - vkey = data->lastVK;
if (ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { - if (!ime_is_unicode( ime )) ToAscii( data->lastVK, scan, state, &chr, 0 ); - else ToUnicodeEx( data->lastVK, scan, state, &chr, 1, 0, GetKeyboardLayout( 0 ) ); - vkey = MAKELONG( data->lastVK, chr ); + if (!ime_is_unicode( ime )) ToAscii( vkey, scan, state, &chr, 0 ); + else ToUnicodeEx( vkey, scan, state, &chr, 1, 0, GetKeyboardLayout( 0 ) ); + vkey = MAKELONG( vkey, chr ); }
count = ime->pImeToAsciiEx( vkey, scan, state, &buffer.list, 0, data->handle ); @@ -3146,8 +3134,6 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar if (count > ARRAY_SIZE(buffer.TransMsg)) ImmGenerateMessage( data->handle ); else for (i = 0; i < count; i++) imc_post_message( data, buffer.TransMsg + i );
- data->lastVK = VK_PROCESSKEY; - return count > 0; }
@@ -3171,7 +3157,7 @@ BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM lparam, DWORD u GetKeyboardState( state );
ret = ime->pImeProcessKey( imc->handle, vkey, lparam, state ); - imc->lastVK = ret ? vkey : VK_PROCESSKEY; + imc->vkey = ret ? vkey : VK_PROCESSKEY;
return ret; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 3c69c1632ac..93de33472e3 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3438,7 +3438,7 @@ static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGL ok_eq( 256, msgs->uMsgCount, UINT, "%u" );
ctx = ImmLockIMC( himc ); - todo_wine ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( ctx->hWnd ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( ctx->hWnd ) );
if (vsc & 0x200) {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 16 +++++----------- dlls/imm32/tests/imm32.c | 22 ++++++++-------------- 2 files changed, 13 insertions(+), 25 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 291972574cd..cba560d98a5 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -821,13 +821,6 @@ BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) return TRUE; }
-static void imc_post_message( struct imc *imc, TRANSMSG *message ) -{ - HWND target; - if (!(target = GetFocus()) && !(target = imc->IMC.hWnd)) return; - PostMessageW( target, message->message, message->wParam, message->lParam ); -} - /*********************************************************************** * ImmSetActiveContext (IMM32.@) */ @@ -3104,6 +3097,7 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar }; TRANSMSGLIST list; } buffer = {.uMsgCount = ARRAY_SIZE(buffer.TransMsg)}; + TRANSMSG *msgs = buffer.TransMsg; UINT scan, vkey, count, i; struct imc *data; struct ime *ime; @@ -3119,7 +3113,7 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar if ((vkey = data->vkey) == VK_PROCESSKEY) return FALSE; data->vkey = VK_PROCESSKEY; GetKeyboardState( state ); - scan = lparam >> 0x10 & 0xff; + scan = lparam >> 0x10;
if (ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { @@ -3129,10 +3123,10 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar }
count = ime->pImeToAsciiEx( vkey, scan, state, &buffer.list, 0, data->handle ); - TRACE( "%u messages generated\n", count ); + if (count >= ARRAY_SIZE(buffer.TransMsg)) return 0;
- if (count > ARRAY_SIZE(buffer.TransMsg)) ImmGenerateMessage( data->handle ); - else for (i = 0; i < count; i++) imc_post_message( data, buffer.TransMsg + i ); + for (i = 0; i < count; i++) PostMessageW( hwnd, msgs[i].message, msgs[i].wParam, msgs[i].lParam ); + TRACE( "%u messages generated\n", count );
return count > 0; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 93de33472e3..f98c55b5468 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6942,7 +6942,7 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY, .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc010)}, }, - {.todo = TRUE}, + {0}, }; const struct ime_call to_ascii_ex_0[] = { @@ -6975,7 +6975,6 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x210}, - .todo_value = TRUE, }, { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, @@ -6984,7 +6983,6 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x410}, - .todo_value = TRUE, }, {0}, }; @@ -6997,7 +6995,6 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0xa10}, - .todo_value = TRUE, }, { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, @@ -7006,7 +7003,6 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0xc10}, - .todo_value = TRUE, }, {0}, }; @@ -7030,7 +7026,7 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) INPUTCONTEXT *ctx; HIMC himc; HKL hkl; - UINT i, ret; + UINT i;
ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; if (kbd_char_first) ime_info.fdwProperty |= IME_PROP_KBD_CHAR_FIRST; @@ -7088,16 +7084,15 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first )
ctx->hWnd = hwnd; ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x210), 0 ) ); - ret = ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ); - todo_wine ok_eq( 1, ret, UINT, "%u" ); + ok_ret( 1, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ) ); ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x410), 0 ) ); ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x410) ) ); ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); ok_seq( to_ascii_ex_2 ); process_messages(); - todo_wine ok_seq( post_messages ); + ok_seq( post_messages ); ok_ret( 1, ImmGenerateMessage( himc ) ); - todo_wine ok_seq( sent_messages ); + ok_seq( sent_messages );
ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xa10), 0 ) ); ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xa10) ) ); @@ -7108,12 +7103,11 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) process_messages(); ok_seq( empty_sequence ); ok_ret( 1, ImmGenerateMessage( himc ) ); - todo_wine ok_seq( sent_messages ); + ok_seq( sent_messages );
ctx->hWnd = 0; ok_ret( 2, ImmProcessKey( other_hwnd, expect_ime, 'Q', MAKELONG(2, 0x210), 0 ) ); - ret = ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ); - todo_wine ok_eq( 1, ret, UINT, "%u" ); + ok_ret( 1, ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ) ); ok_ret( 2, ImmProcessKey( other_hwnd, expect_ime, 'Q', MAKELONG(2, 0x410), 0 ) ); ok_ret( 0, ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x410) ) ); ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( other_hwnd ) ); @@ -7121,7 +7115,7 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) process_messages_( hwnd ); ok_seq( empty_sequence ); process_messages_( other_hwnd ); - todo_wine ok_seq( post_messages ); + ok_seq( post_messages ); ok_ret( 1, ImmGenerateMessage( himc ) ); ok_seq( empty_sequence );
v2: Process messages after changing input context to avoid spurious messages later.
Jinoh Kang (@iamahuman) commented about dlls/imm32/imm.c:
struct { UINT uMsgCount;
TRANSMSG TransMsg[10];
TRANSMSG TransMsg[256];
Maybe we're consuming the stack a bit too much?
(Yes, I'm aware some GDI/win32u functions does the same with bitmap color palettes...)
On Tue May 2 14:57:02 2023 +0000, Jinoh Kang wrote:
Maybe we're consuming the stack a bit too much? (Yes, I'm aware some GDI/win32u functions does the same with bitmap color palettes...)
Well, this is what native does. I don't mind keeping it smaller but we'd then have to bikeshed about a good value.