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
25 #define WIN32_NO_STATUS
29 #include "wine/test.h"
38 static const char *debugstr_wm_ime( UINT 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
)
61 /* skip possible casts */
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, ... ) \
76 ok( v == (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \
78 #define ok_ne( e, r, t, f, ... ) \
82 ok( v != (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \
84 #define ok_wcs( e, r ) \
87 const WCHAR *v = (r); \
88 ok( !wcscmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_w(v) ); \
90 #define ok_str( e, r ) \
93 const char *v = (r); \
94 ok( !strcmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_a(v) ); \
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
)
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) \
251 if (enabled_ ## func) {\
252 ok(expect_ ##func, "unexpected call " #func "\n"); \
253 called_ ## func = TRUE; \
257 #define CHECK_EXPECT(func) \
259 CHECK_EXPECT2(func); \
260 expect_ ## func = FALSE; \
263 #define CHECK_CALLED(func) \
265 ok(called_ ## func, "expected " #func "\n"); \
266 expect_ ## func = called_ ## func = FALSE; \
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
)
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
;
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;
338 IME_SET_ACTIVE_CONTEXT
,
347 enum ime_function func
;
375 } set_active_context
;
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
)
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
)
414 if ((ret
= expected
->select
- received
->select
)) goto done
;
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
;
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
;
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
;
430 case IME_SET_ACTIVE_CONTEXT
:
431 if ((ret
= expected
->set_active_context
.flag
- received
->set_active_context
.flag
)) goto done
;
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
;
444 if (ret
&& broken( expected
->broken
)) return ret
;
446 switch (received
->func
)
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
);
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
);
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
);
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
);
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
);
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
);
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
) );
487 switch (expected
->func
)
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
);
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
);
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
);
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
);
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
);
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
);
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
) );
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
;
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" ))
545 else if (ret
&& broken(expected
->broken
))
549 if (expected
->func
) expected
++;
550 if (received
->func
) received
++;
552 winetest_pop_context();
555 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
)
569 if (ignore_WM_IME_NOTIFY
) return TRUE
;
570 return wparam
> IMN_PRIVATE
;
572 if (ignore_WM_IME_REQUEST
) return TRUE
;
574 case WM_IME_STARTCOMPOSITION
:
575 case WM_IME_ENDCOMPOSITION
:
576 case WM_IME_COMPOSITION
:
577 case WM_IME_SETCONTEXT
:
579 case WM_IME_COMPOSITIONFULL
:
587 return !check_WM_SHOWWINDOW
;
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
}
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
),
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
{
659 static struct _msg_spy
{
662 HHOOK call_wnd_proc_hook
;
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
;
697 return CallNextHookEx(msg_spy
.get_msg_hook
, nCode
, wParam
, lParam
);
700 static LRESULT CALLBACK
call_wnd_proc_filter(int nCode
, WPARAM wParam
,
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
;
715 return CallNextHookEx(msg_spy
.call_wnd_proc_hook
, nCode
, wParam
, lParam
);
718 static void msg_spy_pump_msg_queue(void) {
721 while(PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
722 TranslateMessage(&msg
);
723 DispatchMessageW(&msg
);
729 static void msg_spy_flush_msgs(void) {
730 msg_spy_pump_msg_queue();
734 static imm_msgs
* msg_spy_find_next_msg(UINT message
, UINT
*start
) {
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",
743 for (i
= *start
; i
< msg_spy
.i_msg
; i
++)
744 if (msg_spy
.msgs
[i
].msg
.message
== message
)
747 return &msg_spy
.msgs
[i
];
753 static imm_msgs
* msg_spy_find_msg(UINT message
) {
756 return msg_spy_find_next_msg(message
, &i
);
759 static void msg_spy_init(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());
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
];
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" );
813 static LRESULT WINAPI
wndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
815 HWND default_ime_wnd
;
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
);
824 default_ime_wnd
= get_ime_window();
828 ok(!default_ime_wnd
, "expected no IME windows\n");
831 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
834 break; /* do nothing */
836 if (test_phase
== NCCREATE_CANCEL
)
840 default_ime_wnd
= get_ime_window();
845 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
848 ok(!default_ime_wnd
, "expected no IME windows\n");
851 break; /* do nothing */
855 default_ime_wnd
= get_ime_window();
860 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
863 ok(!default_ime_wnd
, "expected no IME windows\n");
866 break; /* do nothing */
868 if (test_phase
== CREATE_CANCEL
)
873 return DefWindowProcA(hWnd
,msg
,wParam
,lParam
);
876 static BOOL
is_ime_enabled(void)
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
);
891 ImmReleaseContext(wnd
, himc
);
896 static BOOL
init(void) {
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
);
910 wc
.lpfnWndProc
= wndProc
;
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
))
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
);
930 child
= CreateWindowA("edit", "edit", WS_CHILD
| WS_VISIBLE
, 0, 0, 50, 50, hwnd
, 0, 0, 0);
934 ShowWindow(hwnd
, SW_SHOWNORMAL
);
942 static void cleanup(void) {
946 UnregisterClassA(wndcls
, GetModuleHandleW(NULL
));
949 static void test_ImmNotifyIME(void) {
950 static const char string
[] = "wine";
951 char resstr
[16] = "";
955 imc
= ImmGetContext(hwnd
);
956 msg_spy_flush_msgs();
958 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
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);
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
);
1011 WNDPROC old_wnd_proc
;
1012 BOOL catch_result_str
;
1013 BOOL catch_ime_char
;
1016 } ime_composition_test
;
1018 static LRESULT WINAPI
test_ime_wnd_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1022 case WM_IME_COMPOSITION
:
1023 if ((lParam
& GCS_RESULTSTR
) && !ime_composition_test
.catch_result_str
) {
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
;
1053 if (!ime_composition_test
.catch_result_str
)
1054 ime_composition_test
.catch_ime_char
= TRUE
;
1057 if (wParam
== ime_composition_test
.timer_id
) {
1058 HWND parent
= GetParent(hWnd
);
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
);
1065 DestroyWindow(parent
);
1067 SetTimer(hWnd
, wParam
, 100, NULL
);
1072 return CallWindowProcA(ime_composition_test
.old_wnd_proc
,
1073 hWnd
, msg
, wParam
, lParam
);
1076 static void test_SCS_SETSTR(void)
1079 static const WCHAR string
[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e};
1087 imc
= ImmGetContext(hwnd
);
1088 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
, string
, sizeof(string
), NULL
, 0);
1090 win_skip("Composition isn't supported\n");
1091 ImmReleaseContext(hwnd
, imc
);
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 */
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");
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");
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
));
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");
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
;
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
))
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());
1237 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
, NULL
, 0, NULL
, 0);
1240 "ImmSetCompositionStringW() failed.\n");
1242 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGEATTR
,
1244 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
1246 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGECLAUSE
,
1248 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
1250 ret
= ImmSetCompositionStringW(imc
, SCS_CHANGEATTR
| SCS_CHANGECLAUSE
,
1252 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
1254 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGEATTR
| SCS_CHANGECLAUSE
,
1256 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
1258 ImmReleaseContext(hwnd
, imc
);
1261 static void test_ImmIME(void)
1265 imc
= ImmGetContext(hwnd
);
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)
1282 if (!pImmAssociateContextEx
) return;
1284 imc
= ImmGetContext(hwnd
);
1287 HIMC retimc
, newimc
;
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
);
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
);
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
);
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)
1369 if (!pNtUserAssociateInputContext
)
1371 win_skip("NtUserAssociateInputContext not available\n");
1375 imc
= ImmGetContext(hwnd
);
1378 HIMC retimc
, newimc
;
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
);
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
);
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
);
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
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
;
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
) );
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};
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
, ¶ms
, 0, &tid
);
1542 ok_ne( NULL
, thread
, HANDLE
, "%p" );
1543 WaitForSingleObject( params
.event
, INFINITE
);
1545 memset( ime_calls
, 0, sizeof(ime_calls
) );
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)
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
;
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
);
1922 ok(msg_spy_find_msg(test
->msg
) != NULL
, "Windows does send 0x%x\n", test
->msg
);
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)
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
);
1977 static void test_ImmDefaultHwnd(void)
1979 HIMC imc1
, imc2
, imc3
;
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
);
1995 win_skip("IME support not implemented\n");
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"))
2042 static HWND
get_ime_window(void)
2044 HWND ime_window
= NULL
;
2045 EnumThreadWindows(GetCurrentThreadId(), is_ime_window_proc
, (LPARAM
)&ime_window
);
2049 struct testcase_ime_window
{
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
);
2069 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
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
);
2091 ok(!IsWindow(ime_wnd
), "Expected no IME windows\n");
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");
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
);
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
);
2190 static void test_default_ime_window_creation(void)
2194 struct testcase_ime_window testcases
[] = {
2195 /* visible, top-level window */
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)
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)
2240 DWORD count
, ret
, i
;
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
++)
2286 count
= ImmGetIMCLockCount(imc
);
2287 todo_wine
ok(count
== 1, "expect 1, returned %ld\n", count
);
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)
2298 DWORD count
, g_count
, i
;
2302 imcc
= ImmCreateIMCC(sizeof(CANDIDATEINFO
));
2303 count
= ImmGetIMCCLockCount(imcc
);
2304 ok(count
== 0, "expect 0, returned %ld\n", count
);
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
++)
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
++)
2332 count
= ImmGetIMCCLockCount(imcc
);
2333 ok(count
== 1, "expect 1, returned %ld\n", count
);
2335 count
= ImmGetIMCCLockCount(imcc
);
2336 ok(count
== 0, "expect 0, returned %ld\n", count
);
2338 ImmDestroyIMCC(imcc
);
2341 static void test_ImmDestroyContext(void)
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)
2372 DWORD ret
, count
, size
;
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)
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");
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
++;
2440 ImmGenerateMessage(imc
);
2444 msg
= msg_spy_find_next_msg(WM_IME_STARTCOMPOSITION
, &idx
);
2445 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
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
++;
2459 ImmGenerateMessage(imc
);
2463 msg
= msg_spy_find_next_msg(WM_IME_COMPOSITION
, &idx
);
2464 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
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
++;
2478 ImmGenerateMessage(imc
);
2482 msg
= msg_spy_find_next_msg(WM_IME_ENDCOMPOSITION
, &idx
);
2483 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
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
,
2495 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2498 static void test_ime_processkey(void)
2502 HANDLE hInstance
= GetModuleHandleW(NULL
);
2503 TEST_INPUT inputs
[2];
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");
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
);
2536 win_skip("IME not supported\n");
2537 DestroyWindow(hWndTest
);
2541 rc
= ImmSetOpenStatus(imc
, TRUE
);
2544 win_skip("Unable to open IME\n");
2545 ImmReleaseContext(hWndTest
, imc
);
2546 DestroyWindow(hWndTest
);
2550 /* flush pending messages */
2551 while (PeekMessageW(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageW(&msg
);
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
);
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
);
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)
2610 HIMC imc_null
= 0x00000000;
2611 HIMC imc_bad
= (HIMC
)0xdeadcafe;
2613 HIMC imc1
, imc2
, oldimc
;
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
;
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
);
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
)
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
);
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
);
3017 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
3018 ok(r
, "ImmSetActiveContext failed\n");
3023 static void test_com_initialization(void)
3025 APTTYPEQUALIFIER qualifier
;
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
);
3038 r
= ImmSetActiveContext(NULL
, (HIMC
)0xdeadbeef, TRUE
);
3039 ok(!r
, "ImmSetActiveContext succeeded\n");
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");
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
);
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");
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
);
3070 test_apttype(APTTYPE_MAINSTA
);
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
);
3078 hr
= CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
3079 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
3080 test_apttype(APTTYPE_MTA
);
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
);
3097 static DWORD WINAPI
disable_ime_thread(void *arg
)
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");
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
);
3123 static DWORD WINAPI
check_not_disabled_ime_thread(void *arg
)
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
);
3135 static DWORD WINAPI
disable_ime_process(void *arg
)
3137 BOOL r
= ImmDisableIME(-1);
3138 ok(r
, "ImmDisableIME failed\n");
3142 static void test_ImmDisableIME(void)
3144 HANDLE thread
, event
;
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");
3158 WaitForSingleObject(thread
, INFINITE
);
3159 CloseHandle(thread
);
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" );
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" );
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
);
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
);
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
);
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
);
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
);
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
);
3266 ok_str( "EscapeIme", data
);
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" );
3281 ok_eq( 0xdeadbeef, escape
, UINT
, "%#x" );
3282 ok_eq( NULL
, data
, void *, "%p" );
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" );
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
);
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" );
3313 STYLEBUFA
*styleA
= (STYLEBUFA
*)style
;
3314 styleA
->dwStyle
= 0xdeadbeef;
3315 strcpy( styleA
->szDescription
, "StyleDescription" );
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
);
3334 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
3335 wcscpy( ui_class
, ime_ui_class
.lpszClassName
);
3337 WideCharToMultiByte( CP_ACP
, 0, ime_ui_class
.lpszClassName
, -1,
3338 (char *)ui_class
, 17, NULL
, NULL
);
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
);
3371 if (reading
) ok_str( "Reading", (char *)reading
);
3372 if (string
) ok_str( "String", (char *)string
);
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
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" );
3395 ctx
->fdwConversion
= ~0;
3396 ctx
->fdwSentence
= ~0;
3397 ImmUnlockIMC( himc
);
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
;
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
)
3430 todo_wine_if( todo_ImeSetCompositionString
)
3431 ok_eq( 22, comp_len
, UINT
, "%#x" );
3432 ok_wcs( L
"CompString", comp
);
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");
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" );
3455 ok( 0, "unexpected index %#lx\n", index
);
3464 todo_wine_if( todo_ImeSetCompositionString
)
3465 ok_eq( 11, comp_len
, UINT
, "%#x" );
3466 ok_str( "CompString", comp
);
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");
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" );
3490 ok( 0, "unexpected index %#lx\n", index
);
3495 ok_eq( NULL
, read
, const void *, "%p" );
3496 ok_eq( 0, read_len
, UINT
, "%#x" );
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
}
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
) );
3523 msgs
->TransMsg
[0].message
= WM_IME_STARTCOMPOSITION
;
3524 msgs
->TransMsg
[0].wParam
= 1;
3525 msgs
->TransMsg
[0].lParam
= 0;
3527 msgs
->TransMsg
[1].message
= WM_IME_ENDCOMPOSITION
;
3528 msgs
->TransMsg
[1].wParam
= 1;
3529 msgs
->TransMsg
[1].lParam
= 0;
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;
3553 msgs
[ctx
->dwNumMsgBuf
].message
= WM_IME_ENDCOMPOSITION
;
3554 msgs
[ctx
->dwNumMsgBuf
].wParam
= 2;
3555 msgs
[ctx
->dwNumMsgBuf
].lParam
= 0;
3558 ok_ret( 0, ImmUnlockIMCC( ctx
->hMsgBuf
) );
3561 ok_ret( 1, ImmUnlockIMC( himc
) );
3563 if (vsc
& 0x800) count
= ~0;
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
);
3582 if (reading
) ok_str( "Reading", (char *)reading
);
3583 if (string
) ok_str( "String", (char *)string
);
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
;
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
);
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
);
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
);
3625 static struct ime_functions ime_functions
=
3628 ime_ImeConversionList
,
3630 ime_ImeEnumRegisterWord
,
3632 ime_ImeGetImeMenuItems
,
3633 ime_ImeGetRegisterWordStyle
,
3636 ime_ImeRegisterWord
,
3638 ime_ImeSetActiveContext
,
3639 ime_ImeSetCompositionString
,
3641 ime_ImeUnregisterWord
,
3646 static HKL
ime_install(void)
3648 WCHAR buffer
[MAX_PATH
];
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" );
3666 ok( GetLastError() == ERROR_ACCESS_DENIED
, "got error %lu\n", GetLastError() );
3667 win_skip( "Failed to copy DLL to system directory\n" );
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
);
3708 ok( !ret
, "RegQueryValueExW returned %#lx, error %lu\n", ret
, GetLastError() );
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() );
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
;
3725 ret
= UnloadKeyboardLayout( hkl
);
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
;
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
;
3778 static void test_ImmEnumInputContext(void)
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 ) );
3787 ok_ret( 0, ImmEnumInputContext( 1, enum_find_context
, 0 ) );
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)
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
);
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
;
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
) );
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
) );
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
);
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
;
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
];
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
) );
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];
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
) );
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 );
4150 IME_ESC_QUERY_SUPPORT
,
4151 IME_ESC_SEQUENCE_TO_INTERNAL
,
4152 IME_ESC_GET_EUDC_DICTIONARY
,
4153 IME_ESC_SET_EUDC_DICTIONARY
,
4157 IME_ESC_GETHELPFILENAME
,
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
)
4201 ok_eq( 0xcdcd, bufferW
[0], WORD
, "%#x" );
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
)
4232 ok_eq( 0xcd, bufferA
[0], BYTE
, "%#x" );
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();
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
);
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
);
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
) );
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
);
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
) );
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
);
4371 SET_ENABLE( ImeRegisterWord
, FALSE
);
4373 winetest_pop_context();
4376 static void test_ImmGetRegisterWordStyle( BOOL unicode
)
4378 HKL hkl
= GetKeyboardLayout( 0 );
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
) );
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
);
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
);
4422 ok_eq( 0xcdcdcdcd, styleW
.dwStyle
, UINT
, "%#x" );
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
)
4434 ok_eq( 0xcdcdcdcd, styleA
.dwStyle
, UINT
, "%#x" );
4436 ok_eq( 0xcd, styleA
.szDescription
[0], BYTE
, "%#x" );
4440 ok_eq( 0xdeadbeef, styleA
.dwStyle
, UINT
, "%#x" );
4441 ok_str( "StyleDescription", styleA
.szDescription
);
4443 CHECK_CALLED( ImeGetRegisterWordStyle
);
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
) );
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
);
4506 SET_ENABLE( ImeUnregisterWord
, FALSE
);
4508 winetest_pop_context();
4517 static BOOL CALLBACK
enum_thread_ime_windows( HWND hwnd
, LPARAM lparam
)
4519 struct ime_windows
*params
= (void *)lparam
;
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
;
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
},
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
},
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
},
4608 DWORD old_conversion
, old_sentence
, conversion
, sentence
;
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() );
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
) );
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
) );
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" );
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" );
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
) );
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
) );
4729 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
},
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
},
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
},
4778 struct ime_windows ime_windows
= {0};
4779 DWORD old_status
, status
;
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() );
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
) );
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
) );
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
) );
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" );
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" );
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
) );
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
) );
4901 memset( ime_calls
, 0, sizeof(ime_calls
) );
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)},
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)},
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)},
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() );
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
) );
4953 memset( ime_calls
, 0, sizeof(ime_calls
) );
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 );
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
) );
4989 memset( ime_calls
, 0, sizeof(ime_calls
) );
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,
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},
5014 .hkl
= default_hkl
, .himc
= default_himc
,
5015 .func
= IME_SELECT
, .select
= 0,
5019 struct ime_call activate_with_window_seq
[] =
5022 .hkl
= expect_ime
, .himc
= default_himc
,
5023 .func
= IME_SELECT
, .select
= 1,
5027 .hkl
= expect_ime
, .himc
= 0/*himc*/,
5028 .func
= IME_SELECT
, .select
= 1,
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
},
5046 .hkl
= expect_ime
, .himc
= default_himc
,
5047 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCONVERSIONMODE
},
5051 .hkl
= expect_ime
, .himc
= default_himc
,
5052 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETSENTENCEMODE
},
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,
5084 .hkl
= default_hkl
, .himc
= 0/*himc*/,
5085 .func
= IME_SELECT
, .select
= 0,
5091 struct ime_windows ime_windows
= {0};
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() );
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 */
5166 memset( ime_calls
, 0, sizeof(ime_calls
) );
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" );
5193 SET_EXPECT( ImeDestroy
);
5194 ok_ret( 1, ImmFreeLayout( hkl
) );
5195 CHECK_CALLED( ImeDestroy
);
5197 ok_ret( 1, DestroyWindow( hwnd
) );
5199 memset( ime_calls
, 0, sizeof(ime_calls
) );
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,
5218 .hkl
= expect_ime
, .himc
= 0/*himc[0]*/,
5219 .func
= IME_SELECT
, .select
= 1,
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 */
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,
5261 struct ime_call select0_seq
[] =
5264 .hkl
= expect_ime
, .himc
= 0/*himc[1]*/,
5265 .func
= IME_SELECT
, .select
= 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,
5296 .hkl
= default_hkl
, .himc
= 0/*himc[0]*/,
5297 .func
= IME_SELECT
, .select
= 0,
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] );
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() );
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
);
5394 ok_ret( 1, ImmDestroyContext( himc
[0] ) );
5395 ok_ret( 1, DestroyWindow( hwnd
) );
5397 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
}},
5410 const struct ime_call end_composition_seq
[] =
5412 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_ENDCOMPOSITION
}},
5415 const struct ime_call composition_seq
[] =
5417 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_COMPOSITION
}},
5420 const struct ime_call set_context_seq
[] =
5422 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SETCONTEXT
}},
5425 const struct ime_call notify_seq
[] =
5427 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
}},
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
) );
5445 memset( ime_calls
, 0, sizeof(ime_calls
) );
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 );
5473 ok_seq( empty_sequence
);
5474 ret
= DefWindowProcW( hwnd
, WM_IME_KEYUP
, 0, 0 );
5477 ok_seq( empty_sequence
);
5479 ok_ret( 1, ImmActivateLayout( default_hkl
) );
5480 ok_ret( 1, DestroyWindow( hwnd
) );
5483 ok_ret( 1, ImmFreeLayout( hkl
) );
5484 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
}
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
}
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
}
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
}
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
}
5570 struct ime_windows ime_windows
= {0};
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
) );
5586 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
);
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" );
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
) );
5653 ok_ret( 1, ImmFreeLayout( hkl
) );
5654 memset( ime_calls
, 0, sizeof(ime_calls
) );
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*/}
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*/}
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*/}
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*/}
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*/}
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*/}
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*/}
5717 COMPOSITIONFORM comp_form
= {0};
5718 IMECHARPOSITION char_pos
= {0};
5719 RECONVERTSTRING reconv
= {0};
5720 CANDIDATEFORM cand_form
= {0};
5721 LOGFONTW log_font
= {0};
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" );
5741 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
) );
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
) );
5789 ok_ret( 1, ImmFreeLayout( hkl
) );
5790 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
;
5799 CANDIDATEINFO
*cand_info
;
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" );
5847 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
);
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
);
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
) );
5915 ok_ret( 1, ImmFreeLayout( hkl
) );
5916 memset( ime_calls
, 0, sizeof(ime_calls
) );
5920 winetest_pop_context();
5923 static void test_ImmGetCandidateListCount( BOOL unicode
)
5926 CANDIDATEINFO
*cand_info
;
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" );
5951 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
) );
5989 ok_ret( 1, ImmFreeLayout( hkl
) );
5990 memset( ime_calls
, 0, sizeof(ime_calls
) );
5994 winetest_pop_context();
5997 static void test_ImmGetCandidateWindow(void)
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
;
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" );
6027 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
) );
6067 ok_ret( 1, ImmFreeLayout( hkl
) );
6068 memset( ime_calls
, 0, sizeof(ime_calls
) );
6072 static void test_ImmGetCompositionString( BOOL unicode
)
6074 static COMPOSITIONSTRING expect_string_empty
= {.dwSize
= sizeof(COMPOSITIONSTRING
)};
6075 static COMPOSITIONSTRING expect_stringA
=
6078 .dwCompReadAttrLen
= 8,
6079 .dwCompReadAttrOffset
= 116,
6080 .dwCompReadClauseLen
= 8,
6081 .dwCompReadClauseOffset
= 108,
6082 .dwCompReadStrLen
= 8,
6083 .dwCompReadStrOffset
= 100,
6085 .dwCompAttrOffset
= 136,
6086 .dwCompClauseLen
= 8,
6087 .dwCompClauseOffset
= 128,
6089 .dwCompStrOffset
= 124,
6092 .dwResultReadClauseLen
= 8,
6093 .dwResultReadClauseOffset
= 150,
6094 .dwResultReadStrLen
= 10,
6095 .dwResultReadStrOffset
= 140,
6096 .dwResultClauseLen
= 8,
6097 .dwResultClauseOffset
= 164,
6098 .dwResultStrLen
= 6,
6099 .dwResultStrOffset
= 158,
6101 .dwPrivateOffset
= 172,
6103 static const COMPOSITIONSTRING expect_stringW
=
6106 .dwCompReadAttrLen
= 8,
6107 .dwCompReadAttrOffset
= 124,
6108 .dwCompReadClauseLen
= 8,
6109 .dwCompReadClauseOffset
= 116,
6110 .dwCompReadStrLen
= 8,
6111 .dwCompReadStrOffset
= 100,
6113 .dwCompAttrOffset
= 148,
6114 .dwCompClauseLen
= 8,
6115 .dwCompClauseOffset
= 140,
6117 .dwCompStrOffset
= 132,
6120 .dwResultReadClauseLen
= 8,
6121 .dwResultReadClauseOffset
= 172,
6122 .dwResultReadStrLen
= 10,
6123 .dwResultReadStrOffset
= 152,
6124 .dwResultClauseLen
= 8,
6125 .dwResultClauseOffset
= 192,
6126 .dwResultStrLen
= 6,
6127 .dwResultStrOffset
= 180,
6129 .dwPrivateOffset
= 200,
6131 static const UINT gcs_indexes
[] =
6142 GCS_RESULTREADCLAUSE
,
6146 static const UINT scs_indexes
[] =
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};
6155 COMPOSITIONSTRING
*string
;
6157 INPUTCONTEXT
*old_ctx
, *ctx
;
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" );
6186 memset( ime_calls
, 0, sizeof(ime_calls
) );
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";
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
)
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" );
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
);
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
) );
6440 ok_ret( 1, ImmFreeLayout( hkl
) );
6441 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
},
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
},
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};
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" );
6502 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
) );
6525 ok_seq( empty_sequence
);
6526 check_WM_SHOWWINDOW
= TRUE
;
6530 memset( &comp_form
, 0xcd, sizeof(comp_form
) );
6531 ok_ret( 1, ImmSetCompositionWindow( himc
, &comp_form
) );
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
);
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
);
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
) );
6565 ok_ret( 1, ImmFreeLayout( hkl
) );
6566 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
},
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
},
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" );
6617 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
);
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
);
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
) );
6664 ok_ret( 1, ImmFreeLayout( hkl
) );
6665 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
},
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
},
6695 LOGFONTW fontW
, expect_fontW
=
6706 .lfOutPrecision
= 10,
6707 .lfClipPrecision
= 11,
6709 .lfPitchAndFamily
= 13,
6710 .lfFaceName
= L
"FontFace",
6712 LOGFONTA fontA
, expect_fontA
=
6723 .lfOutPrecision
= 10,
6724 .lfClipPrecision
= 11,
6726 .lfPitchAndFamily
= 13,
6727 .lfFaceName
= "FontFace",
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" );
6753 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
);
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
);
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
);
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
) );
6818 ok_ret( 1, ImmFreeLayout( hkl
) );
6819 memset( ime_calls
, 0, sizeof(ime_calls
) );
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},
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
},
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},
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" );
6878 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
;
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
);
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
);
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
) );
6922 ok_ret( 1, ImmFreeLayout( hkl
) );
6923 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
},
6941 TRANSMSG
*msgs
, *tmp_msgs
;
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" );
6962 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
;
6973 msgs
[0].lParam
= GCS_COMPSTR
;
6974 ok_ret( 0, ImmUnlockIMCC( ctx
->hMsgBuf
) );
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
) );
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
) );
7023 ok_ret( 1, ImmFreeLayout( hkl
) );
7024 memset( ime_calls
, 0, sizeof(ime_calls
) );
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)},
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},
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},
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},
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},
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},
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},
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 */
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 */
7151 HWND hwnd
, other_hwnd
;
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() );
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() );
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" );
7181 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
) );
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
);
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
);
7233 ok_seq( empty_sequence
);
7234 ok_ret( 1, ImmGenerateMessage( himc
) );
7235 ok_seq( sent_messages
);
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 );
7257 process_messages_( hwnd
);
7258 ok_seq( key_down_seq
);
7260 keybd_event( VK_RETURN
, 0x1c, KEYEVENTF_KEYUP
, 0 );
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
) );
7277 ok_ret( 1, ImmFreeLayout( hkl
) );
7278 memset( ime_calls
, 0, sizeof(ime_calls
) );
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
[] =
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}},
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
},
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
},
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
},
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
},
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
},
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
},
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}},
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
},
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
},
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
},
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
},
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
},
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
},
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}},
7425 struct ime_call cancel_seq
[] =
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
},
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
},
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
},
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
},
7455 {.hkl
= default_hkl
, .himc
= 0/*himc*/, .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_ENDCOMPOSITION
, .wparam
= 0, .lparam
= 0}},
7458 struct ime_call closed_seq
[] =
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
},
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
},
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
},
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
},
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}},
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
);
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() );
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
) );
7527 keybd_event( 'R', 0x13, 0, 0 );
7529 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP
, 0 );
7531 keybd_event( VK_RETURN
, 0x1c, 0, 0 );
7533 keybd_event( VK_RETURN
, 0x1c, KEYEVENTF_KEYUP
, 0 );
7535 memset( ime_calls
, 0, sizeof(ime_calls
) );
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 );
7551 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP
, 0 );
7553 keybd_event( VK_BACK
, 0x0e, 0, 0 );
7555 keybd_event( VK_BACK
, 0x0e, KEYEVENTF_KEYUP
, 0 );
7557 keybd_event( 'R', 0x13, 0, 0 );
7559 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP
, 0 );
7561 keybd_event( 'K', 0x25, 0, 0 );
7563 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP
, 0 );
7565 keybd_event( 'S', 0x1f, 0, 0 );
7567 keybd_event( 'S', 0x1f, KEYEVENTF_KEYUP
, 0 );
7569 keybd_event( 'K', 0x25, 0, 0 );
7571 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP
, 0 );
7573 keybd_event( 'E', 0x12, 0, 0 );
7575 keybd_event( 'E', 0x12, KEYEVENTF_KEYUP
, 0 );
7577 keybd_event( 'K', 0x25, 0, 0 );
7579 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP
, 0 );
7581 keybd_event( VK_RETURN
, 0x1c, 0, 0 );
7583 keybd_event( VK_RETURN
, 0x1c, KEYEVENTF_KEYUP
, 0 );
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
);
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) ) );
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) ) );
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) ) );
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) ) );
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) ) );
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) ) );
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) ) );
7632 todo_wine
ok_seq( partial_return_seq
);
7635 /* cancelling clears the composition string */
7637 keybd_event( 'R', 0x13, 0, 0 );
7639 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP
, 0 );
7641 keybd_event( 'K', 0x25, 0, 0 );
7643 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP
, 0 );
7645 keybd_event( 'S', 0x1f, 0, 0 );
7647 keybd_event( 'S', 0x1f, KEYEVENTF_KEYUP
, 0 );
7649 keybd_event( 'K', 0x25, 0, 0 );
7651 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP
, 0 );
7653 ok_ret( 1, ImmNotifyIME( himc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0 ) );
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 );
7663 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP
, 0 );
7665 keybd_event( 'K', 0x25, 0, 0 );
7667 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP
, 0 );
7669 keybd_event( 'S', 0x1f, 0, 0 );
7671 keybd_event( 'S', 0x1f, KEYEVENTF_KEYUP
, 0 );
7673 keybd_event( 'K', 0x25, 0, 0 );
7675 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP
, 0 );
7677 ok_ret( 1, ImmNotifyIME( himc
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0 ) );
7680 todo_wine
ok_seq( closed_seq
);
7683 keybd_event( 'R', 0x13, 0, 0 );
7685 keybd_event( 'R', 0x13, KEYEVENTF_KEYUP
, 0 );
7687 keybd_event( 'K', 0x25, 0, 0 );
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 );
7696 keybd_event( 'S', 0x1f, KEYEVENTF_KEYUP
, 0 );
7698 keybd_event( 'K', 0x25, 0, 0 );
7700 keybd_event( 'K', 0x25, KEYEVENTF_KEYUP
, 0 );
7702 ok_ret( 1, ImmSetOpenStatus( himc
, FALSE
) );
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
) );
7721 memset( ime_calls
, 0, sizeof(ime_calls
) );
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}},
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
},
7811 {.hkl
= default_hkl
, .himc
= 0/*himc*/, .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_ENDCOMPOSITION
, .wparam
= 0, .lparam
= 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
},
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}},
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
);
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() );
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
) );
7870 memset( ime_calls
, 0, sizeof(ime_calls
) );
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 );
7883 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP
, 0 );
7885 keybd_event( 'I', 0x17, 0, 0 );
7887 keybd_event( 'I', 0x17, KEYEVENTF_KEYUP
, 0 );
7889 keybd_event( 'H', 0x23, 0, 0 );
7891 keybd_event( 'H', 0x23, KEYEVENTF_KEYUP
, 0 );
7893 keybd_event( 'O', 0x18, 0, 0 );
7895 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP
, 0 );
7897 keybd_event( 'N', 0x31, 0, 0 );
7899 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP
, 0 );
7901 keybd_event( 'G', 0x22, 0, 0 );
7903 keybd_event( 'G', 0x22, KEYEVENTF_KEYUP
, 0 );
7905 keybd_event( 'O', 0x18, 0, 0 );
7907 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP
, 0 );
7909 keybd_event( VK_SPACE
, 0x39, 0, 0 );
7911 keybd_event( VK_SPACE
, 0x39, KEYEVENTF_KEYUP
, 0 );
7913 keybd_event( 'N', 0x31, 0, 0 );
7915 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP
, 0 );
7917 keybd_event( 'O', 0x18, 0, 0 );
7919 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP
, 0 );
7921 keybd_event( VK_RETURN
, 0x1c, 0, 0 );
7923 keybd_event( VK_RETURN
, 0x1c, KEYEVENTF_KEYUP
, 0 );
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) ) );
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) ) );
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 );
7954 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP
, 0 );
7956 keybd_event( 'I', 0x17, 0, 0 );
7958 keybd_event( 'I', 0x17, KEYEVENTF_KEYUP
, 0 );
7960 keybd_event( 'H', 0x23, 0, 0 );
7962 keybd_event( 'H', 0x23, KEYEVENTF_KEYUP
, 0 );
7964 keybd_event( 'O', 0x18, 0, 0 );
7966 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP
, 0 );
7968 ok_ret( 1, ImmNotifyIME( himc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0 ) );
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 );
7978 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP
, 0 );
7980 keybd_event( 'I', 0x17, 0, 0 );
7982 keybd_event( 'I', 0x17, KEYEVENTF_KEYUP
, 0 );
7984 keybd_event( 'H', 0x23, 0, 0 );
7986 keybd_event( 'H', 0x23, KEYEVENTF_KEYUP
, 0 );
7988 keybd_event( 'O', 0x18, 0, 0 );
7990 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP
, 0 );
7992 ok_ret( 1, ImmNotifyIME( himc
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0 ) );
7995 todo_wine
ok_seq( closed_seq
);
7998 keybd_event( 'N', 0x31, 0, 0 );
8000 keybd_event( 'N', 0x31, KEYEVENTF_KEYUP
, 0 );
8002 keybd_event( 'I', 0x17, 0, 0 );
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 );
8011 keybd_event( 'H', 0x23, KEYEVENTF_KEYUP
, 0 );
8013 keybd_event( 'O', 0x18, 0, 0 );
8015 keybd_event( 'O', 0x18, KEYEVENTF_KEYUP
, 0 );
8017 ok_ret( 1, ImmSetOpenStatus( himc
, FALSE
) );
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
) );
8036 memset( ime_calls
, 0, sizeof(ime_calls
) );
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");
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
8063 test_ImmInstallIME();
8064 wineime_hkl
= ime_install();
8066 test_ImmGetDescription();
8067 test_ImmGetIMEFileName();
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
);
8116 test_ImmNotifyIME();
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();
8132 /* Reinitialize the hooks to capture all windows */
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();
8145 UnregisterClassW( test_class
.lpszClassName
, test_class
.hInstance
);