-- v3: imm32: Create the IME UI as child of the IME default window. imm32: Re-create the IME UI window when IME changes. imm32: Keep the IME UI window on the default input context. imm32: Update existing input contexts on layout change. imm32/tests: Test IME UI window and IME window presence. imm32/tests: Test IME UI creation with the installed IME. imm32/tests: Test ImmProcessKey with the installed IME. imm32: Ignore ImmProcessKey if hkl isn't the current layout. imm32: Cleanup ImmProcessKey variables and traces. imm32/tests: Ignore expected calls marked with todo. imm32/tests: Add explicit ImmLoadIME / ImmFreeLayout calls.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 45 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 23 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index e8116081f52..e5949b89dec 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2981,7 +2981,7 @@ static HKL ime_install(void) return hkl; }
-static void ime_cleanup( HKL hkl ) +static void ime_cleanup( HKL hkl, BOOL free ) { HMODULE module = GetModuleHandleW( L"winetest_ime.dll" ); WCHAR buffer[MAX_PATH], value[MAX_PATH]; @@ -2992,6 +2992,8 @@ static void ime_cleanup( HKL hkl ) todo_wine ok( ret, "UnloadKeyboardLayout failed, error %lu\n", GetLastError() );
+ if (free) ok_ret( 1, ImmFreeLayout( hkl ) ); + swprintf( buffer, ARRAY_SIZE(buffer), L"System\CurrentControlSet\Control\Keyboard Layouts\%08x", hkl ); ret = RegDeleteKeyW( HKEY_LOCAL_MACHINE, buffer ); ok( !ret, "RegDeleteKeyW returned %#lx, error %lu\n", ret, GetLastError() ); @@ -3094,7 +3096,7 @@ static void test_ImmInstallIME(void) ret = ImmFreeLayout( hkl ); ok( ret, "ImmFreeLayout returned %#x\n", ret );
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
ime_info.fdwProperty = 0;
@@ -3120,7 +3122,7 @@ static void test_ImmInstallIME(void) ret = ImmFreeLayout( hkl ); ok( ret, "ImmFreeLayout returned %#x\n", ret );
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); @@ -3159,7 +3161,7 @@ static void test_ImmIsIME(void) todo_ImeInquire = FALSE; todo_ImeDestroy = FALSE;
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); @@ -3254,7 +3256,7 @@ static void test_ImmGetProperty(void) todo_ImeDestroy = FALSE; called_ImeDestroy = FALSE;
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
cleanup: SET_ENABLE( ImeInquire, FALSE ); @@ -3327,7 +3329,7 @@ static void test_ImmGetDescription(void) ok( ret == 12, "ImmGetDescriptionA returned %lu\n", ret ); ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) );
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); @@ -3406,7 +3408,7 @@ static void test_ImmGetIMEFileName(void) ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret ); ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) );
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); @@ -3514,7 +3516,7 @@ static void test_ImmEscape( BOOL unicode ) winetest_pop_context(); }
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
cleanup: SET_ENABLE( ImeEscape, FALSE ); @@ -3582,7 +3584,7 @@ static void test_ImmEnumRegisterWord( BOOL unicode ) ok_ret( 0xdeadbeef, ImmEnumRegisterWordA( hkl, enum_register_wordA, "Reading", 0xdeadbeef, "String", NULL ) ); CHECK_CALLED( ImeEnumRegisterWord );
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
cleanup: SET_ENABLE( ImeEnumRegisterWord, FALSE ); @@ -3644,7 +3646,7 @@ static void test_ImmRegisterWord( BOOL unicode ) ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0, "String" ) ); CHECK_CALLED( ImeRegisterWord );
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
cleanup: SET_ENABLE( ImeRegisterWord, FALSE ); @@ -3721,7 +3723,7 @@ skip_null: } CHECK_CALLED( ImeGetRegisterWordStyle );
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
cleanup: SET_ENABLE( ImeGetRegisterWordStyle, FALSE ); @@ -3783,7 +3785,7 @@ static void test_ImmUnregisterWord( BOOL unicode ) ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0, "String" ) ); CHECK_CALLED( ImeUnregisterWord );
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE );
cleanup: SET_ENABLE( ImeUnregisterWord, FALSE ); @@ -3852,6 +3854,7 @@ static void test_ImmActivateLayout(void) ok_ret( 1, ImmActivateLayout( hkl ) ); ok_seq( activate_seq ); CHECK_CALLED( ImeInquire ); + ok_ret( 1, ImmLoadIME( hkl ) );
ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
@@ -3865,7 +3868,7 @@ static void test_ImmActivateLayout(void)
ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
- ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); ok_seq( empty_sequence );
@@ -3892,6 +3895,9 @@ static void test_ImmActivateLayout(void) todo_wine CHECK_CALLED( ImeInquire ); ok_seq( activate_with_window_seq ); + todo_ImeInquire = TRUE; + ok_ret( 1, ImmLoadIME( hkl ) ); + todo_ImeInquire = FALSE;
ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
@@ -3900,15 +3906,8 @@ static void test_ImmActivateLayout(void)
ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
- ime_cleanup( hkl ); - ok_seq( empty_sequence ); - - /* ImmActivateLayout leaks the IME, we need to free it manually */ - SET_EXPECT( ImeDestroy ); - ret = ImmFreeLayout( hkl ); - ok( ret, "ImmFreeLayout returned %u\n", ret ); - todo_wine + ime_cleanup( hkl, TRUE ); CHECK_CALLED( ImeDestroy ); ok_seq( empty_sequence );
@@ -4015,6 +4014,7 @@ static void test_ImmCreateInputContext(void)
if (!(hkl = ime_install())) goto cleanup;
+ ok_ret( 1, ImmLoadIME( hkl ) );
/* Activating the layout calls ImeSelect 1 on existing HIMC */
@@ -4063,8 +4063,7 @@ static void test_ImmCreateInputContext(void)
ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
- ok_ret( 1, ImmFreeLayout( hkl ) ); - ime_cleanup( hkl ); + ime_cleanup( hkl, TRUE ); ok_seq( empty_sequence );
cleanup:
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 42 +++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index e5949b89dec..a2280297d7c 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2527,7 +2527,7 @@ static struct ime_call ime_calls[1024]; static ULONG ime_call_count;
#define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b ) -static void ok_call_( const char *file, int line, const struct ime_call *expected, const struct ime_call *received ) +static int ok_call_( const char *file, int line, const struct ime_call *expected, const struct ime_call *received ) { int ret;
@@ -2554,13 +2554,13 @@ done: 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; + 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; + return ret; }
switch (expected->func) @@ -2576,21 +2576,28 @@ done: expected->notify.value ); 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; + UINT i = 0, ret;
while (expected->func || received->func) { winetest_push_context( "%u%s%s", i++, !expected->func ? " (spurious)" : "", !received->func ? " (missing)" : "" ); - ok_call_( file, line, expected, received ); - if (expected->func) expected++; - if (received->func) received++; + ret = ok_call_( file, line, expected, received ); + if (ret && expected->todo && !strcmp( winetest_platform, "wine" )) + expected++; + else + { + if (expected->func) expected++; + if (received->func) received++; + } winetest_pop_context(); }
@@ -3813,7 +3820,6 @@ static void test_ImmActivateLayout(void) { .hkl = default_hkl, .himc = default_himc, .func = IME_SELECT, .select = 0, - .todo = TRUE, }, {0}, }; @@ -3826,6 +3832,20 @@ static void test_ImmActivateLayout(void) }, {0}, }; + const struct ime_call deactivate_with_window_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, + .todo = TRUE, + }, + { + .hkl = default_hkl, .himc = default_himc, + .func = IME_SELECT, .select = 0, + .todo = TRUE, + }, + {0}, + }; HKL hkl, old_hkl = GetKeyboardLayout( 0 ); UINT ret;
@@ -3902,7 +3922,7 @@ static void test_ImmActivateLayout(void) ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); - ok_seq( deactivate_seq ); + ok_seq( deactivate_with_window_seq );
ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
@@ -3967,12 +3987,12 @@ static void test_ImmCreateInputContext(void) { .hkl = default_hkl, .himc = default_himc, .func = IME_SELECT, .select = 0, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, { .hkl = default_hkl, .himc = 0/*himc[0]*/, .func = IME_SELECT, .select = 0, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, {0}, };
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 2c3af063ac5..e3c7b3d579b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3025,27 +3025,24 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD * ImmProcessKey(IMM32.@) * ( Undocumented, called from user32.dll ) */ -BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown) +BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM lparam, DWORD unknown ) { - struct imc *data; - HIMC imc = ImmGetContext(hwnd); + struct imc *imc; BYTE state[256]; + BOOL ret;
- TRACE("%p %p %x %x %lx\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown); + TRACE( "hwnd %p, hkl %p, vkey %#x, lparam %#Ix, unknown %#lx\n", hwnd, hkl, vkey, lparam, unknown );
- if (!(data = get_imc_data( imc ))) return FALSE; - imc_select_hkl( data, hKL ); - if (!data->ime) return FALSE; + if (!(imc = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; + imc_select_hkl( imc, hkl ); + if (!imc->ime) return FALSE;
- GetKeyboardState(state); - if (data->ime->pImeProcessKey( imc, vKey, lKeyData, state )) - { - data->lastVK = vKey; - return TRUE; - } + GetKeyboardState( state );
- data->lastVK = VK_PROCESSKEY; - return FALSE; + ret = imc->ime->pImeProcessKey( imc->handle, vkey, lparam, state ); + imc->lastVK = ret ? vkey : VK_PROCESSKEY; + + return ret; }
/***********************************************************************
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e3c7b3d579b..447fbded41d 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3033,6 +3033,7 @@ BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM lparam, DWORD u
TRACE( "hwnd %p, hkl %p, vkey %#x, lparam %#Ix, unknown %#lx\n", hwnd, hkl, vkey, lparam, unknown );
+ if (hkl != GetKeyboardLayout( 0 )) return FALSE; if (!(imc = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; imc_select_hkl( imc, hkl ); if (!imc->ime) return FALSE;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 84 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index a2280297d7c..ddfe6121140 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2499,6 +2499,7 @@ enum ime_function { IME_SELECT = 1, IME_NOTIFY, + IME_PROCESS_KEY, };
struct ime_call @@ -2516,6 +2517,11 @@ struct ime_call int index; int value; } notify; + struct + { + WORD vkey; + LPARAM key_data; + } process_key; };
BOOL todo; @@ -2546,6 +2552,10 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected 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; }
done: @@ -2561,6 +2571,11 @@ done: 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; }
switch (expected->func) @@ -2575,6 +2590,11 @@ done: 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; }
return 0; @@ -2772,11 +2792,15 @@ static BOOL WINAPI ime_ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags )
static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYTE *key_state ) { + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = himc, + .func = IME_PROCESS_KEY, .process_key = {.vkey = vkey, .key_data = key_data} + }; ime_trace( "himc %p, vkey %u, key_data %#Ix, key_state %p\n", himc, vkey, key_data, key_state ); - ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ok( 0, "unexpected call\n" ); - return FALSE; + ime_calls[ime_call_count++] = call; + return TRUE; }
static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) @@ -3800,6 +3824,59 @@ cleanup: winetest_pop_context(); }
+static void test_ImmProcessKey(void) +{ + const struct ime_call process_key_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .key_data = 0}, + }, + {0}, + }; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + UINT_PTR ret; + + 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() ); + + ok_ret( 0, ImmProcessKey( hwnd, old_hkl, 'A', 0, 0 ) ); + ok_seq( empty_sequence ); + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 0, ImmProcessKey( 0, hkl, 'A', 0, 0 ) ); + ok_seq( empty_sequence ); + + ret = ImmProcessKey( hwnd, hkl, 'A', 0, 0 ); + todo_wine + ok_ret( 2, ret ); + ok_seq( process_key_seq ); + + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_ret( 0, ImmProcessKey( hwnd, old_hkl, 'A', 0, 0 ) ); + todo_wine + ok_seq( empty_sequence ); + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + + ime_cleanup( hkl, TRUE ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + +cleanup: + ok_ret( 1, DestroyWindow( hwnd ) ); +} + static void test_ImmActivateLayout(void) { const struct ime_call activate_seq[] = @@ -4126,6 +4203,7 @@ START_TEST(imm32)
test_ImmActivateLayout(); test_ImmCreateInputContext(); + test_ImmProcessKey();
if (init()) {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 176 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 171 insertions(+), 5 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index ddfe6121140..855ab7e32c3 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -118,6 +118,17 @@ extern BOOL WINAPI ImmActivateLayout(HKL); DEFINE_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE); DEFINE_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
+static void process_messages(void) +{ + MSG msg; + + while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + } +} + /* * msgspy - record and analyse message traces sent to a certain window */ @@ -2500,6 +2511,7 @@ enum ime_function IME_SELECT = 1, IME_NOTIFY, IME_PROCESS_KEY, + MSG_IME_UI, };
struct ime_call @@ -2522,9 +2534,16 @@ struct ime_call WORD vkey; LPARAM key_data; } process_key; + struct + { + UINT msg; + WPARAM wparam; + LPARAM lparam; + } message; };
BOOL todo; + BOOL broken; BOOL flaky_himc; };
@@ -2556,9 +2575,16 @@ 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.key_data - received->process_key.key_data)) goto done; break; + case MSG_IME_UI: + 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: @@ -2576,6 +2602,11 @@ done: 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 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; }
switch (expected->func) @@ -2595,6 +2626,11 @@ done: 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 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; }
return 0; @@ -2613,6 +2649,8 @@ static void ok_seq_( const char *file, int line, const struct ime_call *expected ret = ok_call_( file, line, expected, received ); if (ret && expected->todo && !strcmp( winetest_platform, "wine" )) expected++; + else if (ret && broken(expected->broken)) + expected++; else { if (expected->func) expected++; @@ -2625,9 +2663,46 @@ static void ok_seq_( const char *file, int line, const struct ime_call *expected ime_call_count = 0; }
+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; + 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 ); }
@@ -2857,7 +2932,6 @@ static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, { 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 ); - ok( 0, "unexpected call\n" ); return 0; }
@@ -3840,6 +3914,7 @@ static void test_ImmProcessKey(void) 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, old_hkl, 'A', 0, 0 ) ); ok_seq( empty_sequence ); @@ -3850,6 +3925,7 @@ static void test_ImmProcessKey(void)
ok_ret( 1, ImmActivateLayout( hkl ) ); ok_ret( 1, ImmLoadIME( hkl ) ); + process_messages(); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0;
@@ -3870,6 +3946,7 @@ static void test_ImmProcessKey(void) ok_ret( 1, ImmActivateLayout( old_hkl ) );
ime_cleanup( hkl, TRUE ); + process_messages(); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0;
@@ -3900,30 +3977,76 @@ static void test_ImmActivateLayout(void) }, {0}, }; - const struct ime_call activate_with_window_seq[] = + struct ime_call activate_with_window_seq[] = { { .hkl = expect_ime, .himc = default_himc, .func = IME_SELECT, .select = 1, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_SELECT, .select = 1, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 1, .lparam = (LPARAM)expect_ime}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_OPENSTATUSWINDOW}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, + .todo = TRUE, .broken = (default_hkl == (HKL)0x04120412), + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE}, .todo = TRUE, }, {0}, }; - const struct ime_call deactivate_with_window_seq[] = + struct ime_call deactivate_with_window_seq[] = { { .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_CLOSESTATUSWINDOW}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 0, .lparam = (LPARAM)expect_ime}, .todo = TRUE, }, { .hkl = default_hkl, .himc = default_himc, .func = IME_SELECT, .select = 0, - .todo = TRUE, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, + .func = IME_SELECT, .select = 0, + .todo = TRUE, .flaky_himc = TRUE, }, {0}, }; HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HIMC himc; UINT ret;
SET_ENABLE( ImeInquire, TRUE ); @@ -3985,12 +4108,18 @@ static void test_ImmActivateLayout(void) 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_seq( empty_sequence ); + + himc = ImmCreateContext(); + ok( !!himc, "got himc %p\n", himc ); ok_seq( empty_sequence );
SET_EXPECT( ImeInquire ); ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); todo_wine CHECK_CALLED( ImeInquire ); + activate_with_window_seq[1].himc = himc; ok_seq( activate_with_window_seq ); todo_ImeInquire = TRUE; ok_ret( 1, ImmLoadIME( hkl ) ); @@ -3998,17 +4127,30 @@ static void test_ImmActivateLayout(void)
ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
+ /* FIXME: ignore spurious VK_CONTROL ImeProcessKey / ImeToAsciiEx calls */ + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + deactivate_with_window_seq[1].himc = himc; + deactivate_with_window_seq[5].himc = himc; ok_seq( deactivate_with_window_seq );
ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
+ ok_ret( 1, ImmDestroyContext( himc ) ); + ok_seq( empty_sequence ); + SET_EXPECT( ImeDestroy ); ime_cleanup( hkl, TRUE ); CHECK_CALLED( ImeDestroy ); ok_seq( empty_sequence );
ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0;
cleanup: @@ -4030,6 +4172,16 @@ static void test_ImmCreateInputContext(void) .func = IME_SELECT, .select = 1, .flaky_himc = TRUE, }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 1, .lparam = (LPARAM)expect_ime}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_OPENSTATUSWINDOW}, + .todo = TRUE, + }, {0}, }; struct ime_call select1_seq[] = @@ -4061,6 +4213,16 @@ static void test_ImmCreateInputContext(void) .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, .todo = TRUE, .flaky_himc = TRUE, }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_CLOSESTATUSWINDOW}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 0, .lparam = (LPARAM)expect_ime}, + .todo = TRUE, + }, { .hkl = default_hkl, .himc = default_himc, .func = IME_SELECT, .select = 0, @@ -4096,6 +4258,7 @@ static void test_ImmCreateInputContext(void) 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();
ctx = ImmLockIMC( default_himc ); ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); @@ -4155,7 +4318,7 @@ static void test_ImmCreateInputContext(void)
ok_ret( 1, ImmActivateLayout( old_hkl ) ); deactivate_seq[1].himc = himc[0]; - deactivate_seq[3].himc = himc[0]; + deactivate_seq[5].himc = himc[0]; ok_seq( deactivate_seq );
ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -4166,6 +4329,9 @@ static void test_ImmCreateInputContext(void) cleanup: ok_ret( 1, ImmDestroyContext( himc[0] ) ); ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0;
ime_info.dwPrivateDataSize = 0; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 46 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 855ab7e32c3..fdce26a7a5c 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3954,6 +3954,37 @@ cleanup: ok_ret( 1, DestroyWindow( hwnd ) ); }
+struct ime_windows +{ + HWND ime_hwnd; + HWND ime_ui_hwnd; +}; + +static BOOL CALLBACK enum_thread_ime_windows( HWND hwnd, LPARAM lparam ) +{ + struct ime_windows *params = (void *)lparam; + WCHAR buffer[256]; + UINT ret; + + ime_trace( "hwnd %p, lparam %#Ix\n", hwnd, lparam ); + + ret = RealGetWindowClassW( hwnd, buffer, ARRAY_SIZE(buffer) ); + ok( ret, "RealGetWindowClassW returned %#x\n", ret ); + + if (!wcscmp( buffer, L"IME" )) + { + ok( !params->ime_hwnd, "Found extra IME window %p\n", hwnd ); + params->ime_hwnd = hwnd; + } + if (!wcscmp( buffer, ime_ui_class.lpszClassName )) + { + ok( !params->ime_ui_hwnd, "Found extra IME UI window %p\n", hwnd ); + params->ime_ui_hwnd = hwnd; + } + + return TRUE; +} + static void test_ImmActivateLayout(void) { const struct ime_call activate_seq[] = @@ -4046,6 +4077,7 @@ static void test_ImmActivateLayout(void) {0}, }; HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + struct ime_windows ime_windows = {0}; HIMC himc; UINT ret;
@@ -4142,10 +4174,22 @@ static void test_ImmActivateLayout(void) ok_ret( 1, ImmDestroyContext( himc ) ); ok_seq( empty_sequence );
+ + ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); + ok( !!ime_windows.ime_hwnd, "missing IME window\n" ); + todo_wine ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); + todo_wine ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) ); + + ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + SET_EXPECT( ImeDestroy ); ime_cleanup( hkl, TRUE ); CHECK_CALLED( ImeDestroy ); - ok_seq( empty_sequence );
ok_ret( 1, DestroyWindow( hwnd ) ); process_messages();
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 5 +++++ dlls/imm32/tests/imm32.c | 15 ++++++++++----- dlls/win32u/input.c | 8 +++++++- include/ntuser.h | 2 ++ 4 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 447fbded41d..62fc855826b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3152,6 +3152,11 @@ static LRESULT ime_internal_msg( WPARAM wparam, LPARAM lparam) ImmSetActiveContext(hwnd, himc, wparam == IME_INTERNAL_ACTIVATE); ImmReleaseContext(hwnd, himc); break; + case IME_INTERNAL_HKL_ACTIVATE: + ImmEnumInputContext( 0, enum_activate_layout, 0 ); + break; + case IME_INTERNAL_HKL_DEACTIVATE: + break; default: FIXME("wparam = %Ix\n", wparam); break; diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index fdce26a7a5c..7da3da1e6c2 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4013,12 +4013,12 @@ static void test_ImmActivateLayout(void) { .hkl = expect_ime, .himc = default_himc, .func = IME_SELECT, .select = 1, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_SELECT, .select = 1, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, { .hkl = expect_ime, .himc = default_himc, @@ -4067,12 +4067,12 @@ static void test_ImmActivateLayout(void) { .hkl = default_hkl, .himc = default_himc, .func = IME_SELECT, .select = 0, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, { .hkl = default_hkl, .himc = 0/*himc*/, .func = IME_SELECT, .select = 0, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, {0}, }; @@ -4149,7 +4149,6 @@ static void test_ImmActivateLayout(void)
SET_EXPECT( ImeInquire ); ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); - todo_wine CHECK_CALLED( ImeInquire ); activate_with_window_seq[1].himc = himc; ok_seq( activate_with_window_seq ); @@ -4164,7 +4163,9 @@ static void test_ImmActivateLayout(void) memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0;
+ todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + todo_ImeDestroy = FALSE; deactivate_with_window_seq[1].himc = himc; deactivate_with_window_seq[5].himc = himc; ok_seq( deactivate_with_window_seq ); @@ -4175,7 +4176,9 @@ static void test_ImmActivateLayout(void) ok_seq( empty_sequence );
+ todo_ImeInquire = TRUE; ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + todo_ImeInquire = FALSE; ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); @@ -4183,7 +4186,9 @@ static void test_ImmActivateLayout(void) todo_wine ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); todo_wine ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) );
+ todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + todo_ImeDestroy = FALSE; ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 34f6727d66e..f806294cb20 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1219,12 +1219,14 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) return 0;
old_layout = info->kbd_layout; - info->kbd_layout = layout; if (old_layout != layout) { + HWND ime_hwnd = get_default_ime_window( 0 ); const NLS_LOCALE_DATA *data; CHARSETINFO cs = {0};
+ if (ime_hwnd) send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_HKL_DEACTIVATE, HandleToUlong(old_layout) ); + if (HIWORD(layout) & 0x8000) FIXME( "Aliased keyboard layout not yet implemented\n" ); else if (!(data = get_locale_data( HIWORD(layout) ))) @@ -1232,7 +1234,11 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) else translate_charset_info( ULongToPtr(data->idefaultansicodepage), &cs, TCI_SRCCODEPAGE );
+ info->kbd_layout = layout; info->kbd_layout_id = 0; + + if (ime_hwnd) send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_HKL_ACTIVATE, HandleToUlong(layout) ); + if ((focus = get_focus()) && get_window_thread( focus, NULL ) == GetCurrentThreadId()) send_message( focus, WM_INPUTLANGCHANGE, cs.ciCharset, (LPARAM)layout ); } diff --git a/include/ntuser.h b/include/ntuser.h index 629f6353fa3..14e1f3757d4 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -487,6 +487,8 @@ enum wine_internal_message #define WM_IME_INTERNAL 0x287 #define IME_INTERNAL_ACTIVATE 0x17 #define IME_INTERNAL_DEACTIVATE 0x18 +#define IME_INTERNAL_HKL_ACTIVATE 0x19 +#define IME_INTERNAL_HKL_DEACTIVATE 0x20
#define WM_SYSTIMER 0x0118
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 61 +++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 26 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 62fc855826b..d68930bade3 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -62,7 +62,6 @@ struct ime
IMEINFO info; WCHAR ui_class[17]; - HWND ui_hwnd;
BOOL (WINAPI *pImeInquire)(IMEINFO *, void *, DWORD); BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *); @@ -93,6 +92,8 @@ struct imc
struct ime *ime; UINT lastVK; + + HWND ui_hwnd; /* IME UI window, on the default input context */ };
#define WINE_IMC_VALID_MAGIC 0x56434D49 @@ -569,6 +570,8 @@ static void imc_select_hkl( struct imc *imc, HKL hkl ) if (imc->ime) { if (imc->ime->hkl == hkl) return; + if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd ); + imc->ui_hwnd = NULL; imc->ime->pImeSelect( imc->handle, FALSE ); ime_release( imc->ime ); ImmDestroyIMCC( imc->IMC.hPrivate ); @@ -614,6 +617,7 @@ static BOOL free_input_context_data( HIMC hIMC )
TRACE( "Destroying %p\n", hIMC );
+ if (data->ui_hwnd) DestroyWindow( data->ui_hwnd ); data->ime->pImeSelect( hIMC, FALSE ); SendMessageW( data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->ime );
@@ -648,7 +652,6 @@ static void IMM_FreeAllImmHkl(void) ime->pImeDestroy( 1 ); FreeLibrary( ime->module );
- if (ime->ui_hwnd) DestroyWindow( ime->ui_hwnd ); free( ime ); } } @@ -923,6 +926,29 @@ static struct imc *get_imc_data( HIMC handle ) return create_input_context(handle); }
+static struct imc *default_input_context(void) +{ + UINT *himc = &NtUserGetThreadInfo()->default_imc; + if (!*himc) *himc = (UINT_PTR)NtUserCreateInputContext( 0 ); + return get_imc_data( (HIMC)(UINT_PTR)*himc ); +} + +static HWND get_ime_ui_window(void) +{ + struct imc *imc = default_input_context(); + + imc_select_hkl( imc, GetKeyboardLayout( 0 ) ); + if (!imc->ime) return 0; + + if (!imc->ui_hwnd) + { + imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, imc->ime->ui_class, NULL, + WS_POPUP, 0, 0, 1, 1, 0, 0, imc->ime->module, 0 ); + SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)imc->handle ); + } + return imc->ui_hwnd; +} + /*********************************************************************** * ImmCreateContext (IMM32.@) */ @@ -2490,6 +2516,7 @@ BOOL WINAPI ImmSetCompositionWindow( { BOOL reshow = FALSE; struct imc *data = get_imc_data( hIMC ); + HWND ui_hwnd;
TRACE("(%p, %p)\n", hIMC, lpCompForm); if (lpCompForm) @@ -2507,15 +2534,15 @@ BOOL WINAPI ImmSetCompositionWindow(
data->IMC.cfCompForm = *lpCompForm;
- if (IsWindowVisible( data->ime->ui_hwnd )) + if ((ui_hwnd = get_ime_ui_window()) && IsWindowVisible( ui_hwnd )) { reshow = TRUE; - ShowWindow( data->ime->ui_hwnd, SW_HIDE ); + ShowWindow( ui_hwnd, SW_HIDE ); }
/* FIXME: this is a partial stub */
- if (reshow) ShowWindow( data->ime->ui_hwnd, SW_SHOWNOACTIVATE ); + if (ui_hwnd && reshow) ShowWindow( ui_hwnd, SW_SHOWNOACTIVATE );
ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0); return TRUE; @@ -2564,6 +2591,7 @@ BOOL WINAPI ImmSetConversionStatus( BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) { struct imc *data = get_imc_data( hIMC ); + HWND ui_hwnd;
TRACE("%p %d\n", hIMC, fOpen);
@@ -2575,14 +2603,7 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
- if (data->ime->ui_hwnd == NULL) - { - /* create the ime window */ - data->ime->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, data->ime->ui_class, NULL, - WS_POPUP, 0, 0, 1, 1, 0, 0, data->ime->module, 0 ); - SetWindowLongPtrW( data->ime->ui_hwnd, IMMGWL_IMC, (LONG_PTR)data ); - } - else if (fOpen) SetWindowLongPtrW( data->ime->ui_hwnd, IMMGWL_IMC, (LONG_PTR)data ); + if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)data );
if (!fOpen != !data->IMC.fOpen) { @@ -3099,18 +3120,6 @@ BOOL WINAPI ImmDisableLegacyIME(void) return TRUE; }
-static HWND get_ui_window(HKL hkl) -{ - struct ime *ime; - HWND hwnd; - - if (!(ime = ime_acquire( hkl ))) return 0; - hwnd = ime->ui_hwnd; - ime_release( ime ); - - return hwnd; -} - static BOOL is_ime_ui_msg(UINT msg) { switch (msg) @@ -3205,7 +3214,7 @@ LRESULT WINAPI __wine_ime_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lp
if (is_ime_ui_msg(msg)) { - if ((ui_hwnd = get_ui_window(NtUserGetKeyboardLayout(0)))) + if ((ui_hwnd = get_ime_ui_window())) { if (ansi) return SendMessageA(ui_hwnd, msg, wparam, lparam);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 5 ++++- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index d68930bade3..ed903cb8d00 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3150,21 +3150,24 @@ static BOOL is_ime_ui_msg(UINT msg)
static LRESULT ime_internal_msg( WPARAM wparam, LPARAM lparam) { - HWND hwnd = (HWND)lparam; + HWND hwnd; HIMC himc;
switch (wparam) { case IME_INTERNAL_ACTIVATE: case IME_INTERNAL_DEACTIVATE: + hwnd = (HWND)lparam; himc = ImmGetContext(hwnd); ImmSetActiveContext(hwnd, himc, wparam == IME_INTERNAL_ACTIVATE); ImmReleaseContext(hwnd, himc); break; case IME_INTERNAL_HKL_ACTIVATE: ImmEnumInputContext( 0, enum_activate_layout, 0 ); + hwnd = get_ime_ui_window(); break; case IME_INTERNAL_HKL_DEACTIVATE: + hwnd = get_ime_ui_window(); break; default: FIXME("wparam = %Ix\n", wparam); diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 7da3da1e6c2..bb9fad29bf0 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4183,7 +4183,7 @@ static void test_ImmActivateLayout(void)
ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); ok( !!ime_windows.ime_hwnd, "missing IME window\n" ); - todo_wine ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); + ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); todo_wine ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) );
todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 4 ++-- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index ed903cb8d00..4cbdceeb9d9 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -942,8 +942,8 @@ static HWND get_ime_ui_window(void)
if (!imc->ui_hwnd) { - imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, imc->ime->ui_class, NULL, - WS_POPUP, 0, 0, 1, 1, 0, 0, imc->ime->module, 0 ); + imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, imc->ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1, + ImmGetDefaultIMEWnd( 0 ), 0, imc->ime->module, 0 ); SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)imc->handle ); } return imc->ui_hwnd; diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index bb9fad29bf0..8352c16f9ec 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4184,7 +4184,7 @@ static void test_ImmActivateLayout(void) ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); ok( !!ime_windows.ime_hwnd, "missing IME window\n" ); ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); - todo_wine ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) ); + ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) );
todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" );
v3: Avoid leaking window when IME installation fails.