From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index a49376d96a9..34f6727d66e 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1207,7 +1207,8 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) return 0; }
- if (NtQueryDefaultLocale( TRUE, &locale ) || LOWORD(layout) != locale) + if (LOWORD(layout) != MAKELANGID(LANG_INVARIANT, SUBLANG_DEFAULT) && + (NtQueryDefaultLocale( TRUE, &locale ) || LOWORD(layout) != locale)) { RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); FIXME_(keyboard)( "Changing user locale is not supported\n" );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/Makefile.in | 2 +- dlls/imm32/imm.c | 26 ++++++++++++++++++++++---- dlls/imm32/tests/imm32.c | 1 - 3 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/dlls/imm32/Makefile.in b/dlls/imm32/Makefile.in index 29de6063792..b4e3039849e 100644 --- a/dlls/imm32/Makefile.in +++ b/dlls/imm32/Makefile.in @@ -1,6 +1,6 @@ MODULE = imm32.dll IMPORTLIB = imm32 -IMPORTS = user32 gdi32 advapi32 win32u +IMPORTS = user32 gdi32 advapi32 kernelbase win32u DELAYIMPORTS = ole32
C_SRCS = \ diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 1b8caf90c1c..e600156f504 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2012,13 +2012,31 @@ HKL WINAPI ImmInstallIMEA( const char *filenameA, const char *descriptionA ) return hkl; }
+static LCID get_ime_file_lang( const WCHAR *filename ) +{ + DWORD *languages; + LCID lcid = 0; + void *info; + UINT len; + + if (!(len = GetFileVersionInfoSizeW( filename, NULL ))) return 0; + if (!(info = malloc( len ))) goto done; + if (!GetFileVersionInfoW( filename, 0, len, info )) goto done; + if (!VerQueryValueW( info, L"\VarFileInfo\Translation", (void **)&languages, &len ) || !len) goto done; + lcid = languages[0]; + +done: + free( info ); + return lcid; +} + /*********************************************************************** * ImmInstallIMEW (IMM32.@) */ HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description ) { WCHAR path[ARRAY_SIZE(layouts_formatW)+8], buffer[MAX_PATH]; - LCID lcid = GetUserDefaultLCID(); + LCID lcid; WORD count = 0x20; const WCHAR *tmp; DWORD length; @@ -2027,7 +2045,7 @@ HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description )
TRACE( "filename %s, description %s\n", debugstr_w(filename), debugstr_w(description) );
- if (!filename || !description) + if (!filename || !description || !(lcid = get_ime_file_lang( filename ))) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; @@ -2037,8 +2055,8 @@ HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description ) { DWORD disposition = 0;
- hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count ); - swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG_PTR)hkl); + hkl = (HKL)(UINT_PTR)MAKELONG( lcid, 0xe000 | count ); + swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG)(ULONG_PTR)hkl); if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, path, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition )) { diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 06880d4c62c..4be94595bca 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2930,7 +2930,6 @@ static HKL ime_install(void) "MoveFileW failed, error %lu\n", GetLastError() );
hkl = ImmInstallIMEW( ime_path, L"WineTest IME" ); - todo_wine ok( hkl == (HKL)(int)0xe020047f, "ImmInstallIMEW returned %p, error %lu\n", hkl, GetLastError() );
swprintf( buffer, ARRAY_SIZE(buffer), L"System\CurrentControlSet\Control\Keyboard Layouts\%08x", hkl );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 65 +++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 17 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 4be94595bca..2eea7f0d8c5 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2489,6 +2489,11 @@ 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; +static HKL expect_ime = (HKL)(int)0xe020047f;
enum ime_function { @@ -2498,8 +2503,9 @@ enum ime_function
struct ime_call { - enum ime_function func; + HKL hkl; HIMC himc; + enum ime_function func;
union { @@ -2526,6 +2532,7 @@ static void ok_call_( const char *file, int line, const struct ime_call *expecte
if ((ret = expected->func - received->func)) goto done; if ((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: @@ -2543,12 +2550,12 @@ done: { case IME_SELECT: todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got IME_SELECT himc %p, select %u\n", received->himc, received->select ); + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SELECT select %u\n", received->hkl, received->himc, received->select ); return; case IME_NOTIFY: todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got IME_NOTIFY himc %p, action %#x, index %#x, value %#x\n", - received->himc, received->notify.action, received->notify.index, + 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; } @@ -2557,12 +2564,12 @@ done: { case IME_SELECT: todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "IME_SELECT himc %p, select %u\n", expected->himc, expected->select ); + 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, "IME_NOTIFY himc %p, action %#x, index %#x, value %#x\n", - expected->himc, expected->notify.action, expected->notify.index, + 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; } @@ -2638,6 +2645,7 @@ static UINT WINAPI ime_ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WC ime_trace( "proc %p, reading %s, style %lu, string %s, data %p\n", proc, debugstr_w(reading), style, debugstr_w(string), data );
+ ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); CHECK_EXPECT( ImeEnumRegisterWord );
if (!style) @@ -2666,6 +2674,7 @@ static LRESULT WINAPI ime_ImeEscape( HIMC himc, UINT escape, void *data ) { ime_trace( "himc %p, escape %#x, data %p\n", himc, escape, data );
+ ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); CHECK_EXPECT( ImeEscape );
switch (escape) @@ -2709,6 +2718,7 @@ static UINT WINAPI ime_ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style ) { ime_trace( "item %u, style %p\n", item, style );
+ ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); CHECK_EXPECT( ImeGetRegisterWordStyle );
if (!style) @@ -2755,6 +2765,7 @@ static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYT { 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; } @@ -2763,6 +2774,7 @@ static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const { ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading), style, debugstr_w(string) );
+ ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); CHECK_EXPECT( ImeRegisterWord );
if (style) ok_eq( 0xdeadbeef, style, UINT, "%#x" ); @@ -2782,7 +2794,11 @@ static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const
static BOOL WINAPI ime_ImeSelect( HIMC himc, BOOL select ) { - struct ime_call call = {.func = IME_SELECT, .himc = himc, .select = select}; + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = himc, + .func = IME_SELECT, .select = select + }; ime_trace( "himc %p, select %d\n", himc, select ); ime_calls[ime_call_count++] = call; return TRUE; @@ -2816,6 +2832,7 @@ static BOOL WINAPI ime_ImeUnregisterWord( const WCHAR *reading, DWORD style, con { ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading), style, debugstr_w(string) );
+ ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); CHECK_EXPECT( ImeUnregisterWord );
if (style) ok_eq( 0xdeadbeef, style, UINT, "%#x" ); @@ -2835,7 +2852,11 @@ static BOOL WINAPI ime_ImeUnregisterWord( const WCHAR *reading, DWORD style, con
static BOOL WINAPI ime_NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) { - struct ime_call call = {.func = IME_NOTIFY, .himc = himc, .notify = {.action = action, .index = index, .value = value}}; + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = himc, + .func = IME_NOTIFY, .notify = {.action = action, .index = index, .value = value} + }; ime_trace( "himc %p, action %#lx, index %lu, value %lu\n", himc, action, index, value ); ime_calls[ime_call_count++] = call; return FALSE; @@ -2886,10 +2907,6 @@ static struct ime_functions ime_functions = ime_DllMain, };
-static UINT ime_count; -static WCHAR ime_path[MAX_PATH]; -static HIMC default_himc; - static HKL ime_install(void) { WCHAR buffer[MAX_PATH]; @@ -2930,7 +2947,7 @@ static HKL ime_install(void) "MoveFileW failed, error %lu\n", GetLastError() );
hkl = ImmInstallIMEW( ime_path, L"WineTest IME" ); - ok( hkl == (HKL)(int)0xe020047f, "ImmInstallIMEW returned %p, error %lu\n", hkl, GetLastError() ); + ok( hkl == expect_ime, "ImmInstallIMEW returned %p, error %lu\n", hkl, GetLastError() );
swprintf( buffer, ARRAY_SIZE(buffer), L"System\CurrentControlSet\Control\Keyboard Layouts\%08x", hkl ); ret = RegOpenKeyW( HKEY_LOCAL_MACHINE, buffer, &hkey ); @@ -3776,13 +3793,25 @@ static void test_ImmActivateLayout(void) { const struct ime_call activate_seq[] = { - {.func = IME_SELECT, .himc = default_himc, .select = 1, .todo = TRUE}, + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_SELECT, .select = 1, + .todo = TRUE, + }, {0}, }; const struct ime_call deactivate_seq[] = { - {.func = IME_NOTIFY, .himc = default_himc, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, .todo = TRUE}, - {.func = IME_SELECT, .himc = default_himc, .select = 0, .todo = TRUE}, + { + .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 ); @@ -3846,6 +3875,8 @@ cleanup:
START_TEST(imm32) { + default_hkl = GetKeyboardLayout( 0 ); + if (!is_ime_enabled()) { win_skip("IME support not implemented\n");
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 8 ++++++-- dlls/imm32/tests/imm32.c | 7 +++---- 2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e600156f504..ee9e673233b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -566,8 +566,12 @@ static void ime_release( struct ime *ime )
BOOL WINAPI ImmActivateLayout( HKL hkl ) { - FIXME( "hkl %p stub!\n", hkl ); - return FALSE; + FIXME( "hkl %p semi-stub!\n", hkl ); + + if (hkl == GetKeyboardLayout( 0 )) return TRUE; + if (!ActivateKeyboardLayout( hkl, 0 )) return FALSE; + + return TRUE; }
static BOOL free_input_context_data( HIMC hIMC ) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 2eea7f0d8c5..204c805f748 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3820,7 +3820,6 @@ static void test_ImmActivateLayout(void) SET_ENABLE( ImeInquire, TRUE ); SET_ENABLE( ImeDestroy, TRUE );
- todo_wine ok_ret( 1, ImmActivateLayout( old_hkl ) );
ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -3840,16 +3839,16 @@ static void test_ImmActivateLayout(void) /* ImmActivateLayout changes active HKL */
SET_EXPECT( ImeInquire ); - todo_wine ok_ret( 1, ImmActivateLayout( hkl ) ); ok_seq( activate_seq ); todo_wine CHECK_CALLED( ImeInquire );
- todo_wine ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
- todo_wine + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_seq( empty_sequence ); + ok_ret( 1, ImmActivateLayout( old_hkl ) ); ok_seq( deactivate_seq );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 161 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 2 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 204c805f748..dffb90b9872 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2519,6 +2519,7 @@ struct ime_call };
BOOL todo; + BOOL flaky_himc; };
struct ime_call empty_sequence[] = {{0}}; @@ -2531,7 +2532,9 @@ static void ok_call_( const char *file, int line, const struct ime_call *expecte int ret;
if ((ret = expected->func - received->func)) goto done; - if ((ret = (UINT_PTR)expected->himc - (UINT_PTR)received->himc)) 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) { @@ -2598,7 +2601,6 @@ static void ok_seq_( const char *file, int line, const struct ime_call *expected static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); - ok( 0, "unexpected call\n" ); return DefWindowProcW( hwnd, msg, wparam, lparam ); }
@@ -3872,6 +3874,160 @@ cleanup: SET_ENABLE( ImeDestroy, FALSE ); }
+static void test_ImmCreateInputContext(void) +{ + struct ime_call activate_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_SELECT, .select = 1, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc[0]*/, + .func = IME_SELECT, .select = 1, + .todo = TRUE, .flaky_himc = TRUE, + }, + {0}, + }; + struct ime_call select1_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc[1]*/, + .func = IME_SELECT, .select = 1, + .todo = TRUE, + }, + {0}, + }; + struct ime_call select0_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc[1]*/, + .func = IME_SELECT, .select = 0, + }, + {0}, + }; + struct ime_call deactivate_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[0]*/, + .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = default_hkl, .himc = default_himc, + .func = IME_SELECT, .select = 0, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = default_hkl, .himc = 0/*himc[0]*/, + .func = IME_SELECT, .select = 0, + .todo = TRUE, .flaky_himc = TRUE, + }, + {0}, + }; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + INPUTCONTEXT *ctx; + HIMC himc[2]; + HWND hwnd; + + ctx = ImmLockIMC( default_himc ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ok_ret( 0, IsWindow( ctx->hWnd ) ); + ok_ret( 1, ImmUnlockIMC( default_himc ) ); + + + /* new input contexts cannot be locked before IME window has been created */ + + himc[0] = ImmCreateContext(); + ok( !!himc[0], "ImmCreateContext failed, error %lu\n", GetLastError() ); + ctx = ImmLockIMC( himc[0] ); + todo_wine + ok( !ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + if (ctx) ImmUnlockIMCC( himc[0] ); + + 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() ); + + ctx = ImmLockIMC( default_himc ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ok_ret( 1, ImmUnlockIMC( default_himc ) ); + + ctx = ImmLockIMC( himc[0] ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ok_ret( 1, ImmUnlockIMC( himc[0] ) ); + + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + ime_info.dwPrivateDataSize = 123; + + if (!(hkl = ime_install())) goto cleanup; + + + /* Activating the layout calls ImeSelect 1 on existing HIMC */ + + ok_seq( empty_sequence ); + ok_ret( 1, ImmActivateLayout( hkl ) ); + activate_seq[1].himc = himc[0]; + ok_seq( activate_seq ); + + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ctx = ImmLockIMC( default_himc ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ok_ret( 1, ImmUnlockIMC( default_himc ) ); + + ctx = ImmLockIMC( himc[0] ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ok_ret( 1, ImmUnlockIMC( himc[0] ) ); + + + /* ImmLockIMC triggers the ImeSelect call, to allocate private data */ + + himc[1] = ImmCreateContext(); + ok( !!himc[1], "ImmCreateContext failed, error %lu\n", GetLastError() ); + + todo_wine + ok_seq( empty_sequence ); + ctx = ImmLockIMC( himc[1] ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + select1_seq[0].himc = himc[1]; + ok_seq( select1_seq ); + + ok_ret( 1, ImmUnlockIMC( himc[1] ) ); + + ok_seq( empty_sequence ); + ok_ret( 1, ImmDestroyContext( himc[1] ) ); + select0_seq[0].himc = himc[1]; + ok_seq( select0_seq ); + + + /* Deactivating the layout calls ImeSelect 0 on existing HIMC */ + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + deactivate_seq[1].himc = himc[0]; + deactivate_seq[3].himc = himc[0]; + ok_seq( deactivate_seq ); + + ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ok_ret( 1, ImmFreeLayout( hkl ) ); + ime_cleanup( hkl ); + ok_seq( empty_sequence ); + +cleanup: + ok_ret( 1, ImmDestroyContext( himc[0] ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + + ime_info.dwPrivateDataSize = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -3904,6 +4060,7 @@ START_TEST(imm32) test_ImmUnregisterWord( TRUE );
test_ImmActivateLayout(); + test_ImmCreateInputContext();
if (init()) {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/tests/imm32.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index dffb90b9872..8340d67deae 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3869,6 +3869,44 @@ static void test_ImmActivateLayout(void) CHECK_CALLED( ImeDestroy ); ok_seq( empty_sequence );
+ + /* when there's a window, ActivateKeyboardLayout calls ImeInquire */ + + if (!(hkl = ime_install())) goto cleanup; + + 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_seq( empty_sequence ); + + SET_EXPECT( ImeInquire ); + ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + todo_wine + CHECK_CALLED( ImeInquire ); + ok_seq( activate_seq ); + + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + ok_seq( deactivate_seq ); + + 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 + CHECK_CALLED( ImeDestroy ); + ok_seq( empty_sequence ); + + ok_ret( 1, DestroyWindow( hwnd ) ); + + cleanup: SET_ENABLE( ImeInquire, FALSE ); SET_ENABLE( ImeDestroy, FALSE );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index ee9e673233b..803fb555786 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -564,13 +564,21 @@ static void ime_release( struct ime *ime ) LeaveCriticalSection( &ime_cs ); }
+static BOOL CALLBACK enum_activate_layout( HIMC himc, LPARAM lparam ) +{ + if (ImmLockIMC( himc )) ImmUnlockIMC( himc ); + return TRUE; +} + BOOL WINAPI ImmActivateLayout( HKL hkl ) { - FIXME( "hkl %p semi-stub!\n", hkl ); + TRACE( "hkl %p\n", hkl );
if (hkl == GetKeyboardLayout( 0 )) return TRUE; if (!ActivateKeyboardLayout( hkl, 0 )) return FALSE;
+ ImmEnumInputContext( 0, enum_activate_layout, 0 ); + return TRUE; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 803fb555786..473f1927753 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -564,6 +564,23 @@ static void ime_release( struct ime *ime ) LeaveCriticalSection( &ime_cs ); }
+static void imc_select_hkl( struct imc *imc, HKL hkl ) +{ + if (imc->ime) + { + if (imc->ime->hkl == hkl) return; + imc->ime->pImeSelect( imc->handle, FALSE ); + ime_release( imc->ime ); + } + + if (!hkl) + imc->ime = NULL; + else if (!(imc->ime = ime_acquire( hkl ))) + WARN( "Failed to acquire IME for HKL %p\n", hkl ); + else + imc->ime->pImeSelect( imc->handle, TRUE ); +} + static BOOL CALLBACK enum_activate_layout( HIMC himc, LPARAM lparam ) { if (ImmLockIMC( himc )) ImmUnlockIMC( himc ); @@ -3026,20 +3043,8 @@ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD TRACE("%p %p %x %x %lx\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
if (!(data = get_imc_data( imc ))) return FALSE; - - /* Make sure we are inputting to the correct keyboard */ - if (data->ime->hkl != hKL) - { - struct ime *new_hkl; - - if (!(new_hkl = ime_acquire( hKL ))) return FALSE; - - data->ime->pImeSelect( imc, FALSE ); - ime_release( data->ime ); - - data->ime = new_hkl; - data->ime->pImeSelect( imc, TRUE ); - } + imc_select_hkl( data, hKL ); + if (!data->ime) return FALSE;
GetKeyboardState(state); if (data->ime->pImeProcessKey( imc, vKey, lKeyData, state ))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 473f1927753..04bfc461658 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -571,6 +571,7 @@ static void imc_select_hkl( struct imc *imc, HKL hkl ) if (imc->ime->hkl == hkl) return; imc->ime->pImeSelect( imc->handle, FALSE ); ime_release( imc->ime ); + ImmDestroyIMCC( imc->IMC.hPrivate ); }
if (!hkl) @@ -578,7 +579,13 @@ static void imc_select_hkl( struct imc *imc, HKL hkl ) else if (!(imc->ime = ime_acquire( hkl ))) WARN( "Failed to acquire IME for HKL %p\n", hkl ); else + { + if (!(imc->IMC.hPrivate = ImmCreateIMCC( imc->ime->info.dwPrivateDataSize ))) + WARN( "Failed to allocate IME private data for IMC %p\n", imc ); + imc->IMC.fdwConversion = imc->ime->info.fdwConversionCaps; + imc->IMC.fdwSentence = imc->ime->info.fdwSentenceCaps; imc->ime->pImeSelect( imc->handle, TRUE ); + } }
static BOOL CALLBACK enum_activate_layout( HIMC himc, LPARAM lparam ) @@ -872,15 +879,7 @@ static struct imc *create_input_context( HIMC default_imc ) LPCANDIDATEINFO ci; int i;
- new_context = calloc( 1, sizeof(*new_context) ); - - /* Load the IME */ - if (!(new_context->ime = ime_acquire( GetKeyboardLayout( 0 ) ))) - { - TRACE("IME dll could not be loaded\n"); - free( new_context ); - return 0; - } + if (!(new_context = calloc( 1, sizeof(*new_context) ))) return NULL;
/* the HIMCCs are never NULL */ new_context->IMC.hCompStr = ImmCreateBlankCompStr(); @@ -899,12 +898,6 @@ static struct imc *create_input_context( HIMC default_imc ) for (i = 0; i < ARRAY_SIZE(new_context->IMC.cfCandForm); i++) new_context->IMC.cfCandForm[i].dwIndex = ~0u;
- /* Initialize the IME Private */ - new_context->IMC.hPrivate = ImmCreateIMCC( new_context->ime->info.dwPrivateDataSize ); - - new_context->IMC.fdwConversion = new_context->ime->info.fdwConversionCaps; - new_context->IMC.fdwSentence = new_context->ime->info.fdwSentenceCaps; - if (!default_imc) new_context->handle = NtUserCreateInputContext((UINT_PTR)new_context); else if (NtUserUpdateInputContext(default_imc, NtUserInputContextClientPtr, (UINT_PTR)new_context)) @@ -915,12 +908,7 @@ static struct imc *create_input_context( HIMC default_imc ) return 0; }
- if (!new_context->ime->pImeSelect( new_context->handle, TRUE )) - { - TRACE("Selection of IME failed\n"); - IMM_DestroyContext(new_context); - return 0; - } + imc_select_hkl( new_context, GetKeyboardLayout( 0 ) ); SendMessageW( GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->ime );
TRACE("Created context %p\n", new_context);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 15 +++++++++------ dlls/imm32/tests/imm32.c | 20 ++++++++++++++------ 2 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 04bfc461658..2c3af063ac5 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2829,14 +2829,17 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE /*********************************************************************** * ImmLockIMC(IMM32.@) */ -LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC) +INPUTCONTEXT *WINAPI ImmLockIMC( HIMC himc ) { - struct imc *data = get_imc_data( hIMC ); + struct imc *imc = get_imc_data( himc );
- if (!data) - return NULL; - data->dwLock++; - return &data->IMC; + TRACE( "himc %p\n", himc ); + + if (!imc) return NULL; + imc->dwLock++; + + imc_select_hkl( imc, GetKeyboardLayout( 0 ) ); + return &imc->IMC; }
/*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 8340d67deae..e8116081f52 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3798,7 +3798,6 @@ static void test_ImmActivateLayout(void) { .hkl = expect_ime, .himc = default_himc, .func = IME_SELECT, .select = 1, - .todo = TRUE, }, {0}, }; @@ -3816,6 +3815,15 @@ static void test_ImmActivateLayout(void) }, {0}, }; + const struct ime_call activate_with_window_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_SELECT, .select = 1, + .todo = TRUE, + }, + {0}, + }; HKL hkl, old_hkl = GetKeyboardLayout( 0 ); UINT ret;
@@ -3843,7 +3851,6 @@ static void test_ImmActivateLayout(void) SET_EXPECT( ImeInquire ); ok_ret( 1, ImmActivateLayout( hkl ) ); ok_seq( activate_seq ); - todo_wine CHECK_CALLED( ImeInquire );
ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -3851,8 +3858,10 @@ static void test_ImmActivateLayout(void) ok_ret( 1, ImmActivateLayout( hkl ) ); ok_seq( empty_sequence );
+ todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_ret( 1, ImmActivateLayout( old_hkl ) ); ok_seq( deactivate_seq ); + todo_ImeDestroy = FALSE;
ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
@@ -3865,7 +3874,6 @@ static void test_ImmActivateLayout(void) SET_EXPECT( ImeDestroy ); ret = ImmFreeLayout( hkl ); ok( ret, "ImmFreeLayout returned %u\n", ret ); - todo_wine CHECK_CALLED( ImeDestroy ); ok_seq( empty_sequence );
@@ -3883,7 +3891,7 @@ static void test_ImmActivateLayout(void) ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); todo_wine CHECK_CALLED( ImeInquire ); - ok_seq( activate_seq ); + ok_seq( activate_with_window_seq );
ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
@@ -3919,12 +3927,12 @@ static void test_ImmCreateInputContext(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[0]*/, .func = IME_SELECT, .select = 1, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, {0}, };
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=131129
Your paranoid android.
=== w11pro64_amd (64 bit report) ===
imm32: imm32.c:757: Test failed: hwnd is not active imm32.c:765: Test failed: expected WM_IME_SETCONTEXT_DEACTIVATE imm32.c:766: Test failed: expected WM_IME_SETCONTEXT_ACTIVATE imm32.c:774: Test failed: expected WM_IME_SETCONTEXT_DEACTIVATE imm32.c:775: Test failed: expected WM_IME_SETCONTEXT_ACTIVATE imm32.c:787: Test failed: expected WM_IME_SETCONTEXT_DEACTIVATE imm32.c:788: Test failed: expected WM_IME_SETCONTEXT_ACTIVATE imm32.c:798: Test failed: expected WM_IME_SETCONTEXT_DEACTIVATE imm32.c:803: Test failed: expected WM_IME_SETCONTEXT_ACTIVATE imm32.c:289: Test failed: unexpected call WM_IME_SETCONTEXT_ACTIVATE imm32.c:882: Test failed: expected WM_IME_SETCONTEXT_ACTIVATE imm32.c:289: Test failed: unexpected call WM_IME_SETCONTEXT_ACTIVATE
Byeongsik Jeon (@bsjeon) commented about dlls/imm32/imm.c:
else if (!(imc->ime = ime_acquire( hkl ))) WARN( "Failed to acquire IME for HKL %p\n", hkl ); else
- {
if (!(imc->IMC.hPrivate = ImmCreateIMCC( imc->ime->info.dwPrivateDataSize )))
WARN( "Failed to allocate IME private data for IMC %p\n", imc );
imc->IMC.fdwConversion = imc->ime->info.fdwConversionCaps;
imc->IMC.fdwSentence = imc->ime->info.fdwSentenceCaps;
This is an issue with the old code, not with this MR, but I'm commenting in hopes that it will be added to the TODO list. Maybe it's already up there.
Setting capability values to default value is not appropriate. This seems to be the domain of IME, not IMM. In fact, there is a native-IME that is misbehaving because of these two lines.
Thanks.
On Tue Mar 28 10:07:09 2023 +0000, Byeongsik Jeon wrote:
This is an issue with the old code, not with this MR, but I'm commenting in hopes that it will be added to the TODO list. Maybe it's already up there. Setting capability values to default value is not appropriate. This seems to be the domain of IME, not IMM. In fact, there is a native-IME that is misbehaving because of these two lines. Thanks.
Noted, I'm curious, which native IME is broken?
On Tue Mar 28 10:12:33 2023 +0000, Rémi Bernon wrote:
Noted, I'm curious, which native IME is broken?
Saenaru. This is not an MS IME, but a DDK-based open source Korean IME.
I think you can check this in the Wine test code.