winex11: Create a global vulkan instance for xrandr.
[wine.git] / dlls / imm32 / tests / imm32.c
blobdb73463ef497ee35a9d4de1a81e0be67c1a952d8
1 /*
2 * Unit tests for imm32
4 * Copyright (c) 2008 Michael Jung
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stddef.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
29 #include "wine/test.h"
30 #include "objbase.h"
31 #include "winuser.h"
32 #include "wingdi.h"
33 #include "imm.h"
34 #include "immdev.h"
36 #include "ime_test.h"
38 static const char *debugstr_wm_ime( UINT msg )
40 switch (msg)
42 case WM_IME_STARTCOMPOSITION: return "WM_IME_STARTCOMPOSITION";
43 case WM_IME_ENDCOMPOSITION: return "WM_IME_ENDCOMPOSITION";
44 case WM_IME_COMPOSITION: return "WM_IME_COMPOSITION";
45 case WM_IME_SETCONTEXT: return "WM_IME_SETCONTEXT";
46 case WM_IME_NOTIFY: return "WM_IME_NOTIFY";
47 case WM_IME_CONTROL: return "WM_IME_CONTROL";
48 case WM_IME_COMPOSITIONFULL: return "WM_IME_COMPOSITIONFULL";
49 case WM_IME_SELECT: return "WM_IME_SELECT";
50 case WM_IME_CHAR: return "WM_IME_CHAR";
51 case WM_IME_REQUEST: return "WM_IME_REQUEST";
52 case WM_IME_KEYDOWN: return "WM_IME_KEYDOWN";
53 case WM_IME_KEYUP: return "WM_IME_KEYUP";
54 default: return wine_dbg_sprintf( "%#x", msg );
58 static const char *debugstr_ok( const char *cond )
60 int c, n = 0;
61 /* skip possible casts */
62 while ((c = *cond++))
64 if (c == '(') n++;
65 if (!n) break;
66 if (c == ')') n--;
68 if (!strchr( cond - 1, '(' )) return wine_dbg_sprintf( "got %s", cond - 1 );
69 return wine_dbg_sprintf( "%.*s returned", (int)strcspn( cond - 1, "( " ), cond - 1 );
72 #define ok_eq( e, r, t, f, ... ) \
73 do \
74 { \
75 t v = (r); \
76 ok( v == (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \
77 } while (0)
78 #define ok_ne( e, r, t, f, ... ) \
79 do \
80 { \
81 t v = (r); \
82 ok( v != (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \
83 } while (0)
84 #define ok_wcs( e, r ) \
85 do \
86 { \
87 const WCHAR *v = (r); \
88 ok( !wcscmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_w(v) ); \
89 } while (0)
90 #define ok_str( e, r ) \
91 do \
92 { \
93 const char *v = (r); \
94 ok( !strcmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_a(v) ); \
95 } while (0)
96 #define ok_ret( e, r ) ok_eq( e, r, UINT_PTR, "%Iu, error %ld", GetLastError() )
98 BOOL WINAPI ImmSetActiveContext(HWND, HIMC, BOOL);
100 static BOOL (WINAPI *pImmAssociateContextEx)(HWND,HIMC,DWORD);
101 static UINT (WINAPI *pNtUserAssociateInputContext)(HWND,HIMC,ULONG);
102 static BOOL (WINAPI *pImmIsUIMessageA)(HWND,UINT,WPARAM,LPARAM);
103 static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t);
105 extern BOOL WINAPI ImmFreeLayout(HKL);
106 extern BOOL WINAPI ImmLoadIME(HKL);
107 extern BOOL WINAPI ImmActivateLayout(HKL);
109 #define check_member_( file, line, val, exp, fmt, member ) \
110 ok_(file, line)( (val).member == (exp).member, "got " #member " " fmt "\n", (val).member )
111 #define check_member( val, exp, fmt, member ) \
112 check_member_( __FILE__, __LINE__, val, exp, fmt, member )
114 #define check_member_wstr_( file, line, val, exp, member ) \
115 ok_(file, line)( !wcscmp( (val).member, (exp).member ), "got " #member " %s\n", \
116 debugstr_w((val).member) )
117 #define check_member_wstr( val, exp, member ) \
118 check_member_wstr_( __FILE__, __LINE__, val, exp, member )
120 #define check_member_str_( file, line, val, exp, member ) \
121 ok_(file, line)( !strcmp( (val).member, (exp).member ), "got " #member " %s\n", \
122 debugstr_a((val).member) )
123 #define check_member_str( val, exp, member ) \
124 check_member_str_( __FILE__, __LINE__, val, exp, member )
126 #define check_member_point_( file, line, val, exp, member ) \
127 ok_(file, line)( !memcmp( &(val).member, &(exp).member, sizeof(POINT) ), \
128 "got " #member " %s\n", wine_dbgstr_point( &(val).member ) )
129 #define check_member_point( val, exp, member ) \
130 check_member_point_( __FILE__, __LINE__, val, exp, member )
132 #define check_member_rect_( file, line, val, exp, member ) \
133 ok_(file, line)( !memcmp( &(val).member, &(exp).member, sizeof(RECT) ), \
134 "got " #member " %s\n", wine_dbgstr_rect( &(val).member ) )
135 #define check_member_rect( val, exp, member ) \
136 check_member_rect_( __FILE__, __LINE__, val, exp, member )
138 #define check_composition_string( a, b ) check_composition_string_( __LINE__, a, b )
139 static void check_composition_string_( int line, COMPOSITIONSTRING *string, const COMPOSITIONSTRING *expect )
141 check_member_( __FILE__, line, *string, *expect, "%lu", dwSize );
142 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadAttrLen );
143 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadAttrOffset );
144 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadClauseLen );
145 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadClauseOffset );
146 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadStrLen );
147 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadStrOffset );
148 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompAttrLen );
149 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompAttrOffset );
150 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompClauseLen );
151 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompClauseOffset );
152 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompStrLen );
153 check_member_( __FILE__, line, *string, *expect, "%lu", dwCompStrOffset );
154 check_member_( __FILE__, line, *string, *expect, "%lu", dwCursorPos );
155 check_member_( __FILE__, line, *string, *expect, "%lu", dwDeltaStart );
156 check_member_( __FILE__, line, *string, *expect, "%lu", dwResultReadClauseLen );
157 check_member_( __FILE__, line, *string, *expect, "%lu", dwResultReadClauseOffset );
158 check_member_( __FILE__, line, *string, *expect, "%lu", dwResultReadStrLen );
159 check_member_( __FILE__, line, *string, *expect, "%lu", dwResultReadStrOffset );
160 check_member_( __FILE__, line, *string, *expect, "%lu", dwResultClauseLen );
161 check_member_( __FILE__, line, *string, *expect, "%lu", dwResultClauseOffset );
162 check_member_( __FILE__, line, *string, *expect, "%lu", dwResultStrLen );
163 check_member_( __FILE__, line, *string, *expect, "%lu", dwResultStrOffset );
164 check_member_( __FILE__, line, *string, *expect, "%lu", dwPrivateSize );
165 check_member_( __FILE__, line, *string, *expect, "%lu", dwPrivateOffset );
168 #define check_candidate_list( a, b ) check_candidate_list_( __LINE__, a, b, TRUE )
169 static void check_candidate_list_( int line, CANDIDATELIST *list, const CANDIDATELIST *expect, BOOL unicode )
171 UINT i;
173 check_member_( __FILE__, line, *list, *expect, "%lu", dwSize );
174 check_member_( __FILE__, line, *list, *expect, "%lu", dwStyle );
175 check_member_( __FILE__, line, *list, *expect, "%lu", dwCount );
176 check_member_( __FILE__, line, *list, *expect, "%lu", dwSelection );
177 check_member_( __FILE__, line, *list, *expect, "%lu", dwPageStart );
178 check_member_( __FILE__, line, *list, *expect, "%lu", dwPageSize );
179 for (i = 0; i < list->dwCount && i < expect->dwCount; ++i)
181 void *list_str = (BYTE *)list + list->dwOffset[i], *expect_str = (BYTE *)expect + expect->dwOffset[i];
182 check_member_( __FILE__, line, *list, *expect, "%lu", dwOffset[i] );
183 if (unicode) ok_( __FILE__, line )( !wcscmp( list_str, expect_str ), "got %s\n", debugstr_w(list_str) );
184 else ok_( __FILE__, line )( !strcmp( list_str, expect_str ), "got %s\n", debugstr_a(list_str) );
188 #define check_candidate_form( a, b ) check_candidate_form_( __LINE__, a, b )
189 static void check_candidate_form_( int line, CANDIDATEFORM *form, const CANDIDATEFORM *expect )
191 check_member_( __FILE__, line, *form, *expect, "%#lx", dwIndex );
192 check_member_( __FILE__, line, *form, *expect, "%#lx", dwStyle );
193 check_member_point_( __FILE__, line, *form, *expect, ptCurrentPos );
194 check_member_rect_( __FILE__, line, *form, *expect, rcArea );
197 #define check_composition_form( a, b ) check_composition_form_( __LINE__, a, b )
198 static void check_composition_form_( int line, COMPOSITIONFORM *form, const COMPOSITIONFORM *expect )
200 check_member_( __FILE__, line, *form, *expect, "%#lx", dwStyle );
201 check_member_point_( __FILE__, line, *form, *expect, ptCurrentPos );
202 check_member_rect_( __FILE__, line, *form, *expect, rcArea );
205 #define check_logfont_w( a, b ) check_logfont_w_( __LINE__, a, b )
206 static void check_logfont_w_( int line, LOGFONTW *font, const LOGFONTW *expect )
208 check_member_( __FILE__, line, *font, *expect, "%lu", lfHeight );
209 check_member_( __FILE__, line, *font, *expect, "%lu", lfWidth );
210 check_member_( __FILE__, line, *font, *expect, "%lu", lfEscapement );
211 check_member_( __FILE__, line, *font, *expect, "%lu", lfOrientation );
212 check_member_( __FILE__, line, *font, *expect, "%lu", lfWeight );
213 check_member_( __FILE__, line, *font, *expect, "%u", lfItalic );
214 check_member_( __FILE__, line, *font, *expect, "%u", lfUnderline );
215 check_member_( __FILE__, line, *font, *expect, "%u", lfStrikeOut );
216 check_member_( __FILE__, line, *font, *expect, "%u", lfCharSet );
217 check_member_( __FILE__, line, *font, *expect, "%u", lfOutPrecision );
218 check_member_( __FILE__, line, *font, *expect, "%u", lfClipPrecision );
219 check_member_( __FILE__, line, *font, *expect, "%u", lfQuality );
220 check_member_( __FILE__, line, *font, *expect, "%u", lfPitchAndFamily );
221 check_member_wstr_( __FILE__, line, *font, *expect, lfFaceName );
224 #define check_logfont_a( a, b ) check_logfont_a_( __LINE__, a, b )
225 static void check_logfont_a_( int line, LOGFONTA *font, const LOGFONTA *expect )
227 check_member_( __FILE__, line, *font, *expect, "%lu", lfHeight );
228 check_member_( __FILE__, line, *font, *expect, "%lu", lfWidth );
229 check_member_( __FILE__, line, *font, *expect, "%lu", lfEscapement );
230 check_member_( __FILE__, line, *font, *expect, "%lu", lfOrientation );
231 check_member_( __FILE__, line, *font, *expect, "%lu", lfWeight );
232 check_member_( __FILE__, line, *font, *expect, "%u", lfItalic );
233 check_member_( __FILE__, line, *font, *expect, "%u", lfUnderline );
234 check_member_( __FILE__, line, *font, *expect, "%u", lfStrikeOut );
235 check_member_( __FILE__, line, *font, *expect, "%u", lfCharSet );
236 check_member_( __FILE__, line, *font, *expect, "%u", lfOutPrecision );
237 check_member_( __FILE__, line, *font, *expect, "%u", lfClipPrecision );
238 check_member_( __FILE__, line, *font, *expect, "%u", lfQuality );
239 check_member_( __FILE__, line, *font, *expect, "%u", lfPitchAndFamily );
240 check_member_str_( __FILE__, line, *font, *expect, lfFaceName );
243 #define DEFINE_EXPECT(func) \
244 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE, enabled_ ## func = FALSE
246 #define SET_EXPECT(func) \
247 expect_ ## func = TRUE
249 #define CHECK_EXPECT2(func) \
250 do { \
251 if (enabled_ ## func) {\
252 ok(expect_ ##func, "unexpected call " #func "\n"); \
253 called_ ## func = TRUE; \
255 }while(0)
257 #define CHECK_EXPECT(func) \
258 do { \
259 CHECK_EXPECT2(func); \
260 expect_ ## func = FALSE; \
261 }while(0)
263 #define CHECK_CALLED(func) \
264 do { \
265 ok(called_ ## func, "expected " #func "\n"); \
266 expect_ ## func = called_ ## func = FALSE; \
267 }while(0)
269 #define SET_ENABLE(func, val) \
270 enabled_ ## func = (val)
272 DEFINE_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
273 DEFINE_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
275 #define process_messages() process_messages_(0)
276 static void process_messages_(HWND hwnd)
278 MSG msg;
280 while (PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ))
282 TranslateMessage( &msg );
283 DispatchMessageA( &msg );
287 /* try to make sure pending X events have been processed before continuing */
288 #define flush_events() flush_events_( 100, 200 )
289 static void flush_events_( int min_timeout, int max_timeout )
291 DWORD time = GetTickCount() + max_timeout;
292 MSG msg;
294 while (max_timeout > 0)
296 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
297 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
299 TranslateMessage( &msg );
300 DispatchMessageA( &msg );
302 max_timeout = time - GetTickCount();
306 #define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ )
308 static BOOL ImeSelect_init_status;
309 static BOOL todo_ImeInquire;
310 DEFINE_EXPECT( ImeInquire );
311 static BOOL todo_ImeDestroy;
312 DEFINE_EXPECT( ImeDestroy );
313 DEFINE_EXPECT( ImeEscape );
314 DEFINE_EXPECT( ImeEnumRegisterWord );
315 DEFINE_EXPECT( ImeRegisterWord );
316 DEFINE_EXPECT( ImeGetRegisterWordStyle );
317 DEFINE_EXPECT( ImeUnregisterWord );
318 static BOOL todo_ImeSetCompositionString;
319 DEFINE_EXPECT( ImeSetCompositionString );
320 static BOOL todo_IME_DLL_PROCESS_ATTACH;
321 DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH );
322 static BOOL todo_IME_DLL_PROCESS_DETACH;
323 DEFINE_EXPECT( IME_DLL_PROCESS_DETACH );
325 static IMEINFO ime_info;
326 static UINT ime_count;
327 static WCHAR ime_path[MAX_PATH];
328 static HIMC default_himc;
329 static HKL default_hkl, wineime_hkl;
330 static HKL expect_ime = (HKL)(int)0xe020047f;
332 enum ime_function
334 IME_SELECT = 1,
335 IME_NOTIFY,
336 IME_PROCESS_KEY,
337 IME_TO_ASCII_EX,
338 IME_SET_ACTIVE_CONTEXT,
339 MSG_IME_UI,
340 MSG_TEST_WIN,
343 struct ime_call
345 HKL hkl;
346 HIMC himc;
347 enum ime_function func;
349 WCHAR comp[16];
350 WCHAR result[16];
352 union
354 int select;
355 struct
357 int action;
358 int index;
359 int value;
360 } notify;
361 struct
363 WORD vkey;
364 LPARAM lparam;
365 } process_key;
366 struct
368 UINT vkey;
369 UINT vsc;
370 UINT flags;
371 } to_ascii_ex;
372 struct
374 int flag;
375 } set_active_context;
376 struct
378 UINT msg;
379 WPARAM wparam;
380 LPARAM lparam;
381 } message;
384 BOOL todo;
385 BOOL broken;
386 BOOL flaky_himc;
387 BOOL todo_value;
388 BOOL todo_himc;
391 struct ime_call empty_sequence[] = {{0}};
392 static struct ime_call ime_calls[1024];
393 static ULONG ime_call_count;
395 #define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b )
396 static int ok_call_( const char *file, int line, const struct ime_call *expected, const struct ime_call *received )
398 int ret;
400 if ((ret = expected->func - received->func)) goto done;
401 /* Wine doesn't allocate HIMC in a deterministic order, ignore them when they are enumerated */
402 if (expected->flaky_himc && (ret = !!(UINT_PTR)expected->himc - !!(UINT_PTR)received->himc)) goto done;
403 if (!expected->flaky_himc && (ret = (UINT_PTR)expected->himc - (UINT_PTR)received->himc))
405 /* on some Wine configurations the IME UI doesn't get an HIMC */
406 if (!winetest_platform_is_wine || !expected->todo_himc) goto done;
407 else todo_wine ok( 0, "got himc %p\n", received->himc );
410 if ((ret = (UINT)(UINT_PTR)expected->hkl - (UINT)(UINT_PTR)received->hkl)) goto done;
411 switch (expected->func)
413 case IME_SELECT:
414 if ((ret = expected->select - received->select)) goto done;
415 break;
416 case IME_NOTIFY:
417 if ((ret = expected->notify.action - received->notify.action)) goto done;
418 if ((ret = expected->notify.index - received->notify.index)) goto done;
419 if ((ret = expected->notify.value - received->notify.value)) goto done;
420 break;
421 case IME_PROCESS_KEY:
422 if ((ret = expected->process_key.vkey - received->process_key.vkey)) goto done;
423 if ((ret = expected->process_key.lparam - received->process_key.lparam)) goto done;
424 break;
425 case IME_TO_ASCII_EX:
426 if ((ret = expected->to_ascii_ex.vkey - received->to_ascii_ex.vkey)) goto done;
427 if ((ret = expected->to_ascii_ex.vsc - received->to_ascii_ex.vsc)) goto done;
428 if ((ret = expected->to_ascii_ex.flags - received->to_ascii_ex.flags)) goto done;
429 break;
430 case IME_SET_ACTIVE_CONTEXT:
431 if ((ret = expected->set_active_context.flag - received->set_active_context.flag)) goto done;
432 break;
433 case MSG_IME_UI:
434 case MSG_TEST_WIN:
435 if ((ret = expected->message.msg - received->message.msg)) goto done;
436 if ((ret = (expected->message.wparam - received->message.wparam))) goto done;
437 if ((ret = (expected->message.lparam - received->message.lparam))) goto done;
438 if ((ret = wcscmp( expected->comp, received->comp ))) goto done;
439 if ((ret = wcscmp( expected->result, received->result ))) goto done;
440 break;
443 done:
444 if (ret && broken( expected->broken )) return ret;
446 switch (received->func)
448 case IME_SELECT:
449 todo_wine_if( expected->todo || expected->todo_value )
450 ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SELECT select %u\n", received->hkl, received->himc, received->select );
451 return ret;
452 case IME_NOTIFY:
453 todo_wine_if( expected->todo || expected->todo_value )
454 ok_(file, line)( !ret, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n",
455 received->hkl, received->himc, received->notify.action, received->notify.index,
456 received->notify.value );
457 return ret;
458 case IME_PROCESS_KEY:
459 todo_wine_if( expected->todo || expected->todo_value )
460 ok_(file, line)( !ret, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n",
461 received->hkl, received->himc, received->process_key.vkey, received->process_key.lparam );
462 return ret;
463 case IME_TO_ASCII_EX:
464 todo_wine_if( expected->todo || expected->todo_value )
465 ok_(file, line)( !ret, "got hkl %p, himc %p, IME_TO_ASCII_EX vkey %#x, vsc %#x, flags %#x\n",
466 received->hkl, received->himc, received->to_ascii_ex.vkey, received->to_ascii_ex.vsc,
467 received->to_ascii_ex.flags );
468 return ret;
469 case IME_SET_ACTIVE_CONTEXT:
470 todo_wine_if( expected->todo || expected->todo_value )
471 ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", received->hkl, received->himc,
472 received->set_active_context.flag );
473 return ret;
474 case MSG_IME_UI:
475 todo_wine_if( expected->todo || expected->todo_value )
476 ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %s, wparam %#Ix, lparam %#Ix\n", received->hkl,
477 received->himc, debugstr_wm_ime(received->message.msg), received->message.wparam, received->message.lparam );
478 return ret;
479 case MSG_TEST_WIN:
480 todo_wine_if( expected->todo || expected->todo_value )
481 ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %s, wparam %#Ix, lparam %#Ix, comp %s, result %s\n", received->hkl,
482 received->himc, debugstr_wm_ime(received->message.msg), received->message.wparam, received->message.lparam,
483 debugstr_w(received->comp), debugstr_w(received->result) );
484 return ret;
487 switch (expected->func)
489 case IME_SELECT:
490 todo_wine_if( expected->todo || expected->todo_value )
491 ok_(file, line)( !ret, "hkl %p, himc %p, IME_SELECT select %u\n", expected->hkl, expected->himc, expected->select );
492 break;
493 case IME_NOTIFY:
494 todo_wine_if( expected->todo || expected->todo_value )
495 ok_(file, line)( !ret, "hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n",
496 expected->hkl, expected->himc, expected->notify.action, expected->notify.index,
497 expected->notify.value );
498 break;
499 case IME_PROCESS_KEY:
500 todo_wine_if( expected->todo || expected->todo_value )
501 ok_(file, line)( !ret, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n",
502 expected->hkl, expected->himc, expected->process_key.vkey, expected->process_key.lparam );
503 break;
504 case IME_TO_ASCII_EX:
505 todo_wine_if( expected->todo || expected->todo_value )
506 ok_(file, line)( !ret, "hkl %p, himc %p, IME_TO_ASCII_EX vkey %#x, vsc %#x, flags %#x\n",
507 expected->hkl, expected->himc, expected->to_ascii_ex.vkey, expected->to_ascii_ex.vsc,
508 expected->to_ascii_ex.flags );
509 break;
510 case IME_SET_ACTIVE_CONTEXT:
511 todo_wine_if( expected->todo || expected->todo_value )
512 ok_(file, line)( !ret, "hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", expected->hkl, expected->himc,
513 expected->set_active_context.flag );
514 break;
515 case MSG_IME_UI:
516 todo_wine_if( expected->todo || expected->todo_value )
517 ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %s, wparam %#Ix, lparam %#Ix\n", expected->hkl,
518 expected->himc, debugstr_wm_ime(expected->message.msg), expected->message.wparam, expected->message.lparam );
519 break;
520 case MSG_TEST_WIN:
521 todo_wine_if( expected->todo || expected->todo_value )
522 ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %s, wparam %#Ix, lparam %#Ix, comp %s, result %s\n", expected->hkl,
523 expected->himc, debugstr_wm_ime(expected->message.msg), expected->message.wparam, expected->message.lparam,
524 debugstr_w(expected->comp), debugstr_w(expected->result) );
525 break;
528 return 0;
531 #define ok_seq( a ) ok_seq_( __FILE__, __LINE__, a, #a )
532 static void ok_seq_( const char *file, int line, const struct ime_call *expected, const char *context )
534 const struct ime_call *received = ime_calls;
535 UINT i = 0, ret;
537 while (expected->func || received->func)
539 winetest_push_context( "%u%s%s", i++, !expected->func ? " (spurious)" : "",
540 !received->func ? " (missing)" : "" );
541 ret = ok_call_( file, line, expected, received );
542 if (ret && expected->todo && expected->func &&
543 !strcmp( winetest_platform, "wine" ))
544 expected++;
545 else if (ret && broken(expected->broken))
546 expected++;
547 else
549 if (expected->func) expected++;
550 if (received->func) received++;
552 winetest_pop_context();
555 memset( ime_calls, 0, sizeof(ime_calls) );
556 ime_call_count = 0;
559 static BOOL check_WM_SHOWWINDOW;
560 static BOOL ignore_IME_NOTIFY;
561 static BOOL ignore_WM_IME_NOTIFY;
562 static BOOL ignore_WM_IME_REQUEST;
564 static BOOL ignore_message( UINT msg, WPARAM wparam )
566 switch (msg)
568 case WM_IME_NOTIFY:
569 if (ignore_WM_IME_NOTIFY) return TRUE;
570 return wparam > IMN_PRIVATE;
571 case WM_IME_REQUEST:
572 if (ignore_WM_IME_REQUEST) return TRUE;
573 return FALSE;
574 case WM_IME_STARTCOMPOSITION:
575 case WM_IME_ENDCOMPOSITION:
576 case WM_IME_COMPOSITION:
577 case WM_IME_SETCONTEXT:
578 case WM_IME_CONTROL:
579 case WM_IME_COMPOSITIONFULL:
580 case WM_IME_SELECT:
581 case WM_IME_CHAR:
582 case 0x287:
583 case WM_IME_KEYDOWN:
584 case WM_IME_KEYUP:
585 return FALSE;
586 case WM_SHOWWINDOW:
587 return !check_WM_SHOWWINDOW;
588 default:
589 return TRUE;
593 static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
595 struct ime_call call =
597 .hkl = GetKeyboardLayout( 0 ), .himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ),
598 .func = MSG_IME_UI, .message = {.msg = msg, .wparam = wparam, .lparam = lparam}
600 LONG_PTR ptr;
602 ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam );
604 if (ignore_message( msg, wparam )) return DefWindowProcW( hwnd, msg, wparam, lparam );
606 ptr = GetWindowLongPtrW( hwnd, IMMGWL_PRIVATE );
607 ok( !ptr, "got IMMGWL_PRIVATE %#Ix\n", ptr );
609 ime_calls[ime_call_count++] = call;
610 return DefWindowProcW( hwnd, msg, wparam, lparam );
613 static LRESULT CALLBACK test_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
615 struct ime_call call =
617 .hkl = GetKeyboardLayout( 0 ), .himc = ImmGetContext( hwnd ),
618 .func = MSG_TEST_WIN, .message = {.msg = msg, .wparam = wparam, .lparam = lparam}
621 ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam );
623 if (ignore_message( msg, wparam )) return DefWindowProcW( hwnd, msg, wparam, lparam );
625 if (msg == WM_IME_COMPOSITION)
627 ImmGetCompositionStringW( call.himc, GCS_COMPSTR, call.comp, sizeof(call.comp) );
628 ImmGetCompositionStringW( call.himc, GCS_RESULTSTR, call.result, sizeof(call.result) );
631 ime_calls[ime_call_count++] = call;
632 return DefWindowProcW( hwnd, msg, wparam, lparam );
635 static WNDCLASSEXW ime_ui_class =
637 .cbSize = sizeof(WNDCLASSEXW),
638 .style = CS_IME,
639 .lpfnWndProc = ime_ui_window_proc,
640 .cbWndExtra = 2 * sizeof(LONG_PTR),
641 .lpszClassName = L"WineTestIME",
644 static WNDCLASSEXW test_class =
646 .cbSize = sizeof(WNDCLASSEXW),
647 .lpfnWndProc = test_window_proc,
648 .lpszClassName = L"WineTest",
652 * msgspy - record and analyse message traces sent to a certain window
654 typedef struct _msgs {
655 CWPSTRUCT msg;
656 BOOL post;
657 } imm_msgs;
659 static struct _msg_spy {
660 HWND hwnd;
661 HHOOK get_msg_hook;
662 HHOOK call_wnd_proc_hook;
663 imm_msgs msgs[64];
664 unsigned int i_msg;
665 } msg_spy;
667 typedef struct
669 DWORD type;
670 union
672 MOUSEINPUT mi;
673 KEYBDINPUT ki;
674 HARDWAREINPUT hi;
675 } u;
676 } TEST_INPUT;
678 static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t);
680 static LRESULT CALLBACK get_msg_filter(int nCode, WPARAM wParam, LPARAM lParam)
682 if (HC_ACTION == nCode) {
683 MSG *msg = (MSG*)lParam;
685 if ((msg->hwnd == msg_spy.hwnd || msg_spy.hwnd == NULL) &&
686 (msg_spy.i_msg < ARRAY_SIZE(msg_spy.msgs)))
688 msg_spy.msgs[msg_spy.i_msg].msg.hwnd = msg->hwnd;
689 msg_spy.msgs[msg_spy.i_msg].msg.message = msg->message;
690 msg_spy.msgs[msg_spy.i_msg].msg.wParam = msg->wParam;
691 msg_spy.msgs[msg_spy.i_msg].msg.lParam = msg->lParam;
692 msg_spy.msgs[msg_spy.i_msg].post = TRUE;
693 msg_spy.i_msg++;
697 return CallNextHookEx(msg_spy.get_msg_hook, nCode, wParam, lParam);
700 static LRESULT CALLBACK call_wnd_proc_filter(int nCode, WPARAM wParam,
701 LPARAM lParam)
703 if (HC_ACTION == nCode) {
704 CWPSTRUCT *cwp = (CWPSTRUCT*)lParam;
706 if (((cwp->hwnd == msg_spy.hwnd || msg_spy.hwnd == NULL)) &&
707 (msg_spy.i_msg < ARRAY_SIZE(msg_spy.msgs)))
709 memcpy(&msg_spy.msgs[msg_spy.i_msg].msg, cwp, sizeof(msg_spy.msgs[0].msg));
710 msg_spy.msgs[msg_spy.i_msg].post = FALSE;
711 msg_spy.i_msg++;
715 return CallNextHookEx(msg_spy.call_wnd_proc_hook, nCode, wParam, lParam);
718 static void msg_spy_pump_msg_queue(void) {
719 MSG msg;
721 while(PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
722 TranslateMessage(&msg);
723 DispatchMessageW(&msg);
726 return;
729 static void msg_spy_flush_msgs(void) {
730 msg_spy_pump_msg_queue();
731 msg_spy.i_msg = 0;
734 static imm_msgs* msg_spy_find_next_msg(UINT message, UINT *start) {
735 UINT i;
737 msg_spy_pump_msg_queue();
739 if (msg_spy.i_msg >= ARRAY_SIZE(msg_spy.msgs))
740 fprintf(stdout, "%s:%d: msg_spy: message buffer overflow!\n",
741 __FILE__, __LINE__);
743 for (i = *start; i < msg_spy.i_msg; i++)
744 if (msg_spy.msgs[i].msg.message == message)
746 *start = i+1;
747 return &msg_spy.msgs[i];
750 return NULL;
753 static imm_msgs* msg_spy_find_msg(UINT message) {
754 UINT i = 0;
756 return msg_spy_find_next_msg(message, &i);
759 static void msg_spy_init(HWND hwnd) {
760 msg_spy.hwnd = hwnd;
761 msg_spy.get_msg_hook =
762 SetWindowsHookExW(WH_GETMESSAGE, get_msg_filter, GetModuleHandleW(NULL),
763 GetCurrentThreadId());
764 msg_spy.call_wnd_proc_hook =
765 SetWindowsHookExW(WH_CALLWNDPROC, call_wnd_proc_filter,
766 GetModuleHandleW(NULL), GetCurrentThreadId());
767 msg_spy.i_msg = 0;
769 msg_spy_flush_msgs();
772 static void msg_spy_cleanup(void) {
773 if (msg_spy.get_msg_hook)
774 UnhookWindowsHookEx(msg_spy.get_msg_hook);
775 if (msg_spy.call_wnd_proc_hook)
776 UnhookWindowsHookEx(msg_spy.call_wnd_proc_hook);
777 memset(&msg_spy, 0, sizeof(msg_spy));
781 * imm32 test cases - Issue some IMM commands on a dummy window and analyse the
782 * messages being sent to this window in response.
784 static const char wndcls[] = "winetest_imm32_wndcls";
785 static enum { PHASE_UNKNOWN, FIRST_WINDOW, SECOND_WINDOW,
786 CREATE_CANCEL, NCCREATE_CANCEL, IME_DISABLED } test_phase;
787 static HWND hwnd, child;
789 static HWND get_ime_window(void);
791 static void load_resource( const WCHAR *name, WCHAR *filename )
793 static WCHAR path[MAX_PATH];
794 DWORD written;
795 HANDLE file;
796 HRSRC res;
797 void *ptr;
799 GetTempPathW( ARRAY_SIZE(path), path );
800 GetTempFileNameW( path, name, 0, filename );
802 file = CreateFileW( filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
803 ok( file != INVALID_HANDLE_VALUE, "failed to create %s, error %lu\n", debugstr_w(filename), GetLastError() );
805 res = FindResourceW( NULL, name, L"TESTDLL" );
806 ok( res != 0, "couldn't find resource\n" );
807 ptr = LockResource( LoadResource( GetModuleHandleW( NULL ), res ) );
808 WriteFile( file, ptr, SizeofResource( GetModuleHandleW( NULL ), res ), &written, NULL );
809 ok( written == SizeofResource( GetModuleHandleW( NULL ), res ), "couldn't write resource\n" );
810 CloseHandle( file );
813 static LRESULT WINAPI wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
815 HWND default_ime_wnd;
816 switch (msg)
818 case WM_IME_SETCONTEXT:
819 if (wParam) CHECK_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
820 else CHECK_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
821 ok(lParam == ISC_SHOWUIALL || !lParam, "lParam = %Ix\n", lParam);
822 return TRUE;
823 case WM_NCCREATE:
824 default_ime_wnd = get_ime_window();
825 switch(test_phase) {
826 case FIRST_WINDOW:
827 case IME_DISABLED:
828 ok(!default_ime_wnd, "expected no IME windows\n");
829 break;
830 case SECOND_WINDOW:
831 ok(default_ime_wnd != NULL, "expected IME window existence\n");
832 break;
833 default:
834 break; /* do nothing */
836 if (test_phase == NCCREATE_CANCEL)
837 return FALSE;
838 return TRUE;
839 case WM_NCCALCSIZE:
840 default_ime_wnd = get_ime_window();
841 switch(test_phase) {
842 case FIRST_WINDOW:
843 case SECOND_WINDOW:
844 case CREATE_CANCEL:
845 ok(default_ime_wnd != NULL, "expected IME window existence\n");
846 break;
847 case IME_DISABLED:
848 ok(!default_ime_wnd, "expected no IME windows\n");
849 break;
850 default:
851 break; /* do nothing */
853 break;
854 case WM_CREATE:
855 default_ime_wnd = get_ime_window();
856 switch(test_phase) {
857 case FIRST_WINDOW:
858 case SECOND_WINDOW:
859 case CREATE_CANCEL:
860 ok(default_ime_wnd != NULL, "expected IME window existence\n");
861 break;
862 case IME_DISABLED:
863 ok(!default_ime_wnd, "expected no IME windows\n");
864 break;
865 default:
866 break; /* do nothing */
868 if (test_phase == CREATE_CANCEL)
869 return -1;
870 return TRUE;
873 return DefWindowProcA(hWnd,msg,wParam,lParam);
876 static BOOL is_ime_enabled(void)
878 HIMC himc;
879 HWND wnd;
881 wnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
882 ok(wnd != NULL, "CreateWindow failed\n");
884 himc = ImmGetContext(wnd);
885 if (!himc)
887 DestroyWindow(wnd);
888 return FALSE;
891 ImmReleaseContext(wnd, himc);
892 DestroyWindow(wnd);
893 return TRUE;
896 static BOOL init(void) {
897 WNDCLASSEXA wc;
898 HMODULE hmod,huser;
900 hmod = GetModuleHandleA("imm32.dll");
901 huser = GetModuleHandleA("user32");
902 pImmAssociateContextEx = (void*)GetProcAddress(hmod, "ImmAssociateContextEx");
903 pImmIsUIMessageA = (void*)GetProcAddress(hmod, "ImmIsUIMessageA");
904 pSendInput = (void*)GetProcAddress(huser, "SendInput");
905 pNtUserAssociateInputContext = (void*)GetProcAddress(GetModuleHandleW(L"win32u.dll"),
906 "NtUserAssociateInputContext");
908 wc.cbSize = sizeof(WNDCLASSEXA);
909 wc.style = 0;
910 wc.lpfnWndProc = wndProc;
911 wc.cbClsExtra = 0;
912 wc.cbWndExtra = 0;
913 wc.hInstance = GetModuleHandleA(NULL);
914 wc.hIcon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
915 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
916 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
917 wc.lpszMenuName = NULL;
918 wc.lpszClassName = wndcls;
919 wc.hIconSm = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
921 if (!RegisterClassExA(&wc))
922 return FALSE;
924 hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
925 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
926 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
927 if (!hwnd)
928 return FALSE;
930 child = CreateWindowA("edit", "edit", WS_CHILD | WS_VISIBLE, 0, 0, 50, 50, hwnd, 0, 0, 0);
931 if (!child)
932 return FALSE;
934 ShowWindow(hwnd, SW_SHOWNORMAL);
935 UpdateWindow(hwnd);
937 msg_spy_init(hwnd);
939 return TRUE;
942 static void cleanup(void) {
943 msg_spy_cleanup();
944 if (hwnd)
945 DestroyWindow(hwnd);
946 UnregisterClassA(wndcls, GetModuleHandleW(NULL));
949 static void test_ImmNotifyIME(void) {
950 static const char string[] = "wine";
951 char resstr[16] = "";
952 HIMC imc;
953 BOOL ret;
955 imc = ImmGetContext(hwnd);
956 msg_spy_flush_msgs();
958 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
959 ok(broken(!ret) ||
960 ret, /* Vista+ */
961 "Canceling an empty composition string should succeed.\n");
962 ok(!msg_spy_find_msg(WM_IME_COMPOSITION), "Windows does not post "
963 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
964 "the composition string being canceled is empty.\n");
966 ImmSetCompositionStringA(imc, SCS_SETSTR, string, sizeof(string), NULL, 0);
967 msg_spy_flush_msgs();
969 ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
970 msg_spy_flush_msgs();
972 /* behavior differs between win9x and NT */
973 ret = ImmGetCompositionStringA(imc, GCS_COMPSTR, resstr, sizeof(resstr));
974 ok(!ret, "After being cancelled the composition string is empty.\n");
976 msg_spy_flush_msgs();
978 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
979 ok(broken(!ret) ||
980 ret, /* Vista+ */
981 "Canceling an empty composition string should succeed.\n");
982 ok(!msg_spy_find_msg(WM_IME_COMPOSITION), "Windows does not post "
983 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
984 "the composition string being canceled is empty.\n");
986 msg_spy_flush_msgs();
987 ImmReleaseContext(hwnd, imc);
989 imc = ImmCreateContext();
990 ImmDestroyContext(imc);
992 SetLastError(0xdeadbeef);
993 ret = ImmNotifyIME((HIMC)0xdeadcafe, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
994 ok (ret == 0, "Bad IME should return 0\n");
995 ret = GetLastError();
996 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
997 SetLastError(0xdeadbeef);
998 ret = ImmNotifyIME(0x00000000, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
999 ok (ret == 0, "NULL IME should return 0\n");
1000 ret = GetLastError();
1001 ok(ret == ERROR_SUCCESS, "wrong last error %08x!\n", ret);
1002 SetLastError(0xdeadbeef);
1003 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
1004 ok (ret == 0, "Destroyed IME should return 0\n");
1005 ret = GetLastError();
1006 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
1010 static struct {
1011 WNDPROC old_wnd_proc;
1012 BOOL catch_result_str;
1013 BOOL catch_ime_char;
1014 DWORD start;
1015 DWORD timer_id;
1016 } ime_composition_test;
1018 static LRESULT WINAPI test_ime_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1020 switch (msg)
1022 case WM_IME_COMPOSITION:
1023 if ((lParam & GCS_RESULTSTR) && !ime_composition_test.catch_result_str) {
1024 HWND hwndIme;
1025 WCHAR wstring[20];
1026 HIMC imc;
1027 LONG size;
1028 LRESULT ret;
1030 hwndIme = ImmGetDefaultIMEWnd(hWnd);
1031 ok(hwndIme != NULL, "expected IME window existence\n");
1033 ok(!ime_composition_test.catch_ime_char, "WM_IME_CHAR is sent\n");
1034 ret = CallWindowProcA(ime_composition_test.old_wnd_proc,
1035 hWnd, msg, wParam, lParam);
1036 ok(ime_composition_test.catch_ime_char, "WM_IME_CHAR isn't sent\n");
1038 ime_composition_test.catch_ime_char = FALSE;
1039 SendMessageA(hwndIme, msg, wParam, lParam);
1040 ok(!ime_composition_test.catch_ime_char, "WM_IME_CHAR is sent\n");
1042 imc = ImmGetContext(hWnd);
1043 size = ImmGetCompositionStringW(imc, GCS_RESULTSTR,
1044 wstring, sizeof(wstring));
1045 ok(size > 0, "ImmGetCompositionString(GCS_RESULTSTR) is %ld\n", size);
1046 ImmReleaseContext(hwnd, imc);
1048 ime_composition_test.catch_result_str = TRUE;
1049 return ret;
1051 break;
1052 case WM_IME_CHAR:
1053 if (!ime_composition_test.catch_result_str)
1054 ime_composition_test.catch_ime_char = TRUE;
1055 break;
1056 case WM_TIMER:
1057 if (wParam == ime_composition_test.timer_id) {
1058 HWND parent = GetParent(hWnd);
1059 char title[64];
1060 int left = 20 - (GetTickCount() - ime_composition_test.start) / 1000;
1061 wsprintfA(title, "%sLeft %d sec. - IME composition test",
1062 ime_composition_test.catch_result_str ? "[*] " : "", left);
1063 SetWindowTextA(parent, title);
1064 if (left <= 0)
1065 DestroyWindow(parent);
1066 else
1067 SetTimer(hWnd, wParam, 100, NULL);
1068 return TRUE;
1070 break;
1072 return CallWindowProcA(ime_composition_test.old_wnd_proc,
1073 hWnd, msg, wParam, lParam);
1076 static void test_SCS_SETSTR(void)
1078 HIMC imc;
1079 static const WCHAR string[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e};
1080 char cstring[20];
1081 WCHAR wstring[20];
1082 LONG len;
1083 LONG alen,wlen;
1084 BOOL ret;
1085 DWORD prop;
1087 imc = ImmGetContext(hwnd);
1088 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, string, sizeof(string), NULL, 0);
1089 if (!ret) {
1090 win_skip("Composition isn't supported\n");
1091 ImmReleaseContext(hwnd, imc);
1092 return;
1095 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, NULL, 128, NULL, 128);
1096 ok(ret, "got error %lu.\n", GetLastError());
1098 alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20);
1099 ok(!alen, "got %ld.\n", alen);
1100 wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 20);
1101 ok(!wlen, "got %ld.\n", alen);
1103 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, string, sizeof(string), NULL, 2);
1104 ok(ret, "got error %lu.\n", GetLastError());
1106 msg_spy_flush_msgs();
1108 alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20);
1109 wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 20);
1110 /* windows machines without any IME installed just return 0 above */
1111 if( alen && wlen)
1113 len = ImmGetCompositionStringW(imc, GCS_COMPATTR, NULL, 0);
1114 ok(len*sizeof(WCHAR)==wlen,"GCS_COMPATTR(W) not returning correct count\n");
1115 len = ImmGetCompositionStringA(imc, GCS_COMPATTR, NULL, 0);
1116 ok(len==alen,"GCS_COMPATTR(A) not returning correct count\n");
1118 /* Get strings with exactly matching buffer sizes. */
1119 memset(wstring, 0x1a, sizeof(wstring));
1120 memset(cstring, 0x1a, sizeof(cstring));
1122 len = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, alen);
1123 ok(len == alen, "Unexpected length %ld.\n", len);
1124 ok(cstring[alen] == 0x1a, "Unexpected buffer contents.\n");
1126 len = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, wlen);
1127 ok(len == wlen, "Unexpected length %ld.\n", len);
1128 ok(wstring[wlen/sizeof(WCHAR)] == 0x1a1a, "Unexpected buffer contents.\n");
1130 /* Get strings with exactly smaller buffer sizes. */
1131 memset(wstring, 0x1a, sizeof(wstring));
1132 memset(cstring, 0x1a, sizeof(cstring));
1134 /* Returns 0 but still fills buffer. */
1135 len = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, alen - 1);
1136 ok(!len, "Unexpected length %ld.\n", len);
1137 ok(cstring[0] == 'w', "Unexpected buffer contents %s.\n", cstring);
1139 len = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, wlen - 1);
1140 ok(len == wlen - 1, "Unexpected length %ld.\n", len);
1141 ok(!memcmp(wstring, string, wlen - 1), "Unexpected buffer contents.\n");
1143 /* Get the size of the required output buffer. */
1144 memset(wstring, 0x1a, sizeof(wstring));
1145 memset(cstring, 0x1a, sizeof(cstring));
1147 len = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 0);
1148 ok(len == alen, "Unexpected length %ld.\n", len);
1149 ok(cstring[0] == 0x1a, "Unexpected buffer contents %s.\n", cstring);
1151 len = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 0);
1152 ok(len == wlen, "Unexpected length %ld.\n", len);
1153 ok(wstring[0] == 0x1a1a, "Unexpected buffer contents.\n");
1155 else
1156 win_skip("Composition string isn't available\n");
1158 ImmReleaseContext(hwnd, imc);
1160 /* Test composition results input by IMM API */
1161 prop = ImmGetProperty(GetKeyboardLayout(0), IGP_SETCOMPSTR);
1162 if (!(prop & SCS_CAP_COMPSTR)) {
1163 /* Wine's IME doesn't support SCS_SETSTR in ImmSetCompositionString */
1164 skip("This IME doesn't support SCS_SETSTR\n");
1166 else {
1167 ime_composition_test.old_wnd_proc =
1168 (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
1169 (LONG_PTR)test_ime_wnd_proc);
1170 imc = ImmGetContext(hwnd);
1171 msg_spy_flush_msgs();
1173 ret = ImmSetCompositionStringW(imc, SCS_SETSTR,
1174 string, sizeof(string), NULL,0);
1175 ok(ret, "ImmSetCompositionStringW failed\n");
1176 wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR,
1177 wstring, sizeof(wstring));
1178 if (wlen > 0) {
1179 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
1180 ok(ret, "ImmNotifyIME(CPS_COMPLETE) failed\n");
1181 msg_spy_flush_msgs();
1182 ok(ime_composition_test.catch_result_str,
1183 "WM_IME_COMPOSITION(GCS_RESULTSTR) isn't sent\n");
1185 else
1186 win_skip("Composition string isn't available\n");
1187 ImmReleaseContext(hwnd, imc);
1188 SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
1189 (LONG_PTR)ime_composition_test.old_wnd_proc);
1190 msg_spy_flush_msgs();
1193 /* Test composition results input by hand */
1194 memset(&ime_composition_test, 0, sizeof(ime_composition_test));
1195 if (winetest_interactive) {
1196 HWND hwndMain, hwndChild;
1197 MSG msg;
1198 const DWORD MY_TIMER = 0xcaffe;
1200 hwndMain = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls,
1201 "IME composition test",
1202 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1203 CW_USEDEFAULT, CW_USEDEFAULT, 320, 160,
1204 NULL, NULL, GetModuleHandleA(NULL), NULL);
1205 hwndChild = CreateWindowExA(0, "static",
1206 "Input a DBCS character here using IME.",
1207 WS_CHILD | WS_VISIBLE,
1208 0, 0, 320, 100, hwndMain, NULL,
1209 GetModuleHandleA(NULL), NULL);
1211 ime_composition_test.old_wnd_proc =
1212 (WNDPROC)SetWindowLongPtrA(hwndChild, GWLP_WNDPROC,
1213 (LONG_PTR)test_ime_wnd_proc);
1215 SetFocus(hwndChild);
1217 ime_composition_test.timer_id = MY_TIMER;
1218 ime_composition_test.start = GetTickCount();
1219 SetTimer(hwndChild, ime_composition_test.timer_id, 100, NULL);
1220 while (GetMessageA(&msg, NULL, 0, 0)) {
1221 TranslateMessage(&msg);
1222 DispatchMessageA(&msg);
1223 if (!IsWindow(hwndMain))
1224 break;
1226 if (!ime_composition_test.catch_result_str)
1227 skip("WM_IME_COMPOSITION(GCS_RESULTSTR) isn't tested\n");
1228 msg_spy_flush_msgs();
1231 SetLastError(0xdeadbeef);
1232 imc = ImmGetContext(hwnd);
1233 ok(imc != 0, "ImmGetContext() failed. Last error: %lu\n", GetLastError());
1234 if (!imc)
1235 return;
1237 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, NULL, 0, NULL, 0);
1238 ok(broken(!ret) ||
1239 ret, /* Vista+ */
1240 "ImmSetCompositionStringW() failed.\n");
1242 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR,
1243 NULL, 0, NULL, 0);
1244 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
1246 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGECLAUSE,
1247 NULL, 0, NULL, 0);
1248 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
1250 ret = ImmSetCompositionStringW(imc, SCS_CHANGEATTR | SCS_CHANGECLAUSE,
1251 NULL, 0, NULL, 0);
1252 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
1254 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR | SCS_CHANGECLAUSE,
1255 NULL, 0, NULL, 0);
1256 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
1258 ImmReleaseContext(hwnd, imc);
1261 static void test_ImmIME(void)
1263 HIMC imc;
1265 imc = ImmGetContext(hwnd);
1266 if (imc)
1268 BOOL rc;
1269 rc = ImmConfigureIMEA(imc, NULL, IME_CONFIG_REGISTERWORD, NULL);
1270 ok (rc == 0, "ImmConfigureIMEA did not fail\n");
1271 rc = ImmConfigureIMEW(imc, NULL, IME_CONFIG_REGISTERWORD, NULL);
1272 ok (rc == 0, "ImmConfigureIMEW did not fail\n");
1274 ImmReleaseContext(hwnd,imc);
1277 static void test_ImmAssociateContextEx(void)
1279 HIMC imc;
1280 BOOL rc;
1282 if (!pImmAssociateContextEx) return;
1284 imc = ImmGetContext(hwnd);
1285 if (imc)
1287 HIMC retimc, newimc;
1288 HWND focus;
1290 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, TRUE);
1291 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, TRUE);
1293 ok(GetActiveWindow() == hwnd, "hwnd is not active\n");
1294 newimc = ImmCreateContext();
1295 ok(newimc != imc, "handles should not be the same\n");
1296 rc = pImmAssociateContextEx(NULL, NULL, 0);
1297 ok(!rc, "ImmAssociateContextEx succeeded\n");
1298 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
1299 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
1300 rc = pImmAssociateContextEx(hwnd, NULL, 0);
1301 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE);
1302 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE);
1303 ok(rc, "ImmAssociateContextEx failed\n");
1304 rc = pImmAssociateContextEx(NULL, imc, 0);
1305 ok(!rc, "ImmAssociateContextEx succeeded\n");
1307 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
1308 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
1309 rc = pImmAssociateContextEx(hwnd, imc, 0);
1310 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE);
1311 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE);
1312 ok(rc, "ImmAssociateContextEx failed\n");
1313 retimc = ImmGetContext(hwnd);
1314 ok(retimc == imc, "handles should be the same\n");
1315 ImmReleaseContext(hwnd,retimc);
1317 rc = pImmAssociateContextEx(hwnd, imc, 0);
1318 ok(rc, "ImmAssociateContextEx failed\n");
1320 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
1321 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
1322 rc = pImmAssociateContextEx(hwnd, newimc, 0);
1323 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE);
1324 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE);
1325 ok(rc, "ImmAssociateContextEx failed\n");
1326 retimc = ImmGetContext(hwnd);
1327 ok(retimc == newimc, "handles should be the same\n");
1328 ImmReleaseContext(hwnd,retimc);
1330 focus = CreateWindowA("button", "button", 0, 0, 0, 0, 0, 0, 0, 0, 0);
1331 ok(focus != NULL, "CreateWindow failed\n");
1332 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
1333 SetFocus(focus);
1334 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE);
1335 rc = pImmAssociateContextEx(hwnd, imc, 0);
1336 ok(rc, "ImmAssociateContextEx failed\n");
1337 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
1338 DestroyWindow(focus);
1339 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE);
1341 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
1342 SetFocus(child);
1343 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE);
1344 rc = pImmAssociateContextEx(hwnd, newimc, 0);
1345 ok(rc, "ImmAssociateContextEx failed\n");
1346 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
1347 SetFocus(hwnd);
1348 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE);
1350 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
1351 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
1352 rc = pImmAssociateContextEx(hwnd, NULL, IACE_DEFAULT);
1353 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE);
1354 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE);
1355 ok(rc, "ImmAssociateContextEx failed\n");
1357 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, FALSE);
1358 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, FALSE);
1360 ImmReleaseContext(hwnd,imc);
1363 /* similar to above, but using NtUserAssociateInputContext */
1364 static void test_NtUserAssociateInputContext(void)
1366 HIMC imc;
1367 UINT rc;
1369 if (!pNtUserAssociateInputContext)
1371 win_skip("NtUserAssociateInputContext not available\n");
1372 return;
1375 imc = ImmGetContext(hwnd);
1376 if (imc)
1378 HIMC retimc, newimc;
1379 HWND focus;
1381 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, TRUE);
1382 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, TRUE);
1384 ok(GetActiveWindow() == hwnd, "hwnd is not active\n");
1385 newimc = ImmCreateContext();
1386 ok(newimc != imc, "handles should not be the same\n");
1387 rc = pNtUserAssociateInputContext(NULL, NULL, 0);
1388 ok(rc == 2, "NtUserAssociateInputContext returned %x\n", rc);
1389 rc = pNtUserAssociateInputContext(hwnd, NULL, 0);
1390 ok(rc == 1, "NtUserAssociateInputContext returned %x\n", rc);
1391 rc = pNtUserAssociateInputContext(NULL, imc, 0);
1392 ok(rc == 2, "NtUserAssociateInputContext returned %x\n", rc);
1394 rc = pNtUserAssociateInputContext(hwnd, imc, 0);
1395 ok(rc == 1, "NtUserAssociateInputContext returned %x\n", rc);
1396 retimc = ImmGetContext(hwnd);
1397 ok(retimc == imc, "handles should be the same\n");
1398 ImmReleaseContext(hwnd,retimc);
1400 rc = pNtUserAssociateInputContext(hwnd, imc, 0);
1401 ok(rc == 0, "NtUserAssociateInputContext returned %x\n", rc);
1403 rc = pNtUserAssociateInputContext(hwnd, newimc, 0);
1404 ok(rc == 1, "NtUserAssociateInputContext returned %x\n", rc);
1405 retimc = ImmGetContext(hwnd);
1406 ok(retimc == newimc, "handles should be the same\n");
1407 ImmReleaseContext(hwnd,retimc);
1409 focus = CreateWindowA("button", "button", 0, 0, 0, 0, 0, 0, 0, 0, 0);
1410 ok(focus != NULL, "CreateWindow failed\n");
1411 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
1412 SetFocus(focus);
1413 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE);
1414 rc = pNtUserAssociateInputContext(hwnd, imc, 0);
1415 ok(rc == 0, "NtUserAssociateInputContext returned %x\n", rc);
1416 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
1417 DestroyWindow(focus);
1418 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE);
1420 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
1421 SetFocus(child);
1422 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE);
1423 rc = pNtUserAssociateInputContext(hwnd, newimc, 0);
1424 ok(rc == 0, "NtUserAssociateInputContext returned %x\n", rc);
1425 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE);
1426 SetFocus(hwnd);
1427 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE);
1429 rc = pNtUserAssociateInputContext(hwnd, NULL, IACE_DEFAULT);
1430 ok(rc == 1, "NtUserAssociateInputContext returned %x\n", rc);
1432 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, FALSE);
1433 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, FALSE);
1435 ImmReleaseContext(hwnd,imc);
1438 struct test_cross_thread_himc_params
1440 HWND hwnd;
1441 HANDLE event;
1442 HIMC himc[2];
1443 INPUTCONTEXT *contexts[2];
1446 static DWORD WINAPI test_cross_thread_himc_thread( void *arg )
1448 CANDIDATEFORM candidate = {.dwIndex = 1, .dwStyle = CFS_CANDIDATEPOS};
1449 struct test_cross_thread_himc_params *params = arg;
1450 COMPOSITIONFORM composition = {0};
1451 INPUTCONTEXT *contexts[2];
1452 HIMC himc[2], tmp_himc;
1453 LOGFONTW fontW = {0};
1454 HWND hwnd, tmp_hwnd;
1455 POINT pos = {0};
1456 MSG msg;
1458 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1459 100, 100, 100, 100, NULL, NULL, NULL, NULL );
1460 ok_ne( NULL, hwnd, HWND, "%p" );
1461 himc[0] = ImmGetContext( hwnd );
1462 ok_ne( NULL, himc[0], HIMC, "%p" );
1463 contexts[0] = ImmLockIMC( himc[0] );
1464 ok_ne( NULL, contexts[0], INPUTCONTEXT *, "%p" );
1465 contexts[0]->hWnd = hwnd;
1467 tmp_hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1468 100, 100, 100, 100, NULL, NULL, NULL, NULL );
1469 tmp_himc = ImmGetContext( tmp_hwnd );
1470 ok_eq( himc[0], tmp_himc, HIMC, "%p" );
1471 ok_ret( 1, ImmReleaseContext( tmp_hwnd, tmp_himc ) );
1472 ok_ret( 1, DestroyWindow( tmp_hwnd ) );
1474 himc[1] = ImmCreateContext();
1475 ok_ne( NULL, himc[1], HIMC, "%p" );
1476 contexts[1] = ImmLockIMC( himc[1] );
1477 ok_ne( NULL, contexts[1], INPUTCONTEXT *, "%p" );
1478 contexts[1]->hWnd = hwnd;
1480 ok_ret( 1, ImmSetOpenStatus( himc[0], 0xdeadbeef ) );
1481 ok_ret( 1, ImmSetOpenStatus( himc[1], 0xfeedcafe ) );
1482 ok_ret( 1, ImmSetCompositionWindow( himc[0], &composition ) );
1483 ok_ret( 1, ImmSetCompositionWindow( himc[1], &composition ) );
1484 ok_ret( 1, ImmSetCandidateWindow( himc[0], &candidate ) );
1485 ok_ret( 1, ImmSetCandidateWindow( himc[1], &candidate ) );
1486 ok_ret( 1, ImmSetStatusWindowPos( himc[0], &pos ) );
1487 ok_ret( 1, ImmSetStatusWindowPos( himc[1], &pos ) );
1488 ok_ret( 1, ImmSetCompositionFontW( himc[0], &fontW ) );
1489 ok_ret( 1, ImmSetCompositionFontW( himc[1], &fontW ) );
1491 params->hwnd = hwnd;
1492 params->himc[0] = himc[0];
1493 params->himc[1] = himc[1];
1494 params->contexts[0] = contexts[0];
1495 params->contexts[1] = contexts[1];
1496 SetEvent( params->event );
1498 while (GetMessageW( &msg, 0, 0, 0 ))
1500 TranslateMessage( &msg );
1501 DispatchMessageW( &msg );
1504 ok_ret( 1, ImmUnlockIMC( himc[0] ) );
1505 ok_ret( 1, ImmUnlockIMC( himc[1] ) );
1507 ok_ret( 1, ImmDestroyContext( himc[1] ) );
1508 ok_ret( 1, ImmReleaseContext( hwnd, himc[0] ) );
1509 ok_ret( 0, DestroyWindow( hwnd ) );
1511 return 1;
1514 static void test_cross_thread_himc(void)
1516 static const WCHAR comp_string[] = L"CompString";
1517 RECONVERTSTRING reconv = {.dwSize = sizeof(RECONVERTSTRING)};
1518 struct test_cross_thread_himc_params params;
1519 COMPOSITIONFORM composition = {0};
1520 DWORD tid, conversion, sentence;
1521 IMECHARPOSITION char_pos = {0};
1522 CANDIDATEFORM candidate = {0};
1523 COMPOSITIONSTRING *string;
1524 HIMC himc[2], tmp_himc;
1525 INPUTCONTEXT *tmp_ctx;
1526 LOGFONTW fontW = {0};
1527 LOGFONTA fontA = {0};
1528 char buffer[512];
1529 POINT pos = {0};
1530 HANDLE thread;
1531 BYTE *dst;
1532 UINT ret;
1534 himc[0] = ImmGetContext( hwnd );
1535 ok_ne( NULL, himc[0], HIMC, "%p" );
1536 ok_ne( NULL, ImmLockIMC( himc[0] ), INPUTCONTEXT *, "%p" );
1537 ok_ret( 1, ImmUnlockIMC( himc[0] ) );
1539 params.event = CreateEventW(NULL, TRUE, FALSE, NULL);
1540 ok_ne( NULL, params.event, HANDLE, "%p" );
1541 thread = CreateThread( NULL, 0, test_cross_thread_himc_thread, &params, 0, &tid );
1542 ok_ne( NULL, thread, HANDLE, "%p" );
1543 WaitForSingleObject( params.event, INFINITE );
1545 memset( ime_calls, 0, sizeof(ime_calls) );
1546 ime_call_count = 0;
1548 tmp_himc = ImmGetContext( params.hwnd );
1549 ok_ne( himc[0], tmp_himc, HIMC, "%p" );
1550 ok_eq( params.himc[0], tmp_himc, HIMC, "%p" );
1551 ok_ret( 1, ImmReleaseContext( params.hwnd, tmp_himc ) );
1553 himc[1] = ImmCreateContext();
1554 ok_ne( NULL, himc[1], HIMC, "%p" );
1555 tmp_ctx = ImmLockIMC( himc[1] );
1556 ok_ne( NULL, tmp_ctx, INPUTCONTEXT *, "%p" );
1558 tmp_ctx->hCompStr = ImmReSizeIMCC( tmp_ctx->hCompStr, 512 );
1559 ok_ne( NULL, tmp_ctx->hCompStr, HIMCC, "%p" );
1560 string = ImmLockIMCC( tmp_ctx->hCompStr );
1561 ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" );
1562 string->dwSize = sizeof(COMPOSITIONSTRING);
1563 string->dwCompStrLen = wcslen( comp_string );
1564 string->dwCompStrOffset = string->dwSize;
1565 dst = (BYTE *)string + string->dwCompStrOffset;
1566 memcpy( dst, comp_string, string->dwCompStrLen * sizeof(WCHAR) );
1567 string->dwSize += string->dwCompStrLen * sizeof(WCHAR);
1569 string->dwCompClauseLen = 2 * sizeof(DWORD);
1570 string->dwCompClauseOffset = string->dwSize;
1571 dst = (BYTE *)string + string->dwCompClauseOffset;
1572 *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0;
1573 *(DWORD *)(dst + 1 * sizeof(DWORD)) = string->dwCompStrLen;
1574 string->dwSize += 2 * sizeof(DWORD);
1576 string->dwCompAttrLen = string->dwCompStrLen;
1577 string->dwCompAttrOffset = string->dwSize;
1578 dst = (BYTE *)string + string->dwCompAttrOffset;
1579 memset( dst, ATTR_INPUT, string->dwCompStrLen );
1580 string->dwSize += string->dwCompStrLen;
1581 ok_ret( 0, ImmUnlockIMCC( tmp_ctx->hCompStr ) );
1583 ok_ret( 1, ImmUnlockIMC( himc[1] ) );
1585 /* ImmLockIMC should succeed with cross thread HIMC */
1587 tmp_ctx = ImmLockIMC( params.himc[0] );
1588 ok_eq( params.contexts[0], tmp_ctx, INPUTCONTEXT *, "%p" );
1589 ret = ImmGetIMCLockCount( params.himc[0] );
1590 ok( ret >= 2, "got ret %u\n", ret );
1592 tmp_ctx->hCompStr = ImmReSizeIMCC( tmp_ctx->hCompStr, 512 );
1593 ok_ne( NULL, tmp_ctx->hCompStr, HIMCC, "%p" );
1594 string = ImmLockIMCC( tmp_ctx->hCompStr );
1595 ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" );
1596 string->dwSize = sizeof(COMPOSITIONSTRING);
1597 string->dwCompStrLen = wcslen( comp_string );
1598 string->dwCompStrOffset = string->dwSize;
1599 dst = (BYTE *)string + string->dwCompStrOffset;
1600 memcpy( dst, comp_string, string->dwCompStrLen * sizeof(WCHAR) );
1601 string->dwSize += string->dwCompStrLen * sizeof(WCHAR);
1603 string->dwCompClauseLen = 2 * sizeof(DWORD);
1604 string->dwCompClauseOffset = string->dwSize;
1605 dst = (BYTE *)string + string->dwCompClauseOffset;
1606 *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0;
1607 *(DWORD *)(dst + 1 * sizeof(DWORD)) = string->dwCompStrLen;
1608 string->dwSize += 2 * sizeof(DWORD);
1610 string->dwCompAttrLen = string->dwCompStrLen;
1611 string->dwCompAttrOffset = string->dwSize;
1612 dst = (BYTE *)string + string->dwCompAttrOffset;
1613 memset( dst, ATTR_INPUT, string->dwCompStrLen );
1614 string->dwSize += string->dwCompStrLen;
1615 ok_ret( 0, ImmUnlockIMCC( tmp_ctx->hCompStr ) );
1617 ok_ret( 1, ImmUnlockIMC( params.himc[0] ) );
1619 tmp_ctx = ImmLockIMC( params.himc[1] );
1620 ok_eq( params.contexts[1], tmp_ctx, INPUTCONTEXT *, "%p" );
1621 ret = ImmGetIMCLockCount( params.himc[1] );
1622 ok( ret >= 2, "got ret %u\n", ret );
1623 ok_ret( 1, ImmUnlockIMC( params.himc[1] ) );
1625 /* ImmSetActiveContext should succeed with cross thread HIMC */
1627 SET_ENABLE( WM_IME_SETCONTEXT_DEACTIVATE, TRUE );
1628 SET_ENABLE( WM_IME_SETCONTEXT_ACTIVATE, TRUE );
1630 SET_EXPECT( WM_IME_SETCONTEXT_ACTIVATE );
1631 ok_ret( 1, ImmSetActiveContext( hwnd, params.himc[0], TRUE ) );
1632 CHECK_CALLED( WM_IME_SETCONTEXT_ACTIVATE );
1634 SET_EXPECT( WM_IME_SETCONTEXT_DEACTIVATE );
1635 ok_ret( 1, ImmSetActiveContext( hwnd, params.himc[0], FALSE ) );
1636 CHECK_CALLED( WM_IME_SETCONTEXT_DEACTIVATE );
1638 SET_ENABLE( WM_IME_SETCONTEXT_DEACTIVATE, FALSE );
1639 SET_ENABLE( WM_IME_SETCONTEXT_ACTIVATE, FALSE );
1641 /* ImmSetOpenStatus should fail with cross thread HIMC */
1643 ok_ret( 1, ImmSetOpenStatus( himc[1], 0xdeadbeef ) );
1644 ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( himc[1] ) );
1646 ok_ret( 0, ImmSetOpenStatus( params.himc[0], TRUE ) );
1647 ok_ret( 0, ImmSetOpenStatus( params.himc[1], TRUE ) );
1648 ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( params.himc[0] ) );
1649 ok_ret( (int)0xfeedcafe, ImmGetOpenStatus( params.himc[1] ) );
1650 ok_ret( 0, ImmSetOpenStatus( params.himc[0], FALSE ) );
1651 ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( params.himc[0] ) );
1653 /* ImmSetConversionStatus should fail with cross thread HIMC */
1655 ok_ret( 1, ImmGetConversionStatus( himc[1], &conversion, &sentence ) );
1656 ok_ret( 1, ImmSetConversionStatus( himc[1], conversion, sentence ) );
1658 ok_ret( 1, ImmGetConversionStatus( params.himc[0], &conversion, &sentence ) );
1659 ok_ret( 1, ImmGetConversionStatus( params.himc[1], &conversion, &sentence ) );
1660 ok_ret( 0, ImmSetConversionStatus( params.himc[0], conversion, sentence ) );
1661 ok_ret( 0, ImmSetConversionStatus( params.himc[1], conversion, sentence ) );
1663 /* ImmSetCompositionFont(W|A) should fail with cross thread HIMC */
1665 ok_ret( 1, ImmSetCompositionFontA( himc[1], &fontA ) );
1666 ok_ret( 1, ImmGetCompositionFontA( himc[1], &fontA ) );
1667 ok_ret( 1, ImmSetCompositionFontW( himc[1], &fontW ) );
1668 ok_ret( 1, ImmGetCompositionFontW( himc[1], &fontW ) );
1670 ok_ret( 0, ImmSetCompositionFontA( params.himc[0], &fontA ) );
1671 ok_ret( 0, ImmSetCompositionFontA( params.himc[1], &fontA ) );
1672 ok_ret( 1, ImmGetCompositionFontA( params.himc[0], &fontA ) );
1673 ok_ret( 1, ImmGetCompositionFontA( params.himc[1], &fontA ) );
1674 ok_ret( 0, ImmSetCompositionFontW( params.himc[0], &fontW ) );
1675 ok_ret( 0, ImmSetCompositionFontW( params.himc[1], &fontW ) );
1676 ok_ret( 1, ImmGetCompositionFontW( params.himc[0], &fontW ) );
1677 ok_ret( 1, ImmGetCompositionFontW( params.himc[1], &fontW ) );
1679 /* ImmRequestMessage(W|A) should fail with cross thread HIMC */
1681 ok_ret( 0, ImmRequestMessageW( himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) );
1682 ok_ret( 0, ImmRequestMessageA( himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) );
1684 ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) );
1685 ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) );
1686 ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) );
1687 ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) );
1689 ok_seq( empty_sequence );
1691 /* ImmSetCompositionString(W|A) should fail with cross thread HIMC */
1693 ok_ret( 10, ImmGetCompositionStringA( himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) );
1694 ok_ret( 20, ImmGetCompositionStringW( himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) );
1695 ok_ret( 1, ImmSetCompositionStringA( himc[1], SCS_SETSTR, "a", 2, NULL, 0 ) );
1696 ok_ret( 1, ImmSetCompositionStringW( himc[1], SCS_SETSTR, L"a", 4, NULL, 0 ) );
1698 ok_ret( 0, ImmSetCompositionStringA( params.himc[0], SCS_SETSTR, "a", 2, NULL, 0 ) );
1699 ok_ret( 0, ImmSetCompositionStringA( params.himc[1], SCS_SETSTR, "a", 2, NULL, 0 ) );
1700 ok_ret( 0, ImmSetCompositionStringW( params.himc[0], SCS_SETSTR, L"a", 4, NULL, 0 ) );
1701 ok_ret( 0, ImmSetCompositionStringW( params.himc[1], SCS_SETSTR, L"a", 4, NULL, 0 ) );
1702 ok_ret( 10, ImmGetCompositionStringA( params.himc[0], GCS_COMPSTR, buffer, sizeof(buffer) ) );
1703 ok_ret( 0, ImmGetCompositionStringA( params.himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) );
1704 ok_ret( 20, ImmGetCompositionStringW( params.himc[0], GCS_COMPSTR, buffer, sizeof(buffer) ) );
1705 ok_ret( 0, ImmGetCompositionStringW( params.himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) );
1707 /* ImmRequestMessage(W|A) should fail with cross thread HIMC */
1709 ok_ret( 0, ImmRequestMessageW( himc[1], IMR_RECONVERTSTRING, 0 ) );
1710 ok_ret( 0, ImmRequestMessageW( himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) );
1711 ok_ret( 0, ImmRequestMessageA( himc[1], IMR_RECONVERTSTRING, 0 ) );
1712 ok_ret( 0, ImmRequestMessageA( himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) );
1714 ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_RECONVERTSTRING, 0 ) );
1715 ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_RECONVERTSTRING, (LPARAM)&reconv ) );
1716 ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_RECONVERTSTRING, 0 ) );
1717 ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_RECONVERTSTRING, (LPARAM)&reconv ) );
1718 ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_RECONVERTSTRING, 0 ) );
1719 ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) );
1720 ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_RECONVERTSTRING, 0 ) );
1721 ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) );
1723 ok_ret( 0, ImmRequestMessageW( himc[1], IMR_DOCUMENTFEED, 0 ) );
1724 ok_ret( 0, ImmRequestMessageW( himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) );
1725 ok_ret( 0, ImmRequestMessageA( himc[1], IMR_DOCUMENTFEED, 0 ) );
1726 ok_ret( 0, ImmRequestMessageA( himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) );
1728 ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_DOCUMENTFEED, 0 ) );
1729 ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_DOCUMENTFEED, (LPARAM)&reconv ) );
1730 ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_DOCUMENTFEED, 0 ) );
1731 ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_DOCUMENTFEED, (LPARAM)&reconv ) );
1732 ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_DOCUMENTFEED, 0 ) );
1733 ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) );
1734 ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_DOCUMENTFEED, 0 ) );
1735 ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) );
1737 ok_ret( 0, ImmRequestMessageW( himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) );
1738 ok_ret( 0, ImmRequestMessageA( himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) );
1740 ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) );
1741 ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) );
1742 ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) );
1743 ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) );
1745 ok_seq( empty_sequence );
1747 /* ImmSetCompositionWindow should fail with cross thread HIMC */
1749 ok_ret( 1, ImmSetCompositionWindow( himc[1], &composition ) );
1750 ok_ret( 1, ImmGetCompositionWindow( himc[1], &composition ) );
1752 ok_ret( 0, ImmSetCompositionWindow( params.himc[0], &composition ) );
1753 ok_ret( 0, ImmSetCompositionWindow( params.himc[1], &composition ) );
1754 ok_ret( 1, ImmGetCompositionWindow( params.himc[0], &composition ) );
1755 ok_ret( 1, ImmGetCompositionWindow( params.himc[1], &composition ) );
1757 /* ImmRequestMessage(W|A) should fail with cross thread HIMC */
1759 ok_ret( 0, ImmRequestMessageW( himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) );
1760 ok_ret( 0, ImmRequestMessageA( himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) );
1762 ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) );
1763 ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) );
1764 ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) );
1765 ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) );
1767 ok_seq( empty_sequence );
1769 /* ImmSetCandidateWindow should fail with cross thread HIMC */
1771 ok_ret( 1, ImmSetCandidateWindow( himc[1], &candidate ) );
1772 ok_ret( 1, ImmGetCandidateWindow( himc[1], 0, &candidate ) );
1774 ok_ret( 1, ImmGetCandidateWindow( params.himc[0], 1, &candidate ) );
1775 ok_ret( 1, ImmGetCandidateWindow( params.himc[1], 1, &candidate ) );
1776 ok_ret( 0, ImmSetCandidateWindow( params.himc[0], &candidate ) );
1777 ok_ret( 0, ImmSetCandidateWindow( params.himc[1], &candidate ) );
1779 /* ImmRequestMessage(W|A) should fail with cross thread HIMC */
1781 candidate.dwIndex = -1;
1782 ok_ret( 0, ImmRequestMessageW( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) );
1783 ok_ret( 0, ImmRequestMessageA( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) );
1785 candidate.dwIndex = 0;
1786 ok_ret( 0, ImmRequestMessageW( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) );
1787 ok_ret( 0, ImmRequestMessageA( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) );
1789 ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) );
1790 ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) );
1791 ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) );
1792 ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) );
1794 ok_seq( empty_sequence );
1796 /* ImmSetStatusWindowPos should fail with cross thread HIMC */
1798 ok_ret( 1, ImmSetStatusWindowPos( himc[1], &pos ) );
1799 ok_ret( 1, ImmGetStatusWindowPos( himc[1], &pos ) );
1801 ok_ret( 0, ImmSetStatusWindowPos( params.himc[0], &pos ) );
1802 ok_ret( 0, ImmSetStatusWindowPos( params.himc[1], &pos ) );
1803 ok_ret( 1, ImmGetStatusWindowPos( params.himc[0], &pos ) );
1804 ok_ret( 1, ImmGetStatusWindowPos( params.himc[1], &pos ) );
1806 /* ImmRequestMessage(W|A) should fail with cross thread HIMC */
1808 ok_ret( 0, ImmRequestMessageW( himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) );
1809 ok_ret( 0, ImmRequestMessageA( himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) );
1811 ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) );
1812 ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) );
1813 ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) );
1814 ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) );
1816 ok_seq( empty_sequence );
1818 /* ImmGenerateMessage should fail with cross thread HIMC */
1820 ok_ret( 1, ImmGenerateMessage( himc[1] ) );
1822 ok_ret( 0, ImmGenerateMessage( params.himc[0] ) );
1823 ok_ret( 0, ImmGenerateMessage( params.himc[1] ) );
1825 /* ImmAssociateContext should fail with cross thread HWND or HIMC */
1827 tmp_himc = ImmAssociateContext( hwnd, params.himc[0] );
1828 ok_eq( NULL, tmp_himc, HIMC, "%p" );
1829 tmp_himc = ImmGetContext( hwnd );
1830 ok_eq( himc[0], tmp_himc, HIMC, "%p" );
1831 ok_ret( 1, ImmReleaseContext( hwnd, tmp_himc ) );
1833 tmp_himc = ImmAssociateContext( hwnd, params.himc[1] );
1834 ok_eq( NULL, tmp_himc, HIMC, "%p" );
1835 tmp_himc = ImmGetContext( hwnd );
1836 ok_eq( himc[0], tmp_himc, HIMC, "%p" );
1837 ok_ret( 1, ImmReleaseContext( hwnd, tmp_himc ) );
1839 tmp_himc = ImmAssociateContext( params.hwnd, params.himc[1] );
1840 ok_eq( NULL, tmp_himc, HIMC, "%p" );
1841 tmp_himc = ImmGetContext( params.hwnd );
1842 ok_eq( params.himc[0], tmp_himc, HIMC, "%p" );
1843 ok_ret( 1, ImmReleaseContext( params.hwnd, tmp_himc ) );
1845 /* ImmAssociateContext should succeed with cross thread HWND and NULL HIMC */
1847 tmp_himc = ImmAssociateContext( params.hwnd, NULL );
1848 ok_eq( params.himc[0], tmp_himc, HIMC, "%p" );
1849 tmp_himc = ImmGetContext( params.hwnd );
1850 ok_eq( NULL, tmp_himc, HIMC, "%p" );
1852 /* ImmReleaseContext / ImmDestroyContext should fail with cross thread HIMC */
1854 ok_ret( 1, ImmReleaseContext( params.hwnd, params.himc[0] ) );
1855 ok_ret( 0, ImmDestroyContext( params.himc[1] ) );
1857 /* ImmGetContext should fail with another process HWND */
1859 tmp_himc = ImmGetContext( GetDesktopWindow() );
1860 ok_eq( NULL, tmp_himc, HIMC, "%p" );
1862 ok_ret( 0, SendMessageW( params.hwnd, WM_CLOSE, 0, 0 ) );
1863 ok_ret( 1, PostThreadMessageW( tid, WM_QUIT, 1, 0 ) );
1864 ok_ret( 0, WaitForSingleObject( thread, 5000 ) );
1865 ok_ret( 1, CloseHandle( thread ) );
1866 ok_ret( 1, CloseHandle( params.event ) );
1868 ok_ret( 1, ImmReleaseContext( hwnd, himc[0] ) );
1869 ok_ret( 1, ImmDestroyContext( himc[1] ) );
1872 static void test_ImmIsUIMessage(void)
1874 struct test
1876 UINT msg;
1877 BOOL ret;
1880 static const struct test tests[] =
1882 { WM_MOUSEMOVE, FALSE },
1883 { WM_IME_STARTCOMPOSITION, TRUE },
1884 { WM_IME_ENDCOMPOSITION, TRUE },
1885 { WM_IME_COMPOSITION, TRUE },
1886 { WM_IME_SETCONTEXT, TRUE },
1887 { WM_IME_NOTIFY, TRUE },
1888 { WM_IME_CONTROL, FALSE },
1889 { WM_IME_COMPOSITIONFULL, TRUE },
1890 { WM_IME_SELECT, TRUE },
1891 { WM_IME_CHAR, FALSE },
1892 { 0x287 /* FIXME */, TRUE },
1893 { WM_IME_REQUEST, FALSE },
1894 { WM_IME_KEYDOWN, FALSE },
1895 { WM_IME_KEYUP, FALSE },
1896 { 0, FALSE } /* mark the end */
1899 UINT WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
1900 UINT WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
1901 UINT WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
1902 UINT WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
1903 UINT WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
1904 UINT WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
1905 UINT WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
1907 const struct test *test;
1908 BOOL ret;
1910 if (!pImmIsUIMessageA) return;
1912 for (test = tests; test->msg; test++)
1914 msg_spy_flush_msgs();
1915 ret = pImmIsUIMessageA(NULL, test->msg, 0, 0);
1916 ok(ret == test->ret, "ImmIsUIMessageA returned %x for %x\n", ret, test->msg);
1917 ok(!msg_spy_find_msg(test->msg), "Windows does not send 0x%x for NULL hwnd\n", test->msg);
1919 ret = pImmIsUIMessageA(hwnd, test->msg, 0, 0);
1920 ok(ret == test->ret, "ImmIsUIMessageA returned %x for %x\n", ret, test->msg);
1921 if (ret)
1922 ok(msg_spy_find_msg(test->msg) != NULL, "Windows does send 0x%x\n", test->msg);
1923 else
1924 ok(!msg_spy_find_msg(test->msg), "Windows does not send 0x%x\n", test->msg);
1927 ret = pImmIsUIMessageA(NULL, WM_MSIME_SERVICE, 0, 0);
1928 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_SERVICE\n");
1929 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERTOPTIONS, 0, 0);
1930 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTOPTIONS\n");
1931 ret = pImmIsUIMessageA(NULL, WM_MSIME_MOUSE, 0, 0);
1932 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_MOUSE\n");
1933 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERTREQUEST, 0, 0);
1934 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTREQUEST\n");
1935 ret = pImmIsUIMessageA(NULL, WM_MSIME_RECONVERT, 0, 0);
1936 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERT\n");
1937 ret = pImmIsUIMessageA(NULL, WM_MSIME_QUERYPOSITION, 0, 0);
1938 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_QUERYPOSITION\n");
1939 ret = pImmIsUIMessageA(NULL, WM_MSIME_DOCUMENTFEED, 0, 0);
1940 ok(!ret, "ImmIsUIMessageA returned TRUE for WM_MSIME_DOCUMENTFEED\n");
1943 static void test_ImmGetContext(void)
1945 HIMC himc;
1946 DWORD err;
1948 SetLastError(0xdeadbeef);
1949 himc = ImmGetContext((HWND)0xffffffff);
1950 err = GetLastError();
1951 ok(himc == NULL, "ImmGetContext succeeded\n");
1952 ok(err == ERROR_INVALID_WINDOW_HANDLE, "got %lu\n", err);
1954 himc = ImmGetContext(hwnd);
1955 ok(himc != NULL, "ImmGetContext failed\n");
1956 ok(ImmReleaseContext(hwnd, himc), "ImmReleaseContext failed\n");
1959 static LRESULT (WINAPI *old_imm_wnd_proc)(HWND, UINT, WPARAM, LPARAM);
1960 static LRESULT WINAPI imm_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1962 ok(msg != WM_DESTROY, "got WM_DESTROY message\n");
1963 return old_imm_wnd_proc(hwnd, msg, wparam, lparam);
1966 static HWND thread_ime_wnd;
1967 static DWORD WINAPI test_ImmGetDefaultIMEWnd_thread(void *arg)
1969 CreateWindowA("static", "static", WS_POPUP, 0, 0, 1, 1, NULL, NULL, NULL, NULL);
1971 thread_ime_wnd = ImmGetDefaultIMEWnd(0);
1972 ok(thread_ime_wnd != 0, "ImmGetDefaultIMEWnd returned NULL\n");
1973 old_imm_wnd_proc = (void*)SetWindowLongPtrW(thread_ime_wnd, GWLP_WNDPROC, (LONG_PTR)imm_wnd_proc);
1974 return 0;
1977 static void test_ImmDefaultHwnd(void)
1979 HIMC imc1, imc2, imc3;
1980 HWND def1, def3;
1981 HANDLE thread;
1982 HWND hwnd;
1983 char title[16];
1984 LONG style;
1986 hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test",
1987 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
1988 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
1990 ShowWindow(hwnd, SW_SHOWNORMAL);
1992 imc1 = ImmGetContext(hwnd);
1993 if (!imc1)
1995 win_skip("IME support not implemented\n");
1996 return;
1999 def1 = ImmGetDefaultIMEWnd(hwnd);
2001 GetWindowTextA(def1, title, sizeof(title));
2002 ok(!strcmp(title, "Default IME"), "got %s\n", title);
2003 style = GetWindowLongA(def1, GWL_STYLE);
2004 ok(style == (WS_DISABLED | WS_POPUP | WS_CLIPSIBLINGS), "got %08lx\n", style);
2005 style = GetWindowLongA(def1, GWL_EXSTYLE);
2006 ok(style == 0, "got %08lx\n", style);
2008 imc2 = ImmCreateContext();
2009 ImmSetOpenStatus(imc2, TRUE);
2011 imc3 = ImmGetContext(hwnd);
2012 def3 = ImmGetDefaultIMEWnd(hwnd);
2014 ok(def3 == def1, "Default IME window should not change\n");
2015 ok(imc1 == imc3, "IME context should not change\n");
2016 ImmSetOpenStatus(imc2, FALSE);
2018 thread = CreateThread(NULL, 0, test_ImmGetDefaultIMEWnd_thread, NULL, 0, NULL);
2019 WaitForSingleObject(thread, INFINITE);
2020 ok(thread_ime_wnd != def1, "thread_ime_wnd == def1\n");
2021 ok(!IsWindow(thread_ime_wnd), "thread_ime_wnd was not destroyed\n");
2022 CloseHandle(thread);
2024 ImmReleaseContext(hwnd, imc1);
2025 ImmReleaseContext(hwnd, imc3);
2026 ImmDestroyContext(imc2);
2027 DestroyWindow(hwnd);
2030 static BOOL CALLBACK is_ime_window_proc(HWND hWnd, LPARAM param)
2032 WCHAR class_nameW[16];
2033 HWND *ime_window = (HWND *)param;
2034 if (GetClassNameW(hWnd, class_nameW, ARRAY_SIZE(class_nameW)) && !lstrcmpW(class_nameW, L"IME"))
2036 *ime_window = hWnd;
2037 return FALSE;
2039 return TRUE;
2042 static HWND get_ime_window(void)
2044 HWND ime_window = NULL;
2045 EnumThreadWindows(GetCurrentThreadId(), is_ime_window_proc, (LPARAM)&ime_window);
2046 return ime_window;
2049 struct testcase_ime_window {
2050 BOOL visible;
2051 BOOL top_level_window;
2054 static DWORD WINAPI test_default_ime_window_cb(void *arg)
2056 struct testcase_ime_window *testcase = (struct testcase_ime_window *)arg;
2057 DWORD visible = testcase->visible ? WS_VISIBLE : 0;
2058 HWND hwnd1, hwnd2, default_ime_wnd, ime_wnd;
2060 ok(!get_ime_window(), "Expected no IME windows\n");
2061 if (testcase->top_level_window) {
2062 test_phase = FIRST_WINDOW;
2063 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
2064 WS_OVERLAPPEDWINDOW | visible,
2065 CW_USEDEFAULT, CW_USEDEFAULT,
2066 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
2068 else {
2069 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test",
2070 WS_CHILD | visible,
2071 CW_USEDEFAULT, CW_USEDEFAULT,
2072 240, 24, hwnd, NULL, GetModuleHandleW(NULL), NULL);
2074 ime_wnd = get_ime_window();
2075 ok(ime_wnd != NULL, "Expected IME window existence\n");
2076 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1);
2077 ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd);
2079 test_phase = SECOND_WINDOW;
2080 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
2081 WS_OVERLAPPEDWINDOW | visible,
2082 CW_USEDEFAULT, CW_USEDEFAULT,
2083 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
2084 DestroyWindow(hwnd2);
2085 ok(IsWindow(ime_wnd) ||
2086 broken(!testcase->visible /* Vista */) ||
2087 broken(!testcase->top_level_window /* Vista */) ,
2088 "Expected IME window existence\n");
2089 DestroyWindow(hwnd1);
2090 flaky
2091 ok(!IsWindow(ime_wnd), "Expected no IME windows\n");
2092 return 1;
2095 static DWORD WINAPI test_default_ime_window_cancel_cb(void *arg)
2097 struct testcase_ime_window *testcase = (struct testcase_ime_window *)arg;
2098 DWORD visible = testcase->visible ? WS_VISIBLE : 0;
2099 HWND hwnd1, hwnd2, default_ime_wnd, ime_wnd;
2101 ok(!get_ime_window(), "Expected no IME windows\n");
2102 test_phase = NCCREATE_CANCEL;
2103 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
2104 WS_OVERLAPPEDWINDOW | visible,
2105 CW_USEDEFAULT, CW_USEDEFAULT,
2106 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
2107 ok(hwnd1 == NULL, "creation succeeded, got %p\n", hwnd1);
2108 ok(!get_ime_window(), "Expected no IME windows\n");
2110 test_phase = CREATE_CANCEL;
2111 hwnd1 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
2112 WS_OVERLAPPEDWINDOW | visible,
2113 CW_USEDEFAULT, CW_USEDEFAULT,
2114 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
2115 ok(hwnd1 == NULL, "creation succeeded, got %p\n", hwnd1);
2116 ok(!get_ime_window(), "Expected no IME windows\n");
2118 test_phase = FIRST_WINDOW;
2119 hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
2120 WS_OVERLAPPEDWINDOW | visible,
2121 CW_USEDEFAULT, CW_USEDEFAULT,
2122 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
2123 ime_wnd = get_ime_window();
2124 ok(ime_wnd != NULL, "Expected IME window existence\n");
2125 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd2);
2126 ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd);
2128 DestroyWindow(hwnd2);
2129 ok(!IsWindow(ime_wnd), "Expected no IME windows\n");
2130 return 1;
2133 static DWORD WINAPI test_default_ime_disabled_cb(void *arg)
2135 HWND hWnd, default_ime_wnd;
2137 ok(!get_ime_window(), "Expected no IME windows\n");
2138 ImmDisableIME(GetCurrentThreadId());
2139 test_phase = IME_DISABLED;
2140 hWnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
2141 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2142 CW_USEDEFAULT, CW_USEDEFAULT,
2143 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
2144 default_ime_wnd = ImmGetDefaultIMEWnd(hWnd);
2145 ok(!default_ime_wnd, "Expected no IME windows\n");
2146 DestroyWindow(hWnd);
2147 return 1;
2150 static DWORD WINAPI test_default_ime_with_message_only_window_cb(void *arg)
2152 HWND hwnd1, hwnd2, default_ime_wnd;
2154 /* Message-only window doesn't create associated IME window. */
2155 test_phase = PHASE_UNKNOWN;
2156 hwnd1 = CreateWindowA(wndcls, "Wine imm32.dll test",
2157 WS_OVERLAPPEDWINDOW,
2158 CW_USEDEFAULT, CW_USEDEFAULT,
2159 240, 120, HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL);
2160 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1);
2161 ok(!default_ime_wnd, "Expected no IME windows, got %p\n", default_ime_wnd);
2163 /* Setting message-only window as owner at creation,
2164 doesn't create associated IME window. */
2165 hwnd2 = CreateWindowA(wndcls, "Wine imm32.dll test",
2166 WS_OVERLAPPEDWINDOW,
2167 CW_USEDEFAULT, CW_USEDEFAULT,
2168 240, 120, hwnd1, NULL, GetModuleHandleW(NULL), NULL);
2169 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd2);
2170 todo_wine ok(!default_ime_wnd || broken(IsWindow(default_ime_wnd)), "Expected no IME windows, got %p\n", default_ime_wnd);
2172 DestroyWindow(hwnd2);
2173 DestroyWindow(hwnd1);
2175 /* Making window message-only after creation,
2176 doesn't disassociate IME window. */
2177 hwnd1 = CreateWindowA(wndcls, "Wine imm32.dll test",
2178 WS_OVERLAPPEDWINDOW,
2179 CW_USEDEFAULT, CW_USEDEFAULT,
2180 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
2181 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1);
2182 ok(IsWindow(default_ime_wnd), "Expected IME window existence\n");
2183 SetParent(hwnd1, HWND_MESSAGE);
2184 default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1);
2185 ok(IsWindow(default_ime_wnd), "Expected IME window existence\n");
2186 DestroyWindow(hwnd1);
2187 return 1;
2190 static void test_default_ime_window_creation(void)
2192 HANDLE thread;
2193 size_t i;
2194 struct testcase_ime_window testcases[] = {
2195 /* visible, top-level window */
2196 { TRUE, TRUE },
2197 { FALSE, TRUE },
2198 { TRUE, FALSE },
2199 { FALSE, FALSE }
2202 for (i = 0; i < ARRAY_SIZE(testcases); i++)
2204 thread = CreateThread(NULL, 0, test_default_ime_window_cb, &testcases[i], 0, NULL);
2205 ok(thread != NULL, "CreateThread failed with error %lu\n", GetLastError());
2206 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)
2208 MSG msg;
2209 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
2211 TranslateMessage(&msg);
2212 DispatchMessageA(&msg);
2215 CloseHandle(thread);
2217 if (testcases[i].top_level_window)
2219 thread = CreateThread(NULL, 0, test_default_ime_window_cancel_cb, &testcases[i], 0, NULL);
2220 ok(thread != NULL, "CreateThread failed with error %lu\n", GetLastError());
2221 WaitForSingleObject(thread, INFINITE);
2222 CloseHandle(thread);
2226 thread = CreateThread(NULL, 0, test_default_ime_disabled_cb, NULL, 0, NULL);
2227 WaitForSingleObject(thread, INFINITE);
2228 CloseHandle(thread);
2230 thread = CreateThread(NULL, 0, test_default_ime_with_message_only_window_cb, NULL, 0, NULL);
2231 WaitForSingleObject(thread, INFINITE);
2232 CloseHandle(thread);
2234 test_phase = PHASE_UNKNOWN;
2237 static void test_ImmGetIMCLockCount(void)
2239 HIMC imc;
2240 DWORD count, ret, i;
2241 INPUTCONTEXT *ic;
2243 imc = ImmCreateContext();
2244 ImmDestroyContext(imc);
2245 SetLastError(0xdeadbeef);
2246 count = ImmGetIMCLockCount((HIMC)0xdeadcafe);
2247 ok(count == 0, "Invalid IMC should return 0\n");
2248 ret = GetLastError();
2249 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2250 SetLastError(0xdeadbeef);
2251 count = ImmGetIMCLockCount(0x00000000);
2252 ok(count == 0, "NULL IMC should return 0\n");
2253 ret = GetLastError();
2254 ok(ret == 0xdeadbeef, "Last Error should remain unchanged: %08lx\n",ret);
2255 count = ImmGetIMCLockCount(imc);
2256 ok(count == 0, "Destroyed IMC should return 0\n");
2257 ret = GetLastError();
2258 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2260 imc = ImmCreateContext();
2261 count = ImmGetIMCLockCount(imc);
2262 ok(count == 0, "expect 0, returned %ld\n", count);
2263 ic = ImmLockIMC(imc);
2264 ok(ic != NULL, "ImmLockIMC failed!\n");
2265 count = ImmGetIMCLockCount(imc);
2266 ok(count == 1, "expect 1, returned %ld\n", count);
2267 ret = ImmUnlockIMC(imc);
2268 ok(ret == TRUE, "expect TRUE, ret %ld\n", ret);
2269 count = ImmGetIMCLockCount(imc);
2270 ok(count == 0, "expect 0, returned %ld\n", count);
2271 ret = ImmUnlockIMC(imc);
2272 ok(ret == TRUE, "expect TRUE, ret %ld\n", ret);
2273 count = ImmGetIMCLockCount(imc);
2274 ok(count == 0, "expect 0, returned %ld\n", count);
2276 for (i = 0; i < GMEM_LOCKCOUNT * 2; i++)
2278 ic = ImmLockIMC(imc);
2279 ok(ic != NULL, "ImmLockIMC failed!\n");
2281 count = ImmGetIMCLockCount(imc);
2282 todo_wine ok(count == GMEM_LOCKCOUNT, "expect GMEM_LOCKCOUNT, returned %ld\n", count);
2284 for (i = 0; i < GMEM_LOCKCOUNT - 1; i++)
2285 ImmUnlockIMC(imc);
2286 count = ImmGetIMCLockCount(imc);
2287 todo_wine ok(count == 1, "expect 1, returned %ld\n", count);
2288 ImmUnlockIMC(imc);
2289 count = ImmGetIMCLockCount(imc);
2290 todo_wine ok(count == 0, "expect 0, returned %ld\n", count);
2292 ImmDestroyContext(imc);
2295 static void test_ImmGetIMCCLockCount(void)
2297 HIMCC imcc;
2298 DWORD count, g_count, i;
2299 BOOL ret;
2300 VOID *p;
2302 imcc = ImmCreateIMCC(sizeof(CANDIDATEINFO));
2303 count = ImmGetIMCCLockCount(imcc);
2304 ok(count == 0, "expect 0, returned %ld\n", count);
2305 ImmLockIMCC(imcc);
2306 count = ImmGetIMCCLockCount(imcc);
2307 ok(count == 1, "expect 1, returned %ld\n", count);
2308 ret = ImmUnlockIMCC(imcc);
2309 ok(ret == FALSE, "expect FALSE, ret %d\n", ret);
2310 count = ImmGetIMCCLockCount(imcc);
2311 ok(count == 0, "expect 0, returned %ld\n", count);
2312 ret = ImmUnlockIMCC(imcc);
2313 ok(ret == FALSE, "expect FALSE, ret %d\n", ret);
2314 count = ImmGetIMCCLockCount(imcc);
2315 ok(count == 0, "expect 0, returned %ld\n", count);
2317 p = ImmLockIMCC(imcc);
2318 ok(GlobalHandle(p) == imcc, "expect %p, returned %p\n", imcc, GlobalHandle(p));
2320 for (i = 0; i < GMEM_LOCKCOUNT * 2; i++)
2322 ImmLockIMCC(imcc);
2323 count = ImmGetIMCCLockCount(imcc);
2324 g_count = GlobalFlags(imcc) & GMEM_LOCKCOUNT;
2325 ok(count == g_count, "count %ld, g_count %ld\n", count, g_count);
2327 count = ImmGetIMCCLockCount(imcc);
2328 ok(count == GMEM_LOCKCOUNT, "expect GMEM_LOCKCOUNT, returned %ld\n", count);
2330 for (i = 0; i < GMEM_LOCKCOUNT - 1; i++)
2331 GlobalUnlock(imcc);
2332 count = ImmGetIMCCLockCount(imcc);
2333 ok(count == 1, "expect 1, returned %ld\n", count);
2334 GlobalUnlock(imcc);
2335 count = ImmGetIMCCLockCount(imcc);
2336 ok(count == 0, "expect 0, returned %ld\n", count);
2338 ImmDestroyIMCC(imcc);
2341 static void test_ImmDestroyContext(void)
2343 HIMC imc;
2344 DWORD ret, count;
2345 INPUTCONTEXT *ic;
2347 imc = ImmCreateContext();
2348 count = ImmGetIMCLockCount(imc);
2349 ok(count == 0, "expect 0, returned %ld\n", count);
2350 ic = ImmLockIMC(imc);
2351 ok(ic != NULL, "ImmLockIMC failed!\n");
2352 count = ImmGetIMCLockCount(imc);
2353 ok(count == 1, "expect 1, returned %ld\n", count);
2354 ret = ImmDestroyContext(imc);
2355 ok(ret == TRUE, "Destroy a locked IMC should success!\n");
2356 ic = ImmLockIMC(imc);
2357 ok(ic == NULL, "Lock a destroyed IMC should fail!\n");
2358 ret = ImmUnlockIMC(imc);
2359 ok(ret == FALSE, "Unlock a destroyed IMC should fail!\n");
2360 count = ImmGetIMCLockCount(imc);
2361 ok(count == 0, "Get lock count of a destroyed IMC should return 0!\n");
2362 SetLastError(0xdeadbeef);
2363 ret = ImmDestroyContext(imc);
2364 ok(ret == FALSE, "Destroy a destroyed IMC should fail!\n");
2365 ret = GetLastError();
2366 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2369 static void test_ImmDestroyIMCC(void)
2371 HIMCC imcc;
2372 DWORD ret, count, size;
2373 VOID *p;
2375 imcc = ImmCreateIMCC(sizeof(CANDIDATEINFO));
2376 count = ImmGetIMCCLockCount(imcc);
2377 ok(count == 0, "expect 0, returned %ld\n", count);
2378 p = ImmLockIMCC(imcc);
2379 ok(p != NULL, "ImmLockIMCC failed!\n");
2380 count = ImmGetIMCCLockCount(imcc);
2381 ok(count == 1, "expect 1, returned %ld\n", count);
2382 size = ImmGetIMCCSize(imcc);
2383 ok(size == sizeof(CANDIDATEINFO), "returned %ld\n", size);
2384 p = ImmDestroyIMCC(imcc);
2385 ok(p == NULL, "Destroy a locked IMCC should success!\n");
2386 p = ImmLockIMCC(imcc);
2387 ok(p == NULL, "Lock a destroyed IMCC should fail!\n");
2388 ret = ImmUnlockIMCC(imcc);
2389 ok(ret == FALSE, "Unlock a destroyed IMCC should return FALSE!\n");
2390 count = ImmGetIMCCLockCount(imcc);
2391 ok(count == 0, "Get lock count of a destroyed IMCC should return 0!\n");
2392 size = ImmGetIMCCSize(imcc);
2393 ok(size == 0, "Get size of a destroyed IMCC should return 0!\n");
2394 SetLastError(0xdeadbeef);
2395 p = ImmDestroyIMCC(imcc);
2396 ok(p != NULL, "returned NULL\n");
2397 ret = GetLastError();
2398 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2401 static void test_ImmMessages(void)
2403 CANDIDATEFORM cf;
2404 imm_msgs *msg;
2405 HWND defwnd;
2406 HIMC imc;
2407 UINT idx = 0;
2409 LPINPUTCONTEXT lpIMC;
2410 LPTRANSMSG lpTransMsg;
2412 HWND hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test",
2413 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
2414 240, 120, NULL, NULL, GetModuleHandleA(NULL), NULL);
2416 ShowWindow(hwnd, SW_SHOWNORMAL);
2417 defwnd = ImmGetDefaultIMEWnd(hwnd);
2418 imc = ImmGetContext(hwnd);
2420 ImmSetOpenStatus(imc, TRUE);
2421 msg_spy_flush_msgs();
2422 SendMessageA(defwnd, WM_IME_CONTROL, IMC_GETCANDIDATEPOS, (LPARAM)&cf );
2425 msg = msg_spy_find_next_msg(WM_IME_CONTROL,&idx);
2426 if (msg) ok(!msg->post, "Message should not be posted\n");
2427 } while (msg);
2428 msg_spy_flush_msgs();
2430 lpIMC = ImmLockIMC(imc);
2431 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG));
2432 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
2433 lpTransMsg += lpIMC->dwNumMsgBuf;
2434 lpTransMsg->message = WM_IME_STARTCOMPOSITION;
2435 lpTransMsg->wParam = 0;
2436 lpTransMsg->lParam = 0;
2437 ImmUnlockIMCC(lpIMC->hMsgBuf);
2438 lpIMC->dwNumMsgBuf++;
2439 ImmUnlockIMC(imc);
2440 ImmGenerateMessage(imc);
2441 idx = 0;
2444 msg = msg_spy_find_next_msg(WM_IME_STARTCOMPOSITION, &idx);
2445 if (msg) ok(!msg->post, "Message should not be posted\n");
2446 } while (msg);
2447 msg_spy_flush_msgs();
2449 lpIMC = ImmLockIMC(imc);
2450 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG));
2451 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
2452 lpTransMsg += lpIMC->dwNumMsgBuf;
2453 lpTransMsg->message = WM_IME_COMPOSITION;
2454 lpTransMsg->wParam = 0;
2455 lpTransMsg->lParam = 0;
2456 ImmUnlockIMCC(lpIMC->hMsgBuf);
2457 lpIMC->dwNumMsgBuf++;
2458 ImmUnlockIMC(imc);
2459 ImmGenerateMessage(imc);
2460 idx = 0;
2463 msg = msg_spy_find_next_msg(WM_IME_COMPOSITION, &idx);
2464 if (msg) ok(!msg->post, "Message should not be posted\n");
2465 } while (msg);
2466 msg_spy_flush_msgs();
2468 lpIMC = ImmLockIMC(imc);
2469 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG));
2470 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
2471 lpTransMsg += lpIMC->dwNumMsgBuf;
2472 lpTransMsg->message = WM_IME_ENDCOMPOSITION;
2473 lpTransMsg->wParam = 0;
2474 lpTransMsg->lParam = 0;
2475 ImmUnlockIMCC(lpIMC->hMsgBuf);
2476 lpIMC->dwNumMsgBuf++;
2477 ImmUnlockIMC(imc);
2478 ImmGenerateMessage(imc);
2479 idx = 0;
2482 msg = msg_spy_find_next_msg(WM_IME_ENDCOMPOSITION, &idx);
2483 if (msg) ok(!msg->post, "Message should not be posted\n");
2484 } while (msg);
2485 msg_spy_flush_msgs();
2487 ImmSetOpenStatus(imc, FALSE);
2488 ImmReleaseContext(hwnd, imc);
2489 DestroyWindow(hwnd);
2492 static LRESULT CALLBACK processkey_wnd_proc( HWND hWnd, UINT msg, WPARAM wParam,
2493 LPARAM lParam )
2495 return DefWindowProcW(hWnd, msg, wParam, lParam);
2498 static void test_ime_processkey(void)
2500 MSG msg;
2501 WNDCLASSW wclass;
2502 HANDLE hInstance = GetModuleHandleW(NULL);
2503 TEST_INPUT inputs[2];
2504 HIMC imc;
2505 INT rc;
2506 HWND hWndTest;
2508 wclass.lpszClassName = L"ProcessKeyTestClass";
2509 wclass.style = CS_HREDRAW | CS_VREDRAW;
2510 wclass.lpfnWndProc = processkey_wnd_proc;
2511 wclass.hInstance = hInstance;
2512 wclass.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
2513 wclass.hCursor = LoadCursorW( NULL, (LPCWSTR)IDC_ARROW);
2514 wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
2515 wclass.lpszMenuName = 0;
2516 wclass.cbClsExtra = 0;
2517 wclass.cbWndExtra = 0;
2518 if(!RegisterClassW(&wclass)){
2519 win_skip("Failed to register window.\n");
2520 return;
2523 /* create the test window that will receive the keystrokes */
2524 hWndTest = CreateWindowW(wclass.lpszClassName, L"ProcessKey",
2525 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100,
2526 NULL, NULL, hInstance, NULL);
2528 ShowWindow(hWndTest, SW_SHOW);
2529 SetWindowPos(hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
2530 SetForegroundWindow(hWndTest);
2531 UpdateWindow(hWndTest);
2533 imc = ImmGetContext(hWndTest);
2534 if (!imc)
2536 win_skip("IME not supported\n");
2537 DestroyWindow(hWndTest);
2538 return;
2541 rc = ImmSetOpenStatus(imc, TRUE);
2542 if (rc != TRUE)
2544 win_skip("Unable to open IME\n");
2545 ImmReleaseContext(hWndTest, imc);
2546 DestroyWindow(hWndTest);
2547 return;
2550 /* flush pending messages */
2551 while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageW(&msg);
2553 SetFocus(hWndTest);
2555 /* init input data that never changes */
2556 inputs[1].type = inputs[0].type = INPUT_KEYBOARD;
2557 inputs[1].u.ki.dwExtraInfo = inputs[0].u.ki.dwExtraInfo = 0;
2558 inputs[1].u.ki.time = inputs[0].u.ki.time = 0;
2560 /* Pressing a key */
2561 inputs[0].u.ki.wVk = 0x41;
2562 inputs[0].u.ki.wScan = 0x1e;
2563 inputs[0].u.ki.dwFlags = 0x0;
2565 pSendInput(1, (INPUT*)inputs, sizeof(INPUT));
2567 while(PeekMessageW(&msg, hWndTest, 0, 0, PM_NOREMOVE)) {
2568 if(msg.message != WM_KEYDOWN)
2569 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
2570 else
2572 ok(msg.wParam != VK_PROCESSKEY,"Incorrect ProcessKey Found\n");
2573 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
2574 if(msg.wParam == VK_PROCESSKEY)
2575 trace("ProcessKey was correctly found\n");
2577 TranslateMessage(&msg);
2578 /* test calling TranslateMessage multiple times */
2579 TranslateMessage(&msg);
2580 DispatchMessageW(&msg);
2583 inputs[0].u.ki.wVk = 0x41;
2584 inputs[0].u.ki.wScan = 0x1e;
2585 inputs[0].u.ki.dwFlags = KEYEVENTF_KEYUP;
2587 pSendInput(1, (INPUT*)inputs, sizeof(INPUT));
2589 while(PeekMessageW(&msg, hWndTest, 0, 0, PM_NOREMOVE)) {
2590 if(msg.message != WM_KEYUP)
2591 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
2592 else
2594 ok(msg.wParam != VK_PROCESSKEY,"Incorrect ProcessKey Found\n");
2595 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
2596 ok(msg.wParam != VK_PROCESSKEY,"ProcessKey should still not be Found\n");
2598 TranslateMessage(&msg);
2599 DispatchMessageW(&msg);
2602 ImmReleaseContext(hWndTest, imc);
2603 ImmSetOpenStatus(imc, FALSE);
2604 DestroyWindow(hWndTest);
2607 static void test_InvalidIMC(void)
2609 HIMC imc_destroy;
2610 HIMC imc_null = 0x00000000;
2611 HIMC imc_bad = (HIMC)0xdeadcafe;
2613 HIMC imc1, imc2, oldimc;
2614 DWORD ret;
2615 DWORD count;
2616 CHAR buffer[1000];
2617 INPUTCONTEXT *ic;
2618 LOGFONTA lf;
2619 BOOL r;
2621 memset(&lf, 0, sizeof(lf));
2623 imc_destroy = ImmCreateContext();
2624 ret = ImmDestroyContext(imc_destroy);
2625 ok(ret == TRUE, "Destroy an IMC should success!\n");
2627 /* Test associating destroyed imc */
2628 imc1 = ImmGetContext(hwnd);
2629 SetLastError(0xdeadbeef);
2630 oldimc = ImmAssociateContext(hwnd, imc_destroy);
2631 ok(!oldimc, "Associating to a destroyed imc should fail!\n");
2632 ret = GetLastError();
2633 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2634 imc2 = ImmGetContext(hwnd);
2635 ok(imc1 == imc2, "imc should not changed! imc1 %p, imc2 %p\n", imc1, imc2);
2637 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, TRUE);
2638 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, TRUE);
2639 r = ImmSetActiveContext(hwnd, imc_destroy, TRUE);
2640 ok(!r, "ImmSetActiveContext succeeded\n");
2641 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE);
2642 r = ImmSetActiveContext(hwnd, imc_destroy, FALSE);
2643 ok(r, "ImmSetActiveContext failed\n");
2644 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE);
2645 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, FALSE);
2646 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, FALSE);
2648 /* Test associating NULL imc, which is different from an invalid imc */
2649 oldimc = ImmAssociateContext(hwnd, imc_null);
2650 ok(oldimc != NULL, "Associating to NULL imc should success!\n");
2651 imc2 = ImmGetContext(hwnd);
2652 ok(!imc2, "expect NULL, returned %p\n", imc2);
2653 oldimc = ImmAssociateContext(hwnd, imc1);
2654 ok(!oldimc, "expect NULL, returned %p\n", oldimc);
2655 imc2 = ImmGetContext(hwnd);
2656 ok(imc2 == imc1, "imc should not changed! imc2 %p, imc1 %p\n", imc2, imc1);
2658 /* Test associating invalid imc */
2659 imc1 = ImmGetContext(hwnd);
2660 SetLastError(0xdeadbeef);
2661 oldimc = ImmAssociateContext(hwnd, imc_bad);
2662 ok(!oldimc, "Associating to a destroyed imc should fail!\n");
2663 ret = GetLastError();
2664 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2665 imc2 = ImmGetContext(hwnd);
2666 ok(imc1 == imc2, "imc should not changed! imc1 %p, imc2 %p\n", imc1, imc2);
2669 /* Test ImmGetCandidateListA */
2670 SetLastError(0xdeadbeef);
2671 ret = ImmGetCandidateListA(imc_bad, 0, NULL, 0);
2672 ok(ret == 0, "Bad IME should return 0\n");
2673 ret = GetLastError();
2674 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2675 SetLastError(0xdeadbeef);
2676 ret = ImmGetCandidateListA(imc_null, 0, NULL, 0);
2677 ok(ret == 0, "NULL IME should return 0\n");
2678 ret = GetLastError();
2679 ok(ret == 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret);
2680 SetLastError(0xdeadbeef);
2681 ret = ImmGetCandidateListA(imc_destroy, 0, NULL, 0);
2682 ok(ret == 0, "Destroyed IME should return 0\n");
2683 ret = GetLastError();
2684 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2686 /* Test ImmGetCandidateListCountA*/
2687 SetLastError(0xdeadbeef);
2688 ret = ImmGetCandidateListCountA(imc_bad,&count);
2689 ok(ret == 0, "Bad IME should return 0\n");
2690 ret = GetLastError();
2691 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2692 SetLastError(0xdeadbeef);
2693 ret = ImmGetCandidateListCountA(imc_null,&count);
2694 ok(ret == 0, "NULL IME should return 0\n");
2695 ret = GetLastError();
2696 ok(ret == 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret);
2697 SetLastError(0xdeadbeef);
2698 ret = ImmGetCandidateListCountA(imc_destroy,&count);
2699 ok(ret == 0, "Destroyed IME should return 0\n");
2700 ret = GetLastError();
2701 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2703 /* Test ImmGetCandidateWindow */
2704 SetLastError(0xdeadbeef);
2705 ret = ImmGetCandidateWindow(imc_bad, 0, (LPCANDIDATEFORM)buffer);
2706 ok(ret == 0, "Bad IME should return 0\n");
2707 ret = GetLastError();
2708 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2709 SetLastError(0xdeadbeef);
2710 ret = ImmGetCandidateWindow(imc_null, 0, (LPCANDIDATEFORM)buffer);
2711 ok(ret == 0, "NULL IME should return 0\n");
2712 ret = GetLastError();
2713 ok(ret == 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret);
2714 SetLastError(0xdeadbeef);
2715 ret = ImmGetCandidateWindow(imc_destroy, 0, (LPCANDIDATEFORM)buffer);
2716 ok(ret == 0, "Destroyed IME should return 0\n");
2717 ret = GetLastError();
2718 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2720 /* Test ImmGetCompositionFontA */
2721 SetLastError(0xdeadbeef);
2722 ret = ImmGetCompositionFontA(imc_bad, (LPLOGFONTA)buffer);
2723 ok(ret == 0, "Bad IME should return 0\n");
2724 ret = GetLastError();
2725 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2726 SetLastError(0xdeadbeef);
2727 ret = ImmGetCompositionFontA(imc_null, (LPLOGFONTA)buffer);
2728 ok(ret == 0, "NULL IME should return 0\n");
2729 ret = GetLastError();
2730 ok(ret == 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret);
2731 SetLastError(0xdeadbeef);
2732 ret = ImmGetCompositionFontA(imc_destroy, (LPLOGFONTA)buffer);
2733 ok(ret == 0, "Destroyed IME should return 0\n");
2734 ret = GetLastError();
2735 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2737 /* Test ImmGetCompositionWindow */
2738 SetLastError(0xdeadbeef);
2739 ret = ImmGetCompositionWindow(imc_bad, (LPCOMPOSITIONFORM)buffer);
2740 ok(ret == 0, "Bad IME should return 0\n");
2741 ret = GetLastError();
2742 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2743 SetLastError(0xdeadbeef);
2744 ret = ImmGetCompositionWindow(imc_null, (LPCOMPOSITIONFORM)buffer);
2745 ok(ret == 0, "NULL IME should return 0\n");
2746 ret = GetLastError();
2747 ok(ret == 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret);
2748 SetLastError(0xdeadbeef);
2749 ret = ImmGetCompositionWindow(imc_destroy, (LPCOMPOSITIONFORM)buffer);
2750 ok(ret == 0, "Destroyed IME should return 0\n");
2751 ret = GetLastError();
2752 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2754 /* Test ImmGetCompositionStringA */
2755 SetLastError(0xdeadbeef);
2756 ret = ImmGetCompositionStringA(imc_bad, GCS_COMPSTR, NULL, 0);
2757 ok(ret == 0, "Bad IME should return 0\n");
2758 ret = GetLastError();
2759 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2760 SetLastError(0xdeadbeef);
2761 ret = ImmGetCompositionStringA(imc_null, GCS_COMPSTR, NULL, 0);
2762 ok(ret == 0, "NULL IME should return 0\n");
2763 ret = GetLastError();
2764 ok(ret == 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret);
2765 SetLastError(0xdeadbeef);
2766 ret = ImmGetCompositionStringA(imc_destroy, GCS_COMPSTR, NULL, 0);
2767 ok(ret == 0, "Destroyed IME should return 0\n");
2768 ret = GetLastError();
2769 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2771 /* Test ImmSetOpenStatus */
2772 SetLastError(0xdeadbeef);
2773 ret = ImmSetOpenStatus(imc_bad, 1);
2774 ok(ret == 0, "Bad IME should return 0\n");
2775 ret = GetLastError();
2776 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2777 SetLastError(0xdeadbeef);
2778 ret = ImmSetOpenStatus(imc_null, 1);
2779 ok(ret == 0, "NULL IME should return 0\n");
2780 ret = GetLastError();
2781 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2782 SetLastError(0xdeadbeef);
2783 ret = ImmSetOpenStatus(imc_destroy, 1);
2784 ok(ret == 0, "Destroyed IME should return 0\n");
2785 ret = GetLastError();
2786 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2788 /* Test ImmGetOpenStatus */
2789 SetLastError(0xdeadbeef);
2790 ret = ImmGetOpenStatus(imc_bad);
2791 ok(ret == 0, "Bad IME should return 0\n");
2792 ret = GetLastError();
2793 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2794 SetLastError(0xdeadbeef);
2795 ret = ImmGetOpenStatus(imc_null);
2796 ok(ret == 0, "NULL IME should return 0\n");
2797 ret = GetLastError();
2798 ok(ret == 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret);
2799 SetLastError(0xdeadbeef);
2800 ret = ImmGetOpenStatus(imc_destroy);
2801 ok(ret == 0, "Destroyed IME should return 0\n");
2802 ret = GetLastError();
2803 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2805 /* Test ImmGetStatusWindowPos */
2806 SetLastError(0xdeadbeef);
2807 ret = ImmGetStatusWindowPos(imc_bad, NULL);
2808 ok(ret == 0, "Bad IME should return 0\n");
2809 ret = GetLastError();
2810 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2811 SetLastError(0xdeadbeef);
2812 ret = ImmGetStatusWindowPos(imc_null, NULL);
2813 ok(ret == 0, "NULL IME should return 0\n");
2814 ret = GetLastError();
2815 ok(ret == 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret);
2816 SetLastError(0xdeadbeef);
2817 ret = ImmGetStatusWindowPos(imc_destroy, NULL);
2818 ok(ret == 0, "Destroyed IME should return 0\n");
2819 ret = GetLastError();
2820 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2822 /* Test ImmRequestMessageA */
2823 SetLastError(0xdeadbeef);
2824 ret = ImmRequestMessageA(imc_bad, WM_CHAR, 0);
2825 ok(ret == 0, "Bad IME should return 0\n");
2826 ret = GetLastError();
2827 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2828 SetLastError(0xdeadbeef);
2829 ret = ImmRequestMessageA(imc_null, WM_CHAR, 0);
2830 ok(ret == 0, "NULL IME should return 0\n");
2831 ret = GetLastError();
2832 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2833 SetLastError(0xdeadbeef);
2834 ret = ImmRequestMessageA(imc_destroy, WM_CHAR, 0);
2835 ok(ret == 0, "Destroyed IME should return 0\n");
2836 ret = GetLastError();
2837 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2839 /* Test ImmSetCompositionFontA */
2840 SetLastError(0xdeadbeef);
2841 ret = ImmSetCompositionFontA(imc_bad, &lf);
2842 ok(ret == 0, "Bad IME should return 0\n");
2843 ret = GetLastError();
2844 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2845 SetLastError(0xdeadbeef);
2846 ret = ImmSetCompositionFontA(imc_null, &lf);
2847 ok(ret == 0, "NULL IME should return 0\n");
2848 ret = GetLastError();
2849 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2850 SetLastError(0xdeadbeef);
2851 ret = ImmSetCompositionFontA(imc_destroy, &lf);
2852 ok(ret == 0, "Destroyed IME should return 0\n");
2853 ret = GetLastError();
2854 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2856 /* Test ImmSetCompositionWindow */
2857 SetLastError(0xdeadbeef);
2858 ret = ImmSetCompositionWindow(imc_bad, NULL);
2859 ok(ret == 0, "Bad IME should return 0\n");
2860 ret = GetLastError();
2861 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2862 SetLastError(0xdeadbeef);
2863 ret = ImmSetCompositionWindow(imc_null, NULL);
2864 ok(ret == 0, "NULL IME should return 0\n");
2865 ret = GetLastError();
2866 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2867 SetLastError(0xdeadbeef);
2868 ret = ImmSetCompositionWindow(imc_destroy, NULL);
2869 ok(ret == 0, "Destroyed IME should return 0\n");
2870 ret = GetLastError();
2871 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2873 /* Test ImmSetConversionStatus */
2874 SetLastError(0xdeadbeef);
2875 ret = ImmSetConversionStatus(imc_bad, 0, 0);
2876 ok(ret == 0, "Bad IME should return 0\n");
2877 ret = GetLastError();
2878 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2879 SetLastError(0xdeadbeef);
2880 ret = ImmSetConversionStatus(imc_null, 0, 0);
2881 ok(ret == 0, "NULL IME should return 0\n");
2882 ret = GetLastError();
2883 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2884 SetLastError(0xdeadbeef);
2885 ret = ImmSetConversionStatus(imc_destroy, 0, 0);
2886 ok(ret == 0, "Destroyed IME should return 0\n");
2887 ret = GetLastError();
2888 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2890 /* Test ImmSetStatusWindowPos */
2891 SetLastError(0xdeadbeef);
2892 ret = ImmSetStatusWindowPos(imc_bad, 0);
2893 ok(ret == 0, "Bad IME should return 0\n");
2894 ret = GetLastError();
2895 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2896 SetLastError(0xdeadbeef);
2897 ret = ImmSetStatusWindowPos(imc_null, 0);
2898 ok(ret == 0, "NULL IME should return 0\n");
2899 ret = GetLastError();
2900 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2901 SetLastError(0xdeadbeef);
2902 ret = ImmSetStatusWindowPos(imc_destroy, 0);
2903 ok(ret == 0, "Destroyed IME should return 0\n");
2904 ret = GetLastError();
2905 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2907 /* Test ImmGetImeMenuItemsA */
2908 SetLastError(0xdeadbeef);
2909 ret = ImmGetImeMenuItemsA(imc_bad, 0, 0, NULL, NULL, 0);
2910 ok(ret == 0, "Bad IME should return 0\n");
2911 ret = GetLastError();
2912 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2913 SetLastError(0xdeadbeef);
2914 ret = ImmGetImeMenuItemsA(imc_null, 0, 0, NULL, NULL, 0);
2915 ok(ret == 0, "NULL IME should return 0\n");
2916 ret = GetLastError();
2917 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2918 SetLastError(0xdeadbeef);
2919 ret = ImmGetImeMenuItemsA(imc_destroy, 0, 0, NULL, NULL, 0);
2920 ok(ret == 0, "Destroyed IME should return 0\n");
2921 ret = GetLastError();
2922 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2924 /* Test ImmLockIMC */
2925 SetLastError(0xdeadbeef);
2926 ic = ImmLockIMC(imc_bad);
2927 ok(ic == 0, "Bad IME should return 0\n");
2928 ret = GetLastError();
2929 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2930 SetLastError(0xdeadbeef);
2931 ic = ImmLockIMC(imc_null);
2932 ok(ic == 0, "NULL IME should return 0\n");
2933 ret = GetLastError();
2934 ok(ret == 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret);
2935 SetLastError(0xdeadbeef);
2936 ic = ImmLockIMC(imc_destroy);
2937 ok(ic == 0, "Destroyed IME should return 0\n");
2938 ret = GetLastError();
2939 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2941 /* Test ImmUnlockIMC */
2942 SetLastError(0xdeadbeef);
2943 ret = ImmUnlockIMC(imc_bad);
2944 ok(ret == 0, "Bad IME should return 0\n");
2945 ret = GetLastError();
2946 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2947 SetLastError(0xdeadbeef);
2948 ret = ImmUnlockIMC(imc_null);
2949 ok(ret == 0, "NULL IME should return 0\n");
2950 ret = GetLastError();
2951 ok(ret == 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret);
2952 SetLastError(0xdeadbeef);
2953 ret = ImmUnlockIMC(imc_destroy);
2954 ok(ret == 0, "Destroyed IME should return 0\n");
2955 ret = GetLastError();
2956 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2958 /* Test ImmGenerateMessage */
2959 SetLastError(0xdeadbeef);
2960 ret = ImmGenerateMessage(imc_bad);
2961 ok(ret == 0, "Bad IME should return 0\n");
2962 ret = GetLastError();
2963 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2964 SetLastError(0xdeadbeef);
2965 ret = ImmGenerateMessage(imc_null);
2966 ok(ret == 0, "NULL IME should return 0\n");
2967 ret = GetLastError();
2968 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2969 SetLastError(0xdeadbeef);
2970 ret = ImmGenerateMessage(imc_destroy);
2971 ok(ret == 0, "Destroyed IME should return 0\n");
2972 ret = GetLastError();
2973 ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08lx!\n", ret);
2976 #define test_apttype(apttype) _test_apttype(apttype, __LINE__)
2977 static void _test_apttype(APTTYPE apttype, unsigned int line)
2979 APTTYPEQUALIFIER qualifier;
2980 HRESULT hr, hr_expected;
2981 APTTYPE type;
2983 hr = CoGetApartmentType(&type, &qualifier);
2984 hr_expected = (apttype == -1 ? CO_E_NOTINITIALIZED : S_OK);
2985 ok_(__FILE__, line)(hr == hr_expected, "CoGetApartmentType returned %lx\n", hr);
2986 if (FAILED(hr))
2987 return;
2989 ok_(__FILE__, line)(type == apttype, "type %x\n", type);
2990 ok_(__FILE__, line)(!qualifier, "qualifier %x\n", qualifier);
2993 static DWORD WINAPI com_initialization_thread(void *arg)
2995 HRESULT hr;
2996 BOOL r;
2998 test_apttype(-1);
2999 ImmDisableIME(GetCurrentThreadId());
3000 r = ImmSetActiveContext(NULL, NULL, TRUE);
3001 ok(r, "ImmSetActiveContext failed\n");
3002 test_apttype(APTTYPE_MAINSTA);
3003 hr = CoInitialize(NULL);
3004 ok(hr == S_OK, "CoInitialize returned %lx\n", hr);
3005 CoUninitialize();
3006 test_apttype(-1);
3008 /* Changes IMM behavior so it no longer initialized COM */
3009 r = ImmSetActiveContext(NULL, NULL, TRUE);
3010 ok(r, "ImmSetActiveContext failed\n");
3011 test_apttype(APTTYPE_MAINSTA);
3012 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
3013 ok(hr == S_OK, "CoInitialize returned %lx\n", hr);
3014 test_apttype(APTTYPE_MTA);
3015 CoUninitialize();
3016 test_apttype(-1);
3017 r = ImmSetActiveContext(NULL, NULL, TRUE);
3018 ok(r, "ImmSetActiveContext failed\n");
3019 test_apttype(-1);
3020 return 0;
3023 static void test_com_initialization(void)
3025 APTTYPEQUALIFIER qualifier;
3026 HANDLE thread;
3027 APTTYPE type;
3028 HRESULT hr;
3029 HWND wnd;
3030 BOOL r;
3032 thread = CreateThread(NULL, 0, com_initialization_thread, NULL, 0, NULL);
3033 ok(thread != NULL, "CreateThread failed\n");
3034 WaitForSingleObject(thread, INFINITE);
3035 CloseHandle(thread);
3037 test_apttype(-1);
3038 r = ImmSetActiveContext(NULL, (HIMC)0xdeadbeef, TRUE);
3039 ok(!r, "ImmSetActiveContext succeeded\n");
3040 test_apttype(-1);
3042 r = ImmSetActiveContext(NULL, NULL, TRUE);
3043 ok(r, "ImmSetActiveContext failed\n");
3044 test_apttype(APTTYPE_MAINSTA);
3046 /* Force default IME window destruction */
3047 wnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
3048 ok(wnd != NULL, "CreateWindow failed\n");
3049 DestroyWindow(wnd);
3050 test_apttype(-1);
3052 r = ImmSetActiveContext(NULL, NULL, TRUE);
3053 ok(r, "ImmSetActiveContext failed\n");
3054 test_apttype(APTTYPE_MAINSTA);
3055 hr = CoInitialize(NULL);
3056 ok(hr == S_OK, "CoInitialize returned %lx\n", hr);
3057 CoUninitialize();
3058 test_apttype(-1);
3060 /* Test with default IME window created */
3061 wnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
3062 ok(wnd != NULL, "CreateWindow failed\n");
3063 test_apttype(-1);
3064 r = ImmSetActiveContext(NULL, NULL, TRUE);
3065 ok(r, "ImmSetActiveContext failed\n");
3066 test_apttype(APTTYPE_MAINSTA);
3067 hr = CoInitialize(NULL);
3068 ok(hr == S_OK, "CoInitialize returned %lx\n", hr);
3069 CoUninitialize();
3070 test_apttype(APTTYPE_MAINSTA);
3071 DestroyWindow(wnd);
3072 test_apttype(-1);
3074 wnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
3075 ok(wnd != NULL, "CreateWindow failed\n");
3076 r = ImmSetActiveContext(NULL, NULL, TRUE);
3077 CoUninitialize();
3078 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
3079 ok(hr == S_OK, "CoInitialize returned %lx\n", hr);
3080 test_apttype(APTTYPE_MTA);
3081 DestroyWindow(wnd);
3083 hr = CoGetApartmentType(&type, &qualifier);
3084 ok(hr == CO_E_NOTINITIALIZED || broken(hr == S_OK) /* w10v22H2 */,
3085 "CoGetApartmentType returned %#lx\n", hr);
3086 test_apttype(hr == S_OK ? APTTYPE_MTA : -1);
3088 wnd = CreateWindowA("static", "static", WS_POPUP, 0, 0, 100, 100, 0, 0, 0, 0);
3089 ok(wnd != NULL, "CreateWindow failed\n");
3090 test_apttype(hr == S_OK ? APTTYPE_MTA : -1);
3091 ShowWindow(wnd, SW_SHOW);
3092 test_apttype(hr == S_OK ? APTTYPE_MTA : APTTYPE_MAINSTA);
3093 DestroyWindow(wnd);
3094 test_apttype(-1);
3097 static DWORD WINAPI disable_ime_thread(void *arg)
3099 HWND h, def;
3100 MSG msg;
3101 BOOL r;
3103 h = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
3104 ok(h != NULL, "CreateWindow failed\n");
3105 def = ImmGetDefaultIMEWnd(h);
3106 ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n");
3108 r = ImmDisableIME(arg ? GetCurrentThreadId() : 0);
3109 ok(r, "ImmDisableIME failed\n");
3111 if (arg)
3113 def = ImmGetDefaultIMEWnd(h);
3114 todo_wine ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n");
3115 while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3116 DispatchMessageA(&msg);
3118 def = ImmGetDefaultIMEWnd(h);
3119 ok(!def, "ImmGetDefaultIMEWnd returned %p\n", def);
3120 return 0;
3123 static DWORD WINAPI check_not_disabled_ime_thread(void *arg)
3125 HWND def, hwnd;
3127 WaitForSingleObject(arg, INFINITE);
3128 hwnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
3129 ok(hwnd != NULL, "CreateWindow failed\n");
3130 def = ImmGetDefaultIMEWnd(hwnd);
3131 ok(def != NULL, "ImmGetDefaultIMEWnd returned %p\n", def);
3132 return 0;
3135 static DWORD WINAPI disable_ime_process(void *arg)
3137 BOOL r = ImmDisableIME(-1);
3138 ok(r, "ImmDisableIME failed\n");
3139 return 0;
3142 static void test_ImmDisableIME(void)
3144 HANDLE thread, event;
3145 DWORD tid;
3146 HWND def, def2;
3147 BOOL r;
3149 def = ImmGetDefaultIMEWnd(hwnd);
3150 ok(def != NULL, "ImmGetDefaultIMEWnd(hwnd) returned NULL\n");
3152 event = CreateEventW(NULL, TRUE, FALSE, FALSE);
3153 thread = CreateThread(NULL, 0, check_not_disabled_ime_thread, event, 0, &tid);
3154 ok(thread != NULL, "CreateThread failed\n");
3155 r = ImmDisableIME(tid);
3156 ok(!r, "ImmDisableIME(tid) succeeded\n");
3157 SetEvent(event);
3158 WaitForSingleObject(thread, INFINITE);
3159 CloseHandle(thread);
3160 CloseHandle(event);
3162 thread = CreateThread(NULL, 0, disable_ime_thread, 0, 0, NULL);
3163 ok(thread != NULL, "CreateThread failed\n");
3164 WaitForSingleObject(thread, INFINITE);
3165 CloseHandle(thread);
3167 thread = CreateThread(NULL, 0, disable_ime_thread, (void*)1, 0, NULL);
3168 ok(thread != NULL, "CreateThread failed\n");
3169 WaitForSingleObject(thread, INFINITE);
3170 CloseHandle(thread);
3172 msg_spy_pump_msg_queue();
3173 thread = CreateThread(NULL, 0, disable_ime_process, 0, 0, NULL);
3174 ok(thread != NULL, "CreateThread failed\n");
3175 WaitForSingleObject(thread, INFINITE);
3176 CloseHandle(thread);
3178 ok(IsWindow(def), "not a window\n");
3179 def2 = ImmGetDefaultIMEWnd(hwnd);
3180 ok(def2 == def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def2);
3181 ok(IsWindow(def), "not a window\n");
3182 msg_spy_pump_msg_queue();
3183 ok(!IsWindow(def), "window is still valid\n");
3184 def = ImmGetDefaultIMEWnd(hwnd);
3185 ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def);
3187 r = ImmDisableIME(-1);
3188 ok(r, "ImmDisableIME(-1) failed\n");
3189 def = ImmGetDefaultIMEWnd(hwnd);
3190 ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def);
3193 static BOOL WINAPI ime_ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data )
3195 ime_trace( "hkl %p, hwnd %p, mode %lu, data %p\n", hkl, hwnd, mode, data );
3196 ok( 0, "unexpected call\n" );
3197 return FALSE;
3200 static DWORD WINAPI ime_ImeConversionList( HIMC himc, const WCHAR *source, CANDIDATELIST *dest,
3201 DWORD dest_len, UINT flag )
3203 ime_trace( "himc %p, source %s, dest %p, dest_len %lu, flag %#x\n",
3204 himc, debugstr_w(source), dest, dest_len, flag );
3205 ok( 0, "unexpected call\n" );
3206 return 0;
3209 static BOOL WINAPI ime_ImeDestroy( UINT force )
3211 ime_trace( "force %u\n", force );
3213 todo_wine_if( todo_ImeDestroy )
3214 CHECK_EXPECT( ImeDestroy );
3216 ok( !force, "got force %u\n", force );
3218 return TRUE;
3221 static UINT WINAPI ime_ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WCHAR *reading, DWORD style,
3222 const WCHAR *string, void *data )
3224 ime_trace( "proc %p, reading %s, style %lu, string %s, data %p\n",
3225 proc, debugstr_w(reading), style, debugstr_w(string), data );
3227 ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
3228 CHECK_EXPECT( ImeEnumRegisterWord );
3230 if (!style)
3232 ok_eq( 0, reading, const void *, "%p" );
3233 ok_eq( 0, string, const void *, "%p" );
3235 else if (ime_info.fdwProperty & IME_PROP_UNICODE)
3237 ok_eq( 0xdeadbeef, style, UINT, "%#x" );
3238 ok_wcs( L"Reading", reading );
3239 ok_wcs( L"String", string );
3241 else
3243 ok_eq( 0xdeadbeef, style, UINT, "%#x" );
3244 ok_str( "Reading", (char *)reading );
3245 ok_str( "String", (char *)string );
3248 if (style) return proc( reading, style, string, data );
3249 return 0;
3252 static LRESULT WINAPI ime_ImeEscape( HIMC himc, UINT escape, void *data )
3254 ime_trace( "himc %p, escape %#x, data %p\n", himc, escape, data );
3256 ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
3257 CHECK_EXPECT( ImeEscape );
3259 switch (escape)
3261 case IME_ESC_SET_EUDC_DICTIONARY:
3262 if (!data) return 4;
3263 if (ime_info.fdwProperty & IME_PROP_UNICODE)
3264 ok_wcs( L"EscapeIme", data );
3265 else
3266 ok_str( "EscapeIme", data );
3267 /* fallthrough */
3268 case IME_ESC_QUERY_SUPPORT:
3269 case IME_ESC_SEQUENCE_TO_INTERNAL:
3270 case IME_ESC_GET_EUDC_DICTIONARY:
3271 case IME_ESC_MAX_KEY:
3272 case IME_ESC_IME_NAME:
3273 case IME_ESC_HANJA_MODE:
3274 case IME_ESC_GETHELPFILENAME:
3275 if (!data) return 4;
3276 if (ime_info.fdwProperty & IME_PROP_UNICODE) wcscpy( data, L"ImeEscape" );
3277 else strcpy( data, "ImeEscape" );
3278 return 4;
3281 ok_eq( 0xdeadbeef, escape, UINT, "%#x" );
3282 ok_eq( NULL, data, void *, "%p" );
3284 return TRUE;
3287 static DWORD WINAPI ime_ImeGetImeMenuItems( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parent,
3288 IMEMENUITEMINFOW *menu, DWORD size )
3290 ime_trace( "himc %p, flags %#lx, type %lu, parent %p, menu %p, size %#lx\n",
3291 himc, flags, type, parent, menu, size );
3292 ok( 0, "unexpected call\n" );
3293 return 0;
3296 static UINT WINAPI ime_ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style )
3298 ime_trace( "item %u, style %p\n", item, style );
3300 ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
3301 CHECK_EXPECT( ImeGetRegisterWordStyle );
3303 if (!style)
3304 ok_eq( 16, item, UINT, "%u" );
3305 else if (ime_info.fdwProperty & IME_PROP_UNICODE)
3307 STYLEBUFW *styleW = style;
3308 styleW->dwStyle = 0xdeadbeef;
3309 wcscpy( styleW->szDescription, L"StyleDescription" );
3311 else
3313 STYLEBUFA *styleA = (STYLEBUFA *)style;
3314 styleA->dwStyle = 0xdeadbeef;
3315 strcpy( styleA->szDescription, "StyleDescription" );
3318 return 0xdeadbeef;
3321 static BOOL WINAPI ime_ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags )
3323 ime_trace( "info %p, ui_class %p, flags %#lx\n", info, ui_class, flags );
3325 todo_wine_if( todo_ImeInquire )
3326 CHECK_EXPECT( ImeInquire );
3328 ok( !!info, "got info %p\n", info );
3329 ok( !!ui_class, "got ui_class %p\n", ui_class );
3330 ok( !flags, "got flags %#lx\n", flags );
3332 *info = ime_info;
3334 if (ime_info.fdwProperty & IME_PROP_UNICODE)
3335 wcscpy( ui_class, ime_ui_class.lpszClassName );
3336 else
3337 WideCharToMultiByte( CP_ACP, 0, ime_ui_class.lpszClassName, -1,
3338 (char *)ui_class, 17, NULL, NULL );
3340 return TRUE;
3343 static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE *state )
3345 struct ime_call call =
3347 .hkl = GetKeyboardLayout( 0 ), .himc = himc,
3348 .func = IME_PROCESS_KEY, .process_key = {.vkey = vkey, .lparam = lparam}
3350 ime_trace( "himc %p, vkey %u, lparam %#Ix, state %p\n",
3351 himc, vkey, lparam, state );
3352 ime_calls[ime_call_count++] = call;
3353 return LOWORD(lparam);
3356 static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string )
3358 ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading), style, debugstr_w(string) );
3360 ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
3361 CHECK_EXPECT( ImeRegisterWord );
3363 if (style) ok_eq( 0xdeadbeef, style, UINT, "%#x" );
3364 if (ime_info.fdwProperty & IME_PROP_UNICODE)
3366 if (reading) ok_wcs( L"Reading", reading );
3367 if (string) ok_wcs( L"String", string );
3369 else
3371 if (reading) ok_str( "Reading", (char *)reading );
3372 if (string) ok_str( "String", (char *)string );
3375 return FALSE;
3378 static BOOL WINAPI ime_ImeSelect( HIMC himc, BOOL select )
3380 struct ime_call call =
3382 .hkl = GetKeyboardLayout( 0 ), .himc = himc,
3383 .func = IME_SELECT, .select = select
3385 INPUTCONTEXT *ctx;
3387 ime_trace( "himc %p, select %d\n", himc, select );
3388 ime_calls[ime_call_count++] = call;
3390 if (ImeSelect_init_status && select)
3392 ctx = ImmLockIMC( himc );
3393 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
3394 ctx->fOpen = ~0;
3395 ctx->fdwConversion = ~0;
3396 ctx->fdwSentence = ~0;
3397 ImmUnlockIMC( himc );
3400 return TRUE;
3403 static BOOL WINAPI ime_ImeSetActiveContext( HIMC himc, BOOL flag )
3405 struct ime_call call =
3407 .hkl = GetKeyboardLayout( 0 ), .himc = himc,
3408 .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = flag}
3410 ime_trace( "himc %p, flag %#x\n", himc, flag );
3411 ime_calls[ime_call_count++] = call;
3412 return TRUE;
3415 static BOOL WINAPI ime_ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, DWORD comp_len,
3416 const void *read, DWORD read_len )
3418 ime_trace( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu\n",
3419 himc, index, comp, comp_len, read, read_len );
3420 CHECK_EXPECT( ImeSetCompositionString );
3422 ok_eq( expect_ime, GetKeyboardLayout( 0 ), HKL, "%p" );
3423 ok_ne( default_himc, himc, HIMC, "%p" );
3425 if (ime_info.fdwProperty & IME_PROP_UNICODE)
3427 switch (index)
3429 case SCS_SETSTR:
3430 todo_wine_if( todo_ImeSetCompositionString )
3431 ok_eq( 22, comp_len, UINT, "%#x" );
3432 ok_wcs( L"CompString", comp );
3433 break;
3434 case SCS_CHANGECLAUSE:
3436 const UINT *clause = comp;
3437 ok_eq( 8, comp_len, UINT, "%#x" );
3438 ok_eq( 0, clause[0], UINT, "%#x" );
3439 todo_wine_if( todo_ImeSetCompositionString )
3440 ok_eq( 1, clause[1], UINT, "%#x");
3441 break;
3443 case SCS_CHANGEATTR:
3445 const BYTE *attr = comp;
3446 todo_wine_if( todo_ImeSetCompositionString && comp_len != 4 )
3447 ok_eq( 4, comp_len, UINT, "%#x" );
3448 todo_wine_if( todo_ImeSetCompositionString && attr[0] != 0xcd )
3449 ok_eq( 0xcd, attr[0], UINT, "%#x" );
3450 todo_wine_if( todo_ImeSetCompositionString )
3451 ok_eq( 0xcd, attr[1], UINT, "%#x" );
3452 break;
3454 default:
3455 ok( 0, "unexpected index %#lx\n", index );
3456 break;
3459 else
3461 switch (index)
3463 case SCS_SETSTR:
3464 todo_wine_if( todo_ImeSetCompositionString )
3465 ok_eq( 11, comp_len, UINT, "%#x" );
3466 ok_str( "CompString", comp );
3467 break;
3468 case SCS_CHANGECLAUSE:
3470 const UINT *clause = comp;
3471 ok_eq( 8, comp_len, UINT, "%#x" );
3472 todo_wine_if( todo_ImeSetCompositionString )
3473 ok_eq( 0, clause[0], UINT, "%#x" );
3474 todo_wine_if( todo_ImeSetCompositionString )
3475 ok_eq( 1, clause[1], UINT, "%#x");
3476 break;
3478 case SCS_CHANGEATTR:
3480 const BYTE *attr = comp;
3481 todo_wine_if( todo_ImeSetCompositionString && comp_len != 4 )
3482 ok_eq( 4, comp_len, UINT, "%#x" );
3483 todo_wine_if( todo_ImeSetCompositionString )
3484 ok_eq( 0xcd, attr[0], UINT, "%#x" );
3485 todo_wine_if( todo_ImeSetCompositionString )
3486 ok_eq( 0xcd, attr[1], UINT, "%#x" );
3487 break;
3489 default:
3490 ok( 0, "unexpected index %#lx\n", index );
3491 break;
3495 ok_eq( NULL, read, const void *, "%p" );
3496 ok_eq( 0, read_len, UINT, "%#x" );
3498 return TRUE;
3501 static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, UINT flags, HIMC himc )
3503 struct ime_call call =
3505 .hkl = GetKeyboardLayout( 0 ), .himc = himc,
3506 .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = vkey, .vsc = vsc, .flags = flags}
3508 INPUTCONTEXT *ctx;
3509 UINT count = 0;
3511 ime_trace( "vkey %#x, vsc %#x, state %p, msgs %p, flags %#x, himc %p\n",
3512 vkey, vsc, state, msgs, flags, himc );
3513 ime_calls[ime_call_count++] = call;
3515 ok_ne( NULL, msgs, TRANSMSGLIST *, "%p" );
3516 todo_wine ok_eq( 256, msgs->uMsgCount, UINT, "%u" );
3518 ctx = ImmLockIMC( himc );
3519 ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( ctx->hWnd ) );
3521 if (vsc & 0x200)
3523 msgs->TransMsg[0].message = WM_IME_STARTCOMPOSITION;
3524 msgs->TransMsg[0].wParam = 1;
3525 msgs->TransMsg[0].lParam = 0;
3526 count++;
3527 msgs->TransMsg[1].message = WM_IME_ENDCOMPOSITION;
3528 msgs->TransMsg[1].wParam = 1;
3529 msgs->TransMsg[1].lParam = 0;
3530 count++;
3533 if (vsc & 0x400)
3535 TRANSMSG *msgs;
3537 ctx = ImmLockIMC( himc );
3538 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
3540 ok_ne( NULL, ctx->hMsgBuf, HIMCC, "%p" );
3541 ok_eq( 0, ctx->dwNumMsgBuf, UINT, "%u" );
3543 ctx->hMsgBuf = ImmReSizeIMCC( ctx->hMsgBuf, 64 * sizeof(*msgs) );
3544 ok_ne( NULL, ctx->hMsgBuf, HIMCC, "%p" );
3546 msgs = ImmLockIMCC( ctx->hMsgBuf );
3547 ok_ne( NULL, msgs, TRANSMSG *, "%p" );
3549 msgs[ctx->dwNumMsgBuf].message = WM_IME_STARTCOMPOSITION;
3550 msgs[ctx->dwNumMsgBuf].wParam = 2;
3551 msgs[ctx->dwNumMsgBuf].lParam = 0;
3552 ctx->dwNumMsgBuf++;
3553 msgs[ctx->dwNumMsgBuf].message = WM_IME_ENDCOMPOSITION;
3554 msgs[ctx->dwNumMsgBuf].wParam = 2;
3555 msgs[ctx->dwNumMsgBuf].lParam = 0;
3556 ctx->dwNumMsgBuf++;
3558 ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) );
3561 ok_ret( 1, ImmUnlockIMC( himc ) );
3563 if (vsc & 0x800) count = ~0;
3564 return count;
3567 static BOOL WINAPI ime_ImeUnregisterWord( const WCHAR *reading, DWORD style, const WCHAR *string )
3569 ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading), style, debugstr_w(string) );
3571 ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
3572 CHECK_EXPECT( ImeUnregisterWord );
3574 if (style) ok_eq( 0xdeadbeef, style, UINT, "%#x" );
3575 if (ime_info.fdwProperty & IME_PROP_UNICODE)
3577 if (reading) ok_wcs( L"Reading", reading );
3578 if (string) ok_wcs( L"String", string );
3580 else
3582 if (reading) ok_str( "Reading", (char *)reading );
3583 if (string) ok_str( "String", (char *)string );
3586 return FALSE;
3589 static BOOL WINAPI ime_NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value )
3591 struct ime_call call =
3593 .hkl = GetKeyboardLayout( 0 ), .himc = himc,
3594 .func = IME_NOTIFY, .notify = {.action = action, .index = index, .value = value}
3596 ime_trace( "himc %p, action %#lx, index %lu, value %lu\n", himc, action, index, value );
3597 if (!ignore_IME_NOTIFY) ime_calls[ime_call_count++] = call;
3598 return FALSE;
3601 static BOOL WINAPI ime_DllMain( HINSTANCE instance, DWORD reason, LPVOID reserved )
3603 ime_trace( "instance %p, reason %lu, reserved %p.\n", instance, reason, reserved );
3605 switch (reason)
3607 case DLL_PROCESS_ATTACH:
3608 DisableThreadLibraryCalls( instance );
3609 ime_ui_class.hInstance = instance;
3610 RegisterClassExW( &ime_ui_class );
3611 todo_wine_if(todo_IME_DLL_PROCESS_ATTACH)
3612 CHECK_EXPECT( IME_DLL_PROCESS_ATTACH );
3613 break;
3615 case DLL_PROCESS_DETACH:
3616 UnregisterClassW( ime_ui_class.lpszClassName, instance );
3617 todo_wine_if(todo_IME_DLL_PROCESS_DETACH)
3618 CHECK_EXPECT( IME_DLL_PROCESS_DETACH );
3619 break;
3622 return TRUE;
3625 static struct ime_functions ime_functions =
3627 ime_ImeConfigure,
3628 ime_ImeConversionList,
3629 ime_ImeDestroy,
3630 ime_ImeEnumRegisterWord,
3631 ime_ImeEscape,
3632 ime_ImeGetImeMenuItems,
3633 ime_ImeGetRegisterWordStyle,
3634 ime_ImeInquire,
3635 ime_ImeProcessKey,
3636 ime_ImeRegisterWord,
3637 ime_ImeSelect,
3638 ime_ImeSetActiveContext,
3639 ime_ImeSetCompositionString,
3640 ime_ImeToAsciiEx,
3641 ime_ImeUnregisterWord,
3642 ime_NotifyIME,
3643 ime_DllMain,
3646 static HKL ime_install(void)
3648 WCHAR buffer[MAX_PATH];
3649 HMODULE module;
3650 DWORD len, ret;
3651 HKEY hkey;
3652 HKL hkl;
3654 /* IME module gets cached and won't reload from disk as soon as a window has
3655 * loaded it. To workaround the issue we load the module first as a DLL,
3656 * set its function pointers from the test, and later when the cached IME
3657 * gets loaded, read the function pointers from the separately loaded DLL.
3660 load_resource( L"ime_wrapper.dll", buffer );
3662 SetLastError( 0xdeadbeef );
3663 ret = MoveFileW( buffer, L"c:\\windows\\system32\\winetest_ime.dll" );
3664 if (!ret)
3666 ok( GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError() );
3667 win_skip( "Failed to copy DLL to system directory\n" );
3668 return 0;
3671 module = LoadLibraryW( L"c:\\windows\\system32\\winetest_ime.dll" );
3672 ok( !!module, "LoadLibraryW failed, error %lu\n", GetLastError() );
3673 *(struct ime_functions *)GetProcAddress( module, "ime_functions" ) = ime_functions;
3675 /* install the actual IME module, it will lookup the functions from the DLL */
3676 load_resource( L"ime_wrapper.dll", buffer );
3678 SetLastError( 0xdeadbeef );
3679 swprintf( ime_path, ARRAY_SIZE(ime_path), L"c:\\windows\\system32\\wine%04x.ime", ime_count++ );
3680 ret = MoveFileW( buffer, ime_path );
3681 todo_wine_if( GetLastError() == ERROR_ALREADY_EXISTS )
3682 ok( ret || broken( !ret ) /* sometimes still in use */,
3683 "MoveFileW failed, error %lu\n", GetLastError() );
3685 hkl = ImmInstallIMEW( ime_path, L"WineTest IME" );
3686 ok( hkl == expect_ime, "ImmInstallIMEW returned %p, error %lu\n", hkl, GetLastError() );
3688 swprintf( buffer, ARRAY_SIZE(buffer), L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl );
3689 ret = RegOpenKeyW( HKEY_LOCAL_MACHINE, buffer, &hkey );
3690 ok( !ret, "RegOpenKeyW returned %#lx, error %lu\n", ret, GetLastError() );
3692 len = sizeof(buffer);
3693 memset( buffer, 0xcd, sizeof(buffer) );
3694 ret = RegQueryValueExW( hkey, L"Ime File", NULL, NULL, (BYTE *)buffer, &len );
3695 ok( !ret, "RegQueryValueExW returned %#lx, error %lu\n", ret, GetLastError() );
3696 ok( !wcsicmp( buffer, wcsrchr( ime_path, '\\' ) + 1 ), "got Ime File %s\n", debugstr_w(buffer) );
3698 len = sizeof(buffer);
3699 memset( buffer, 0xcd, sizeof(buffer) );
3700 ret = RegQueryValueExW( hkey, L"Layout Text", NULL, NULL, (BYTE *)buffer, &len );
3701 ok( !ret, "RegQueryValueExW returned %#lx, error %lu\n", ret, GetLastError() );
3702 ok( !wcscmp( buffer, L"WineTest IME" ), "got Layout Text %s\n", debugstr_w(buffer) );
3704 len = sizeof(buffer);
3705 memset( buffer, 0, sizeof(buffer) );
3706 ret = RegQueryValueExW( hkey, L"Layout File", NULL, NULL, (BYTE *)buffer, &len );
3707 todo_wine
3708 ok( !ret, "RegQueryValueExW returned %#lx, error %lu\n", ret, GetLastError() );
3709 todo_wine
3710 ok( !wcscmp( buffer, L"kbdus.dll" ), "got Layout File %s\n", debugstr_w(buffer) );
3712 ret = RegCloseKey( hkey );
3713 ok( !ret, "RegCloseKey returned %#lx, error %lu\n", ret, GetLastError() );
3715 return hkl;
3718 static void ime_cleanup( HKL hkl, BOOL free )
3720 HMODULE module = GetModuleHandleW( L"winetest_ime.dll" );
3721 WCHAR buffer[MAX_PATH], value[MAX_PATH];
3722 DWORD i, buffer_len, value_len, ret;
3723 HKEY hkey;
3725 ret = UnloadKeyboardLayout( hkl );
3726 todo_wine
3727 ok( ret, "UnloadKeyboardLayout failed, error %lu\n", GetLastError() );
3729 if (free) ok_ret( 1, ImmFreeLayout( hkl ) );
3731 swprintf( buffer, ARRAY_SIZE(buffer), L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl );
3732 ret = RegDeleteKeyW( HKEY_LOCAL_MACHINE, buffer );
3733 ok( !ret, "RegDeleteKeyW returned %#lx, error %lu\n", ret, GetLastError() );
3735 ret = RegOpenKeyW( HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", &hkey );
3736 ok( !ret, "RegOpenKeyW returned %#lx, error %lu\n", ret, GetLastError() );
3738 value_len = ARRAY_SIZE(value);
3739 buffer_len = sizeof(buffer);
3740 for (i = 0; !RegEnumValueW( hkey, i, value, &value_len, NULL, NULL, (void *)buffer, &buffer_len ); i++)
3742 value_len = ARRAY_SIZE(value);
3743 buffer_len = sizeof(buffer);
3744 if (HandleToUlong( hkl ) != wcstoul( buffer, NULL, 16 )) continue;
3745 ret = RegDeleteValueW( hkey, value );
3746 ok( !ret, "RegDeleteValueW returned %#lx, error %lu\n", ret, GetLastError() );
3749 ret = RegCloseKey( hkey );
3750 ok( !ret, "RegCloseKey returned %#lx, error %lu\n", ret, GetLastError() );
3752 ret = DeleteFileW( ime_path );
3753 todo_wine_if( GetLastError() == ERROR_ACCESS_DENIED )
3754 ok( ret || broken( !ret ) /* sometimes still in use */,
3755 "DeleteFileW failed, error %lu\n", GetLastError() );
3757 ret = FreeLibrary( module );
3758 ok( ret, "FreeLibrary failed, error %lu\n", GetLastError() );
3760 ret = DeleteFileW( L"c:\\windows\\system32\\winetest_ime.dll" );
3761 ok( ret, "DeleteFileW failed, error %lu\n", GetLastError() );
3764 static BOOL CALLBACK enum_get_context( HIMC himc, LPARAM lparam )
3766 ime_trace( "himc %p\n", himc );
3767 *(HIMC *)lparam = himc;
3768 return TRUE;
3771 static BOOL CALLBACK enum_find_context( HIMC himc, LPARAM lparam )
3773 ime_trace( "himc %p\n", himc );
3774 if (lparam && lparam == (LPARAM)himc) return FALSE;
3775 return TRUE;
3778 static void test_ImmEnumInputContext(void)
3780 HIMC himc;
3782 ok_ret( 1, ImmEnumInputContext( 0, enum_get_context, (LPARAM)&default_himc ) );
3783 ok_ret( 1, ImmEnumInputContext( -1, enum_find_context, 0 ) );
3784 ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, 0 ) );
3786 todo_wine
3787 ok_ret( 0, ImmEnumInputContext( 1, enum_find_context, 0 ) );
3788 todo_wine
3789 ok_ret( 0, ImmEnumInputContext( GetCurrentProcessId(), enum_find_context, 0 ) );
3791 himc = ImmCreateContext();
3792 ok_ne( NULL, himc, HIMC, "%p" );
3793 ok_ret( 0, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, (LPARAM)himc ) );
3794 ok_ret( 1, ImmDestroyContext( himc ) );
3795 ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, (LPARAM)himc ) );
3798 static void test_ImmInstallIME(void)
3800 UINT ret;
3801 HKL hkl;
3803 SET_ENABLE( IME_DLL_PROCESS_ATTACH, TRUE );
3804 SET_ENABLE( ImeInquire, TRUE );
3805 SET_ENABLE( ImeDestroy, TRUE );
3806 SET_ENABLE( IME_DLL_PROCESS_DETACH, TRUE );
3808 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3809 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
3811 if (!(hkl = ime_install())) goto cleanup;
3813 SET_EXPECT( IME_DLL_PROCESS_ATTACH );
3814 SET_EXPECT( ImeInquire );
3815 ret = ImmLoadIME( hkl );
3816 ok( ret, "ImmLoadIME returned %#x\n", ret );
3817 CHECK_CALLED( IME_DLL_PROCESS_ATTACH );
3818 CHECK_CALLED( ImeInquire );
3820 ret = ImmLoadIME( hkl );
3821 ok( ret, "ImmLoadIME returned %#x\n", ret );
3823 SET_EXPECT( ImeDestroy );
3824 SET_EXPECT( IME_DLL_PROCESS_DETACH );
3825 ret = ImmFreeLayout( hkl );
3826 ok( ret, "ImmFreeLayout returned %#x\n", ret );
3827 CHECK_CALLED( ImeDestroy );
3828 CHECK_CALLED( IME_DLL_PROCESS_DETACH );
3830 ret = ImmFreeLayout( hkl );
3831 ok( ret, "ImmFreeLayout returned %#x\n", ret );
3833 ime_info.fdwProperty = 0;
3835 SET_EXPECT( IME_DLL_PROCESS_ATTACH );
3836 SET_EXPECT( ImeInquire );
3837 ret = ImmLoadIME( hkl );
3838 ok( ret, "ImmLoadIME returned %#x\n", ret );
3839 CHECK_CALLED( IME_DLL_PROCESS_ATTACH );
3840 CHECK_CALLED( ImeInquire );
3842 ret = ImmLoadIME( hkl );
3843 ok( ret, "ImmLoadIME returned %#x\n", ret );
3845 SET_EXPECT( ImeDestroy );
3846 SET_EXPECT( IME_DLL_PROCESS_DETACH );
3847 ret = ImmFreeLayout( hkl );
3848 ok( ret, "ImmFreeLayout returned %#x\n", ret );
3849 CHECK_CALLED( ImeDestroy );
3850 CHECK_CALLED( IME_DLL_PROCESS_DETACH );
3852 ret = ImmFreeLayout( hkl );
3853 ok( ret, "ImmFreeLayout returned %#x\n", ret );
3855 ime_cleanup( hkl, FALSE );
3857 cleanup:
3858 SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE );
3859 SET_ENABLE( ImeInquire, FALSE );
3860 SET_ENABLE( ImeDestroy, FALSE );
3861 SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE );
3864 static void test_ImmIsIME(void)
3866 HKL hkl = GetKeyboardLayout( 0 );
3868 SET_ENABLE( IME_DLL_PROCESS_ATTACH, TRUE );
3869 SET_ENABLE( ImeInquire, TRUE );
3870 SET_ENABLE( ImeDestroy, TRUE );
3871 SET_ENABLE( IME_DLL_PROCESS_DETACH, TRUE );
3873 SetLastError( 0xdeadbeef );
3874 ok_ret( 0, ImmIsIME( 0 ) );
3875 ok_ret( 0xdeadbeef, GetLastError() );
3876 ok_ret( 1, ImmIsIME( hkl ) );
3878 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3879 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
3881 if (!(hkl = wineime_hkl)) goto cleanup;
3883 todo_ImeInquire = TRUE;
3884 todo_ImeDestroy = TRUE;
3885 todo_IME_DLL_PROCESS_ATTACH = TRUE;
3886 todo_IME_DLL_PROCESS_DETACH = TRUE;
3887 ok_ret( 1, ImmIsIME( hkl ) );
3888 todo_IME_DLL_PROCESS_ATTACH = FALSE;
3889 todo_IME_DLL_PROCESS_DETACH = FALSE;
3890 todo_ImeInquire = FALSE;
3891 todo_ImeDestroy = FALSE;
3893 cleanup:
3894 SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE );
3895 SET_ENABLE( ImeInquire, FALSE );
3896 SET_ENABLE( ImeDestroy, FALSE );
3897 SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE );
3900 static void test_ImmGetProperty(void)
3902 static const IMEINFO expect_ime_info =
3904 .fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET,
3906 static const IMEINFO expect_ime_info_ja_JP = /* MS Japanese IME */
3908 .fdwProperty = IME_PROP_CANDLIST_START_FROM_1 | IME_PROP_UNICODE | IME_PROP_AT_CARET | 0xa,
3909 .fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE | IME_CMODE_KATAKANA,
3910 .fdwSentenceCaps = IME_SMODE_PLAURALCLAUSE | IME_SMODE_CONVERSATION,
3911 .fdwSCSCaps = SCS_CAP_COMPSTR | SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD,
3912 .fdwSelectCaps = SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE,
3913 .fdwUICaps = UI_CAP_ROT90,
3915 static const IMEINFO expect_ime_info_ko_KR = /* MS Korean IME */
3917 .fdwProperty = IME_PROP_CANDLIST_START_FROM_1 | IME_PROP_UNICODE | IME_PROP_AT_CARET | 0xa,
3918 .fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE,
3919 .fdwSentenceCaps = IME_SMODE_NONE,
3920 .fdwSCSCaps = SCS_CAP_COMPSTR | SCS_CAP_SETRECONVERTSTRING,
3921 .fdwSelectCaps = SELECT_CAP_CONVERSION,
3922 .fdwUICaps = UI_CAP_ROT90,
3924 static const IMEINFO expect_ime_info_zh_CN = /* MS Chinese IME */
3926 .fdwProperty = IME_PROP_CANDLIST_START_FROM_1 | IME_PROP_UNICODE | IME_PROP_AT_CARET | 0xa,
3927 .fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE,
3928 .fdwSentenceCaps = IME_SMODE_PLAURALCLAUSE,
3929 .fdwSCSCaps = SCS_CAP_COMPSTR | SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD,
3930 .fdwUICaps = UI_CAP_ROT90,
3932 HKL hkl = GetKeyboardLayout( 0 );
3933 const IMEINFO *expect;
3935 SET_ENABLE( ImeInquire, TRUE );
3936 SET_ENABLE( ImeDestroy, TRUE );
3938 SetLastError( 0xdeadbeef );
3939 ok_ret( 0, ImmGetProperty( 0, 0 ) );
3940 ok_ret( 0, ImmGetProperty( hkl, 0 ) );
3942 if (hkl == (HKL)0x04110411) expect = &expect_ime_info_ja_JP;
3943 else if (hkl == (HKL)0x04120412) expect = &expect_ime_info_ko_KR;
3944 else if (hkl == (HKL)0x08040804) expect = &expect_ime_info_zh_CN;
3945 else expect = &expect_ime_info;
3947 /* IME_PROP_COMPLETE_ON_UNSELECT seems to be sometimes set on CJK locales IMEs, sometimes not */
3948 todo_wine_if( expect != &expect_ime_info )
3949 ok_ret( expect->fdwProperty, ImmGetProperty( hkl, IGP_PROPERTY ) & ~IME_PROP_COMPLETE_ON_UNSELECT );
3950 todo_wine_if( expect != &expect_ime_info_zh_CN && expect != &expect_ime_info_ko_KR )
3951 ok_ret( expect->fdwConversionCaps, ImmGetProperty( hkl, IGP_CONVERSION ) );
3952 todo_wine
3953 ok_ret( expect->fdwSentenceCaps, ImmGetProperty( hkl, IGP_SENTENCE ) );
3954 todo_wine_if( expect != &expect_ime_info )
3955 ok_ret( expect->fdwSCSCaps, ImmGetProperty( hkl, IGP_SETCOMPSTR ) );
3956 todo_wine_if( expect != &expect_ime_info_ko_KR )
3957 ok_ret( expect->fdwSelectCaps, ImmGetProperty( hkl, IGP_SELECT ) );
3958 ok_ret( IMEVER_0400, ImmGetProperty( hkl, IGP_GETIMEVERSION ) );
3959 todo_wine_if( expect != &expect_ime_info )
3960 ok_ret( expect->fdwUICaps, ImmGetProperty( hkl, IGP_UI ) );
3961 todo_wine
3962 ok_ret( 0xdeadbeef, GetLastError() );
3964 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3965 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
3967 if (!(hkl = wineime_hkl)) goto cleanup;
3969 SET_EXPECT( ImeInquire );
3970 SET_EXPECT( ImeDestroy );
3971 ok_ret( 0, ImmGetProperty( hkl, 0 ) );
3972 CHECK_CALLED( ImeInquire );
3973 CHECK_CALLED( ImeDestroy );
3975 expect = &ime_info;
3976 todo_ImeInquire = TRUE;
3977 todo_ImeDestroy = TRUE;
3978 ok_ret( expect->fdwProperty, ImmGetProperty( hkl, IGP_PROPERTY ) );
3979 ok_ret( expect->fdwConversionCaps, ImmGetProperty( hkl, IGP_CONVERSION ) );
3980 ok_ret( expect->fdwSentenceCaps, ImmGetProperty( hkl, IGP_SENTENCE ) );
3981 ok_ret( expect->fdwSCSCaps, ImmGetProperty( hkl, IGP_SETCOMPSTR ) );
3982 ok_ret( expect->fdwSelectCaps, ImmGetProperty( hkl, IGP_SELECT ) );
3983 ok_ret( IMEVER_0400, ImmGetProperty( hkl, IGP_GETIMEVERSION ) );
3984 ok_ret( expect->fdwUICaps, ImmGetProperty( hkl, IGP_UI ) );
3985 todo_ImeInquire = FALSE;
3986 called_ImeInquire = FALSE;
3987 todo_ImeDestroy = FALSE;
3988 called_ImeDestroy = FALSE;
3990 cleanup:
3991 SET_ENABLE( ImeInquire, FALSE );
3992 SET_ENABLE( ImeDestroy, FALSE );
3995 static void test_ImmGetDescription(void)
3997 HKL hkl = GetKeyboardLayout( 0 );
3998 WCHAR bufferW[MAX_PATH];
3999 char bufferA[MAX_PATH];
4000 DWORD ret;
4002 SET_ENABLE( IME_DLL_PROCESS_ATTACH, TRUE );
4003 SET_ENABLE( ImeInquire, TRUE );
4004 SET_ENABLE( ImeDestroy, TRUE );
4005 SET_ENABLE( IME_DLL_PROCESS_DETACH, TRUE );
4007 SetLastError( 0xdeadbeef );
4008 ret = ImmGetDescriptionW( NULL, NULL, 0 );
4009 ok( !ret, "ImmGetDescriptionW returned %lu\n", ret );
4010 ret = ImmGetDescriptionA( NULL, NULL, 0 );
4011 ok( !ret, "ImmGetDescriptionA returned %lu\n", ret );
4012 ret = ImmGetDescriptionW( NULL, NULL, 100 );
4013 ok( !ret, "ImmGetDescriptionW returned %lu\n", ret );
4014 ret = ImmGetDescriptionA( NULL, NULL, 100 );
4015 ok( !ret, "ImmGetDescriptionA returned %lu\n", ret );
4016 ret = ImmGetDescriptionW( hkl, bufferW, 100 );
4017 ok( !ret, "ImmGetDescriptionW returned %lu\n", ret );
4018 ret = ImmGetDescriptionA( hkl, bufferA, 100 );
4019 ok( !ret, "ImmGetDescriptionA returned %lu\n", ret );
4020 ret = GetLastError();
4021 ok( ret == 0xdeadbeef, "got error %lu\n", ret );
4023 if (!(hkl = wineime_hkl)) goto cleanup;
4025 memset( bufferW, 0xcd, sizeof(bufferW) );
4026 ret = ImmGetDescriptionW( hkl, bufferW, 2 );
4027 ok( ret == 1, "ImmGetDescriptionW returned %lu\n", ret );
4028 ok( !wcscmp( bufferW, L"W" ), "got bufferW %s\n", debugstr_w(bufferW) );
4029 memset( bufferA, 0xcd, sizeof(bufferA) );
4030 ret = ImmGetDescriptionA( hkl, bufferA, 2 );
4031 ok( ret == 0, "ImmGetDescriptionA returned %lu\n", ret );
4032 ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) );
4034 memset( bufferW, 0xcd, sizeof(bufferW) );
4035 ret = ImmGetDescriptionW( hkl, bufferW, 11 );
4036 ok( ret == 10, "ImmGetDescriptionW returned %lu\n", ret );
4037 ok( !wcscmp( bufferW, L"WineTest I" ), "got bufferW %s\n", debugstr_w(bufferW) );
4038 memset( bufferA, 0xcd, sizeof(bufferA) );
4039 ret = ImmGetDescriptionA( hkl, bufferA, 11 );
4040 ok( ret == 0, "ImmGetDescriptionA returned %lu\n", ret );
4041 ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) );
4043 memset( bufferW, 0xcd, sizeof(bufferW) );
4044 ret = ImmGetDescriptionW( hkl, bufferW, 12 );
4045 ok( ret == 11, "ImmGetDescriptionW returned %lu\n", ret );
4046 ok( !wcscmp( bufferW, L"WineTest IM" ), "got bufferW %s\n", debugstr_w(bufferW) );
4047 memset( bufferA, 0xcd, sizeof(bufferA) );
4048 ret = ImmGetDescriptionA( hkl, bufferA, 12 );
4049 ok( ret == 12, "ImmGetDescriptionA returned %lu\n", ret );
4050 ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) );
4052 memset( bufferW, 0xcd, sizeof(bufferW) );
4053 ret = ImmGetDescriptionW( hkl, bufferW, 13 );
4054 ok( ret == 12, "ImmGetDescriptionW returned %lu\n", ret );
4055 ok( !wcscmp( bufferW, L"WineTest IME" ), "got bufferW %s\n", debugstr_w(bufferW) );
4056 memset( bufferA, 0xcd, sizeof(bufferA) );
4057 ret = ImmGetDescriptionA( hkl, bufferA, 13 );
4058 ok( ret == 12, "ImmGetDescriptionA returned %lu\n", ret );
4059 ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) );
4061 cleanup:
4062 SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE );
4063 SET_ENABLE( ImeInquire, FALSE );
4064 SET_ENABLE( ImeDestroy, FALSE );
4065 SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE );
4068 static void test_ImmGetIMEFileName(void)
4070 HKL hkl = GetKeyboardLayout( 0 );
4071 WCHAR bufferW[MAX_PATH], expectW[16];
4072 char bufferA[MAX_PATH], expectA[16];
4073 DWORD ret;
4075 SET_ENABLE( IME_DLL_PROCESS_ATTACH, TRUE );
4076 SET_ENABLE( ImeInquire, TRUE );
4077 SET_ENABLE( ImeDestroy, TRUE );
4078 SET_ENABLE( IME_DLL_PROCESS_DETACH, TRUE );
4080 SetLastError( 0xdeadbeef );
4081 ret = ImmGetIMEFileNameW( NULL, NULL, 0 );
4082 ok( !ret, "ImmGetIMEFileNameW returned %lu\n", ret );
4083 ret = ImmGetIMEFileNameA( NULL, NULL, 0 );
4084 ok( !ret, "ImmGetIMEFileNameA returned %lu\n", ret );
4085 ret = ImmGetIMEFileNameW( NULL, NULL, 100 );
4086 ok( !ret, "ImmGetIMEFileNameW returned %lu\n", ret );
4087 ret = ImmGetIMEFileNameA( NULL, NULL, 100 );
4088 ok( !ret, "ImmGetIMEFileNameA returned %lu\n", ret );
4089 ret = ImmGetIMEFileNameW( hkl, bufferW, 100 );
4090 ok( !ret, "ImmGetIMEFileNameW returned %lu\n", ret );
4091 ret = ImmGetIMEFileNameA( hkl, bufferA, 100 );
4092 ok( !ret, "ImmGetIMEFileNameA returned %lu\n", ret );
4093 ret = GetLastError();
4094 ok( ret == 0xdeadbeef, "got error %lu\n", ret );
4096 if (!(hkl = wineime_hkl)) goto cleanup;
4098 memset( bufferW, 0xcd, sizeof(bufferW) );
4099 ret = ImmGetIMEFileNameW( hkl, bufferW, 2 );
4100 ok( ret == 1, "ImmGetIMEFileNameW returned %lu\n", ret );
4101 ok( !wcscmp( bufferW, L"W" ), "got bufferW %s\n", debugstr_w(bufferW) );
4102 memset( bufferA, 0xcd, sizeof(bufferA) );
4103 ret = ImmGetIMEFileNameA( hkl, bufferA, 2 );
4104 ok( ret == 0, "ImmGetIMEFileNameA returned %lu\n", ret );
4105 ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) );
4107 swprintf( expectW, ARRAY_SIZE(expectW), L"WINE%04X.I", ime_count - 1 );
4108 memset( bufferW, 0xcd, sizeof(bufferW) );
4109 ret = ImmGetIMEFileNameW( hkl, bufferW, 11 );
4110 ok( ret == 10, "ImmGetIMEFileNameW returned %lu\n", ret );
4111 ok( !wcscmp( bufferW, expectW ), "got bufferW %s\n", debugstr_w(bufferW) );
4112 memset( bufferA, 0xcd, sizeof(bufferA) );
4113 ret = ImmGetIMEFileNameA( hkl, bufferA, 11 );
4114 ok( ret == 0, "ImmGetIMEFileNameA returned %lu\n", ret );
4115 ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) );
4117 swprintf( expectW, ARRAY_SIZE(expectW), L"WINE%04X.IM", ime_count - 1 );
4118 memset( bufferW, 0xcd, sizeof(bufferW) );
4119 ret = ImmGetIMEFileNameW( hkl, bufferW, 12 );
4120 ok( ret == 11, "ImmGetIMEFileNameW returned %lu\n", ret );
4121 ok( !wcscmp( bufferW, expectW ), "got bufferW %s\n", debugstr_w(bufferW) );
4122 snprintf( expectA, ARRAY_SIZE(expectA), "WINE%04X.IME", ime_count - 1 );
4123 memset( bufferA, 0xcd, sizeof(bufferA) );
4124 ret = ImmGetIMEFileNameA( hkl, bufferA, 12 );
4125 ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret );
4126 ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) );
4128 swprintf( expectW, ARRAY_SIZE(expectW), L"WINE%04X.IME", ime_count - 1 );
4129 memset( bufferW, 0xcd, sizeof(bufferW) );
4130 ret = ImmGetIMEFileNameW( hkl, bufferW, 13 );
4131 ok( ret == 12, "ImmGetIMEFileNameW returned %lu\n", ret );
4132 ok( !wcscmp( bufferW, expectW ), "got bufferW %s\n", debugstr_w(bufferW) );
4133 memset( bufferA, 0xcd, sizeof(bufferA) );
4134 ret = ImmGetIMEFileNameA( hkl, bufferA, 13 );
4135 ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret );
4136 ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) );
4138 cleanup:
4139 SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE );
4140 SET_ENABLE( ImeInquire, FALSE );
4141 SET_ENABLE( ImeDestroy, FALSE );
4142 SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE );
4145 static void test_ImmEscape( BOOL unicode )
4147 HKL hkl = GetKeyboardLayout( 0 );
4148 DWORD i, codes[] =
4150 IME_ESC_QUERY_SUPPORT,
4151 IME_ESC_SEQUENCE_TO_INTERNAL,
4152 IME_ESC_GET_EUDC_DICTIONARY,
4153 IME_ESC_SET_EUDC_DICTIONARY,
4154 IME_ESC_MAX_KEY,
4155 IME_ESC_IME_NAME,
4156 IME_ESC_HANJA_MODE,
4157 IME_ESC_GETHELPFILENAME,
4159 WCHAR bufferW[512];
4160 char bufferA[512];
4162 SET_ENABLE( ImeEscape, TRUE );
4164 winetest_push_context( unicode ? "unicode" : "ansi" );
4166 ok_ret( 0, ImmEscapeW( hkl, 0, 0, NULL ) );
4167 ok_ret( 0, ImmEscapeA( hkl, 0, 0, NULL ) );
4169 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
4170 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
4171 if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
4173 if (!(hkl = wineime_hkl)) goto cleanup;
4175 for (i = 0; i < ARRAY_SIZE(codes); ++i)
4177 winetest_push_context( "esc %#lx", codes[i] );
4179 SET_EXPECT( ImeEscape );
4180 ok_ret( 4, ImmEscapeW( hkl, 0, codes[i], NULL ) );
4181 CHECK_CALLED( ImeEscape );
4183 SET_EXPECT( ImeEscape );
4184 memset( bufferW, 0xcd, sizeof(bufferW) );
4185 if (codes[i] == IME_ESC_SET_EUDC_DICTIONARY) wcscpy( bufferW, L"EscapeIme" );
4186 ok_ret( 4, ImmEscapeW( hkl, 0, codes[i], bufferW ) );
4187 if (unicode || codes[i] == IME_ESC_GET_EUDC_DICTIONARY || codes[i] == IME_ESC_IME_NAME ||
4188 codes[i] == IME_ESC_GETHELPFILENAME)
4190 ok_wcs( L"ImeEscape", bufferW );
4191 ok_eq( 0xcdcd, bufferW[10], WORD, "%#x" );
4193 else if (codes[i] == IME_ESC_SET_EUDC_DICTIONARY)
4195 ok_wcs( L"EscapeIme", bufferW );
4196 ok_eq( 0xcdcd, bufferW[10], WORD, "%#x" );
4198 else if (codes[i] == IME_ESC_HANJA_MODE)
4200 todo_wine
4201 ok_eq( 0xcdcd, bufferW[0], WORD, "%#x" );
4203 else
4205 ok( !memcmp( bufferW, "ImeEscape", 10 ), "got bufferW %s\n", debugstr_w(bufferW) );
4206 ok_eq( 0xcdcd, bufferW[5], WORD, "%#x" );
4208 CHECK_CALLED( ImeEscape );
4210 SET_EXPECT( ImeEscape );
4211 ok_ret( 4, ImmEscapeA( hkl, 0, codes[i], NULL ) );
4212 CHECK_CALLED( ImeEscape );
4214 SET_EXPECT( ImeEscape );
4215 memset( bufferA, 0xcd, sizeof(bufferA) );
4216 if (codes[i] == IME_ESC_SET_EUDC_DICTIONARY) strcpy( bufferA, "EscapeIme" );
4217 ok_ret( 4, ImmEscapeA( hkl, 0, codes[i], bufferA ) );
4218 if (!unicode || codes[i] == IME_ESC_GET_EUDC_DICTIONARY || codes[i] == IME_ESC_IME_NAME ||
4219 codes[i] == IME_ESC_GETHELPFILENAME)
4221 ok_str( "ImeEscape", bufferA );
4222 ok_eq( 0xcd, bufferA[10], BYTE, "%#x" );
4224 else if (codes[i] == IME_ESC_SET_EUDC_DICTIONARY)
4226 ok_str( "EscapeIme", bufferA );
4227 ok_eq( 0xcd, bufferA[10], BYTE, "%#x" );
4229 else if (codes[i] == IME_ESC_HANJA_MODE)
4231 todo_wine
4232 ok_eq( 0xcd, bufferA[0], BYTE, "%#x" );
4234 else
4236 ok( !memcmp( bufferA, L"ImeEscape", 10 * sizeof(WCHAR) ), "got bufferA %s\n", debugstr_a(bufferA) );
4237 ok_eq( 0xcd, bufferA[20], BYTE, "%#x" );
4239 CHECK_CALLED( ImeEscape );
4241 winetest_pop_context();
4244 cleanup:
4245 SET_ENABLE( ImeEscape, FALSE );
4247 winetest_pop_context();
4250 static int CALLBACK enum_register_wordA( const char *reading, DWORD style, const char *string, void *user )
4252 ime_trace( "reading %s, style %#lx, string %s, user %p\n", debugstr_a(reading), style, debugstr_a(string), user );
4254 ok_eq( 0xdeadbeef, style, UINT, "%#x" );
4255 ok_str( "Reading", reading );
4256 ok_str( "String", string );
4258 return 0xdeadbeef;
4261 static int CALLBACK enum_register_wordW( const WCHAR *reading, DWORD style, const WCHAR *string, void *user )
4263 ime_trace( "reading %s, style %#lx, string %s, user %p\n", debugstr_w(reading), style, debugstr_w(string), user );
4265 ok_eq( 0xdeadbeef, style, UINT, "%#x" );
4266 ok_wcs( L"Reading", reading );
4267 ok_wcs( L"String", string );
4269 return 0xdeadbeef;
4272 static void test_ImmEnumRegisterWord( BOOL unicode )
4274 HKL hkl = GetKeyboardLayout( 0 );
4276 winetest_push_context( unicode ? "unicode" : "ansi" );
4278 SET_ENABLE( ImeEnumRegisterWord, TRUE );
4280 SetLastError( 0xdeadbeef );
4281 ok_ret( 0, ImmEnumRegisterWordW( NULL, enum_register_wordW, NULL, 0, NULL, NULL ) );
4282 ok_ret( 0, ImmEnumRegisterWordA( NULL, enum_register_wordA, NULL, 0, NULL, NULL ) );
4283 ok_ret( 0, ImmEnumRegisterWordW( hkl, enum_register_wordW, NULL, 0, NULL, NULL ) );
4284 ok_ret( 0, ImmEnumRegisterWordA( hkl, enum_register_wordA, NULL, 0, NULL, NULL ) );
4285 todo_wine
4286 ok_ret( 0xdeadbeef, GetLastError() );
4288 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
4289 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
4290 if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
4292 if (!(hkl = wineime_hkl)) goto cleanup;
4294 SET_EXPECT( ImeEnumRegisterWord );
4295 ok_ret( 0, ImmEnumRegisterWordW( hkl, enum_register_wordW, NULL, 0, NULL, NULL ) );
4296 CHECK_CALLED( ImeEnumRegisterWord );
4298 SET_EXPECT( ImeEnumRegisterWord );
4299 ok_ret( 0, ImmEnumRegisterWordA( hkl, enum_register_wordA, NULL, 0, NULL, NULL ) );
4300 CHECK_CALLED( ImeEnumRegisterWord );
4302 SET_EXPECT( ImeEnumRegisterWord );
4303 ok_ret( 0xdeadbeef, ImmEnumRegisterWordW( hkl, enum_register_wordW, L"Reading", 0xdeadbeef, L"String", NULL ) );
4304 CHECK_CALLED( ImeEnumRegisterWord );
4306 SET_EXPECT( ImeEnumRegisterWord );
4307 ok_ret( 0xdeadbeef, ImmEnumRegisterWordA( hkl, enum_register_wordA, "Reading", 0xdeadbeef, "String", NULL ) );
4308 CHECK_CALLED( ImeEnumRegisterWord );
4310 cleanup:
4311 SET_ENABLE( ImeEnumRegisterWord, FALSE );
4313 winetest_pop_context();
4316 static void test_ImmRegisterWord( BOOL unicode )
4318 HKL hkl = GetKeyboardLayout( 0 );
4320 SET_ENABLE( ImeRegisterWord, TRUE );
4322 winetest_push_context( unicode ? "unicode" : "ansi" );
4324 SetLastError( 0xdeadbeef );
4325 ok_ret( 0, ImmRegisterWordW( NULL, NULL, 0, NULL ) );
4326 ok_ret( 0, ImmRegisterWordA( NULL, NULL, 0, NULL ) );
4327 ok_ret( 0, ImmRegisterWordW( hkl, NULL, 0, NULL ) );
4328 ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0, NULL ) );
4329 todo_wine
4330 ok_ret( 0xdeadbeef, GetLastError() );
4332 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
4333 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
4334 if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
4336 if (!(hkl = wineime_hkl)) goto cleanup;
4338 SET_EXPECT( ImeRegisterWord );
4339 ok_ret( 0, ImmRegisterWordW( hkl, NULL, 0, NULL ) );
4340 CHECK_CALLED( ImeRegisterWord );
4342 SET_EXPECT( ImeRegisterWord );
4343 ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0, NULL ) );
4344 CHECK_CALLED( ImeRegisterWord );
4346 SET_EXPECT( ImeRegisterWord );
4347 ok_ret( 0, ImmRegisterWordW( hkl, L"Reading", 0, NULL ) );
4348 CHECK_CALLED( ImeRegisterWord );
4350 SET_EXPECT( ImeRegisterWord );
4351 ok_ret( 0, ImmRegisterWordA( hkl, "Reading", 0, NULL ) );
4352 CHECK_CALLED( ImeRegisterWord );
4354 SET_EXPECT( ImeRegisterWord );
4355 ok_ret( 0, ImmRegisterWordW( hkl, NULL, 0xdeadbeef, NULL ) );
4356 CHECK_CALLED( ImeRegisterWord );
4358 SET_EXPECT( ImeRegisterWord );
4359 ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0xdeadbeef, NULL ) );
4360 CHECK_CALLED( ImeRegisterWord );
4362 SET_EXPECT( ImeRegisterWord );
4363 ok_ret( 0, ImmRegisterWordW( hkl, NULL, 0, L"String" ) );
4364 CHECK_CALLED( ImeRegisterWord );
4366 SET_EXPECT( ImeRegisterWord );
4367 ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0, "String" ) );
4368 CHECK_CALLED( ImeRegisterWord );
4370 cleanup:
4371 SET_ENABLE( ImeRegisterWord, FALSE );
4373 winetest_pop_context();
4376 static void test_ImmGetRegisterWordStyle( BOOL unicode )
4378 HKL hkl = GetKeyboardLayout( 0 );
4379 STYLEBUFW styleW;
4380 STYLEBUFA styleA;
4382 winetest_push_context( unicode ? "unicode" : "ansi" );
4384 SET_ENABLE( ImeGetRegisterWordStyle, TRUE );
4386 SetLastError( 0xdeadbeef );
4387 ok_ret( 0, ImmGetRegisterWordStyleW( NULL, 0, &styleW ) );
4388 ok_ret( 0, ImmGetRegisterWordStyleA( NULL, 0, &styleA ) );
4389 ok_ret( 0, ImmGetRegisterWordStyleW( hkl, 0, &styleW ) );
4390 ok_ret( 0, ImmGetRegisterWordStyleA( hkl, 0, &styleA ) );
4391 todo_wine
4392 ok_ret( 0xdeadbeef, GetLastError() );
4394 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
4395 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
4396 if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
4398 if (!(hkl = wineime_hkl)) goto cleanup;
4400 if (!strcmp( winetest_platform, "wine" )) goto skip_null;
4402 SET_EXPECT( ImeGetRegisterWordStyle );
4403 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleW( hkl, 16, NULL ) );
4404 CHECK_CALLED( ImeGetRegisterWordStyle );
4406 SET_EXPECT( ImeGetRegisterWordStyle );
4407 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleA( hkl, 16, NULL ) );
4408 CHECK_CALLED( ImeGetRegisterWordStyle );
4410 skip_null:
4411 SET_EXPECT( ImeGetRegisterWordStyle );
4412 memset( &styleW, 0xcd, sizeof(styleW) );
4413 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleW( hkl, 1, &styleW ) );
4414 if (ime_info.fdwProperty & IME_PROP_UNICODE)
4416 ok_eq( 0xdeadbeef, styleW.dwStyle, UINT, "%#x" );
4417 ok_wcs( L"StyleDescription", styleW.szDescription );
4419 else
4421 todo_wine
4422 ok_eq( 0xcdcdcdcd, styleW.dwStyle, UINT, "%#x" );
4423 todo_wine
4424 ok_eq( 0xcdcd, styleW.szDescription[0], WORD, "%#x" );
4426 CHECK_CALLED( ImeGetRegisterWordStyle );
4428 SET_EXPECT( ImeGetRegisterWordStyle );
4429 memset( &styleA, 0xcd, sizeof(styleA) );
4430 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleA( hkl, 1, &styleA ) );
4431 if (ime_info.fdwProperty & IME_PROP_UNICODE)
4433 todo_wine
4434 ok_eq( 0xcdcdcdcd, styleA.dwStyle, UINT, "%#x" );
4435 todo_wine
4436 ok_eq( 0xcd, styleA.szDescription[0], BYTE, "%#x" );
4438 else
4440 ok_eq( 0xdeadbeef, styleA.dwStyle, UINT, "%#x" );
4441 ok_str( "StyleDescription", styleA.szDescription );
4443 CHECK_CALLED( ImeGetRegisterWordStyle );
4445 cleanup:
4446 SET_ENABLE( ImeGetRegisterWordStyle, FALSE );
4448 winetest_pop_context();
4451 static void test_ImmUnregisterWord( BOOL unicode )
4453 HKL hkl = GetKeyboardLayout( 0 );
4455 winetest_push_context( unicode ? "unicode" : "ansi" );
4457 SET_ENABLE( ImeUnregisterWord, TRUE );
4459 SetLastError( 0xdeadbeef );
4460 ok_ret( 0, ImmUnregisterWordW( NULL, NULL, 0, NULL ) );
4461 ok_ret( 0, ImmUnregisterWordA( NULL, NULL, 0, NULL ) );
4462 ok_ret( 0, ImmUnregisterWordW( hkl, NULL, 0, NULL ) );
4463 ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0, NULL ) );
4464 todo_wine
4465 ok_ret( 0xdeadbeef, GetLastError() );
4467 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
4468 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
4469 if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
4471 if (!(hkl = wineime_hkl)) goto cleanup;
4473 SET_EXPECT( ImeUnregisterWord );
4474 ok_ret( 0, ImmUnregisterWordW( hkl, NULL, 0, NULL ) );
4475 CHECK_CALLED( ImeUnregisterWord );
4477 SET_EXPECT( ImeUnregisterWord );
4478 ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0, NULL ) );
4479 CHECK_CALLED( ImeUnregisterWord );
4481 SET_EXPECT( ImeUnregisterWord );
4482 ok_ret( 0, ImmUnregisterWordW( hkl, L"Reading", 0, NULL ) );
4483 CHECK_CALLED( ImeUnregisterWord );
4485 SET_EXPECT( ImeUnregisterWord );
4486 ok_ret( 0, ImmUnregisterWordA( hkl, "Reading", 0, NULL ) );
4487 CHECK_CALLED( ImeUnregisterWord );
4489 SET_EXPECT( ImeUnregisterWord );
4490 ok_ret( 0, ImmUnregisterWordW( hkl, NULL, 0xdeadbeef, NULL ) );
4491 CHECK_CALLED( ImeUnregisterWord );
4493 SET_EXPECT( ImeUnregisterWord );
4494 ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0xdeadbeef, NULL ) );
4495 CHECK_CALLED( ImeUnregisterWord );
4497 SET_EXPECT( ImeUnregisterWord );
4498 ok_ret( 0, ImmUnregisterWordW( hkl, NULL, 0, L"String" ) );
4499 CHECK_CALLED( ImeUnregisterWord );
4501 SET_EXPECT( ImeUnregisterWord );
4502 ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0, "String" ) );
4503 CHECK_CALLED( ImeUnregisterWord );
4505 cleanup:
4506 SET_ENABLE( ImeUnregisterWord, FALSE );
4508 winetest_pop_context();
4511 struct ime_windows
4513 HWND ime_hwnd;
4514 HWND ime_ui_hwnd;
4517 static BOOL CALLBACK enum_thread_ime_windows( HWND hwnd, LPARAM lparam )
4519 struct ime_windows *params = (void *)lparam;
4520 WCHAR buffer[256];
4521 UINT ret;
4523 ime_trace( "hwnd %p, lparam %#Ix\n", hwnd, lparam );
4525 ret = RealGetWindowClassW( hwnd, buffer, ARRAY_SIZE(buffer) );
4526 ok( ret, "RealGetWindowClassW returned %#x\n", ret );
4528 if (!wcscmp( buffer, L"IME" ))
4530 ok( !params->ime_hwnd, "Found extra IME window %p\n", hwnd );
4531 params->ime_hwnd = hwnd;
4533 if (!wcscmp( buffer, ime_ui_class.lpszClassName ))
4535 ok( !params->ime_ui_hwnd, "Found extra IME UI window %p\n", hwnd );
4536 params->ime_ui_hwnd = hwnd;
4539 return TRUE;
4542 static void test_ImmSetConversionStatus(void)
4544 const struct ime_call set_conversion_status_0_seq[] =
4547 .hkl = expect_ime, .himc = default_himc,
4548 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCONVERSIONMODE},
4551 .hkl = expect_ime, .himc = default_himc,
4552 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE},
4555 .hkl = expect_ime, .himc = default_himc,
4556 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE},
4559 .hkl = expect_ime, .himc = default_himc,
4560 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETSENTENCEMODE},
4563 .hkl = expect_ime, .himc = default_himc,
4564 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE},
4567 .hkl = expect_ime, .himc = default_himc,
4568 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE},
4570 {0},
4572 const struct ime_call set_conversion_status_1_seq[] =
4575 .hkl = expect_ime, .himc = default_himc,
4576 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0xdeadbeef, .value = IMC_SETCONVERSIONMODE},
4578 {0},
4580 const struct ime_call set_conversion_status_2_seq[] =
4583 .hkl = expect_ime, .himc = default_himc,
4584 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCONVERSIONMODE},
4587 .hkl = expect_ime, .himc = default_himc,
4588 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE},
4591 .hkl = expect_ime, .himc = default_himc,
4592 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE},
4595 .hkl = expect_ime, .himc = default_himc,
4596 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0xfeedcafe, .value = IMC_SETSENTENCEMODE},
4599 .hkl = expect_ime, .himc = default_himc,
4600 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE},
4603 .hkl = expect_ime, .himc = default_himc,
4604 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE},
4606 {0},
4608 DWORD old_conversion, old_sentence, conversion, sentence;
4609 HKL hkl;
4610 INPUTCONTEXT *ctx;
4611 HWND hwnd;
4613 ok_ret( 0, ImmGetConversionStatus( 0, &old_conversion, &old_sentence ) );
4614 ok_ret( 1, ImmGetConversionStatus( default_himc, &old_conversion, &old_sentence ) );
4616 ctx = ImmLockIMC( default_himc );
4617 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
4618 ok_eq( old_conversion, ctx->fdwConversion, UINT, "%#x" );
4619 ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" );
4621 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4622 100, 100, 100, 100, NULL, NULL, NULL, NULL );
4623 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
4624 process_messages();
4626 ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) );
4627 ok_eq( old_conversion, conversion, UINT, "%#x" );
4628 ok_eq( old_sentence, sentence, UINT, "%#x" );
4629 ok_eq( old_conversion, ctx->fdwConversion, UINT, "%#x" );
4630 ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" );
4632 ok_ret( 1, ImmSetConversionStatus( default_himc, 0, 0 ) );
4633 ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) );
4634 ok_eq( 0, conversion, UINT, "%#x" );
4635 ok_eq( 0, sentence, UINT, "%#x" );
4636 ok_eq( 0, ctx->fdwConversion, UINT, "%#x" );
4637 ok_eq( 0, ctx->fdwSentence, UINT, "%#x" );
4639 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
4641 if (!(hkl = wineime_hkl)) goto cleanup;
4643 ok_ret( 1, ImmActivateLayout( hkl ) );
4644 ok_ret( 1, ImmLoadIME( hkl ) );
4645 process_messages();
4646 /* initial values are dependent on both old and new IME */
4647 ok_ret( 1, ImmSetConversionStatus( default_himc, 0, 0 ) );
4648 memset( ime_calls, 0, sizeof(ime_calls) );
4649 ime_call_count = 0;
4651 ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) );
4652 ok_eq( 0, conversion, UINT, "%#x" );
4653 ok_eq( 0, sentence, UINT, "%#x" );
4654 ok_eq( 0, ctx->fdwConversion, UINT, "%#x" );
4655 ok_eq( 0, ctx->fdwSentence, UINT, "%#x" );
4657 ok_seq( empty_sequence );
4658 ok_ret( 1, ImmSetConversionStatus( default_himc, 0xdeadbeef, 0xfeedcafe ) );
4659 ok_seq( set_conversion_status_0_seq );
4661 ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) );
4662 ok_eq( 0xdeadbeef, conversion, UINT, "%#x" );
4663 ok_eq( 0xfeedcafe, sentence, UINT, "%#x" );
4664 ok_eq( 0xdeadbeef, ctx->fdwConversion, UINT, "%#x" );
4665 ok_eq( 0xfeedcafe, ctx->fdwSentence, UINT, "%#x" );
4667 ok_ret( 1, ImmSetConversionStatus( default_himc, 0xdeadbeef, 0xfeedcafe ) );
4668 ok_seq( empty_sequence );
4670 ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, NULL ) );
4671 ok_eq( 0xdeadbeef, conversion, UINT, "%#x" );
4672 ok_eq( 0xdeadbeef, ctx->fdwConversion, UINT, "%#x" );
4673 ok_eq( 0xfeedcafe, ctx->fdwSentence, UINT, "%#x" );
4675 ctx->hWnd = 0;
4676 ok_seq( empty_sequence );
4677 ok_ret( 1, ImmSetConversionStatus( default_himc, 0, 0xfeedcafe ) );
4678 ok_seq( set_conversion_status_1_seq );
4680 ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) );
4681 ok_eq( 0, conversion, UINT, "%#x" );
4682 ok_eq( 0xfeedcafe, sentence, UINT, "%#x" );
4683 ok_eq( 0, ctx->fdwConversion, UINT, "%#x" );
4684 ok_eq( 0xfeedcafe, ctx->fdwSentence, UINT, "%#x" );
4686 ctx->hWnd = hwnd;
4687 ok_seq( empty_sequence );
4688 ok_ret( 1, ImmSetConversionStatus( default_himc, ~0, ~0 ) );
4689 ok_seq( set_conversion_status_2_seq );
4691 ok_ret( 1, ImmGetConversionStatus( default_himc, NULL, &sentence ) );
4692 ok_eq( ~0, sentence, UINT, "%#x" );
4693 ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" );
4694 ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" );
4696 ok_ret( 1, ImmSetConversionStatus( default_himc, ~0, ~0 ) );
4697 ok_seq( empty_sequence );
4699 ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) );
4700 ok_eq( ~0, conversion, UINT, "%#x" );
4701 ok_eq( ~0, sentence, UINT, "%#x" );
4702 ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" );
4703 ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" );
4705 /* status is cached and some bits are kept from the previous active IME */
4706 ok_ret( 1, ImmActivateLayout( default_hkl ) );
4707 todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" );
4708 ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" );
4709 ok_ret( 1, ImmActivateLayout( hkl ) );
4710 ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" );
4711 ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" );
4712 ok_ret( 1, ImmActivateLayout( default_hkl ) );
4713 todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" );
4714 ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" );
4716 ok_ret( 1, ImmFreeLayout( hkl ) );
4718 cleanup:
4719 /* sanitize conversion status to some sane default */
4720 ok_ret( 1, ImmSetConversionStatus( default_himc, 0, 0 ) );
4721 ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) );
4722 ok_eq( 0, conversion, UINT, "%#x" );
4723 ok_eq( 0, sentence, UINT, "%#x" );
4724 ok_eq( 0, ctx->fdwConversion, UINT, "%#x" );
4725 ok_eq( 0, ctx->fdwSentence, UINT, "%#x" );
4727 ok_ret( 1, DestroyWindow( hwnd ) );
4728 process_messages();
4729 memset( ime_calls, 0, sizeof(ime_calls) );
4730 ime_call_count = 0;
4732 ok_ret( 1, ImmUnlockIMC( default_himc ) );
4735 static void test_ImmSetOpenStatus(void)
4737 const struct ime_call set_open_status_0_seq[] =
4740 .hkl = expect_ime, .himc = default_himc,
4741 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS},
4744 .hkl = expect_ime, .himc = default_himc,
4745 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS},
4748 .hkl = expect_ime, .himc = default_himc,
4749 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS},
4751 {0},
4753 const struct ime_call set_open_status_1_seq[] =
4756 .hkl = expect_ime, .himc = default_himc,
4757 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS},
4759 {0},
4761 const struct ime_call set_open_status_2_seq[] =
4764 .hkl = expect_ime, .himc = default_himc,
4765 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS},
4768 .hkl = expect_ime, .himc = default_himc,
4769 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS},
4772 .hkl = expect_ime, .himc = default_himc,
4773 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS},
4775 {0},
4777 HKL hkl;
4778 struct ime_windows ime_windows = {0};
4779 DWORD old_status, status;
4780 INPUTCONTEXT *ctx;
4781 HIMC himc;
4782 HWND hwnd;
4784 ok_ret( 0, ImmGetOpenStatus( 0 ) );
4785 old_status = ImmGetOpenStatus( default_himc );
4787 ctx = ImmLockIMC( default_himc );
4788 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
4789 ok_eq( old_status, ctx->fOpen, UINT, "%#x" );
4791 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4792 100, 100, 100, 100, NULL, NULL, NULL, NULL );
4793 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
4794 process_messages();
4796 status = ImmGetOpenStatus( default_himc );
4797 ok_eq( old_status, status, UINT, "%#x" );
4798 ok_eq( old_status, ctx->fOpen, UINT, "%#x" );
4800 ok_ret( 1, ImmSetOpenStatus( default_himc, 0 ) );
4801 status = ImmGetOpenStatus( default_himc );
4802 ok_eq( 0, status, UINT, "%#x" );
4803 ok_eq( 0, ctx->fOpen, UINT, "%#x" );
4805 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
4807 if (!(hkl = wineime_hkl)) goto cleanup;
4809 ok_ret( 1, ImmActivateLayout( hkl ) );
4810 ok_ret( 1, ImmLoadIME( hkl ) );
4811 process_messages();
4812 /* initial values are dependent on both old and new IME */
4813 ok_ret( 1, ImmSetOpenStatus( default_himc, 0 ) );
4814 memset( ime_calls, 0, sizeof(ime_calls) );
4815 ime_call_count = 0;
4817 status = ImmGetOpenStatus( default_himc );
4818 ok_eq( 0, status, UINT, "%#x" );
4819 ok_eq( 0, ctx->fOpen, UINT, "%#x" );
4821 ok_seq( empty_sequence );
4822 ok_ret( 1, ImmSetOpenStatus( default_himc, 0xdeadbeef ) );
4823 ok_seq( set_open_status_0_seq );
4825 status = ImmGetOpenStatus( default_himc );
4826 ok_eq( 0xdeadbeef, status, UINT, "%#x" );
4827 ok_eq( 0xdeadbeef, ctx->fOpen, UINT, "%#x" );
4829 ok_ret( 1, ImmSetOpenStatus( default_himc, 0xdeadbeef ) );
4830 ok_seq( empty_sequence );
4832 himc = ImmCreateContext();
4833 ok_ne( NULL, himc, HIMC, "%p" );
4834 ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) );
4835 ok_ne( NULL, ime_windows.ime_hwnd, HWND, "%p" );
4836 ok_ne( NULL, ime_windows.ime_ui_hwnd, HWND, "%p" );
4837 ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" );
4838 ok_ret( 1, ImmSetOpenStatus( himc, TRUE ) );
4839 ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" );
4840 ok_ret( 1, ImmSetOpenStatus( himc, FALSE ) );
4841 ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" );
4842 ok_ret( 1, ImmDestroyContext( himc ) );
4843 memset( ime_calls, 0, sizeof(ime_calls) );
4844 ime_call_count = 0;
4846 status = ImmGetOpenStatus( default_himc );
4847 ok( status == 0xdeadbeef || status == 0 /* MS Korean IME */, "got status %#lx\n", status );
4848 ok_eq( status, ctx->fOpen, UINT, "%#x" );
4850 ctx->hWnd = 0;
4851 ok_ret( 1, ImmSetOpenStatus( default_himc, 0xfeedcafe ) );
4852 ok_seq( set_open_status_1_seq );
4854 status = ImmGetOpenStatus( default_himc );
4855 ok_eq( 0xfeedcafe, status, UINT, "%#x" );
4856 ok_eq( 0xfeedcafe, ctx->fOpen, UINT, "%#x" );
4858 ctx->hWnd = hwnd;
4859 ok_seq( empty_sequence );
4860 ok_ret( 1, ImmSetOpenStatus( default_himc, ~0 ) );
4861 ok_seq( set_open_status_2_seq );
4863 status = ImmGetOpenStatus( default_himc );
4864 ok_eq( ~0, status, UINT, "%#x" );
4865 ok_eq( ~0, ctx->fOpen, UINT, "%#x" );
4867 ok_ret( 1, ImmSetOpenStatus( default_himc, ~0 ) );
4868 ok_seq( empty_sequence );
4870 status = ImmGetOpenStatus( default_himc );
4871 ok_eq( ~0, status, UINT, "%#x" );
4872 ok_eq( ~0, ctx->fOpen, UINT, "%#x" );
4874 /* status is cached between IME activations */
4876 ok_ret( 1, ImmActivateLayout( default_hkl ) );
4877 status = ImmGetOpenStatus( default_himc );
4878 ok_eq( old_status, status, UINT, "%#x" );
4879 ok_eq( old_status, ctx->fOpen, UINT, "%#x" );
4880 ok_ret( 1, ImmActivateLayout( hkl ) );
4881 status = ImmGetOpenStatus( default_himc );
4882 todo_wine ok_eq( 1, status, UINT, "%#x" );
4883 todo_wine ok_eq( 1, ctx->fOpen, UINT, "%#x" );
4884 ok_ret( 1, ImmSetOpenStatus( default_himc, 0 ) );
4885 ok_ret( 1, ImmActivateLayout( default_hkl ) );
4886 status = ImmGetOpenStatus( default_himc );
4887 ok_eq( old_status, status, UINT, "%#x" );
4888 ok_eq( old_status, ctx->fOpen, UINT, "%#x" );
4890 ok_ret( 1, ImmFreeLayout( hkl ) );
4892 cleanup:
4893 /* sanitize open status to some sane default */
4894 ok_ret( 1, ImmSetOpenStatus( default_himc, 0 ) );
4895 status = ImmGetOpenStatus( default_himc );
4896 ok_eq( 0, status, UINT, "%#x" );
4897 ok_eq( 0, ctx->fOpen, UINT, "%#x" );
4899 ok_ret( 1, DestroyWindow( hwnd ) );
4900 process_messages();
4901 memset( ime_calls, 0, sizeof(ime_calls) );
4902 ime_call_count = 0;
4904 ok_ret( 1, ImmUnlockIMC( default_himc ) );
4907 static void test_ImmProcessKey(void)
4909 const struct ime_call process_key_0[] =
4912 .hkl = expect_ime, .himc = default_himc,
4913 .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = MAKELONG(0, 0x1e)},
4915 {0},
4917 const struct ime_call process_key_1[] =
4920 .hkl = expect_ime, .himc = default_himc,
4921 .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = MAKELONG(1, 0x1e)},
4923 {0},
4925 const struct ime_call process_key_2[] =
4928 .hkl = expect_ime, .himc = default_himc,
4929 .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = MAKELONG(2, 0x1e)},
4931 {0},
4933 HKL hkl;
4934 UINT_PTR ret;
4935 HIMC himc;
4936 HWND hwnd;
4938 hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4939 100, 100, 100, 100, NULL, NULL, NULL, NULL );
4940 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
4941 process_messages();
4943 ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', MAKELONG(1, 0x1e), 0 ) );
4944 ok_seq( empty_sequence );
4946 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
4948 if (!(hkl = wineime_hkl)) goto cleanup;
4950 ok_ret( 1, ImmActivateLayout( hkl ) );
4951 ok_ret( 1, ImmLoadIME( hkl ) );
4952 process_messages();
4953 memset( ime_calls, 0, sizeof(ime_calls) );
4954 ime_call_count = 0;
4956 ok_ret( 0, ImmProcessKey( 0, hkl, 'A', MAKELONG(1, 0x1e), 0 ) );
4957 ok_seq( empty_sequence );
4959 ok_ret( 0, ImmProcessKey( hwnd, hkl, 'A', MAKELONG(0, 0x1e), 0 ) );
4960 ok_seq( process_key_0 );
4961 ret = ImmProcessKey( hwnd, hkl, 'A', MAKELONG(1, 0x1e), 0 );
4962 todo_wine
4963 ok_ret( 2, ret );
4964 ok_seq( process_key_1 );
4965 ok_ret( 2, ImmProcessKey( hwnd, hkl, 'A', MAKELONG(2, 0x1e), 0 ) );
4966 ok_seq( process_key_2 );
4968 ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
4969 ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', MAKELONG(1, 0x1e), 0 ) );
4970 ok_seq( empty_sequence );
4971 ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
4973 himc = ImmCreateContext();
4974 ok_ne( NULL, himc, HIMC, "%p" );
4975 ok_ret( 'A', ImmGetVirtualKey( hwnd ) );
4976 ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" );
4977 todo_wine ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) );
4978 ok_eq( himc, ImmAssociateContext( hwnd, default_himc ), HIMC, "%p" );
4979 ok_ret( 'A', ImmGetVirtualKey( hwnd ) );
4980 ImmDestroyContext( himc );
4982 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'A', 0 ) );
4983 ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) );
4985 ok_ret( 1, ImmActivateLayout( default_hkl ) );
4987 ok_ret( 1, ImmFreeLayout( hkl ) );
4988 process_messages();
4989 memset( ime_calls, 0, sizeof(ime_calls) );
4990 ime_call_count = 0;
4992 cleanup:
4993 ok_ret( 1, DestroyWindow( hwnd ) );
4996 static void test_ImmActivateLayout(void)
4998 const struct ime_call activate_seq[] =
5001 .hkl = expect_ime, .himc = default_himc,
5002 .func = IME_SELECT, .select = 1,
5004 {0},
5006 const struct ime_call deactivate_seq[] =
5009 .hkl = expect_ime, .himc = default_himc,
5010 .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0},
5011 .todo = TRUE,
5014 .hkl = default_hkl, .himc = default_himc,
5015 .func = IME_SELECT, .select = 0,
5017 {0},
5019 struct ime_call activate_with_window_seq[] =
5022 .hkl = expect_ime, .himc = default_himc,
5023 .func = IME_SELECT, .select = 1,
5024 .flaky_himc = TRUE,
5027 .hkl = expect_ime, .himc = 0/*himc*/,
5028 .func = IME_SELECT, .select = 1,
5029 .flaky_himc = TRUE,
5032 .hkl = expect_ime, .himc = default_himc,
5033 .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 1, .lparam = (LPARAM)expect_ime},
5036 .hkl = expect_ime, .himc = default_himc,
5037 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_OPENSTATUSWINDOW},
5038 .todo = TRUE, .broken = TRUE, /* broken after SetForegroundWindow(GetDesktopWindow()) as in d3d8:device */
5041 .hkl = expect_ime, .himc = default_himc,
5042 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS},
5043 .todo = TRUE,
5046 .hkl = expect_ime, .himc = default_himc,
5047 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE},
5048 .todo = TRUE,
5051 .hkl = expect_ime, .himc = default_himc,
5052 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE},
5053 .todo = TRUE,
5055 {0},
5057 struct ime_call deactivate_with_window_seq[] =
5060 .hkl = expect_ime, .himc = default_himc,
5061 .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0},
5062 .todo = TRUE, .flaky_himc = TRUE,
5065 .hkl = expect_ime, .himc = 0/*himc*/,
5066 .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0},
5067 .todo = TRUE, .flaky_himc = TRUE,
5070 .hkl = expect_ime, .himc = default_himc,
5071 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_CLOSESTATUSWINDOW},
5072 .todo = TRUE, .broken = TRUE, /* broken after SetForegroundWindow(GetDesktopWindow()) as in d3d8:device */
5075 .hkl = expect_ime, .himc = default_himc,
5076 .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 0, .lparam = (LPARAM)expect_ime},
5079 .hkl = default_hkl, .himc = default_himc,
5080 .func = IME_SELECT, .select = 0,
5081 .flaky_himc = TRUE,
5084 .hkl = default_hkl, .himc = 0/*himc*/,
5085 .func = IME_SELECT, .select = 0,
5086 .flaky_himc = TRUE,
5088 {0},
5090 HKL hkl;
5091 struct ime_windows ime_windows = {0};
5092 HIMC himc;
5093 HWND hwnd;
5094 UINT ret;
5096 SET_ENABLE( ImeInquire, TRUE );
5097 SET_ENABLE( ImeDestroy, TRUE );
5099 ok_ret( 1, ImmActivateLayout( default_hkl ) );
5101 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
5103 if (!(hkl = wineime_hkl)) goto cleanup;
5105 /* ActivateKeyboardLayout doesn't call ImeInquire / ImeDestroy */
5107 ok_seq( empty_sequence );
5108 ok_eq( default_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" );
5109 ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
5110 ok_eq( hkl, ActivateKeyboardLayout( default_hkl, 0 ), HKL, "%p" );
5111 ok_seq( empty_sequence );
5112 ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
5115 /* ImmActivateLayout changes active HKL */
5117 SET_EXPECT( ImeInquire );
5118 ok_ret( 1, ImmActivateLayout( hkl ) );
5119 ok_seq( activate_seq );
5120 CHECK_CALLED( ImeInquire );
5121 ok_ret( 1, ImmLoadIME( hkl ) );
5123 ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
5125 ok_ret( 1, ImmActivateLayout( hkl ) );
5126 ok_seq( empty_sequence );
5128 ok_ret( 1, ImmActivateLayout( default_hkl ) );
5129 ok_seq( deactivate_seq );
5131 ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
5134 /* ImmActivateLayout leaks the IME, we need to free it manually */
5136 SET_EXPECT( ImeDestroy );
5137 ret = ImmFreeLayout( hkl );
5138 ok( ret, "ImmFreeLayout returned %u\n", ret );
5139 CHECK_CALLED( ImeDestroy );
5140 ok_seq( empty_sequence );
5143 /* when there's a window, ActivateKeyboardLayout calls ImeInquire */
5145 hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5146 100, 100, 100, 100, NULL, NULL, NULL, NULL );
5147 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
5148 process_messages();
5149 ok_seq( empty_sequence );
5151 himc = ImmCreateContext();
5152 ok( !!himc, "got himc %p\n", himc );
5153 ok_seq( empty_sequence );
5155 SET_EXPECT( ImeInquire );
5156 ok_eq( default_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" );
5157 CHECK_CALLED( ImeInquire );
5158 activate_with_window_seq[1].himc = himc;
5159 ok_seq( activate_with_window_seq );
5160 ok_ret( 1, ImmLoadIME( hkl ) );
5162 ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
5164 /* FIXME: ignore spurious VK_CONTROL ImeProcessKey / ImeToAsciiEx calls */
5165 process_messages();
5166 memset( ime_calls, 0, sizeof(ime_calls) );
5167 ime_call_count = 0;
5169 ok_eq( hkl, ActivateKeyboardLayout( default_hkl, 0 ), HKL, "%p" );
5170 deactivate_with_window_seq[1].himc = himc;
5171 deactivate_with_window_seq[5].himc = himc;
5172 ok_seq( deactivate_with_window_seq );
5174 ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
5176 ok_ret( 1, ImmDestroyContext( himc ) );
5177 ok_seq( empty_sequence );
5180 ok_eq( default_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" );
5181 ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
5183 ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) );
5184 ok( !!ime_windows.ime_hwnd, "missing IME window\n" );
5185 ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" );
5186 ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) );
5188 ok_eq( hkl, ActivateKeyboardLayout( default_hkl, 0 ), HKL, "%p" );
5189 ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
5190 process_messages();
5193 SET_EXPECT( ImeDestroy );
5194 ok_ret( 1, ImmFreeLayout( hkl ) );
5195 CHECK_CALLED( ImeDestroy );
5197 ok_ret( 1, DestroyWindow( hwnd ) );
5198 process_messages();
5199 memset( ime_calls, 0, sizeof(ime_calls) );
5200 ime_call_count = 0;
5203 cleanup:
5204 SET_ENABLE( ImeInquire, FALSE );
5205 SET_ENABLE( ImeDestroy, FALSE );
5208 static void test_ImmCreateInputContext(void)
5210 struct ime_call activate_seq[] =
5213 .hkl = expect_ime, .himc = default_himc,
5214 .func = IME_SELECT, .select = 1,
5215 .flaky_himc = TRUE,
5218 .hkl = expect_ime, .himc = 0/*himc[0]*/,
5219 .func = IME_SELECT, .select = 1,
5220 .flaky_himc = TRUE,
5223 .hkl = expect_ime, .himc = default_himc,
5224 .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 1, .lparam = (LPARAM)expect_ime},
5227 .hkl = expect_ime, .himc = default_himc,
5228 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_OPENSTATUSWINDOW},
5229 .todo = TRUE, .broken = TRUE, /* broken after SetForegroundWindow(GetDesktopWindow()) as in d3d8:device */
5231 {0},
5233 struct ime_call select1_seq[] =
5236 .hkl = expect_ime, .himc = 0/*himc[0]*/,
5237 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS},
5238 .todo = TRUE, .flaky_himc = TRUE, .broken = TRUE /* sometimes */,
5241 .hkl = expect_ime, .himc = default_himc,
5242 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS},
5243 .todo = TRUE, .flaky_himc = TRUE, .broken = TRUE /* sometimes */,
5246 .hkl = expect_ime, .himc = default_himc,
5247 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS},
5248 .todo = TRUE, .broken = TRUE /* sometimes */,
5251 .hkl = expect_ime, .himc = default_himc,
5252 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE},
5253 .todo = TRUE, .broken = TRUE /* sometimes */,
5256 .hkl = expect_ime, .himc = 0/*himc[1]*/,
5257 .func = IME_SELECT, .select = 1,
5259 {0},
5261 struct ime_call select0_seq[] =
5264 .hkl = expect_ime, .himc = 0/*himc[1]*/,
5265 .func = IME_SELECT, .select = 0,
5267 {0},
5269 struct ime_call deactivate_seq[] =
5272 .hkl = expect_ime, .himc = default_himc,
5273 .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0},
5274 .todo = TRUE, .flaky_himc = TRUE,
5277 .hkl = expect_ime, .himc = 0/*himc[0]*/,
5278 .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0},
5279 .todo = TRUE, .flaky_himc = TRUE,
5282 .hkl = expect_ime, .himc = default_himc,
5283 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_CLOSESTATUSWINDOW},
5284 .todo = TRUE, .broken = TRUE, /* broken after SetForegroundWindow(GetDesktopWindow()) as in d3d8:device */
5287 .hkl = expect_ime, .himc = default_himc,
5288 .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 0, .lparam = (LPARAM)expect_ime},
5291 .hkl = default_hkl, .himc = default_himc,
5292 .func = IME_SELECT, .select = 0,
5293 .flaky_himc = TRUE,
5296 .hkl = default_hkl, .himc = 0/*himc[0]*/,
5297 .func = IME_SELECT, .select = 0,
5298 .flaky_himc = TRUE,
5300 {0},
5302 HKL hkl;
5303 INPUTCONTEXT *ctx;
5304 HIMC himc[2];
5305 HWND hwnd;
5307 ctx = ImmLockIMC( default_himc );
5308 ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() );
5309 ok_ret( 0, IsWindow( ctx->hWnd ) );
5310 ok_ret( 1, ImmUnlockIMC( default_himc ) );
5313 /* new input contexts cannot be locked before IME window has been created */
5315 himc[0] = ImmCreateContext();
5316 ok( !!himc[0], "ImmCreateContext failed, error %lu\n", GetLastError() );
5317 ctx = ImmLockIMC( himc[0] );
5318 todo_wine
5319 ok( !ctx, "ImmLockIMC failed, error %lu\n", GetLastError() );
5320 if (ctx) ImmUnlockIMCC( himc[0] );
5322 hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5323 100, 100, 100, 100, NULL, NULL, NULL, NULL );
5324 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
5325 process_messages();
5327 ctx = ImmLockIMC( default_himc );
5328 ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() );
5329 ok_ret( 1, ImmUnlockIMC( default_himc ) );
5331 ctx = ImmLockIMC( himc[0] );
5332 ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() );
5333 ok_ret( 1, ImmUnlockIMC( himc[0] ) );
5336 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
5337 ime_info.dwPrivateDataSize = 123;
5339 if (!(hkl = wineime_hkl)) goto cleanup;
5341 ok_ret( 1, ImmLoadIME( hkl ) );
5343 /* Activating the layout calls ImeSelect 1 on existing HIMC */
5345 ok_seq( empty_sequence );
5346 ok_ret( 1, ImmActivateLayout( hkl ) );
5347 activate_seq[1].himc = himc[0];
5348 ok_seq( activate_seq );
5350 ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
5352 ctx = ImmLockIMC( default_himc );
5353 ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() );
5354 ok_ret( 1, ImmUnlockIMC( default_himc ) );
5356 ctx = ImmLockIMC( himc[0] );
5357 ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() );
5358 ok_ret( 1, ImmUnlockIMC( himc[0] ) );
5361 /* ImmLockIMC triggers the ImeSelect call, to allocate private data */
5363 himc[1] = ImmCreateContext();
5364 ok( !!himc[1], "ImmCreateContext failed, error %lu\n", GetLastError() );
5366 ok_seq( empty_sequence );
5367 ctx = ImmLockIMC( himc[1] );
5368 ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() );
5369 select1_seq[0].himc = himc[0];
5370 select1_seq[4].himc = himc[1];
5371 ok_seq( select1_seq );
5373 ok_ret( 1, ImmUnlockIMC( himc[1] ) );
5375 ok_seq( empty_sequence );
5376 ok_ret( 1, ImmDestroyContext( himc[1] ) );
5377 select0_seq[0].himc = himc[1];
5378 ok_seq( select0_seq );
5381 /* Deactivating the layout calls ImeSelect 0 on existing HIMC */
5383 ok_ret( 1, ImmActivateLayout( default_hkl ) );
5384 deactivate_seq[1].himc = himc[0];
5385 deactivate_seq[5].himc = himc[0];
5386 ok_seq( deactivate_seq );
5388 ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" );
5390 ok_ret( 1, ImmFreeLayout( hkl ) );
5391 ok_seq( empty_sequence );
5393 cleanup:
5394 ok_ret( 1, ImmDestroyContext( himc[0] ) );
5395 ok_ret( 1, DestroyWindow( hwnd ) );
5396 process_messages();
5397 memset( ime_calls, 0, sizeof(ime_calls) );
5398 ime_call_count = 0;
5400 ime_info.dwPrivateDataSize = 0;
5403 static void test_DefWindowProc(void)
5405 const struct ime_call start_composition_seq[] =
5407 {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_STARTCOMPOSITION}},
5408 {0},
5410 const struct ime_call end_composition_seq[] =
5412 {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_ENDCOMPOSITION}},
5413 {0},
5415 const struct ime_call composition_seq[] =
5417 {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_COMPOSITION}},
5418 {0},
5420 const struct ime_call set_context_seq[] =
5422 {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT}},
5423 {0},
5425 const struct ime_call notify_seq[] =
5427 {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY}},
5428 {0},
5430 HKL hkl;
5431 UINT_PTR ret;
5432 HWND hwnd;
5434 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
5436 if (!(hkl = wineime_hkl)) return;
5438 hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5439 100, 100, 100, 100, NULL, NULL, NULL, NULL );
5440 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
5442 ok_ret( 1, ImmActivateLayout( hkl ) );
5443 ok_ret( 1, ImmLoadIME( hkl ) );
5444 process_messages();
5445 memset( ime_calls, 0, sizeof(ime_calls) );
5446 ime_call_count = 0;
5448 ok_ret( 0, DefWindowProcW( hwnd, WM_IME_STARTCOMPOSITION, 0, 0 ) );
5449 ok_seq( start_composition_seq );
5450 ok_ret( 0, DefWindowProcW( hwnd, WM_IME_ENDCOMPOSITION, 0, 0 ) );
5451 ok_seq( end_composition_seq );
5452 ok_ret( 0, DefWindowProcW( hwnd, WM_IME_COMPOSITION, 0, 0 ) );
5453 ok_seq( composition_seq );
5454 ok_ret( 0, DefWindowProcW( hwnd, WM_IME_SETCONTEXT, 0, 0 ) );
5455 ok_seq( set_context_seq );
5456 ok_ret( 0, DefWindowProcW( hwnd, WM_IME_NOTIFY, 0, 0 ) );
5457 ok_seq( notify_seq );
5458 ok_ret( 0, DefWindowProcW( hwnd, WM_IME_CONTROL, 0, 0 ) );
5459 ok_seq( empty_sequence );
5460 ok_ret( 0, DefWindowProcW( hwnd, WM_IME_COMPOSITIONFULL, 0, 0 ) );
5461 ok_seq( empty_sequence );
5462 ok_ret( 0, DefWindowProcW( hwnd, WM_IME_SELECT, 0, 0 ) );
5463 ok_seq( empty_sequence );
5464 ok_ret( 0, DefWindowProcW( hwnd, WM_IME_CHAR, 0, 0 ) );
5465 ok_seq( empty_sequence );
5466 ok_ret( 0, DefWindowProcW( hwnd, 0x287, 0, 0 ) );
5467 ok_seq( empty_sequence );
5468 ok_ret( 0, DefWindowProcW( hwnd, WM_IME_REQUEST, 0, 0 ) );
5469 ok_seq( empty_sequence );
5470 ret = DefWindowProcW( hwnd, WM_IME_KEYDOWN, 0, 0 );
5471 todo_wine
5472 ok_ret( 0, ret );
5473 ok_seq( empty_sequence );
5474 ret = DefWindowProcW( hwnd, WM_IME_KEYUP, 0, 0 );
5475 todo_wine
5476 ok_ret( 0, ret );
5477 ok_seq( empty_sequence );
5479 ok_ret( 1, ImmActivateLayout( default_hkl ) );
5480 ok_ret( 1, DestroyWindow( hwnd ) );
5481 process_messages();
5483 ok_ret( 1, ImmFreeLayout( hkl ) );
5484 memset( ime_calls, 0, sizeof(ime_calls) );
5485 ime_call_count = 0;
5488 static void test_ImmSetActiveContext(void)
5490 const struct ime_call activate_0_seq[] =
5493 .hkl = expect_ime, .himc = default_himc,
5494 .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = 1}
5497 .hkl = expect_ime, .himc = default_himc,
5498 .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT, .wparam = 1, .lparam = ISC_SHOWUIALL}
5500 {0},
5502 const struct ime_call deactivate_0_seq[] =
5505 .hkl = expect_ime, .himc = default_himc,
5506 .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = 0}
5509 .hkl = expect_ime, .himc = default_himc,
5510 .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT, .wparam = 0, .lparam = ISC_SHOWUIALL}
5512 {0},
5514 struct ime_call deactivate_1_seq[] =
5517 .hkl = expect_ime, .himc = default_himc,
5518 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS},
5519 .todo = TRUE, .flaky_himc = TRUE, .broken = TRUE /* sometimes */,
5522 .hkl = expect_ime, .himc = default_himc,
5523 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS},
5524 .todo = TRUE, .broken = TRUE /* sometimes */,
5527 .hkl = expect_ime, .himc = default_himc,
5528 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE},
5529 .todo = TRUE, .broken = TRUE /* sometimes */,
5532 .hkl = expect_ime, .himc = 0/*himc*/,
5533 .func = IME_SELECT, .select = 1,
5536 .hkl = expect_ime, .himc = 0/*himc*/,
5537 .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = 0}
5540 .hkl = expect_ime, .himc = default_himc,
5541 .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT, .wparam = 0, .lparam = ISC_SHOWUIALL}
5543 {0},
5545 struct ime_call deactivate_2_seq[] =
5548 .hkl = expect_ime, .himc = 0/*himc*/,
5549 .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = 0}
5552 .hkl = expect_ime, .himc = default_himc,
5553 .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT, .wparam = 0, .lparam = ISC_SHOWUIALL}
5555 {0},
5557 struct ime_call activate_1_seq[] =
5560 .hkl = expect_ime, .himc = 0/*himc*/,
5561 .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = 1}
5564 .hkl = expect_ime, .himc = default_himc,
5565 .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT, .wparam = 1, .lparam = ISC_SHOWUIALL}
5567 {0},
5569 HKL hkl;
5570 struct ime_windows ime_windows = {0};
5571 INPUTCONTEXT *ctx;
5572 HIMC himc;
5573 HWND hwnd;
5575 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
5577 if (!(hkl = wineime_hkl)) return;
5579 hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5580 100, 100, 100, 100, NULL, NULL, NULL, NULL );
5581 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
5583 ok_ret( 1, ImmActivateLayout( hkl ) );
5584 ok_ret( 1, ImmLoadIME( hkl ) );
5585 process_messages();
5586 memset( ime_calls, 0, sizeof(ime_calls) );
5587 ime_call_count = 0;
5589 ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) );
5590 ok_ne( NULL, ime_windows.ime_hwnd, HWND, "%p" );
5591 ok_ne( NULL, ime_windows.ime_ui_hwnd, HWND, "%p" );
5592 ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) );
5594 SetLastError( 0xdeadbeef );
5595 ok_ret( 1, ImmSetActiveContext( hwnd, default_himc, TRUE ) );
5596 ok_seq( activate_0_seq );
5597 ok_ret( 0, GetLastError() );
5598 ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) );
5599 ok_ret( 1, ImmSetActiveContext( hwnd, default_himc, TRUE ) );
5600 ok_seq( activate_0_seq );
5601 ok_ret( 1, ImmSetActiveContext( hwnd, default_himc, FALSE ) );
5602 ok_seq( deactivate_0_seq );
5604 himc = ImmCreateContext();
5605 ok_ne( NULL, himc, HIMC, "%p" );
5606 ctx = ImmLockIMC( himc );
5607 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
5608 ok_eq( 0, ctx->hWnd, HWND, "%p" );
5610 ok_ret( 1, ImmSetActiveContext( hwnd, himc, FALSE ) );
5611 deactivate_1_seq[3].himc = himc;
5612 deactivate_1_seq[4].himc = himc;
5613 ok_seq( deactivate_1_seq );
5614 ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) );
5615 activate_1_seq[0].himc = himc;
5616 ok_seq( activate_1_seq );
5618 ctx->hWnd = (HWND)0xdeadbeef;
5619 ok_ret( 1, ImmSetActiveContext( hwnd, himc, FALSE ) );
5620 ok_eq( (HWND)0xdeadbeef, ctx->hWnd, HWND, "%p" );
5621 deactivate_2_seq[0].himc = himc;
5622 ok_seq( deactivate_2_seq );
5624 ctx->hWnd = 0;
5625 ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) );
5626 ok_eq( hwnd, ctx->hWnd, HWND, "%p" );
5627 activate_1_seq[0].himc = himc;
5628 ok_seq( activate_1_seq );
5630 ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" );
5631 ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) );
5632 ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) );
5633 ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" );
5635 ctx->hWnd = 0;
5636 ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" );
5637 ok_eq( himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" );
5638 ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) );
5639 ok_eq( hwnd, ctx->hWnd, HWND, "%p" );
5641 ctx->hWnd = (HWND)0xdeadbeef;
5642 ok_eq( himc, ImmGetContext( hwnd ), HIMC, "%p" );
5643 ok_eq( (HWND)0xdeadbeef, ctx->hWnd, HWND, "%p" );
5644 ok_ret( 1, ImmReleaseContext( hwnd, himc ) );
5646 ok_ret( 1, ImmUnlockIMC( himc ) );
5647 ok_ret( 1, ImmDestroyContext( himc ) );
5649 ok_ret( 1, ImmActivateLayout( default_hkl ) );
5650 ok_ret( 1, DestroyWindow( hwnd ) );
5651 process_messages();
5653 ok_ret( 1, ImmFreeLayout( hkl ) );
5654 memset( ime_calls, 0, sizeof(ime_calls) );
5655 ime_call_count = 0;
5658 static void test_ImmRequestMessage(void)
5660 struct ime_call composition_window_seq[] =
5663 .hkl = expect_ime, .himc = default_himc,
5664 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_COMPOSITIONWINDOW, .lparam = 0/*&comp_form*/}
5666 {0},
5668 struct ime_call candidate_window_seq[] =
5671 .hkl = expect_ime, .himc = default_himc,
5672 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_CANDIDATEWINDOW, .lparam = 0/*&cand_form*/}
5674 {0},
5676 struct ime_call composition_font_seq[] =
5679 .hkl = expect_ime, .himc = default_himc,
5680 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_COMPOSITIONFONT, .lparam = 0/*&log_font*/}
5682 {0},
5684 struct ime_call reconvert_string_seq[] =
5687 .hkl = expect_ime, .himc = default_himc,
5688 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_RECONVERTSTRING, .lparam = 0/*&reconv*/}
5690 {0},
5692 struct ime_call confirm_reconvert_string_seq[] =
5695 .hkl = expect_ime, .himc = default_himc,
5696 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_CONFIRMRECONVERTSTRING, .lparam = 0/*&reconv*/}
5698 {0},
5700 struct ime_call query_char_position_seq[] =
5703 .hkl = expect_ime, .himc = default_himc,
5704 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_QUERYCHARPOSITION, .lparam = 0/*&char_pos*/}
5706 {0},
5708 struct ime_call document_feed_seq[] =
5711 .hkl = expect_ime, .himc = default_himc,
5712 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_DOCUMENTFEED, .lparam = 0/*&reconv*/}
5714 {0},
5716 HKL hkl;
5717 COMPOSITIONFORM comp_form = {0};
5718 IMECHARPOSITION char_pos = {0};
5719 RECONVERTSTRING reconv = {0};
5720 CANDIDATEFORM cand_form = {0};
5721 LOGFONTW log_font = {0};
5722 INPUTCONTEXT *ctx;
5723 HIMC himc;
5724 HWND hwnd;
5726 if (!(hkl = wineime_hkl)) return;
5728 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5729 100, 100, 100, 100, NULL, NULL, NULL, NULL );
5730 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
5732 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
5734 ok_ret( 1, ImmActivateLayout( hkl ) );
5735 ok_ret( 1, ImmLoadIME( hkl ) );
5736 himc = ImmCreateContext();
5737 ok_ne( NULL, himc, HIMC, "%p" );
5738 ctx = ImmLockIMC( himc );
5739 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
5740 process_messages();
5741 memset( ime_calls, 0, sizeof(ime_calls) );
5742 ime_call_count = 0;
5744 ok_ret( 0, ImmRequestMessageW( default_himc, 0xdeadbeef, 0 ) );
5745 todo_wine ok_seq( empty_sequence );
5746 ok_ret( 0, ImmRequestMessageW( default_himc, IMR_COMPOSITIONWINDOW, (LPARAM)&comp_form ) );
5747 composition_window_seq[0].message.lparam = (LPARAM)&comp_form;
5748 ok_seq( composition_window_seq );
5749 ok_ret( 0, ImmRequestMessageW( default_himc, IMR_CANDIDATEWINDOW, (LPARAM)&cand_form ) );
5750 candidate_window_seq[0].message.lparam = (LPARAM)&cand_form;
5751 ok_seq( candidate_window_seq );
5752 ok_ret( 0, ImmRequestMessageW( default_himc, IMR_COMPOSITIONFONT, (LPARAM)&log_font ) );
5753 composition_font_seq[0].message.lparam = (LPARAM)&log_font;
5754 ok_seq( composition_font_seq );
5755 ok_ret( 0, ImmRequestMessageW( default_himc, IMR_RECONVERTSTRING, (LPARAM)&reconv ) );
5756 todo_wine ok_seq( empty_sequence );
5757 reconv.dwSize = sizeof(RECONVERTSTRING);
5758 ok_ret( 0, ImmRequestMessageW( default_himc, IMR_RECONVERTSTRING, (LPARAM)&reconv ) );
5759 reconvert_string_seq[0].message.lparam = (LPARAM)&reconv;
5760 ok_seq( reconvert_string_seq );
5761 ok_ret( 0, ImmRequestMessageW( default_himc, IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) );
5762 confirm_reconvert_string_seq[0].message.lparam = (LPARAM)&reconv;
5763 ok_seq( confirm_reconvert_string_seq );
5764 ok_ret( 0, ImmRequestMessageW( default_himc, IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) );
5765 query_char_position_seq[0].message.lparam = (LPARAM)&char_pos;
5766 ok_seq( query_char_position_seq );
5767 ok_ret( 0, ImmRequestMessageW( default_himc, IMR_DOCUMENTFEED, (LPARAM)&reconv ) );
5768 document_feed_seq[0].message.lparam = (LPARAM)&reconv;
5769 ok_seq( document_feed_seq );
5771 ok_ret( 0, ImmRequestMessageW( himc, IMR_CANDIDATEWINDOW, (LPARAM)&cand_form ) );
5772 ok_seq( empty_sequence );
5773 ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) );
5774 memset( ime_calls, 0, sizeof(ime_calls) );
5775 ime_call_count = 0;
5776 ok_ret( 0, ImmRequestMessageW( himc, IMR_CANDIDATEWINDOW, (LPARAM)&cand_form ) );
5777 candidate_window_seq[0].message.lparam = (LPARAM)&cand_form;
5778 ok_seq( candidate_window_seq );
5779 ok_ret( 0, ImmRequestMessageW( default_himc, IMR_CANDIDATEWINDOW, (LPARAM)&cand_form ) );
5780 ok_seq( candidate_window_seq );
5782 ok_ret( 1, ImmUnlockIMC( himc ) );
5783 ok_ret( 1, ImmDestroyContext( himc ) );
5785 ok_ret( 1, ImmActivateLayout( default_hkl ) );
5786 ok_ret( 1, DestroyWindow( hwnd ) );
5787 process_messages();
5789 ok_ret( 1, ImmFreeLayout( hkl ) );
5790 memset( ime_calls, 0, sizeof(ime_calls) );
5791 ime_call_count = 0;
5794 static void test_ImmGetCandidateList( BOOL unicode )
5796 char buffer[512], expect_bufW[512] = {0}, expect_bufA[512] = {0};
5797 CANDIDATELIST *cand_list = (CANDIDATELIST *)buffer, *expect_listW, *expect_listA;
5798 HKL hkl;
5799 CANDIDATEINFO *cand_info;
5800 INPUTCONTEXT *ctx;
5801 HIMC himc;
5802 HWND hwnd;
5804 expect_listW = (CANDIDATELIST *)expect_bufW;
5805 expect_listW->dwSize = offsetof(CANDIDATELIST, dwOffset[2]) + 32 * sizeof(WCHAR);
5806 expect_listW->dwStyle = 0xdeadbeef;
5807 expect_listW->dwCount = 2;
5808 expect_listW->dwSelection = 3;
5809 expect_listW->dwPageStart = 4;
5810 expect_listW->dwPageSize = 5;
5811 expect_listW->dwOffset[0] = offsetof(CANDIDATELIST, dwOffset[2]) + 2 * sizeof(WCHAR);
5812 expect_listW->dwOffset[1] = offsetof(CANDIDATELIST, dwOffset[2]) + 16 * sizeof(WCHAR);
5813 wcscpy( (WCHAR *)(expect_bufW + expect_listW->dwOffset[0]), L"Candidate 1" );
5814 wcscpy( (WCHAR *)(expect_bufW + expect_listW->dwOffset[1]), L"Candidate 2" );
5816 expect_listA = (CANDIDATELIST *)expect_bufA;
5817 expect_listA->dwSize = offsetof(CANDIDATELIST, dwOffset[2]) + 32;
5818 expect_listA->dwStyle = 0xdeadbeef;
5819 expect_listA->dwCount = 2;
5820 expect_listA->dwSelection = 3;
5821 expect_listA->dwPageStart = 4;
5822 expect_listA->dwPageSize = 5;
5823 expect_listA->dwOffset[0] = offsetof(CANDIDATELIST, dwOffset[2]) + 2;
5824 expect_listA->dwOffset[1] = offsetof(CANDIDATELIST, dwOffset[2]) + 16;
5825 strcpy( (char *)(expect_bufA + expect_listA->dwOffset[0]), "Candidate 1" );
5826 strcpy( (char *)(expect_bufA + expect_listA->dwOffset[1]), "Candidate 2" );
5828 winetest_push_context( unicode ? "unicode" : "ansi" );
5830 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
5831 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
5832 if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
5834 if (!(hkl = wineime_hkl)) goto cleanup;
5836 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5837 100, 100, 100, 100, NULL, NULL, NULL, NULL );
5838 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
5840 ok_ret( 1, ImmActivateLayout( hkl ) );
5841 ok_ret( 1, ImmLoadIME( hkl ) );
5842 himc = ImmCreateContext();
5843 ok_ne( NULL, himc, HIMC, "%p" );
5844 ctx = ImmLockIMC( himc );
5845 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
5846 process_messages();
5847 memset( ime_calls, 0, sizeof(ime_calls) );
5848 ime_call_count = 0;
5850 ok_ret( 0, ImmGetCandidateListW( default_himc, 0, NULL, 0 ) );
5851 ok_seq( empty_sequence );
5852 ok_ret( 0, ImmGetCandidateListW( default_himc, 1, NULL, 0 ) );
5853 ok_seq( empty_sequence );
5854 ok_ret( 0, ImmGetCandidateListW( default_himc, 0, cand_list, sizeof(buffer) ) );
5855 ok_seq( empty_sequence );
5857 ok_ret( 0, ImmGetCandidateListW( himc, 0, cand_list, sizeof(buffer) ) );
5858 ok_seq( empty_sequence );
5860 todo_wine ok_seq( empty_sequence );
5861 ctx->hCandInfo = ImmReSizeIMCC( ctx->hCandInfo, sizeof(*cand_info) + sizeof(buffer) );
5862 ok( !!ctx->hCandInfo, "ImmReSizeIMCC failed, error %lu\n", GetLastError() );
5864 cand_info = ImmLockIMCC( ctx->hCandInfo );
5865 ok( !!cand_info, "ImmLockIMCC failed, error %lu\n", GetLastError() );
5866 cand_info->dwCount = 1;
5867 cand_info->dwOffset[0] = sizeof(*cand_info);
5868 if (unicode) memcpy( cand_info + 1, expect_bufW, sizeof(expect_bufW) );
5869 else memcpy( cand_info + 1, expect_bufA, sizeof(expect_bufA) );
5870 ok_ret( 0, ImmUnlockIMCC( ctx->hCandInfo ) );
5872 ok_ret( (unicode ? 96 : 80), ImmGetCandidateListW( himc, 0, NULL, 0 ) );
5873 ok_seq( empty_sequence );
5874 ok_ret( 0, ImmGetCandidateListW( himc, 1, NULL, 0 ) );
5875 ok_seq( empty_sequence );
5876 memset( buffer, 0xcd, sizeof(buffer) );
5877 ok_ret( (unicode ? 96 : 80), ImmGetCandidateListW( himc, 0, cand_list, sizeof(buffer) ) );
5878 ok_seq( empty_sequence );
5880 if (!unicode)
5882 expect_listW->dwSize = offsetof(CANDIDATELIST, dwOffset[2]) + 24 * sizeof(WCHAR);
5883 expect_listW->dwOffset[0] = offsetof(CANDIDATELIST, dwOffset[2]);
5884 expect_listW->dwOffset[1] = offsetof(CANDIDATELIST, dwOffset[2]) + 12 * sizeof(WCHAR);
5885 wcscpy( (WCHAR *)(expect_bufW + expect_listW->dwOffset[0]), L"Candidate 1" );
5886 wcscpy( (WCHAR *)(expect_bufW + expect_listW->dwOffset[1]), L"Candidate 2" );
5888 check_candidate_list_( __LINE__, cand_list, expect_listW, TRUE );
5890 ok_ret( (unicode ? 56 : 64), ImmGetCandidateListA( himc, 0, NULL, 0 ) );
5891 ok_seq( empty_sequence );
5892 ok_ret( 0, ImmGetCandidateListA( himc, 1, NULL, 0 ) );
5893 ok_seq( empty_sequence );
5894 memset( buffer, 0xcd, sizeof(buffer) );
5895 ok_ret( (unicode ? 56 : 64), ImmGetCandidateListA( himc, 0, cand_list, sizeof(buffer) ) );
5896 ok_seq( empty_sequence );
5898 if (unicode)
5900 expect_listA->dwSize = offsetof(CANDIDATELIST, dwOffset[2]) + 24;
5901 expect_listA->dwOffset[0] = offsetof(CANDIDATELIST, dwOffset[2]);
5902 expect_listA->dwOffset[1] = offsetof(CANDIDATELIST, dwOffset[2]) + 12;
5903 strcpy( (char *)(expect_bufA + expect_listA->dwOffset[0]), "Candidate 1" );
5904 strcpy( (char *)(expect_bufA + expect_listA->dwOffset[1]), "Candidate 2" );
5906 check_candidate_list_( __LINE__, cand_list, expect_listA, FALSE );
5908 ok_ret( 1, ImmUnlockIMC( himc ) );
5909 ok_ret( 1, ImmDestroyContext( himc ) );
5911 ok_ret( 1, ImmActivateLayout( default_hkl ) );
5912 ok_ret( 1, DestroyWindow( hwnd ) );
5913 process_messages();
5915 ok_ret( 1, ImmFreeLayout( hkl ) );
5916 memset( ime_calls, 0, sizeof(ime_calls) );
5917 ime_call_count = 0;
5919 cleanup:
5920 winetest_pop_context();
5923 static void test_ImmGetCandidateListCount( BOOL unicode )
5925 HKL hkl;
5926 CANDIDATEINFO *cand_info;
5927 INPUTCONTEXT *ctx;
5928 DWORD count;
5929 HIMC himc;
5930 HWND hwnd;
5932 winetest_push_context( unicode ? "unicode" : "ansi" );
5934 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
5935 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
5936 if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
5938 if (!(hkl = wineime_hkl)) goto cleanup;
5940 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5941 100, 100, 100, 100, NULL, NULL, NULL, NULL );
5942 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
5944 ok_ret( 1, ImmActivateLayout( hkl ) );
5945 ok_ret( 1, ImmLoadIME( hkl ) );
5946 himc = ImmCreateContext();
5947 ok_ne( NULL, himc, HIMC, "%p" );
5948 ctx = ImmLockIMC( himc );
5949 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
5950 process_messages();
5951 memset( ime_calls, 0, sizeof(ime_calls) );
5952 ime_call_count = 0;
5954 ok_ret( 144, ImmGetCandidateListCountW( default_himc, &count ) );
5955 ok_eq( 0, count, UINT, "%u" );
5956 ok_seq( empty_sequence );
5957 ok_ret( 144, ImmGetCandidateListCountA( default_himc, &count ) );
5958 ok_eq( 0, count, UINT, "%u" );
5959 ok_seq( empty_sequence );
5961 ok_ret( 144, ImmGetCandidateListCountW( himc, &count ) );
5962 ok_eq( 0, count, UINT, "%u" );
5963 ok_seq( empty_sequence );
5964 ok_ret( 144, ImmGetCandidateListCountA( himc, &count ) );
5965 ok_eq( 0, count, UINT, "%u" );
5966 ok_seq( empty_sequence );
5968 cand_info = ImmLockIMCC( ctx->hCandInfo );
5969 ok( !!cand_info, "ImmLockIMCC failed, error %lu\n", GetLastError() );
5970 cand_info->dwCount = 1;
5971 ok_ret( 0, ImmUnlockIMCC( ctx->hCandInfo ) );
5973 todo_wine_if(!unicode)
5974 ok_ret( (unicode ? 144 : 172), ImmGetCandidateListCountW( himc, &count ) );
5975 ok_eq( 1, count, UINT, "%u" );
5976 ok_seq( empty_sequence );
5977 todo_wine_if(unicode)
5978 ok_ret( (unicode ? 172 : 144), ImmGetCandidateListCountA( himc, &count ) );
5979 ok_eq( 1, count, UINT, "%u" );
5980 ok_seq( empty_sequence );
5982 ok_ret( 1, ImmUnlockIMC( himc ) );
5983 ok_ret( 1, ImmDestroyContext( himc ) );
5985 ok_ret( 1, ImmActivateLayout( default_hkl ) );
5986 ok_ret( 1, DestroyWindow( hwnd ) );
5987 process_messages();
5989 ok_ret( 1, ImmFreeLayout( hkl ) );
5990 memset( ime_calls, 0, sizeof(ime_calls) );
5991 ime_call_count = 0;
5993 cleanup:
5994 winetest_pop_context();
5997 static void test_ImmGetCandidateWindow(void)
5999 HKL hkl;
6000 const CANDIDATEFORM expect_form =
6002 .dwIndex = 0xdeadbeef,
6003 .dwStyle = 0xfeedcafe,
6004 .ptCurrentPos = {.x = 123, .y = 456},
6005 .rcArea = {.left = 1, .top = 2, .right = 3, .bottom = 4},
6007 CANDIDATEFORM cand_form;
6008 INPUTCONTEXT *ctx;
6009 HIMC himc;
6010 HWND hwnd;
6012 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
6014 if (!(hkl = wineime_hkl)) return;
6016 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6017 100, 100, 100, 100, NULL, NULL, NULL, NULL );
6018 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
6020 ok_ret( 1, ImmActivateLayout( hkl ) );
6021 ok_ret( 1, ImmLoadIME( hkl ) );
6022 himc = ImmCreateContext();
6023 ok_ne( NULL, himc, HIMC, "%p" );
6024 ctx = ImmLockIMC( himc );
6025 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
6026 process_messages();
6027 memset( ime_calls, 0, sizeof(ime_calls) );
6028 ime_call_count = 0;
6030 memset( &cand_form, 0xcd, sizeof(cand_form) );
6031 ok_ret( 0, ImmGetCandidateWindow( default_himc, 0, &cand_form ) );
6032 ok_eq( 0xcdcdcdcd, cand_form.dwIndex, UINT, "%u" );
6033 ok_ret( 0, ImmGetCandidateWindow( default_himc, 1, &cand_form ) );
6034 ok_eq( 0xcdcdcdcd, cand_form.dwIndex, UINT, "%u" );
6035 ok_ret( 0, ImmGetCandidateWindow( default_himc, 2, &cand_form ) );
6036 ok_eq( 0xcdcdcdcd, cand_form.dwIndex, UINT, "%u" );
6037 ok_ret( 0, ImmGetCandidateWindow( default_himc, 3, &cand_form ) );
6038 ok_eq( 0xcdcdcdcd, cand_form.dwIndex, UINT, "%u" );
6039 ok_ret( 1, ImmGetCandidateWindow( default_himc, 4, &cand_form ) );
6040 ok_seq( empty_sequence );
6042 ok_ret( 0, ImmGetCandidateWindow( himc, 0, &cand_form ) );
6043 ok_seq( empty_sequence );
6045 ok_seq( empty_sequence );
6046 ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() );
6047 ctx->cfCandForm[0] = expect_form;
6049 ok_ret( 1, ImmGetCandidateWindow( himc, 0, &cand_form ) );
6050 check_candidate_form( &cand_form, &expect_form );
6051 ok_seq( empty_sequence );
6053 ok_seq( empty_sequence );
6054 ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() );
6055 ctx->cfCandForm[0].dwIndex = -1;
6057 ok_ret( 0, ImmGetCandidateWindow( himc, 0, &cand_form ) );
6058 ok_seq( empty_sequence );
6060 ok_ret( 1, ImmUnlockIMC( himc ) );
6061 ok_ret( 1, ImmDestroyContext( himc ) );
6063 ok_ret( 1, ImmActivateLayout( default_hkl ) );
6064 ok_ret( 1, DestroyWindow( hwnd ) );
6065 process_messages();
6067 ok_ret( 1, ImmFreeLayout( hkl ) );
6068 memset( ime_calls, 0, sizeof(ime_calls) );
6069 ime_call_count = 0;
6072 static void test_ImmGetCompositionString( BOOL unicode )
6074 static COMPOSITIONSTRING expect_string_empty = {.dwSize = sizeof(COMPOSITIONSTRING)};
6075 static COMPOSITIONSTRING expect_stringA =
6077 .dwSize = 176,
6078 .dwCompReadAttrLen = 8,
6079 .dwCompReadAttrOffset = 116,
6080 .dwCompReadClauseLen = 8,
6081 .dwCompReadClauseOffset = 108,
6082 .dwCompReadStrLen = 8,
6083 .dwCompReadStrOffset = 100,
6084 .dwCompAttrLen = 4,
6085 .dwCompAttrOffset = 136,
6086 .dwCompClauseLen = 8,
6087 .dwCompClauseOffset = 128,
6088 .dwCompStrLen = 4,
6089 .dwCompStrOffset = 124,
6090 .dwCursorPos = 3,
6091 .dwDeltaStart = 1,
6092 .dwResultReadClauseLen = 8,
6093 .dwResultReadClauseOffset = 150,
6094 .dwResultReadStrLen = 10,
6095 .dwResultReadStrOffset = 140,
6096 .dwResultClauseLen = 8,
6097 .dwResultClauseOffset = 164,
6098 .dwResultStrLen = 6,
6099 .dwResultStrOffset = 158,
6100 .dwPrivateSize = 4,
6101 .dwPrivateOffset = 172,
6103 static const COMPOSITIONSTRING expect_stringW =
6105 .dwSize = 204,
6106 .dwCompReadAttrLen = 8,
6107 .dwCompReadAttrOffset = 124,
6108 .dwCompReadClauseLen = 8,
6109 .dwCompReadClauseOffset = 116,
6110 .dwCompReadStrLen = 8,
6111 .dwCompReadStrOffset = 100,
6112 .dwCompAttrLen = 4,
6113 .dwCompAttrOffset = 148,
6114 .dwCompClauseLen = 8,
6115 .dwCompClauseOffset = 140,
6116 .dwCompStrLen = 4,
6117 .dwCompStrOffset = 132,
6118 .dwCursorPos = 3,
6119 .dwDeltaStart = 1,
6120 .dwResultReadClauseLen = 8,
6121 .dwResultReadClauseOffset = 172,
6122 .dwResultReadStrLen = 10,
6123 .dwResultReadStrOffset = 152,
6124 .dwResultClauseLen = 8,
6125 .dwResultClauseOffset = 192,
6126 .dwResultStrLen = 6,
6127 .dwResultStrOffset = 180,
6128 .dwPrivateSize = 4,
6129 .dwPrivateOffset = 200,
6131 static const UINT gcs_indexes[] =
6133 GCS_COMPREADSTR,
6134 GCS_COMPREADATTR,
6135 GCS_COMPREADCLAUSE,
6136 GCS_COMPSTR,
6137 GCS_COMPATTR,
6138 GCS_COMPCLAUSE,
6139 GCS_CURSORPOS,
6140 GCS_DELTASTART,
6141 GCS_RESULTREADSTR,
6142 GCS_RESULTREADCLAUSE,
6143 GCS_RESULTSTR,
6144 GCS_RESULTCLAUSE,
6146 static const UINT scs_indexes[] =
6148 SCS_SETSTR,
6149 SCS_CHANGEATTR,
6150 SCS_CHANGECLAUSE,
6152 static const UINT expect_retW[ARRAY_SIZE(gcs_indexes)] = {16, 8, 8, 8, 4, 8, 3, 1, 20, 8, 12, 8};
6153 static const UINT expect_retA[ARRAY_SIZE(gcs_indexes)] = {8, 8, 8, 4, 4, 8, 3, 1, 10, 8, 6, 8};
6154 HKL hkl;
6155 COMPOSITIONSTRING *string;
6156 char buffer[1024];
6157 INPUTCONTEXT *old_ctx, *ctx;
6158 const void *str;
6159 HIMCC old_himcc;
6160 UINT i, len;
6161 BYTE *dst;
6162 HIMC himc;
6163 HWND hwnd;
6165 SET_ENABLE( ImeSetCompositionString, TRUE );
6167 winetest_push_context( unicode ? "unicode" : "ansi" );
6169 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
6170 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
6171 if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
6173 if (!(hkl = wineime_hkl)) goto cleanup;
6175 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6176 100, 100, 100, 100, NULL, NULL, NULL, NULL );
6177 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
6179 ok_ret( 1, ImmActivateLayout( hkl ) );
6180 ok_ret( 1, ImmLoadIME( hkl ) );
6181 himc = ImmCreateContext();
6182 ok_ne( NULL, himc, HIMC, "%p" );
6183 ctx = ImmLockIMC( himc );
6184 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
6185 process_messages();
6186 memset( ime_calls, 0, sizeof(ime_calls) );
6187 ime_call_count = 0;
6189 memset( buffer, 0xcd, sizeof(buffer) );
6190 todo_wine ok_ret( -2, ImmGetCompositionStringW( default_himc, GCS_COMPSTR | GCS_COMPATTR, buffer, sizeof(buffer) ) );
6191 memset( buffer, 0xcd, sizeof(buffer) );
6192 todo_wine ok_ret( -2, ImmGetCompositionStringA( default_himc, GCS_COMPSTR | GCS_COMPATTR, buffer, sizeof(buffer) ) );
6194 for (i = 0; i < ARRAY_SIZE(gcs_indexes); ++i)
6196 memset( buffer, 0xcd, sizeof(buffer) );
6197 ok_ret( 0, ImmGetCompositionStringW( default_himc, gcs_indexes[i], buffer, sizeof(buffer) ) );
6198 memset( buffer, 0xcd, sizeof(buffer) );
6199 ok_ret( 0, ImmGetCompositionStringA( default_himc, gcs_indexes[i], buffer, sizeof(buffer) ) );
6201 memset( buffer, 0xcd, sizeof(buffer) );
6202 ok_ret( 0, ImmGetCompositionStringW( himc, gcs_indexes[i], buffer, sizeof(buffer) ) );
6203 memset( buffer, 0xcd, sizeof(buffer) );
6204 ok_ret( 0, ImmGetCompositionStringA( himc, gcs_indexes[i], buffer, sizeof(buffer) ) );
6207 ctx->hCompStr = ImmReSizeIMCC( ctx->hCompStr, unicode ? expect_stringW.dwSize : expect_stringA.dwSize );
6208 string = ImmLockIMCC( ctx->hCompStr );
6209 ok( !!string, "ImmLockIMCC failed, error %lu\n", GetLastError() );
6210 check_composition_string( string, &expect_string_empty );
6212 string->dwCursorPos = 3;
6213 string->dwDeltaStart = 1;
6215 if (unicode) str = L"ReadComp";
6216 else str = "ReadComp";
6217 len = unicode ? wcslen( str ) : strlen( str );
6219 string->dwCompReadStrLen = len;
6220 string->dwCompReadStrOffset = string->dwSize;
6221 dst = (BYTE *)string + string->dwCompReadStrOffset;
6222 memcpy( dst, str, len * (unicode ? sizeof(WCHAR) : 1) );
6223 string->dwSize += len * (unicode ? sizeof(WCHAR) : 1);
6225 string->dwCompReadClauseLen = 2 * sizeof(DWORD);
6226 string->dwCompReadClauseOffset = string->dwSize;
6227 dst = (BYTE *)string + string->dwCompReadClauseOffset;
6228 *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0;
6229 *(DWORD *)(dst + 1 * sizeof(DWORD)) = len;
6230 string->dwSize += 2 * sizeof(DWORD);
6232 string->dwCompReadAttrLen = len;
6233 string->dwCompReadAttrOffset = string->dwSize;
6234 dst = (BYTE *)string + string->dwCompReadAttrOffset;
6235 memset( dst, ATTR_INPUT, len );
6236 string->dwSize += len;
6238 if (unicode) str = L"Comp";
6239 else str = "Comp";
6240 len = unicode ? wcslen( str ) : strlen( str );
6242 string->dwCompStrLen = len;
6243 string->dwCompStrOffset = string->dwSize;
6244 dst = (BYTE *)string + string->dwCompStrOffset;
6245 memcpy( dst, str, len * (unicode ? sizeof(WCHAR) : 1) );
6246 string->dwSize += len * (unicode ? sizeof(WCHAR) : 1);
6248 string->dwCompClauseLen = 2 * sizeof(DWORD);
6249 string->dwCompClauseOffset = string->dwSize;
6250 dst = (BYTE *)string + string->dwCompClauseOffset;
6251 *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0;
6252 *(DWORD *)(dst + 1 * sizeof(DWORD)) = len;
6253 string->dwSize += 2 * sizeof(DWORD);
6255 string->dwCompAttrLen = len;
6256 string->dwCompAttrOffset = string->dwSize;
6257 dst = (BYTE *)string + string->dwCompAttrOffset;
6258 memset( dst, ATTR_INPUT, len );
6259 string->dwSize += len;
6261 if (unicode) str = L"ReadResult";
6262 else str = "ReadResult";
6263 len = unicode ? wcslen( str ) : strlen( str );
6265 string->dwResultReadStrLen = len;
6266 string->dwResultReadStrOffset = string->dwSize;
6267 dst = (BYTE *)string + string->dwResultReadStrOffset;
6268 memcpy( dst, str, len * (unicode ? sizeof(WCHAR) : 1) );
6269 string->dwSize += len * (unicode ? sizeof(WCHAR) : 1);
6271 string->dwResultReadClauseLen = 2 * sizeof(DWORD);
6272 string->dwResultReadClauseOffset = string->dwSize;
6273 dst = (BYTE *)string + string->dwResultReadClauseOffset;
6274 *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0;
6275 *(DWORD *)(dst + 1 * sizeof(DWORD)) = len;
6276 string->dwSize += 2 * sizeof(DWORD);
6278 if (unicode) str = L"Result";
6279 else str = "Result";
6280 len = unicode ? wcslen( str ) : strlen( str );
6282 string->dwResultStrLen = len;
6283 string->dwResultStrOffset = string->dwSize;
6284 dst = (BYTE *)string + string->dwResultStrOffset;
6285 memcpy( dst, str, len * (unicode ? sizeof(WCHAR) : 1) );
6286 string->dwSize += len * (unicode ? sizeof(WCHAR) : 1);
6288 string->dwResultClauseLen = 2 * sizeof(DWORD);
6289 string->dwResultClauseOffset = string->dwSize;
6290 dst = (BYTE *)string + string->dwResultClauseOffset;
6291 *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0;
6292 *(DWORD *)(dst + 1 * sizeof(DWORD)) = len;
6293 string->dwSize += 2 * sizeof(DWORD);
6295 string->dwPrivateSize = 4;
6296 string->dwPrivateOffset = string->dwSize;
6297 dst = (BYTE *)string + string->dwPrivateOffset;
6298 memset( dst, 0xa5, string->dwPrivateSize );
6299 string->dwSize += 4;
6301 check_composition_string( string, unicode ? &expect_stringW : &expect_stringA );
6302 ok_ret( 0, ImmUnlockIMCC( ctx->hCompStr ) );
6303 old_himcc = ctx->hCompStr;
6305 for (i = 0; i < ARRAY_SIZE(gcs_indexes); ++i)
6307 UINT_PTR expect;
6309 winetest_push_context( "%u", i );
6311 memset( buffer, 0xcd, sizeof(buffer) );
6312 expect = expect_retW[i];
6313 ok_ret( expect, ImmGetCompositionStringW( himc, gcs_indexes[i], buffer, sizeof(buffer) ) );
6314 memset( buffer + expect, 0, 4 );
6316 if (i == 0) ok_wcs( L"ReadComp", (WCHAR *)buffer );
6317 else if (i == 3) ok_wcs( L"Comp", (WCHAR *)buffer );
6318 else if (i == 8) ok_wcs( L"ReadResult", (WCHAR *)buffer );
6319 else if (i == 10) ok_wcs( L"Result", (WCHAR *)buffer );
6320 else if (i != 6 && i != 7) ok_wcs( L"", (WCHAR *)buffer );
6322 memset( buffer, 0xcd, sizeof(buffer) );
6323 expect = expect_retA[i];
6324 ok_ret( expect, ImmGetCompositionStringA( himc, gcs_indexes[i], buffer, sizeof(buffer) ) );
6325 memset( buffer + expect, 0, 4 );
6327 if (i == 0) ok_str( "ReadComp", (char *)buffer );
6328 else if (i == 3) ok_str( "Comp", (char *)buffer );
6329 else if (i == 8) ok_str( "ReadResult", (char *)buffer );
6330 else if (i == 10) ok_str( "Result", (char *)buffer );
6331 else if (i != 6 && i != 7) ok_str( "", (char *)buffer );
6333 winetest_pop_context();
6336 for (i = 0; i < ARRAY_SIZE(gcs_indexes); ++i)
6338 winetest_push_context( "%u", i );
6339 ok_ret( 0, ImmSetCompositionStringW( himc, gcs_indexes[i], buffer, sizeof(buffer), NULL, 0 ) );
6340 ok_ret( 0, ImmSetCompositionStringA( himc, gcs_indexes[i], buffer, sizeof(buffer), NULL, 0 ) );
6341 winetest_pop_context();
6343 ok_ret( 0, ImmSetCompositionStringW( himc, SCS_SETSTR | SCS_CHANGEATTR, buffer, sizeof(buffer), NULL, 0 ) );
6344 ok_ret( 0, ImmSetCompositionStringA( himc, SCS_SETSTR | SCS_CHANGEATTR, buffer, sizeof(buffer), NULL, 0 ) );
6345 ok_ret( 0, ImmSetCompositionStringW( himc, SCS_CHANGECLAUSE | SCS_CHANGEATTR, buffer, sizeof(buffer), NULL, 0 ) );
6346 ok_ret( 0, ImmSetCompositionStringA( himc, SCS_CHANGECLAUSE | SCS_CHANGEATTR, buffer, sizeof(buffer), NULL, 0 ) );
6348 for (i = 0; i < ARRAY_SIZE(scs_indexes); ++i)
6350 winetest_push_context( "%u", i );
6352 if (scs_indexes[i] == SCS_CHANGECLAUSE)
6354 memset( buffer, 0, sizeof(buffer) );
6355 *((DWORD *)buffer + 1) = 1;
6356 len = 2 * sizeof(DWORD);
6358 else if (scs_indexes[i] == SCS_CHANGEATTR)
6360 memset( buffer, 0xcd, sizeof(buffer) );
6361 len = expect_stringW.dwCompAttrLen;
6363 else if (scs_indexes[i] == SCS_SETSTR)
6365 wcscpy( (WCHAR *)buffer, L"CompString" );
6366 len = 11 * sizeof(WCHAR);
6369 todo_ImeSetCompositionString = !unicode;
6370 SET_EXPECT( ImeSetCompositionString );
6371 ok_ret( 1, ImmSetCompositionStringW( himc, scs_indexes[i], buffer, len, NULL, 0 ) );
6372 CHECK_CALLED( ImeSetCompositionString );
6373 todo_ImeSetCompositionString = FALSE;
6374 ok_seq( empty_sequence );
6376 string = ImmLockIMCC( ctx->hCompStr );
6377 ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" );
6378 check_composition_string( string, unicode ? &expect_stringW : &expect_stringA );
6379 ok_ret( 0, ImmUnlockIMCC( ctx->hCompStr ) );
6381 if (scs_indexes[i] == SCS_CHANGECLAUSE)
6383 memset( buffer, 0, sizeof(buffer) );
6384 *((DWORD *)buffer + 1) = 1;
6385 len = 2 * sizeof(DWORD);
6387 else if (scs_indexes[i] == SCS_CHANGEATTR)
6389 memset( buffer, 0xcd, sizeof(buffer) );
6390 len = expect_stringA.dwCompAttrLen;
6392 else if (scs_indexes[i] == SCS_SETSTR)
6394 strcpy( buffer, "CompString" );
6395 len = 11;
6398 todo_ImeSetCompositionString = unicode;
6399 SET_EXPECT( ImeSetCompositionString );
6400 ok_ret( 1, ImmSetCompositionStringA( himc, scs_indexes[i], buffer, len, NULL, 0 ) );
6401 CHECK_CALLED( ImeSetCompositionString );
6402 todo_ImeSetCompositionString = FALSE;
6403 ok_seq( empty_sequence );
6405 string = ImmLockIMCC( ctx->hCompStr );
6406 ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" );
6407 check_composition_string( string, unicode ? &expect_stringW : &expect_stringA );
6408 ok_ret( 0, ImmUnlockIMCC( ctx->hCompStr ) );
6410 winetest_pop_context();
6412 ok_seq( empty_sequence );
6414 old_ctx = ctx;
6415 ok_ret( 1, ImmUnlockIMC( himc ) );
6417 /* composition strings are kept between IME selections */
6418 ok_ret( 1, ImmActivateLayout( default_hkl ) );
6419 ctx = ImmLockIMC( himc );
6420 ok_eq( old_ctx, ctx, INPUTCONTEXT *, "%p" );
6421 ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" );
6422 string = ImmLockIMCC( ctx->hCompStr );
6423 ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" );
6424 *string = expect_string_empty;
6425 ok_ret( 0, ImmUnlockIMCC( ctx->hCompStr ) );
6426 ok_ret( 1, ImmActivateLayout( hkl ) );
6427 ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" );
6428 check_composition_string( string, &expect_string_empty );
6429 ok_ret( 1, ImmActivateLayout( default_hkl ) );
6430 ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" );
6431 check_composition_string( string, &expect_string_empty );
6433 ok_ret( 1, ImmUnlockIMC( himc ) );
6434 ok_ret( 1, ImmDestroyContext( himc ) );
6436 ok_ret( 1, ImmActivateLayout( default_hkl ) );
6437 ok_ret( 1, DestroyWindow( hwnd ) );
6438 process_messages();
6440 ok_ret( 1, ImmFreeLayout( hkl ) );
6441 memset( ime_calls, 0, sizeof(ime_calls) );
6442 ime_call_count = 0;
6444 cleanup:
6445 winetest_pop_context();
6446 SET_ENABLE( ImeSetCompositionString, FALSE );
6449 static void test_ImmSetCompositionWindow(void)
6451 struct ime_call set_composition_window_0_seq[] =
6454 .hkl = expect_ime, .himc = 0/*himc*/,
6455 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONWINDOW},
6458 .hkl = expect_ime, .himc = default_himc,
6459 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCOMPOSITIONWINDOW},
6462 .hkl = expect_ime, .himc = default_himc,
6463 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCOMPOSITIONWINDOW},
6465 {0},
6467 struct ime_call set_composition_window_1_seq[] =
6470 .hkl = expect_ime, .himc = 0/*himc*/,
6471 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONWINDOW},
6473 {0},
6475 COMPOSITIONFORM comp_form, expect_form =
6477 .dwStyle = 0xfeedcafe,
6478 .ptCurrentPos = {.x = 123, .y = 456},
6479 .rcArea = {.left = 1, .top = 2, .right = 3, .bottom = 4},
6481 struct ime_windows ime_windows = {0};
6482 INPUTCONTEXT *ctx;
6483 HIMC himc;
6484 HWND hwnd;
6485 HKL hkl;
6487 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
6489 if (!(hkl = wineime_hkl)) return;
6491 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6492 100, 100, 100, 100, NULL, NULL, NULL, NULL );
6493 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
6495 ok_ret( 1, ImmActivateLayout( hkl ) );
6496 ok_ret( 1, ImmLoadIME( hkl ) );
6497 himc = ImmCreateContext();
6498 ok_ne( NULL, himc, HIMC, "%p" );
6499 ctx = ImmLockIMC( himc );
6500 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
6501 process_messages();
6502 memset( ime_calls, 0, sizeof(ime_calls) );
6503 ime_call_count = 0;
6505 set_composition_window_0_seq[0].himc = himc;
6506 set_composition_window_1_seq[0].himc = himc;
6508 ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) );
6509 ok_ne( NULL, ime_windows.ime_hwnd, HWND, "%p" );
6510 ok_ne( NULL, ime_windows.ime_ui_hwnd, HWND, "%p" );
6512 ctx->cfCompForm = expect_form;
6513 ctx->fdwInit = ~INIT_COMPFORM;
6514 memset( &comp_form, 0xcd, sizeof(comp_form) );
6515 ok_ret( 0, ImmGetCompositionWindow( himc, &comp_form ) );
6516 ok_eq( 0xcdcdcdcd, comp_form.dwStyle, UINT, "%#x" );
6517 ctx->fdwInit = INIT_COMPFORM;
6518 ok_ret( 1, ImmGetCompositionWindow( himc, &comp_form ) );
6519 check_composition_form( &comp_form, &expect_form );
6520 ok_seq( empty_sequence );
6521 ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) );
6523 ok_ret( 0, ShowWindow( ime_windows.ime_ui_hwnd, SW_SHOWNOACTIVATE ) );
6524 process_messages();
6525 ok_seq( empty_sequence );
6526 check_WM_SHOWWINDOW = TRUE;
6528 ctx->hWnd = hwnd;
6529 ctx->fdwInit = 0;
6530 memset( &comp_form, 0xcd, sizeof(comp_form) );
6531 ok_ret( 1, ImmSetCompositionWindow( himc, &comp_form ) );
6532 process_messages();
6533 ok_seq( set_composition_window_0_seq );
6534 ok_eq( INIT_COMPFORM, ctx->fdwInit, UINT, "%u" );
6535 check_composition_form( &ctx->cfCompForm, &comp_form );
6536 ok_ret( 1, IsWindowVisible( ime_windows.ime_ui_hwnd ) );
6537 check_WM_SHOWWINDOW = FALSE;
6539 ShowWindow( ime_windows.ime_ui_hwnd, SW_HIDE );
6540 process_messages();
6541 ok_seq( empty_sequence );
6543 ok_ret( 1, ImmSetCompositionWindow( himc, &expect_form ) );
6544 ok_seq( set_composition_window_0_seq );
6545 check_composition_form( &ctx->cfCompForm, &expect_form );
6547 ctx->cfCompForm = expect_form;
6548 ok_ret( 1, ImmGetCompositionWindow( himc, &comp_form ) );
6549 check_composition_form( &comp_form, &expect_form );
6550 ok_seq( empty_sequence );
6552 ctx->hWnd = 0;
6553 memset( &comp_form, 0xcd, sizeof(comp_form) );
6554 ok_ret( 1, ImmSetCompositionWindow( himc, &comp_form ) );
6555 ok_seq( set_composition_window_1_seq );
6556 check_composition_form( &ctx->cfCompForm, &comp_form );
6558 ok_ret( 1, ImmUnlockIMC( himc ) );
6559 ok_ret( 1, ImmDestroyContext( himc ) );
6561 ok_ret( 1, ImmActivateLayout( default_hkl ) );
6562 ok_ret( 1, DestroyWindow( hwnd ) );
6563 process_messages();
6565 ok_ret( 1, ImmFreeLayout( hkl ) );
6566 memset( ime_calls, 0, sizeof(ime_calls) );
6567 ime_call_count = 0;
6570 static void test_ImmSetStatusWindowPos(void)
6572 struct ime_call set_status_window_pos_0_seq[] =
6575 .hkl = expect_ime, .himc = 0/*himc*/,
6576 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETSTATUSWINDOWPOS},
6579 .hkl = expect_ime, .himc = default_himc,
6580 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSTATUSWINDOWPOS},
6583 .hkl = expect_ime, .himc = default_himc,
6584 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSTATUSWINDOWPOS},
6586 {0},
6588 struct ime_call set_status_window_pos_1_seq[] =
6591 .hkl = expect_ime, .himc = 0/*himc*/,
6592 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETSTATUSWINDOWPOS},
6594 {0},
6596 INPUTCONTEXT *ctx;
6597 POINT pos;
6598 HIMC himc;
6599 HWND hwnd;
6600 HKL hkl;
6602 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
6604 if (!(hkl = wineime_hkl)) return;
6606 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6607 100, 100, 100, 100, NULL, NULL, NULL, NULL );
6608 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
6610 ok_ret( 1, ImmActivateLayout( hkl ) );
6611 ok_ret( 1, ImmLoadIME( hkl ) );
6612 himc = ImmCreateContext();
6613 ok_ne( NULL, himc, HIMC, "%p" );
6614 ctx = ImmLockIMC( himc );
6615 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
6616 process_messages();
6617 memset( ime_calls, 0, sizeof(ime_calls) );
6618 ime_call_count = 0;
6620 set_status_window_pos_0_seq[0].himc = himc;
6621 set_status_window_pos_1_seq[0].himc = himc;
6623 memset( &pos, 0xcd, sizeof(pos) );
6624 ctx->ptStatusWndPos.x = 0xdeadbeef;
6625 ctx->ptStatusWndPos.y = 0xfeedcafe;
6626 ctx->fdwInit = ~INIT_STATUSWNDPOS;
6627 ok_ret( 0, ImmGetStatusWindowPos( himc, &pos ) );
6628 ok_eq( 0xcdcdcdcd, pos.x, UINT, "%u" );
6629 ok_eq( 0xcdcdcdcd, pos.y, UINT, "%u" );
6630 ctx->fdwInit = INIT_STATUSWNDPOS;
6631 ok_ret( 1, ImmGetStatusWindowPos( himc, &pos ) );
6632 ok_eq( 0xdeadbeef, pos.x, UINT, "%u" );
6633 ok_eq( 0xfeedcafe, pos.y, UINT, "%u" );
6634 ok_seq( empty_sequence );
6636 pos.x = 123;
6637 pos.y = 456;
6638 ctx->hWnd = hwnd;
6639 ctx->fdwInit = 0;
6640 ok_ret( 1, ImmSetStatusWindowPos( himc, &pos ) );
6641 ok_seq( set_status_window_pos_0_seq );
6642 ok_eq( INIT_STATUSWNDPOS, ctx->fdwInit, UINT, "%u" );
6644 ok_ret( 1, ImmSetStatusWindowPos( himc, &pos ) );
6645 ok_seq( set_status_window_pos_0_seq );
6646 ok_ret( 1, ImmGetStatusWindowPos( himc, &pos ) );
6647 ok_eq( 123, pos.x, UINT, "%u" );
6648 ok_eq( 123, ctx->ptStatusWndPos.x, UINT, "%u" );
6649 ok_eq( 456, pos.y, UINT, "%u" );
6650 ok_eq( 456, ctx->ptStatusWndPos.y, UINT, "%u" );
6651 ok_seq( empty_sequence );
6653 ctx->hWnd = 0;
6654 ok_ret( 1, ImmSetStatusWindowPos( himc, &pos ) );
6655 ok_seq( set_status_window_pos_1_seq );
6657 ok_ret( 1, ImmUnlockIMC( himc ) );
6658 ok_ret( 1, ImmDestroyContext( himc ) );
6660 ok_ret( 1, ImmActivateLayout( default_hkl ) );
6661 ok_ret( 1, DestroyWindow( hwnd ) );
6662 process_messages();
6664 ok_ret( 1, ImmFreeLayout( hkl ) );
6665 memset( ime_calls, 0, sizeof(ime_calls) );
6666 ime_call_count = 0;
6669 static void test_ImmSetCompositionFont( BOOL unicode )
6671 struct ime_call set_composition_font_0_seq[] =
6674 .hkl = expect_ime, .himc = 0/*himc*/,
6675 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONFONT},
6678 .hkl = expect_ime, .himc = default_himc,
6679 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCOMPOSITIONFONT},
6682 .hkl = expect_ime, .himc = default_himc,
6683 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCOMPOSITIONFONT},
6685 {0},
6687 struct ime_call set_composition_font_1_seq[] =
6690 .hkl = expect_ime, .himc = 0/*himc*/,
6691 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONFONT},
6693 {0},
6695 LOGFONTW fontW, expect_fontW =
6697 .lfHeight = 1,
6698 .lfWidth = 2,
6699 .lfEscapement = 3,
6700 .lfOrientation = 4,
6701 .lfWeight = 5,
6702 .lfItalic = 6,
6703 .lfUnderline = 7,
6704 .lfStrikeOut = 8,
6705 .lfCharSet = 8,
6706 .lfOutPrecision = 10,
6707 .lfClipPrecision = 11,
6708 .lfQuality = 12,
6709 .lfPitchAndFamily = 13,
6710 .lfFaceName = L"FontFace",
6712 LOGFONTA fontA, expect_fontA =
6714 .lfHeight = 1,
6715 .lfWidth = 2,
6716 .lfEscapement = 3,
6717 .lfOrientation = 4,
6718 .lfWeight = 5,
6719 .lfItalic = 6,
6720 .lfUnderline = 7,
6721 .lfStrikeOut = 8,
6722 .lfCharSet = 8,
6723 .lfOutPrecision = 10,
6724 .lfClipPrecision = 11,
6725 .lfQuality = 12,
6726 .lfPitchAndFamily = 13,
6727 .lfFaceName = "FontFace",
6729 INPUTCONTEXT *ctx;
6730 HIMC himc;
6731 HWND hwnd;
6732 HKL hkl;
6734 winetest_push_context( unicode ? "unicode" : "ansi" );
6736 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
6737 ime_info.fdwProperty = IME_PROP_END_UNLOAD;
6738 if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE;
6740 if (!(hkl = wineime_hkl)) goto cleanup;
6742 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6743 100, 100, 100, 100, NULL, NULL, NULL, NULL );
6744 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
6746 ok_ret( 1, ImmActivateLayout( hkl ) );
6747 ok_ret( 1, ImmLoadIME( hkl ) );
6748 himc = ImmCreateContext();
6749 ok_ne( NULL, himc, HIMC, "%p" );
6750 ctx = ImmLockIMC( himc );
6751 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
6752 process_messages();
6753 memset( ime_calls, 0, sizeof(ime_calls) );
6754 ime_call_count = 0;
6756 set_composition_font_0_seq[0].himc = himc;
6757 set_composition_font_1_seq[0].himc = himc;
6759 memset( &fontW, 0xcd, sizeof(fontW) );
6760 memset( &fontA, 0xcd, sizeof(fontA) );
6762 if (unicode) ctx->lfFont.W = expect_fontW;
6763 else ctx->lfFont.A = expect_fontA;
6764 ctx->fdwInit = ~INIT_LOGFONT;
6765 ok_ret( 0, ImmGetCompositionFontW( himc, &fontW ) );
6766 ok_ret( 0, ImmGetCompositionFontA( himc, &fontA ) );
6767 ctx->fdwInit = INIT_LOGFONT;
6768 ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) );
6769 check_logfont_w( &fontW, &expect_fontW );
6770 ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) );
6771 check_logfont_a( &fontA, &expect_fontA );
6773 ctx->hWnd = hwnd;
6774 ctx->fdwInit = 0;
6775 memset( &ctx->lfFont, 0xcd, sizeof(ctx->lfFont) );
6776 ok_ret( 1, ImmSetCompositionFontW( himc, &expect_fontW ) );
6777 ok_eq( INIT_LOGFONT, ctx->fdwInit, UINT, "%u" );
6778 ok_seq( set_composition_font_0_seq );
6779 ok_ret( 1, ImmSetCompositionFontW( himc, &expect_fontW ) );
6780 ok_seq( set_composition_font_0_seq );
6781 if (unicode) check_logfont_w( &ctx->lfFont.W, &expect_fontW );
6782 else check_logfont_a( &ctx->lfFont.A, &expect_fontA );
6784 ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) );
6785 check_logfont_w( &fontW, &expect_fontW );
6786 ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) );
6787 check_logfont_a( &fontA, &expect_fontA );
6789 ctx->hWnd = hwnd;
6790 ctx->fdwInit = 0;
6791 memset( &ctx->lfFont, 0xcd, sizeof(ctx->lfFont) );
6792 ok_ret( 1, ImmSetCompositionFontA( himc, &expect_fontA ) );
6793 ok_eq( INIT_LOGFONT, ctx->fdwInit, UINT, "%u" );
6794 ok_seq( set_composition_font_0_seq );
6795 ok_ret( 1, ImmSetCompositionFontA( himc, &expect_fontA ) );
6796 ok_seq( set_composition_font_0_seq );
6797 if (unicode) check_logfont_w( &ctx->lfFont.W, &expect_fontW );
6798 else check_logfont_a( &ctx->lfFont.A, &expect_fontA );
6800 ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) );
6801 check_logfont_w( &fontW, &expect_fontW );
6802 ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) );
6803 check_logfont_a( &fontA, &expect_fontA );
6805 ctx->hWnd = 0;
6806 ok_ret( 1, ImmSetCompositionFontW( himc, &expect_fontW ) );
6807 ok_seq( set_composition_font_1_seq );
6808 ok_ret( 1, ImmSetCompositionFontA( himc, &expect_fontA ) );
6809 ok_seq( set_composition_font_1_seq );
6811 ok_ret( 1, ImmUnlockIMC( himc ) );
6812 ok_ret( 1, ImmDestroyContext( himc ) );
6814 ok_ret( 1, ImmActivateLayout( default_hkl ) );
6815 ok_ret( 1, DestroyWindow( hwnd ) );
6816 process_messages();
6818 ok_ret( 1, ImmFreeLayout( hkl ) );
6819 memset( ime_calls, 0, sizeof(ime_calls) );
6820 ime_call_count = 0;
6822 cleanup:
6823 winetest_pop_context();
6826 static void test_ImmSetCandidateWindow(void)
6828 struct ime_call set_candidate_window_0_seq[] =
6831 .hkl = expect_ime, .himc = 0/*himc*/,
6832 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCANDIDATEPOS},
6835 .hkl = expect_ime, .himc = default_himc,
6836 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCANDIDATEPOS, .lparam = 4},
6839 .hkl = expect_ime, .himc = default_himc,
6840 .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCANDIDATEPOS, .lparam = 4},
6842 {0},
6844 struct ime_call set_candidate_window_1_seq[] =
6847 .hkl = expect_ime, .himc = 0/*himc*/,
6848 .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCANDIDATEPOS},
6850 {0},
6852 CANDIDATEFORM cand_form, expect_form =
6854 .dwIndex = 2, .dwStyle = 0xfeedcafe,
6855 .ptCurrentPos = {.x = 123, .y = 456},
6856 .rcArea = {.left = 1, .top = 2, .right = 3, .bottom = 4},
6858 INPUTCONTEXT *ctx;
6859 HIMC himc;
6860 HWND hwnd;
6861 HKL hkl;
6863 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
6865 if (!(hkl = wineime_hkl)) return;
6867 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6868 100, 100, 100, 100, NULL, NULL, NULL, NULL );
6869 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
6871 ok_ret( 1, ImmActivateLayout( hkl ) );
6872 ok_ret( 1, ImmLoadIME( hkl ) );
6873 himc = ImmCreateContext();
6874 ok_ne( NULL, himc, HIMC, "%p" );
6875 ctx = ImmLockIMC( himc );
6876 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
6877 process_messages();
6878 memset( ime_calls, 0, sizeof(ime_calls) );
6879 ime_call_count = 0;
6881 set_candidate_window_0_seq[0].himc = himc;
6882 set_candidate_window_1_seq[0].himc = himc;
6884 ctx->cfCandForm[1] = expect_form;
6885 ctx->cfCandForm[2] = expect_form;
6886 ctx->fdwInit = 0;
6887 memset( &cand_form, 0xcd, sizeof(cand_form) );
6888 ok_ret( 0, ImmGetCandidateWindow( himc, 0, &cand_form ) );
6889 ok_eq( 0xcdcdcdcd, cand_form.dwStyle, UINT, "%#x" );
6890 ok_ret( 1, ImmGetCandidateWindow( himc, 1, &cand_form ) );
6891 check_candidate_form( &cand_form, &expect_form );
6892 ok_ret( 1, ImmGetCandidateWindow( himc, 2, &cand_form ) );
6893 check_candidate_form( &cand_form, &expect_form );
6894 ok_seq( empty_sequence );
6896 ctx->hWnd = hwnd;
6897 memset( &cand_form, 0xcd, sizeof(cand_form) );
6898 cand_form.dwIndex = 2;
6899 ok_ret( 1, ImmSetCandidateWindow( himc, &cand_form ) );
6900 ok_seq( set_candidate_window_0_seq );
6901 check_candidate_form( &ctx->cfCandForm[2], &cand_form );
6902 ok_eq( 0, ctx->fdwInit, UINT, "%u" );
6904 ok_ret( 1, ImmSetCandidateWindow( himc, &expect_form ) );
6905 ok_seq( set_candidate_window_0_seq );
6906 check_candidate_form( &ctx->cfCandForm[2], &expect_form );
6908 ctx->hWnd = 0;
6909 memset( &cand_form, 0xcd, sizeof(cand_form) );
6910 cand_form.dwIndex = 2;
6911 ok_ret( 1, ImmSetCandidateWindow( himc, &cand_form ) );
6912 ok_seq( set_candidate_window_1_seq );
6913 check_candidate_form( &ctx->cfCandForm[2], &cand_form );
6915 ok_ret( 1, ImmUnlockIMC( himc ) );
6916 ok_ret( 1, ImmDestroyContext( himc ) );
6918 ok_ret( 1, ImmActivateLayout( default_hkl ) );
6919 ok_ret( 1, DestroyWindow( hwnd ) );
6920 process_messages();
6922 ok_ret( 1, ImmFreeLayout( hkl ) );
6923 memset( ime_calls, 0, sizeof(ime_calls) );
6924 ime_call_count = 0;
6927 static void test_ImmGenerateMessage(void)
6929 const struct ime_call generate_sequence[] =
6932 .hkl = expect_ime, .himc = default_himc,
6933 .func = MSG_TEST_WIN, .message = {.msg = WM_IME_COMPOSITION, .wparam = 0, .lparam = GCS_COMPSTR},
6936 .hkl = expect_ime, .himc = default_himc,
6937 .func = MSG_IME_UI, .message = {.msg = WM_IME_COMPOSITION, .wparam = 0, .lparam = GCS_COMPSTR},
6939 {0},
6941 TRANSMSG *msgs, *tmp_msgs;
6942 INPUTCONTEXT *ctx;
6943 HIMC himc;
6944 HWND hwnd;
6945 HKL hkl;
6947 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
6949 if (!(hkl = wineime_hkl)) return;
6951 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6952 100, 100, 100, 100, NULL, NULL, NULL, NULL );
6953 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
6955 ok_ret( 1, ImmActivateLayout( hkl ) );
6956 ok_ret( 1, ImmLoadIME( hkl ) );
6957 himc = ImmCreateContext();
6958 ok_ne( NULL, himc, HIMC, "%p" );
6959 ctx = ImmLockIMC( himc );
6960 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
6961 process_messages();
6962 memset( ime_calls, 0, sizeof(ime_calls) );
6963 ime_call_count = 0;
6965 todo_wine ok_ret( 4, ImmGetIMCCSize( ctx->hMsgBuf ) );
6966 ctx->hMsgBuf = ImmReSizeIMCC( ctx->hMsgBuf, sizeof(*msgs) );
6967 ok_ne( NULL, ctx->hMsgBuf, HIMCC, "%p" );
6969 msgs = ImmLockIMCC( ctx->hMsgBuf );
6970 ok_ne( NULL, msgs, TRANSMSG *, "%p" );
6971 msgs[0].message = WM_IME_COMPOSITION;
6972 msgs[0].wParam = 0;
6973 msgs[0].lParam = GCS_COMPSTR;
6974 ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) );
6976 ctx->hWnd = 0;
6977 ctx->dwNumMsgBuf = 0;
6978 ok_ret( 1, ImmGenerateMessage( himc ) );
6979 ok_seq( empty_sequence );
6980 ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) );
6981 tmp_msgs = ImmLockIMCC( ctx->hMsgBuf );
6982 ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" );
6983 ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) );
6985 ctx->dwNumMsgBuf = 1;
6986 ok_ret( 1, ImmGenerateMessage( himc ) );
6987 ok_seq( empty_sequence );
6988 ok_eq( 0, ctx->dwNumMsgBuf, UINT, "%u" );
6989 ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) );
6990 tmp_msgs = ImmLockIMCC( ctx->hMsgBuf );
6991 ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" );
6992 ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) );
6994 ctx->hWnd = hwnd;
6995 ctx->dwNumMsgBuf = 0;
6996 ok_ret( 1, ImmGenerateMessage( himc ) );
6997 ok_seq( empty_sequence );
6998 ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) );
6999 tmp_msgs = ImmLockIMCC( ctx->hMsgBuf );
7000 ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" );
7001 ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) );
7003 ctx->dwNumMsgBuf = 1;
7004 ok_ret( 1, ImmGenerateMessage( himc ) );
7005 ok_seq( generate_sequence );
7006 ok_eq( 0, ctx->dwNumMsgBuf, UINT, "%u" );
7007 ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) );
7008 tmp_msgs = ImmLockIMCC( ctx->hMsgBuf );
7009 ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" );
7010 ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) );
7012 tmp_msgs = ImmLockIMCC( ctx->hMsgBuf );
7013 ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" );
7014 ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) );
7016 ok_ret( 1, ImmUnlockIMC( himc ) );
7017 ok_ret( 1, ImmDestroyContext( himc ) );
7019 ok_ret( 1, ImmActivateLayout( default_hkl ) );
7020 ok_ret( 1, DestroyWindow( hwnd ) );
7021 process_messages();
7023 ok_ret( 1, ImmFreeLayout( hkl ) );
7024 memset( ime_calls, 0, sizeof(ime_calls) );
7025 ime_call_count = 0;
7028 static void test_ImmTranslateMessage( BOOL kbd_char_first )
7030 const struct ime_call process_key_seq[] =
7033 .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY,
7034 .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0x10)},
7037 .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY,
7038 .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc010)},
7040 {0},
7042 const struct ime_call to_ascii_ex_0[] =
7045 .hkl = expect_ime, .himc = default_himc, .func = IME_TO_ASCII_EX,
7046 .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x10},
7048 {0},
7050 const struct ime_call to_ascii_ex_1[] =
7053 .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY,
7054 .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc010)},
7057 .hkl = expect_ime, .himc = default_himc, .func = IME_TO_ASCII_EX,
7058 /* FIXME what happened to kbd_char_first here!? */
7059 .to_ascii_ex = {.vkey = 'Q', .vsc = 0xc010},
7061 {0},
7063 struct ime_call to_ascii_ex_2[] =
7066 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY,
7067 .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0x210)},
7070 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX,
7071 .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x210},
7074 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY,
7075 .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0x410)},
7078 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX,
7079 .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x410},
7081 {0},
7083 struct ime_call to_ascii_ex_3[] =
7086 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY,
7087 .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xa10)},
7090 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX,
7091 .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0xa10},
7094 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY,
7095 .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc10)},
7098 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX,
7099 .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0xc10},
7101 {0},
7103 struct ime_call key_down_seq[] =
7106 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY,
7107 .process_key = {.vkey = VK_RETURN, .lparam = MAKELONG(1, 0x1c)},
7110 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX,
7111 .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG(VK_RETURN, VK_RETURN) : VK_RETURN, .vsc = 0x1c},
7113 {0},
7115 struct ime_call key_up_seq[] =
7118 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY,
7119 .process_key = {.vkey = VK_RETURN, .lparam = MAKELONG(1, 0xc01c)},
7122 .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX,
7123 .to_ascii_ex = {.vkey = VK_RETURN, .vsc = 0xc01c},
7125 {0},
7127 struct ime_call post_messages[] =
7129 {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 1}},
7130 {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 1},
7131 .todo_himc = TRUE /* on some Wine configurations the IME UI doesn't get an HIMC */
7133 {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 1}},
7134 {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 1},
7135 .todo_himc = TRUE /* on some Wine configurations the IME UI doesn't get an HIMC */
7137 {0},
7139 struct ime_call sent_messages[] =
7141 {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 2}},
7142 {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 2},
7143 .todo_himc = TRUE /* on some Wine configurations the IME UI doesn't get an HIMC */
7145 {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 2}},
7146 {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 2},
7147 .todo_himc = TRUE /* on some Wine configurations the IME UI doesn't get an HIMC */
7149 {0},
7151 HWND hwnd, other_hwnd;
7152 INPUTCONTEXT *ctx;
7153 HIMC himc;
7154 HKL hkl;
7155 UINT i;
7157 ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE;
7158 if (kbd_char_first) ime_info.fdwProperty |= IME_PROP_KBD_CHAR_FIRST;
7160 winetest_push_context( kbd_char_first ? "kbd_char_first" : "default" );
7162 if (!(hkl = wineime_hkl)) goto cleanup;
7164 other_hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7165 100, 100, 100, 100, NULL, NULL, NULL, NULL );
7166 ok( !!other_hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
7167 flush_events();
7169 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7170 100, 100, 100, 100, NULL, NULL, NULL, NULL );
7171 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
7172 flush_events();
7174 ok_ret( 1, ImmActivateLayout( hkl ) );
7175 ok_ret( 1, ImmLoadIME( hkl ) );
7176 himc = ImmCreateContext();
7177 ok_ne( NULL, himc, HIMC, "%p" );
7178 ctx = ImmLockIMC( himc );
7179 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
7180 process_messages();
7181 memset( ime_calls, 0, sizeof(ime_calls) );
7182 ime_call_count = 0;
7184 ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x10), 0 ) );
7185 ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc010), 0 ) );
7187 ok_ret( 0, ImmTranslateMessage( hwnd, 0, 0, 0 ) );
7188 ok_ret( 'Q', ImmGetVirtualKey( hwnd ) );
7189 ok_seq( process_key_seq );
7191 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'Q', MAKELONG(2, 0x10) ) );
7192 ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) );
7193 ok_seq( to_ascii_ex_0 );
7195 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc010) ) );
7196 ok_seq( empty_sequence );
7198 ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc010), 0 ) );
7199 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc010) ) );
7200 ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) );
7201 ok_seq( to_ascii_ex_1 );
7203 ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" );
7204 ok_eq( default_himc, ImmAssociateContext( other_hwnd, himc ), HIMC, "%p" );
7205 for (i = 0; i < ARRAY_SIZE(to_ascii_ex_2); i++) to_ascii_ex_2[i].himc = himc;
7206 for (i = 0; i < ARRAY_SIZE(to_ascii_ex_3); i++) to_ascii_ex_3[i].himc = himc;
7207 for (i = 0; i < ARRAY_SIZE(post_messages); i++) post_messages[i].himc = himc;
7208 for (i = 0; i < ARRAY_SIZE(sent_messages); i++) sent_messages[i].himc = himc;
7209 for (i = 0; i < ARRAY_SIZE(key_down_seq); i++) key_down_seq[i].himc = himc;
7210 for (i = 0; i < ARRAY_SIZE(key_up_seq); i++) key_up_seq[i].himc = himc;
7211 memset( ime_calls, 0, sizeof(ime_calls) );
7212 ime_call_count = 0;
7214 ctx->hWnd = hwnd;
7215 ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x210), 0 ) );
7216 ok_ret( 1, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ) );
7217 ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x410), 0 ) );
7218 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x410) ) );
7219 ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) );
7220 ok_seq( to_ascii_ex_2 );
7221 process_messages();
7222 ok_seq( post_messages );
7223 ok_ret( 1, ImmGenerateMessage( himc ) );
7224 ok_seq( sent_messages );
7226 ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xa10), 0 ) );
7227 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xa10) ) );
7228 ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc10), 0 ) );
7229 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc10) ) );
7230 ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) );
7231 ok_seq( to_ascii_ex_3 );
7232 process_messages();
7233 ok_seq( empty_sequence );
7234 ok_ret( 1, ImmGenerateMessage( himc ) );
7235 ok_seq( sent_messages );
7237 ctx->hWnd = 0;
7238 ok_ret( 2, ImmProcessKey( other_hwnd, expect_ime, 'Q', MAKELONG(2, 0x210), 0 ) );
7239 ok_ret( 1, ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ) );
7240 ok_ret( 2, ImmProcessKey( other_hwnd, expect_ime, 'Q', MAKELONG(2, 0x410), 0 ) );
7241 ok_ret( 0, ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x410) ) );
7242 ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( other_hwnd ) );
7243 ok_seq( to_ascii_ex_2 );
7244 process_messages_( hwnd );
7245 ok_seq( empty_sequence );
7246 process_messages_( other_hwnd );
7247 ok_seq( post_messages );
7248 ok_ret( 1, ImmGenerateMessage( himc ) );
7249 ok_seq( empty_sequence );
7252 ignore_WM_IME_NOTIFY = TRUE;
7253 ignore_IME_NOTIFY = TRUE;
7255 keybd_event( VK_RETURN, 0x1c, 0, 0 );
7256 flush_events();
7257 process_messages_( hwnd );
7258 ok_seq( key_down_seq );
7260 keybd_event( VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0 );
7261 flush_events();
7262 process_messages_( hwnd );
7263 ok_seq( key_up_seq );
7265 ignore_WM_IME_NOTIFY = FALSE;
7266 ignore_IME_NOTIFY = FALSE;
7269 ok_ret( 1, ImmUnlockIMC( himc ) );
7270 ok_ret( 1, ImmDestroyContext( himc ) );
7272 ok_ret( 1, ImmActivateLayout( default_hkl ) );
7273 ok_ret( 1, DestroyWindow( other_hwnd ) );
7274 ok_ret( 1, DestroyWindow( hwnd ) );
7275 process_messages();
7277 ok_ret( 1, ImmFreeLayout( hkl ) );
7278 memset( ime_calls, 0, sizeof(ime_calls) );
7279 ime_call_count = 0;
7281 cleanup:
7282 winetest_pop_context();
7285 static void test_ga_na_da(void)
7287 /* These sequences have some additional WM_IME_NOTIFY messages with unknown wparam > IMN_PRIVATE */
7288 struct ime_call complete_seq[] =
7290 /* G */
7291 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}},
7293 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u3131", .result = L"",
7294 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x3131, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7298 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"",
7299 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x1b, .lparam = GCS_CURSORPOS|GCS_DELTASTART|GCS_COMPSTR|GCS_COMPATTR|GCS_COMPCLAUSE|
7300 GCS_COMPREADSTR|GCS_COMPREADATTR|GCS_COMPREADCLAUSE},
7302 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}},
7304 /* G */
7305 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}},
7307 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u3131", .result = L"",
7308 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x3131, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7310 /* A */
7312 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac00", .result = L"",
7313 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7315 /* N */
7317 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac04", .result = L"",
7318 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac04, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7320 /* A */
7322 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00",
7323 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_RESULTSTR},
7325 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xac00, .lparam = 0x1}},
7327 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00",
7328 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7330 /* D */
7332 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub09f", .result = L"",
7333 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb09f, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7335 /* A */
7337 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub2e4", .result = L"\ub098",
7338 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_RESULTSTR},
7340 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xb098, .lparam = 0x1}},
7342 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub2e4", .result = L"\ub098",
7343 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb2e4, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7345 /* RETURN */
7346 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}},
7348 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"\ub2e4",
7349 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb2e4, .lparam = GCS_RESULTSTR},
7351 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xb2e4, .lparam = 0x1}},
7352 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_KEYDOWN, .wparam = 0xd, .lparam = 0x1c0001}},
7353 {0},
7355 struct ime_call partial_g_seq[] =
7357 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}},
7359 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u3131", .result = L"",
7360 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x3131, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7362 {0},
7364 struct ime_call partial_ga_seq[] =
7367 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac00", .result = L"",
7368 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7370 {0},
7372 struct ime_call partial_n_seq[] =
7375 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac04", .result = L"",
7376 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac04, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7378 {0},
7380 struct ime_call partial_na_seq[] =
7383 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00",
7384 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_RESULTSTR},
7386 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xac00, .lparam = 0x1}},
7388 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00",
7389 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7391 {0},
7393 struct ime_call partial_d_seq[] =
7396 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub09f", .result = L"",
7397 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb09f, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7399 {0},
7401 struct ime_call partial_da_seq[] =
7404 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub2e4", .result = L"\ub098",
7405 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_RESULTSTR},
7407 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xb098, .lparam = 0x1}},
7409 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub2e4", .result = L"\ub098",
7410 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb2e4, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7412 {0},
7414 struct ime_call partial_return_seq[] =
7416 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}},
7418 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"\ub2e4",
7419 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb2e4, .lparam = GCS_RESULTSTR},
7421 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xb2e4, .lparam = 0x1}},
7422 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_KEYDOWN, .wparam = 0xd, .lparam = 0x1c0001}},
7423 {0},
7425 struct ime_call cancel_seq[] =
7427 /* G */
7428 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}},
7430 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u3131", .result = L"",
7431 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x3131, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7433 /* A */
7435 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac00", .result = L"",
7436 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7438 /* N */
7440 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac04", .result = L"",
7441 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac04, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7443 /* A */
7445 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00",
7446 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_RESULTSTR},
7448 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xac00, .lparam = 0x1}},
7450 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00",
7451 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7454 /* CPS_CANCEL */
7455 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}},
7456 {0},
7458 struct ime_call closed_seq[] =
7460 /* G */
7461 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}},
7463 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u3131", .result = L"",
7464 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x3131, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7466 /* A */
7468 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac00", .result = L"",
7469 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7471 /* N */
7473 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac04", .result = L"",
7474 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac04, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7476 /* A */
7478 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00",
7479 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_RESULTSTR},
7481 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xac00, .lparam = 0x1}},
7483 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00",
7484 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET},
7487 /* CPS_COMPLETE */
7488 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}},
7490 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"\ub098",
7491 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_RESULTSTR},
7493 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xb098, .lparam = 0x1}},
7494 {0},
7497 INPUTCONTEXT *ctx;
7498 HWND hwnd;
7499 HIMC himc;
7500 UINT i;
7502 /* this test doesn't work on Win32 / WoW64 */
7503 if (broken(sizeof(void *) == 4) || default_hkl != (HKL)0x04120412 /* MS Korean IME */)
7505 skip( "Got hkl %p, skipping Korean IME-specific test\n", default_hkl );
7506 process_messages();
7507 return;
7510 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7511 100, 100, 100, 100, NULL, NULL, NULL, NULL );
7512 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
7513 flush_events();
7515 ignore_WM_IME_NOTIFY = TRUE;
7516 ignore_IME_NOTIFY = TRUE;
7518 himc = ImmCreateContext();
7519 ok_ne( NULL, himc, HIMC, "%p" );
7520 ctx = ImmLockIMC( himc );
7521 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
7522 ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" );
7523 ok_ret( 1, ImmSetOpenStatus( himc, TRUE ) );
7524 ok_ret( 1, ImmSetConversionStatus( himc, IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE, IME_SMODE_PHRASEPREDICT ) );
7525 flush_events();
7527 keybd_event( 'R', 0x13, 0, 0 );
7528 flush_events();
7529 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP, 0 );
7531 keybd_event( VK_RETURN, 0x1c, 0, 0 );
7532 flush_events();
7533 keybd_event( VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0 );
7534 flush_events();
7535 memset( ime_calls, 0, sizeof(ime_calls) );
7536 ime_call_count = 0;
7538 for (i = 0; i < ARRAY_SIZE(complete_seq); i++) complete_seq[i].himc = himc;
7539 for (i = 0; i < ARRAY_SIZE(partial_g_seq); i++) partial_g_seq[i].himc = himc;
7540 for (i = 0; i < ARRAY_SIZE(partial_ga_seq); i++) partial_ga_seq[i].himc = himc;
7541 for (i = 0; i < ARRAY_SIZE(partial_n_seq); i++) partial_n_seq[i].himc = himc;
7542 for (i = 0; i < ARRAY_SIZE(partial_na_seq); i++) partial_na_seq[i].himc = himc;
7543 for (i = 0; i < ARRAY_SIZE(partial_d_seq); i++) partial_d_seq[i].himc = himc;
7544 for (i = 0; i < ARRAY_SIZE(partial_da_seq); i++) partial_da_seq[i].himc = himc;
7545 for (i = 0; i < ARRAY_SIZE(partial_return_seq); i++) partial_return_seq[i].himc = himc;
7546 for (i = 0; i < ARRAY_SIZE(cancel_seq); i++) cancel_seq[i].himc = himc;
7547 for (i = 0; i < ARRAY_SIZE(closed_seq); i++) closed_seq[i].himc = himc;
7549 keybd_event( 'R', 0x13, 0, 0 );
7550 flush_events();
7551 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP, 0 );
7553 keybd_event( VK_BACK, 0x0e, 0, 0 );
7554 flush_events();
7555 keybd_event( VK_BACK, 0x0e, KEYEVENTF_KEYUP, 0 );
7557 keybd_event( 'R', 0x13, 0, 0 );
7558 flush_events();
7559 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP, 0 );
7561 keybd_event( 'K', 0x25, 0, 0 );
7562 flush_events();
7563 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 );
7565 keybd_event( 'S', 0x1f, 0, 0 );
7566 flush_events();
7567 keybd_event( 'S', 0x1f, KEYEVENTF_KEYUP, 0 );
7569 keybd_event( 'K', 0x25, 0, 0 );
7570 flush_events();
7571 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 );
7573 keybd_event( 'E', 0x12, 0, 0 );
7574 flush_events();
7575 keybd_event( 'E', 0x12, KEYEVENTF_KEYUP, 0 );
7577 keybd_event( 'K', 0x25, 0, 0 );
7578 flush_events();
7579 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 );
7581 keybd_event( VK_RETURN, 0x1c, 0, 0 );
7582 flush_events();
7583 keybd_event( VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0 );
7585 flush_events();
7586 todo_wine ok_seq( complete_seq );
7589 /* Korean IME uses ImeProcessKey and posts messages */
7591 todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'R', MAKELONG(1, 0x13), 0 ) );
7592 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'R', MAKELONG(1, 0x13) ) );
7593 ok_seq( empty_sequence );
7594 process_messages();
7595 todo_wine ok_seq( partial_g_seq );
7597 /* Korean IME doesn't eat WM_KEYUP */
7599 ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'R', MAKELONG(1, 0xc013), 0 ) );
7600 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'R', MAKELONG(1, 0xc013) ) );
7601 process_messages();
7602 ok_seq( empty_sequence );
7604 todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'K', MAKELONG(1, 0x25), 0 ) );
7605 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'K', MAKELONG(1, 0x25) ) );
7606 process_messages();
7607 todo_wine ok_seq( partial_ga_seq );
7609 todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'S', MAKELONG(1, 0x1f), 0 ) );
7610 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'S', MAKELONG(1, 0x1f) ) );
7611 process_messages();
7612 todo_wine ok_seq( partial_n_seq );
7614 todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'K', MAKELONG(1, 0x25), 0 ) );
7615 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'K', MAKELONG(1, 0x25) ) );
7616 process_messages();
7617 todo_wine ok_seq( partial_na_seq );
7619 todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'E', MAKELONG(1, 0x12), 0 ) );
7620 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'E', MAKELONG(1, 0x12) ) );
7621 process_messages();
7622 todo_wine ok_seq( partial_d_seq );
7624 todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'K', MAKELONG(1, 0x25), 0 ) );
7625 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'K', MAKELONG(1, 0x25) ) );
7626 process_messages();
7627 todo_wine ok_seq( partial_da_seq );
7629 todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, VK_RETURN, MAKELONG(1, 0x1c), 0 ) );
7630 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, VK_RETURN, MAKELONG(1, 0x1c) ) );
7631 process_messages();
7632 todo_wine ok_seq( partial_return_seq );
7635 /* cancelling clears the composition string */
7637 keybd_event( 'R', 0x13, 0, 0 );
7638 flush_events();
7639 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP, 0 );
7641 keybd_event( 'K', 0x25, 0, 0 );
7642 flush_events();
7643 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 );
7645 keybd_event( 'S', 0x1f, 0, 0 );
7646 flush_events();
7647 keybd_event( 'S', 0x1f, KEYEVENTF_KEYUP, 0 );
7649 keybd_event( 'K', 0x25, 0, 0 );
7650 flush_events();
7651 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 );
7653 ok_ret( 1, ImmNotifyIME( himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0 ) );
7655 flush_events();
7656 todo_wine ok_seq( cancel_seq );
7659 /* CPS_COMPLETE and ImmSetOpenStatus( himc, FALSE ) do the same thing */
7661 keybd_event( 'R', 0x13, 0, 0 );
7662 flush_events();
7663 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP, 0 );
7665 keybd_event( 'K', 0x25, 0, 0 );
7666 flush_events();
7667 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 );
7669 keybd_event( 'S', 0x1f, 0, 0 );
7670 flush_events();
7671 keybd_event( 'S', 0x1f, KEYEVENTF_KEYUP, 0 );
7673 keybd_event( 'K', 0x25, 0, 0 );
7674 flush_events();
7675 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 );
7677 ok_ret( 1, ImmNotifyIME( himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0 ) );
7679 flush_events();
7680 todo_wine ok_seq( closed_seq );
7683 keybd_event( 'R', 0x13, 0, 0 );
7684 flush_events();
7685 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP, 0 );
7687 keybd_event( 'K', 0x25, 0, 0 );
7688 flush_events();
7689 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 );
7691 /* does nothing, already open */
7692 ok_ret( 1, ImmSetOpenStatus( himc, TRUE ) );
7694 keybd_event( 'S', 0x1f, 0, 0 );
7695 flush_events();
7696 keybd_event( 'S', 0x1f, KEYEVENTF_KEYUP, 0 );
7698 keybd_event( 'K', 0x25, 0, 0 );
7699 flush_events();
7700 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 );
7702 ok_ret( 1, ImmSetOpenStatus( himc, FALSE ) );
7704 flush_events();
7705 todo_wine ok_seq( closed_seq );
7707 ignore_WM_IME_NOTIFY = FALSE;
7708 ignore_IME_NOTIFY = FALSE;
7712 ok_ret( 1, ImmSetConversionStatus( himc, 0, IME_SMODE_PHRASEPREDICT ) );
7713 ok_ret( 1, ImmSetOpenStatus( himc, FALSE ) );
7715 ok_ret( 1, ImmUnlockIMC( himc ) );
7716 ok_ret( 1, ImmDestroyContext( himc ) );
7718 ok_ret( 1, DestroyWindow( hwnd ) );
7719 process_messages();
7721 memset( ime_calls, 0, sizeof(ime_calls) );
7722 ime_call_count = 0;
7725 static void test_nihongo_no(void)
7727 /* These sequences have some additional WM_IME_NOTIFY messages with wparam > IMN_PRIVATE */
7728 /* Some out-of-order WM_IME_REQUEST and WM_IME_NOTIFY messages are also ignored */
7729 struct ime_call complete_seq[] =
7731 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}},
7733 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uff4e", .result = L"",
7734 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xff4e, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7737 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b", .result = L"",
7738 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7741 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\uff48", .result = L"",
7742 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7745 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\u307b", .result = L"",
7746 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7749 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\u307b\uff4e", .result = L"",
7750 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7753 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\u307b\u3093\uff47", .result = L"",
7754 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7757 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\u307b\u3093\u3054", .result = L"",
7758 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7761 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u65e5\u672c\u8a9e", .result = L"",
7762 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x65e5, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7765 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"\u65e5\u672c\u8a9e",
7766 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x65e5, .lparam = GCS_RESULTSTR|GCS_RESULTCLAUSE|GCS_RESULTREADSTR|GCS_RESULTREADCLAUSE},
7768 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0x65e5, .lparam = 0x1}},
7769 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0x672c, .lparam = 0x1}},
7770 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0x8a9e, .lparam = 0x1}},
7771 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}},
7772 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}},
7774 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uff4e", .result = L"",
7775 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xff4e, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7778 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306e", .result = L"",
7779 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306e, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7782 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"\u306e",
7783 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306e, .lparam = GCS_RESULTSTR|GCS_RESULTCLAUSE|GCS_RESULTREADSTR|GCS_RESULTREADCLAUSE},
7785 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0x306e, .lparam = 0x1}},
7786 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}},
7787 {0},
7790 struct ime_call cancel_seq[] =
7792 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}},
7794 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uff4e", .result = L"",
7795 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xff4e, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7798 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b", .result = L"",
7799 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7802 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\uff48", .result = L"",
7803 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7806 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\u307b", .result = L"",
7807 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7810 /* CPS_CANCEL */
7811 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}},
7812 {0},
7814 struct ime_call closed_seq[] =
7816 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}},
7818 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uff4e", .result = L"",
7819 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xff4e, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7822 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b", .result = L"",
7823 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7826 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\uff48", .result = L"",
7827 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7830 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\u307b", .result = L"",
7831 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS},
7834 /* CPS_COMPLETE */
7836 .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"\u306b\u307b",
7837 .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_RESULTSTR|GCS_RESULTCLAUSE|GCS_RESULTREADSTR|GCS_RESULTREADCLAUSE},
7839 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0x306b, .lparam = 1}},
7840 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0x307b, .lparam = 1}},
7841 {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}},
7842 {0},
7845 INPUTCONTEXT *ctx;
7846 HWND hwnd;
7847 HIMC himc;
7848 UINT i;
7850 /* this test doesn't work on Win32 / WoW64 */
7851 if (broken(sizeof(void *) == 4) || default_hkl != (HKL)0x04110411 /* MS Japanese IME */)
7853 skip( "Got hkl %p, skipping Japanese IME-specific test\n", default_hkl );
7854 return;
7857 hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7858 100, 100, 100, 100, NULL, NULL, NULL, NULL );
7859 ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
7860 flush_events();
7862 himc = ImmCreateContext();
7863 ok_ne( NULL, himc, HIMC, "%p" );
7864 ctx = ImmLockIMC( himc );
7865 ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" );
7866 ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" );
7867 ok_ret( 1, ImmSetOpenStatus( himc, TRUE ) );
7868 ok_ret( 1, ImmSetConversionStatus( himc, IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE, IME_SMODE_PHRASEPREDICT ) );
7869 flush_events();
7870 memset( ime_calls, 0, sizeof(ime_calls) );
7871 ime_call_count = 0;
7873 for (i = 0; i < ARRAY_SIZE(complete_seq); i++) complete_seq[i].himc = himc;
7874 for (i = 0; i < ARRAY_SIZE(cancel_seq); i++) cancel_seq[i].himc = himc;
7875 for (i = 0; i < ARRAY_SIZE(closed_seq); i++) closed_seq[i].himc = himc;
7876 ignore_WM_IME_REQUEST = TRUE;
7877 ignore_WM_IME_NOTIFY = TRUE;
7878 ignore_IME_NOTIFY = TRUE;
7881 keybd_event( 'N', 0x31, 0, 0 );
7882 flush_events();
7883 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP, 0 );
7885 keybd_event( 'I', 0x17, 0, 0 );
7886 flush_events();
7887 keybd_event( 'I', 0x17, KEYEVENTF_KEYUP, 0 );
7889 keybd_event( 'H', 0x23, 0, 0 );
7890 flush_events();
7891 keybd_event( 'H', 0x23, KEYEVENTF_KEYUP, 0 );
7893 keybd_event( 'O', 0x18, 0, 0 );
7894 flush_events();
7895 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP, 0 );
7897 keybd_event( 'N', 0x31, 0, 0 );
7898 flush_events();
7899 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP, 0 );
7901 keybd_event( 'G', 0x22, 0, 0 );
7902 flush_events();
7903 keybd_event( 'G', 0x22, KEYEVENTF_KEYUP, 0 );
7905 keybd_event( 'O', 0x18, 0, 0 );
7906 flush_events();
7907 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP, 0 );
7909 keybd_event( VK_SPACE, 0x39, 0, 0 );
7910 flush_events();
7911 keybd_event( VK_SPACE, 0x39, KEYEVENTF_KEYUP, 0 );
7913 keybd_event( 'N', 0x31, 0, 0 );
7914 flush_events();
7915 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP, 0 );
7917 keybd_event( 'O', 0x18, 0, 0 );
7918 flush_events();
7919 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP, 0 );
7921 keybd_event( VK_RETURN, 0x1c, 0, 0 );
7922 flush_events();
7923 keybd_event( VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0 );
7925 flush_events();
7926 todo_wine ok_seq( complete_seq );
7928 ignore_WM_IME_REQUEST = FALSE;
7929 ignore_WM_IME_NOTIFY = FALSE;
7930 ignore_IME_NOTIFY = FALSE;
7932 /* Japanese IME doesn't take input from ImmProcessKey */
7934 ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'N', MAKELONG(1, 0x31), 0 ) );
7935 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'N', MAKELONG(1, 0x31) ) );
7936 flush_events();
7937 ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'N', MAKELONG(1, 0xc031), 0 ) );
7938 ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'N', MAKELONG(1, 0xc031) ) );
7939 flush_events();
7940 ok_seq( empty_sequence );
7943 /* changing the open status completes the composition string */
7945 ignore_WM_IME_REQUEST = TRUE;
7946 ignore_WM_IME_NOTIFY = TRUE;
7947 ignore_IME_NOTIFY = TRUE;
7950 /* cancelling clears the composition string */
7952 keybd_event( 'N', 0x31, 0, 0 );
7953 flush_events();
7954 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP, 0 );
7956 keybd_event( 'I', 0x17, 0, 0 );
7957 flush_events();
7958 keybd_event( 'I', 0x17, KEYEVENTF_KEYUP, 0 );
7960 keybd_event( 'H', 0x23, 0, 0 );
7961 flush_events();
7962 keybd_event( 'H', 0x23, KEYEVENTF_KEYUP, 0 );
7964 keybd_event( 'O', 0x18, 0, 0 );
7965 flush_events();
7966 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP, 0 );
7968 ok_ret( 1, ImmNotifyIME( himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0 ) );
7970 flush_events();
7971 todo_wine ok_seq( cancel_seq );
7974 /* CPS_COMPLETE and ImmSetOpenStatus( himc, FALSE ) do the same thing */
7976 keybd_event( 'N', 0x31, 0, 0 );
7977 flush_events();
7978 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP, 0 );
7980 keybd_event( 'I', 0x17, 0, 0 );
7981 flush_events();
7982 keybd_event( 'I', 0x17, KEYEVENTF_KEYUP, 0 );
7984 keybd_event( 'H', 0x23, 0, 0 );
7985 flush_events();
7986 keybd_event( 'H', 0x23, KEYEVENTF_KEYUP, 0 );
7988 keybd_event( 'O', 0x18, 0, 0 );
7989 flush_events();
7990 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP, 0 );
7992 ok_ret( 1, ImmNotifyIME( himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0 ) );
7994 flush_events();
7995 todo_wine ok_seq( closed_seq );
7998 keybd_event( 'N', 0x31, 0, 0 );
7999 flush_events();
8000 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP, 0 );
8002 keybd_event( 'I', 0x17, 0, 0 );
8003 flush_events();
8004 keybd_event( 'I', 0x17, KEYEVENTF_KEYUP, 0 );
8006 /* does nothing, already open */
8007 ok_ret( 1, ImmSetOpenStatus( himc, TRUE ) );
8009 keybd_event( 'H', 0x23, 0, 0 );
8010 flush_events();
8011 keybd_event( 'H', 0x23, KEYEVENTF_KEYUP, 0 );
8013 keybd_event( 'O', 0x18, 0, 0 );
8014 flush_events();
8015 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP, 0 );
8017 ok_ret( 1, ImmSetOpenStatus( himc, FALSE ) );
8019 flush_events();
8020 todo_wine ok_seq( closed_seq );
8022 ignore_WM_IME_REQUEST = FALSE;
8023 ignore_WM_IME_NOTIFY = FALSE;
8024 ignore_IME_NOTIFY = FALSE;
8027 ok_ret( 1, ImmSetConversionStatus( himc, 0, IME_SMODE_PHRASEPREDICT ) );
8028 ok_ret( 1, ImmSetOpenStatus( himc, FALSE ) );
8030 ok_ret( 1, ImmUnlockIMC( himc ) );
8031 ok_ret( 1, ImmDestroyContext( himc ) );
8033 ok_ret( 1, DestroyWindow( hwnd ) );
8034 process_messages();
8036 memset( ime_calls, 0, sizeof(ime_calls) );
8037 ime_call_count = 0;
8040 START_TEST(imm32)
8042 default_hkl = GetKeyboardLayout( 0 );
8044 test_class.hInstance = GetModuleHandleW( NULL );
8045 RegisterClassExW( &test_class );
8047 if (!is_ime_enabled())
8049 win_skip("IME support not implemented\n");
8050 return;
8053 test_com_initialization();
8055 test_ImmEnumInputContext();
8057 /* run these before installing the custom IME, sometimes it takes a moment
8058 * to uninstall and the default IME doesn't activate immediately
8060 test_ga_na_da();
8061 test_nihongo_no();
8063 test_ImmInstallIME();
8064 wineime_hkl = ime_install();
8066 test_ImmGetDescription();
8067 test_ImmGetIMEFileName();
8068 test_ImmIsIME();
8069 test_ImmGetProperty();
8071 test_ImmEscape( FALSE );
8072 test_ImmEscape( TRUE );
8073 test_ImmEnumRegisterWord( FALSE );
8074 test_ImmEnumRegisterWord( TRUE );
8075 test_ImmRegisterWord( FALSE );
8076 test_ImmRegisterWord( TRUE );
8077 test_ImmGetRegisterWordStyle( FALSE );
8078 test_ImmGetRegisterWordStyle( TRUE );
8079 test_ImmUnregisterWord( FALSE );
8080 test_ImmUnregisterWord( TRUE );
8082 /* test these first to sanitize conversion / open statuses */
8083 test_ImmSetConversionStatus();
8084 test_ImmSetOpenStatus();
8085 ImeSelect_init_status = TRUE;
8087 test_ImmActivateLayout();
8088 test_ImmCreateInputContext();
8089 test_ImmProcessKey();
8090 test_DefWindowProc();
8091 test_ImmSetActiveContext();
8092 test_ImmRequestMessage();
8094 test_ImmGetCandidateList( TRUE );
8095 test_ImmGetCandidateList( FALSE );
8096 test_ImmGetCandidateListCount( TRUE );
8097 test_ImmGetCandidateListCount( FALSE );
8098 test_ImmGetCandidateWindow();
8100 test_ImmGetCompositionString( TRUE );
8101 test_ImmGetCompositionString( FALSE );
8102 test_ImmSetCompositionWindow();
8103 test_ImmSetStatusWindowPos();
8104 test_ImmSetCompositionFont( TRUE );
8105 test_ImmSetCompositionFont( FALSE );
8106 test_ImmSetCandidateWindow();
8108 test_ImmGenerateMessage();
8109 test_ImmTranslateMessage( FALSE );
8110 test_ImmTranslateMessage( TRUE );
8112 if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE );
8114 if (init())
8116 test_ImmNotifyIME();
8117 test_SCS_SETSTR();
8118 test_ImmIME();
8119 test_ImmAssociateContextEx();
8120 test_NtUserAssociateInputContext();
8121 test_cross_thread_himc();
8122 test_ImmIsUIMessage();
8123 test_ImmGetContext();
8124 test_ImmDefaultHwnd();
8125 test_default_ime_window_creation();
8126 test_ImmGetIMCLockCount();
8127 test_ImmGetIMCCLockCount();
8128 test_ImmDestroyContext();
8129 test_ImmDestroyIMCC();
8130 test_InvalidIMC();
8131 msg_spy_cleanup();
8132 /* Reinitialize the hooks to capture all windows */
8133 msg_spy_init(NULL);
8134 test_ImmMessages();
8135 msg_spy_cleanup();
8136 if (pSendInput)
8137 test_ime_processkey();
8138 else win_skip("SendInput is not available\n");
8140 /* there's no way of enabling IME - keep the test last */
8141 test_ImmDisableIME();
8143 cleanup();
8145 UnregisterClassW( test_class.lpszClassName, test_class.hInstance );