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_ok( const char *cond
)
41 /* skip possible casts */
48 if (!strchr( cond
- 1, '(' )) return wine_dbg_sprintf( "got %s", cond
- 1 );
49 return wine_dbg_sprintf( "%.*s returned", (int)strcspn( cond
- 1, "( " ), cond
- 1 );
52 #define ok_eq( e, r, t, f, ... ) \
56 ok( v == (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \
58 #define ok_ne( e, r, t, f, ... ) \
62 ok( v != (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \
64 #define ok_wcs( e, r ) \
67 const WCHAR *v = (r); \
68 ok( !wcscmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_w(v) ); \
70 #define ok_str( e, r ) \
73 const char *v = (r); \
74 ok( !strcmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_a(v) ); \
76 #define ok_ret( e, r ) ok_eq( e, r, UINT_PTR, "%Iu, error %ld", GetLastError() )
78 BOOL WINAPI
ImmSetActiveContext(HWND
, HIMC
, BOOL
);
80 static BOOL (WINAPI
*pImmAssociateContextEx
)(HWND
,HIMC
,DWORD
);
81 static UINT (WINAPI
*pNtUserAssociateInputContext
)(HWND
,HIMC
,ULONG
);
82 static BOOL (WINAPI
*pImmIsUIMessageA
)(HWND
,UINT
,WPARAM
,LPARAM
);
83 static UINT (WINAPI
*pSendInput
) (UINT
, INPUT
*, size_t);
85 extern BOOL WINAPI
ImmFreeLayout(HKL
);
86 extern BOOL WINAPI
ImmLoadIME(HKL
);
87 extern BOOL WINAPI
ImmActivateLayout(HKL
);
89 #define check_member_( file, line, val, exp, fmt, member ) \
90 ok_(file, line)( (val).member == (exp).member, "got " #member " " fmt "\n", (val).member )
91 #define check_member( val, exp, fmt, member ) \
92 check_member_( __FILE__, __LINE__, val, exp, fmt, member )
94 #define check_member_wstr_( file, line, val, exp, member ) \
95 ok_(file, line)( !wcscmp( (val).member, (exp).member ), "got " #member " %s\n", \
96 debugstr_w((val).member) )
97 #define check_member_wstr( val, exp, member ) \
98 check_member_wstr_( __FILE__, __LINE__, val, exp, member )
100 #define check_member_str_( file, line, val, exp, member ) \
101 ok_(file, line)( !strcmp( (val).member, (exp).member ), "got " #member " %s\n", \
102 debugstr_a((val).member) )
103 #define check_member_str( val, exp, member ) \
104 check_member_str_( __FILE__, __LINE__, val, exp, member )
106 #define check_member_point_( file, line, val, exp, member ) \
107 ok_(file, line)( !memcmp( &(val).member, &(exp).member, sizeof(POINT) ), \
108 "got " #member " %s\n", wine_dbgstr_point( &(val).member ) )
109 #define check_member_point( val, exp, member ) \
110 check_member_point_( __FILE__, __LINE__, val, exp, member )
112 #define check_member_rect_( file, line, val, exp, member ) \
113 ok_(file, line)( !memcmp( &(val).member, &(exp).member, sizeof(RECT) ), \
114 "got " #member " %s\n", wine_dbgstr_rect( &(val).member ) )
115 #define check_member_rect( val, exp, member ) \
116 check_member_rect_( __FILE__, __LINE__, val, exp, member )
118 #define check_composition_string( a, b ) check_composition_string_( __LINE__, a, b )
119 static void check_composition_string_( int line
, COMPOSITIONSTRING
*string
, const COMPOSITIONSTRING
*expect
)
121 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwSize
);
122 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompReadAttrLen
);
123 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompReadAttrOffset
);
124 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompReadClauseLen
);
125 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompReadClauseOffset
);
126 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompReadStrLen
);
127 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompReadStrOffset
);
128 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompAttrLen
);
129 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompAttrOffset
);
130 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompClauseLen
);
131 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompClauseOffset
);
132 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompStrLen
);
133 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCompStrOffset
);
134 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwCursorPos
);
135 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwDeltaStart
);
136 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwResultReadClauseLen
);
137 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwResultReadClauseOffset
);
138 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwResultReadStrLen
);
139 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwResultReadStrOffset
);
140 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwResultClauseLen
);
141 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwResultClauseOffset
);
142 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwResultStrLen
);
143 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwResultStrOffset
);
144 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwPrivateSize
);
145 check_member_( __FILE__
, line
, *string
, *expect
, "%lu", dwPrivateOffset
);
148 #define check_candidate_list( a, b ) check_candidate_list_( __LINE__, a, b, TRUE )
149 static void check_candidate_list_( int line
, CANDIDATELIST
*list
, const CANDIDATELIST
*expect
, BOOL unicode
)
153 check_member_( __FILE__
, line
, *list
, *expect
, "%lu", dwSize
);
154 check_member_( __FILE__
, line
, *list
, *expect
, "%lu", dwStyle
);
155 check_member_( __FILE__
, line
, *list
, *expect
, "%lu", dwCount
);
156 check_member_( __FILE__
, line
, *list
, *expect
, "%lu", dwSelection
);
157 check_member_( __FILE__
, line
, *list
, *expect
, "%lu", dwPageStart
);
158 check_member_( __FILE__
, line
, *list
, *expect
, "%lu", dwPageSize
);
159 for (i
= 0; i
< list
->dwCount
&& i
< expect
->dwCount
; ++i
)
161 void *list_str
= (BYTE
*)list
+ list
->dwOffset
[i
], *expect_str
= (BYTE
*)expect
+ expect
->dwOffset
[i
];
162 check_member_( __FILE__
, line
, *list
, *expect
, "%lu", dwOffset
[i
] );
163 if (unicode
) ok_( __FILE__
, line
)( !wcscmp( list_str
, expect_str
), "got %s\n", debugstr_w(list_str
) );
164 else ok_( __FILE__
, line
)( !strcmp( list_str
, expect_str
), "got %s\n", debugstr_a(list_str
) );
168 #define check_candidate_form( a, b ) check_candidate_form_( __LINE__, a, b )
169 static void check_candidate_form_( int line
, CANDIDATEFORM
*form
, const CANDIDATEFORM
*expect
)
171 check_member_( __FILE__
, line
, *form
, *expect
, "%#lx", dwIndex
);
172 check_member_( __FILE__
, line
, *form
, *expect
, "%#lx", dwStyle
);
173 check_member_point_( __FILE__
, line
, *form
, *expect
, ptCurrentPos
);
174 check_member_rect_( __FILE__
, line
, *form
, *expect
, rcArea
);
177 #define check_composition_form( a, b ) check_composition_form_( __LINE__, a, b )
178 static void check_composition_form_( int line
, COMPOSITIONFORM
*form
, const COMPOSITIONFORM
*expect
)
180 check_member_( __FILE__
, line
, *form
, *expect
, "%#lx", dwStyle
);
181 check_member_point_( __FILE__
, line
, *form
, *expect
, ptCurrentPos
);
182 check_member_rect_( __FILE__
, line
, *form
, *expect
, rcArea
);
185 #define check_logfont_w( a, b ) check_logfont_w_( __LINE__, a, b )
186 static void check_logfont_w_( int line
, LOGFONTW
*font
, const LOGFONTW
*expect
)
188 check_member_( __FILE__
, line
, *font
, *expect
, "%lu", lfHeight
);
189 check_member_( __FILE__
, line
, *font
, *expect
, "%lu", lfWidth
);
190 check_member_( __FILE__
, line
, *font
, *expect
, "%lu", lfEscapement
);
191 check_member_( __FILE__
, line
, *font
, *expect
, "%lu", lfOrientation
);
192 check_member_( __FILE__
, line
, *font
, *expect
, "%lu", lfWeight
);
193 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfItalic
);
194 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfUnderline
);
195 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfStrikeOut
);
196 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfCharSet
);
197 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfOutPrecision
);
198 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfClipPrecision
);
199 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfQuality
);
200 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfPitchAndFamily
);
201 check_member_wstr_( __FILE__
, line
, *font
, *expect
, lfFaceName
);
204 #define check_logfont_a( a, b ) check_logfont_a_( __LINE__, a, b )
205 static void check_logfont_a_( int line
, LOGFONTA
*font
, const LOGFONTA
*expect
)
207 check_member_( __FILE__
, line
, *font
, *expect
, "%lu", lfHeight
);
208 check_member_( __FILE__
, line
, *font
, *expect
, "%lu", lfWidth
);
209 check_member_( __FILE__
, line
, *font
, *expect
, "%lu", lfEscapement
);
210 check_member_( __FILE__
, line
, *font
, *expect
, "%lu", lfOrientation
);
211 check_member_( __FILE__
, line
, *font
, *expect
, "%lu", lfWeight
);
212 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfItalic
);
213 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfUnderline
);
214 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfStrikeOut
);
215 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfCharSet
);
216 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfOutPrecision
);
217 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfClipPrecision
);
218 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfQuality
);
219 check_member_( __FILE__
, line
, *font
, *expect
, "%u", lfPitchAndFamily
);
220 check_member_str_( __FILE__
, line
, *font
, *expect
, lfFaceName
);
223 #define DEFINE_EXPECT(func) \
224 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE, enabled_ ## func = FALSE
226 #define SET_EXPECT(func) \
227 expect_ ## func = TRUE
229 #define CHECK_EXPECT2(func) \
231 if (enabled_ ## func) {\
232 ok(expect_ ##func, "unexpected call " #func "\n"); \
233 called_ ## func = TRUE; \
237 #define CHECK_EXPECT(func) \
239 CHECK_EXPECT2(func); \
240 expect_ ## func = FALSE; \
243 #define CHECK_CALLED(func) \
245 ok(called_ ## func, "expected " #func "\n"); \
246 expect_ ## func = called_ ## func = FALSE; \
249 #define SET_ENABLE(func, val) \
250 enabled_ ## func = (val)
252 DEFINE_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
253 DEFINE_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
255 #define process_messages() process_messages_(0)
256 static void process_messages_(HWND hwnd
)
260 while (PeekMessageA( &msg
, hwnd
, 0, 0, PM_REMOVE
))
262 TranslateMessage( &msg
);
263 DispatchMessageA( &msg
);
267 /* try to make sure pending X events have been processed before continuing */
268 #define flush_events() flush_events_( 100, 200 )
269 static void flush_events_( int min_timeout
, int max_timeout
)
271 DWORD time
= GetTickCount() + max_timeout
;
274 while (max_timeout
> 0)
276 if (MsgWaitForMultipleObjects( 0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
277 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
))
279 TranslateMessage( &msg
);
280 DispatchMessageA( &msg
);
282 max_timeout
= time
- GetTickCount();
286 #define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ )
288 static BOOL ImeSelect_init_status
;
289 static BOOL todo_ImeInquire
;
290 DEFINE_EXPECT( ImeInquire
);
291 static BOOL todo_ImeDestroy
;
292 DEFINE_EXPECT( ImeDestroy
);
293 DEFINE_EXPECT( ImeEscape
);
294 DEFINE_EXPECT( ImeEnumRegisterWord
);
295 DEFINE_EXPECT( ImeRegisterWord
);
296 DEFINE_EXPECT( ImeGetRegisterWordStyle
);
297 DEFINE_EXPECT( ImeUnregisterWord
);
298 static BOOL todo_ImeSetCompositionString
;
299 DEFINE_EXPECT( ImeSetCompositionString
);
300 static BOOL todo_IME_DLL_PROCESS_ATTACH
;
301 DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH
);
302 static BOOL todo_IME_DLL_PROCESS_DETACH
;
303 DEFINE_EXPECT( IME_DLL_PROCESS_DETACH
);
305 static IMEINFO ime_info
;
306 static UINT ime_count
;
307 static WCHAR ime_path
[MAX_PATH
];
308 static HIMC default_himc
;
309 static HKL default_hkl
, wineime_hkl
;
310 static HKL expect_ime
= (HKL
)(int)0xe020047f;
318 IME_SET_ACTIVE_CONTEXT
,
327 enum ime_function func
;
352 } set_active_context
;
367 struct ime_call empty_sequence
[] = {{0}};
368 static struct ime_call ime_calls
[1024];
369 static ULONG ime_call_count
;
371 #define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b )
372 static int ok_call_( const char *file
, int line
, const struct ime_call
*expected
, const struct ime_call
*received
)
376 if ((ret
= expected
->func
- received
->func
)) goto done
;
377 /* Wine doesn't allocate HIMC in a deterministic order, ignore them when they are enumerated */
378 if (expected
->flaky_himc
&& (ret
= !!(UINT_PTR
)expected
->himc
- !!(UINT_PTR
)received
->himc
)) goto done
;
379 if (!expected
->flaky_himc
&& (ret
= (UINT_PTR
)expected
->himc
- (UINT_PTR
)received
->himc
)) goto done
;
380 if ((ret
= (UINT
)(UINT_PTR
)expected
->hkl
- (UINT
)(UINT_PTR
)received
->hkl
)) goto done
;
381 switch (expected
->func
)
384 if ((ret
= expected
->select
- received
->select
)) goto done
;
387 if ((ret
= expected
->notify
.action
- received
->notify
.action
)) goto done
;
388 if ((ret
= expected
->notify
.index
- received
->notify
.index
)) goto done
;
389 if ((ret
= expected
->notify
.value
- received
->notify
.value
)) goto done
;
391 case IME_PROCESS_KEY
:
392 if ((ret
= expected
->process_key
.vkey
- received
->process_key
.vkey
)) goto done
;
393 if ((ret
= expected
->process_key
.lparam
- received
->process_key
.lparam
)) goto done
;
395 case IME_TO_ASCII_EX
:
396 if ((ret
= expected
->to_ascii_ex
.vkey
- received
->to_ascii_ex
.vkey
)) goto done
;
397 if ((ret
= expected
->to_ascii_ex
.vsc
- received
->to_ascii_ex
.vsc
)) goto done
;
398 if ((ret
= expected
->to_ascii_ex
.flags
- received
->to_ascii_ex
.flags
)) goto done
;
400 case IME_SET_ACTIVE_CONTEXT
:
401 if ((ret
= expected
->set_active_context
.flag
- received
->set_active_context
.flag
)) goto done
;
405 if ((ret
= expected
->message
.msg
- received
->message
.msg
)) goto done
;
406 if ((ret
= (expected
->message
.wparam
- received
->message
.wparam
))) goto done
;
407 if ((ret
= (expected
->message
.lparam
- received
->message
.lparam
))) goto done
;
412 if (ret
&& broken( expected
->broken
)) return ret
;
414 switch (received
->func
)
417 todo_wine_if( expected
->todo
|| expected
->todo_value
)
418 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, IME_SELECT select %u\n", received
->hkl
, received
->himc
, received
->select
);
421 todo_wine_if( expected
->todo
|| expected
->todo_value
)
422 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n",
423 received
->hkl
, received
->himc
, received
->notify
.action
, received
->notify
.index
,
424 received
->notify
.value
);
426 case IME_PROCESS_KEY
:
427 todo_wine_if( expected
->todo
|| expected
->todo_value
)
428 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n",
429 received
->hkl
, received
->himc
, received
->process_key
.vkey
, received
->process_key
.lparam
);
431 case IME_TO_ASCII_EX
:
432 todo_wine_if( expected
->todo
|| expected
->todo_value
)
433 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, IME_TO_ASCII_EX vkey %#x, vsc %#x, flags %#x\n",
434 received
->hkl
, received
->himc
, received
->to_ascii_ex
.vkey
, received
->to_ascii_ex
.vsc
,
435 received
->to_ascii_ex
.flags
);
437 case IME_SET_ACTIVE_CONTEXT
:
438 todo_wine_if( expected
->todo
|| expected
->todo_value
)
439 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", received
->hkl
, received
->himc
,
440 received
->set_active_context
.flag
);
443 todo_wine_if( expected
->todo
|| expected
->todo_value
)
444 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received
->hkl
,
445 received
->himc
, received
->message
.msg
, received
->message
.wparam
, received
->message
.lparam
);
448 todo_wine_if( expected
->todo
|| expected
->todo_value
)
449 ok_(file
, line
)( !ret
, "got hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", received
->hkl
,
450 received
->himc
, received
->message
.msg
, received
->message
.wparam
, received
->message
.lparam
);
454 switch (expected
->func
)
457 todo_wine_if( expected
->todo
|| expected
->todo_value
)
458 ok_(file
, line
)( !ret
, "hkl %p, himc %p, IME_SELECT select %u\n", expected
->hkl
, expected
->himc
, expected
->select
);
461 todo_wine_if( expected
->todo
|| expected
->todo_value
)
462 ok_(file
, line
)( !ret
, "hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n",
463 expected
->hkl
, expected
->himc
, expected
->notify
.action
, expected
->notify
.index
,
464 expected
->notify
.value
);
466 case IME_PROCESS_KEY
:
467 todo_wine_if( expected
->todo
|| expected
->todo_value
)
468 ok_(file
, line
)( !ret
, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n",
469 expected
->hkl
, expected
->himc
, expected
->process_key
.vkey
, expected
->process_key
.lparam
);
471 case IME_TO_ASCII_EX
:
472 todo_wine_if( expected
->todo
|| expected
->todo_value
)
473 ok_(file
, line
)( !ret
, "hkl %p, himc %p, IME_TO_ASCII_EX vkey %#x, vsc %#x, flags %#x\n",
474 expected
->hkl
, expected
->himc
, expected
->to_ascii_ex
.vkey
, expected
->to_ascii_ex
.vsc
,
475 expected
->to_ascii_ex
.flags
);
477 case IME_SET_ACTIVE_CONTEXT
:
478 todo_wine_if( expected
->todo
|| expected
->todo_value
)
479 ok_(file
, line
)( !ret
, "hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", expected
->hkl
, expected
->himc
,
480 expected
->set_active_context
.flag
);
483 todo_wine_if( expected
->todo
|| expected
->todo_value
)
484 ok_(file
, line
)( !ret
, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected
->hkl
,
485 expected
->himc
, expected
->message
.msg
, expected
->message
.wparam
, expected
->message
.lparam
);
488 todo_wine_if( expected
->todo
|| expected
->todo_value
)
489 ok_(file
, line
)( !ret
, "hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", expected
->hkl
,
490 expected
->himc
, expected
->message
.msg
, expected
->message
.wparam
, expected
->message
.lparam
);
497 #define ok_seq( a ) ok_seq_( __FILE__, __LINE__, a, #a )
498 static void ok_seq_( const char *file
, int line
, const struct ime_call
*expected
, const char *context
)
500 const struct ime_call
*received
= ime_calls
;
503 while (expected
->func
|| received
->func
)
505 winetest_push_context( "%u%s%s", i
++, !expected
->func
? " (spurious)" : "",
506 !received
->func
? " (missing)" : "" );
507 ret
= ok_call_( file
, line
, expected
, received
);
508 if (ret
&& expected
->todo
&& expected
->func
&&
509 !strcmp( winetest_platform
, "wine" ))
511 else if (ret
&& broken(expected
->broken
))
515 if (expected
->func
) expected
++;
516 if (received
->func
) received
++;
518 winetest_pop_context();
521 memset( ime_calls
, 0, sizeof(ime_calls
) );
525 static BOOL check_WM_SHOWWINDOW
;
527 static BOOL
ignore_message( UINT msg
)
531 case WM_IME_STARTCOMPOSITION
:
532 case WM_IME_ENDCOMPOSITION
:
533 case WM_IME_COMPOSITION
:
534 case WM_IME_SETCONTEXT
:
537 case WM_IME_COMPOSITIONFULL
:
546 return !check_WM_SHOWWINDOW
;
552 static LRESULT CALLBACK
ime_ui_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
554 struct ime_call call
=
556 .hkl
= GetKeyboardLayout( 0 ), .himc
= (HIMC
)GetWindowLongPtrW( hwnd
, IMMGWL_IMC
),
557 .func
= MSG_IME_UI
, .message
= {.msg
= msg
, .wparam
= wparam
, .lparam
= lparam
}
561 ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd
, msg
, wparam
, lparam
);
563 if (ignore_message( msg
)) return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
565 ptr
= GetWindowLongPtrW( hwnd
, IMMGWL_PRIVATE
);
566 ok( !ptr
, "got IMMGWL_PRIVATE %#Ix\n", ptr
);
568 ime_calls
[ime_call_count
++] = call
;
569 return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
572 static LRESULT CALLBACK
test_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
574 struct ime_call call
=
576 .hkl
= GetKeyboardLayout( 0 ), .himc
= ImmGetContext( hwnd
),
577 .func
= MSG_TEST_WIN
, .message
= {.msg
= msg
, .wparam
= wparam
, .lparam
= lparam
}
580 ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd
, msg
, wparam
, lparam
);
582 if (ignore_message( msg
)) return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
584 ime_calls
[ime_call_count
++] = call
;
585 return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
588 static WNDCLASSEXW ime_ui_class
=
590 .cbSize
= sizeof(WNDCLASSEXW
),
592 .lpfnWndProc
= ime_ui_window_proc
,
593 .cbWndExtra
= 2 * sizeof(LONG_PTR
),
594 .lpszClassName
= L
"WineTestIME",
597 static WNDCLASSEXW test_class
=
599 .cbSize
= sizeof(WNDCLASSEXW
),
600 .lpfnWndProc
= test_window_proc
,
601 .lpszClassName
= L
"WineTest",
605 * msgspy - record and analyse message traces sent to a certain window
607 typedef struct _msgs
{
612 static struct _msg_spy
{
615 HHOOK call_wnd_proc_hook
;
631 static UINT (WINAPI
*pSendInput
) (UINT
, INPUT
*, size_t);
633 static LRESULT CALLBACK
get_msg_filter(int nCode
, WPARAM wParam
, LPARAM lParam
)
635 if (HC_ACTION
== nCode
) {
636 MSG
*msg
= (MSG
*)lParam
;
638 if ((msg
->hwnd
== msg_spy
.hwnd
|| msg_spy
.hwnd
== NULL
) &&
639 (msg_spy
.i_msg
< ARRAY_SIZE(msg_spy
.msgs
)))
641 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.hwnd
= msg
->hwnd
;
642 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.message
= msg
->message
;
643 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.wParam
= msg
->wParam
;
644 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.lParam
= msg
->lParam
;
645 msg_spy
.msgs
[msg_spy
.i_msg
].post
= TRUE
;
650 return CallNextHookEx(msg_spy
.get_msg_hook
, nCode
, wParam
, lParam
);
653 static LRESULT CALLBACK
call_wnd_proc_filter(int nCode
, WPARAM wParam
,
656 if (HC_ACTION
== nCode
) {
657 CWPSTRUCT
*cwp
= (CWPSTRUCT
*)lParam
;
659 if (((cwp
->hwnd
== msg_spy
.hwnd
|| msg_spy
.hwnd
== NULL
)) &&
660 (msg_spy
.i_msg
< ARRAY_SIZE(msg_spy
.msgs
)))
662 memcpy(&msg_spy
.msgs
[msg_spy
.i_msg
].msg
, cwp
, sizeof(msg_spy
.msgs
[0].msg
));
663 msg_spy
.msgs
[msg_spy
.i_msg
].post
= FALSE
;
668 return CallNextHookEx(msg_spy
.call_wnd_proc_hook
, nCode
, wParam
, lParam
);
671 static void msg_spy_pump_msg_queue(void) {
674 while(PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
675 TranslateMessage(&msg
);
676 DispatchMessageW(&msg
);
682 static void msg_spy_flush_msgs(void) {
683 msg_spy_pump_msg_queue();
687 static imm_msgs
* msg_spy_find_next_msg(UINT message
, UINT
*start
) {
690 msg_spy_pump_msg_queue();
692 if (msg_spy
.i_msg
>= ARRAY_SIZE(msg_spy
.msgs
))
693 fprintf(stdout
, "%s:%d: msg_spy: message buffer overflow!\n",
696 for (i
= *start
; i
< msg_spy
.i_msg
; i
++)
697 if (msg_spy
.msgs
[i
].msg
.message
== message
)
700 return &msg_spy
.msgs
[i
];
706 static imm_msgs
* msg_spy_find_msg(UINT message
) {
709 return msg_spy_find_next_msg(message
, &i
);
712 static void msg_spy_init(HWND hwnd
) {
714 msg_spy
.get_msg_hook
=
715 SetWindowsHookExW(WH_GETMESSAGE
, get_msg_filter
, GetModuleHandleW(NULL
),
716 GetCurrentThreadId());
717 msg_spy
.call_wnd_proc_hook
=
718 SetWindowsHookExW(WH_CALLWNDPROC
, call_wnd_proc_filter
,
719 GetModuleHandleW(NULL
), GetCurrentThreadId());
722 msg_spy_flush_msgs();
725 static void msg_spy_cleanup(void) {
726 if (msg_spy
.get_msg_hook
)
727 UnhookWindowsHookEx(msg_spy
.get_msg_hook
);
728 if (msg_spy
.call_wnd_proc_hook
)
729 UnhookWindowsHookEx(msg_spy
.call_wnd_proc_hook
);
730 memset(&msg_spy
, 0, sizeof(msg_spy
));
734 * imm32 test cases - Issue some IMM commands on a dummy window and analyse the
735 * messages being sent to this window in response.
737 static const char wndcls
[] = "winetest_imm32_wndcls";
738 static enum { PHASE_UNKNOWN
, FIRST_WINDOW
, SECOND_WINDOW
,
739 CREATE_CANCEL
, NCCREATE_CANCEL
, IME_DISABLED
} test_phase
;
740 static HWND hwnd
, child
;
742 static HWND
get_ime_window(void);
744 static void load_resource( const WCHAR
*name
, WCHAR
*filename
)
746 static WCHAR path
[MAX_PATH
];
752 GetTempPathW( ARRAY_SIZE(path
), path
);
753 GetTempFileNameW( path
, name
, 0, filename
);
755 file
= CreateFileW( filename
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0 );
756 ok( file
!= INVALID_HANDLE_VALUE
, "failed to create %s, error %lu\n", debugstr_w(filename
), GetLastError() );
758 res
= FindResourceW( NULL
, name
, L
"TESTDLL" );
759 ok( res
!= 0, "couldn't find resource\n" );
760 ptr
= LockResource( LoadResource( GetModuleHandleW( NULL
), res
) );
761 WriteFile( file
, ptr
, SizeofResource( GetModuleHandleW( NULL
), res
), &written
, NULL
);
762 ok( written
== SizeofResource( GetModuleHandleW( NULL
), res
), "couldn't write resource\n" );
766 static LRESULT WINAPI
wndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
768 HWND default_ime_wnd
;
771 case WM_IME_SETCONTEXT
:
772 if (wParam
) CHECK_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
773 else CHECK_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
774 ok(lParam
== ISC_SHOWUIALL
|| !lParam
, "lParam = %Ix\n", lParam
);
777 default_ime_wnd
= get_ime_window();
781 ok(!default_ime_wnd
, "expected no IME windows\n");
784 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
787 break; /* do nothing */
789 if (test_phase
== NCCREATE_CANCEL
)
793 default_ime_wnd
= get_ime_window();
798 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
801 ok(!default_ime_wnd
, "expected no IME windows\n");
804 break; /* do nothing */
808 default_ime_wnd
= get_ime_window();
813 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
816 ok(!default_ime_wnd
, "expected no IME windows\n");
819 break; /* do nothing */
821 if (test_phase
== CREATE_CANCEL
)
826 return DefWindowProcA(hWnd
,msg
,wParam
,lParam
);
829 static BOOL
is_ime_enabled(void)
834 wnd
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
835 ok(wnd
!= NULL
, "CreateWindow failed\n");
837 himc
= ImmGetContext(wnd
);
844 ImmReleaseContext(wnd
, himc
);
849 static BOOL
init(void) {
853 hmod
= GetModuleHandleA("imm32.dll");
854 huser
= GetModuleHandleA("user32");
855 pImmAssociateContextEx
= (void*)GetProcAddress(hmod
, "ImmAssociateContextEx");
856 pImmIsUIMessageA
= (void*)GetProcAddress(hmod
, "ImmIsUIMessageA");
857 pSendInput
= (void*)GetProcAddress(huser
, "SendInput");
858 pNtUserAssociateInputContext
= (void*)GetProcAddress(GetModuleHandleW(L
"win32u.dll"),
859 "NtUserAssociateInputContext");
861 wc
.cbSize
= sizeof(WNDCLASSEXA
);
863 wc
.lpfnWndProc
= wndProc
;
866 wc
.hInstance
= GetModuleHandleA(NULL
);
867 wc
.hIcon
= LoadIconA(NULL
, (LPCSTR
)IDI_APPLICATION
);
868 wc
.hCursor
= LoadCursorA(NULL
, (LPCSTR
)IDC_ARROW
);
869 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+1);
870 wc
.lpszMenuName
= NULL
;
871 wc
.lpszClassName
= wndcls
;
872 wc
.hIconSm
= LoadIconA(NULL
, (LPCSTR
)IDI_APPLICATION
);
874 if (!RegisterClassExA(&wc
))
877 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
878 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
879 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
883 child
= CreateWindowA("edit", "edit", WS_CHILD
| WS_VISIBLE
, 0, 0, 50, 50, hwnd
, 0, 0, 0);
887 ShowWindow(hwnd
, SW_SHOWNORMAL
);
895 static void cleanup(void) {
899 UnregisterClassA(wndcls
, GetModuleHandleW(NULL
));
902 static void test_ImmNotifyIME(void) {
903 static const char string
[] = "wine";
904 char resstr
[16] = "";
908 imc
= ImmGetContext(hwnd
);
909 msg_spy_flush_msgs();
911 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
914 "Canceling an empty composition string should succeed.\n");
915 ok(!msg_spy_find_msg(WM_IME_COMPOSITION
), "Windows does not post "
916 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
917 "the composition string being canceled is empty.\n");
919 ImmSetCompositionStringA(imc
, SCS_SETSTR
, string
, sizeof(string
), NULL
, 0);
920 msg_spy_flush_msgs();
922 ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
923 msg_spy_flush_msgs();
925 /* behavior differs between win9x and NT */
926 ret
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, resstr
, sizeof(resstr
));
927 ok(!ret
, "After being cancelled the composition string is empty.\n");
929 msg_spy_flush_msgs();
931 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
934 "Canceling an empty composition string should succeed.\n");
935 ok(!msg_spy_find_msg(WM_IME_COMPOSITION
), "Windows does not post "
936 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
937 "the composition string being canceled is empty.\n");
939 msg_spy_flush_msgs();
940 ImmReleaseContext(hwnd
, imc
);
942 imc
= ImmCreateContext();
943 ImmDestroyContext(imc
);
945 SetLastError(0xdeadbeef);
946 ret
= ImmNotifyIME((HIMC
)0xdeadcafe, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
947 ok (ret
== 0, "Bad IME should return 0\n");
948 ret
= GetLastError();
949 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
950 SetLastError(0xdeadbeef);
951 ret
= ImmNotifyIME(0x00000000, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
952 ok (ret
== 0, "NULL IME should return 0\n");
953 ret
= GetLastError();
954 ok(ret
== ERROR_SUCCESS
, "wrong last error %08x!\n", ret
);
955 SetLastError(0xdeadbeef);
956 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
957 ok (ret
== 0, "Destroyed IME should return 0\n");
958 ret
= GetLastError();
959 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
964 WNDPROC old_wnd_proc
;
965 BOOL catch_result_str
;
969 } ime_composition_test
;
971 static LRESULT WINAPI
test_ime_wnd_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
975 case WM_IME_COMPOSITION
:
976 if ((lParam
& GCS_RESULTSTR
) && !ime_composition_test
.catch_result_str
) {
983 hwndIme
= ImmGetDefaultIMEWnd(hWnd
);
984 ok(hwndIme
!= NULL
, "expected IME window existence\n");
986 ok(!ime_composition_test
.catch_ime_char
, "WM_IME_CHAR is sent\n");
987 ret
= CallWindowProcA(ime_composition_test
.old_wnd_proc
,
988 hWnd
, msg
, wParam
, lParam
);
989 ok(ime_composition_test
.catch_ime_char
, "WM_IME_CHAR isn't sent\n");
991 ime_composition_test
.catch_ime_char
= FALSE
;
992 SendMessageA(hwndIme
, msg
, wParam
, lParam
);
993 ok(!ime_composition_test
.catch_ime_char
, "WM_IME_CHAR is sent\n");
995 imc
= ImmGetContext(hWnd
);
996 size
= ImmGetCompositionStringW(imc
, GCS_RESULTSTR
,
997 wstring
, sizeof(wstring
));
998 ok(size
> 0, "ImmGetCompositionString(GCS_RESULTSTR) is %ld\n", size
);
999 ImmReleaseContext(hwnd
, imc
);
1001 ime_composition_test
.catch_result_str
= TRUE
;
1006 if (!ime_composition_test
.catch_result_str
)
1007 ime_composition_test
.catch_ime_char
= TRUE
;
1010 if (wParam
== ime_composition_test
.timer_id
) {
1011 HWND parent
= GetParent(hWnd
);
1013 int left
= 20 - (GetTickCount() - ime_composition_test
.start
) / 1000;
1014 wsprintfA(title
, "%sLeft %d sec. - IME composition test",
1015 ime_composition_test
.catch_result_str
? "[*] " : "", left
);
1016 SetWindowTextA(parent
, title
);
1018 DestroyWindow(parent
);
1020 SetTimer(hWnd
, wParam
, 100, NULL
);
1025 return CallWindowProcA(ime_composition_test
.old_wnd_proc
,
1026 hWnd
, msg
, wParam
, lParam
);
1029 static void test_SCS_SETSTR(void)
1032 static const WCHAR string
[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e};
1040 imc
= ImmGetContext(hwnd
);
1041 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
, string
, sizeof(string
), NULL
,0);
1043 win_skip("Composition isn't supported\n");
1044 ImmReleaseContext(hwnd
, imc
);
1047 msg_spy_flush_msgs();
1049 alen
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, 20);
1050 wlen
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, 20);
1051 /* windows machines without any IME installed just return 0 above */
1054 len
= ImmGetCompositionStringW(imc
, GCS_COMPATTR
, NULL
, 0);
1055 ok(len
*sizeof(WCHAR
)==wlen
,"GCS_COMPATTR(W) not returning correct count\n");
1056 len
= ImmGetCompositionStringA(imc
, GCS_COMPATTR
, NULL
, 0);
1057 ok(len
==alen
,"GCS_COMPATTR(A) not returning correct count\n");
1059 /* Get strings with exactly matching buffer sizes. */
1060 memset(wstring
, 0x1a, sizeof(wstring
));
1061 memset(cstring
, 0x1a, sizeof(cstring
));
1063 len
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, alen
);
1064 ok(len
== alen
, "Unexpected length %ld.\n", len
);
1065 ok(cstring
[alen
] == 0x1a, "Unexpected buffer contents.\n");
1067 len
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, wlen
);
1068 ok(len
== wlen
, "Unexpected length %ld.\n", len
);
1069 ok(wstring
[wlen
/sizeof(WCHAR
)] == 0x1a1a, "Unexpected buffer contents.\n");
1071 /* Get strings with exactly smaller buffer sizes. */
1072 memset(wstring
, 0x1a, sizeof(wstring
));
1073 memset(cstring
, 0x1a, sizeof(cstring
));
1075 /* Returns 0 but still fills buffer. */
1076 len
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, alen
- 1);
1077 ok(!len
, "Unexpected length %ld.\n", len
);
1078 ok(cstring
[0] == 'w', "Unexpected buffer contents %s.\n", cstring
);
1080 len
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, wlen
- 1);
1081 ok(len
== wlen
- 1, "Unexpected length %ld.\n", len
);
1082 ok(!memcmp(wstring
, string
, wlen
- 1), "Unexpected buffer contents.\n");
1084 /* Get the size of the required output buffer. */
1085 memset(wstring
, 0x1a, sizeof(wstring
));
1086 memset(cstring
, 0x1a, sizeof(cstring
));
1088 len
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, 0);
1089 ok(len
== alen
, "Unexpected length %ld.\n", len
);
1090 ok(cstring
[0] == 0x1a, "Unexpected buffer contents %s.\n", cstring
);
1092 len
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, 0);
1093 ok(len
== wlen
, "Unexpected length %ld.\n", len
);
1094 ok(wstring
[0] == 0x1a1a, "Unexpected buffer contents.\n");
1097 win_skip("Composition string isn't available\n");
1099 ImmReleaseContext(hwnd
, imc
);
1101 /* Test composition results input by IMM API */
1102 prop
= ImmGetProperty(GetKeyboardLayout(0), IGP_SETCOMPSTR
);
1103 if (!(prop
& SCS_CAP_COMPSTR
)) {
1104 /* Wine's IME doesn't support SCS_SETSTR in ImmSetCompositionString */
1105 skip("This IME doesn't support SCS_SETSTR\n");
1108 ime_composition_test
.old_wnd_proc
=
1109 (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
1110 (LONG_PTR
)test_ime_wnd_proc
);
1111 imc
= ImmGetContext(hwnd
);
1112 msg_spy_flush_msgs();
1114 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
,
1115 string
, sizeof(string
), NULL
,0);
1116 ok(ret
, "ImmSetCompositionStringW failed\n");
1117 wlen
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
,
1118 wstring
, sizeof(wstring
));
1120 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
1121 ok(ret
, "ImmNotifyIME(CPS_COMPLETE) failed\n");
1122 msg_spy_flush_msgs();
1123 ok(ime_composition_test
.catch_result_str
,
1124 "WM_IME_COMPOSITION(GCS_RESULTSTR) isn't sent\n");
1127 win_skip("Composition string isn't available\n");
1128 ImmReleaseContext(hwnd
, imc
);
1129 SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
1130 (LONG_PTR
)ime_composition_test
.old_wnd_proc
);
1131 msg_spy_flush_msgs();
1134 /* Test composition results input by hand */
1135 memset(&ime_composition_test
, 0, sizeof(ime_composition_test
));
1136 if (winetest_interactive
) {
1137 HWND hwndMain
, hwndChild
;
1139 const DWORD MY_TIMER
= 0xcaffe;
1141 hwndMain
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
,
1142 "IME composition test",
1143 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1144 CW_USEDEFAULT
, CW_USEDEFAULT
, 320, 160,
1145 NULL
, NULL
, GetModuleHandleA(NULL
), NULL
);
1146 hwndChild
= CreateWindowExA(0, "static",
1147 "Input a DBCS character here using IME.",
1148 WS_CHILD
| WS_VISIBLE
,
1149 0, 0, 320, 100, hwndMain
, NULL
,
1150 GetModuleHandleA(NULL
), NULL
);
1152 ime_composition_test
.old_wnd_proc
=
1153 (WNDPROC
)SetWindowLongPtrA(hwndChild
, GWLP_WNDPROC
,
1154 (LONG_PTR
)test_ime_wnd_proc
);
1156 SetFocus(hwndChild
);
1158 ime_composition_test
.timer_id
= MY_TIMER
;
1159 ime_composition_test
.start
= GetTickCount();
1160 SetTimer(hwndChild
, ime_composition_test
.timer_id
, 100, NULL
);
1161 while (GetMessageA(&msg
, NULL
, 0, 0)) {
1162 TranslateMessage(&msg
);
1163 DispatchMessageA(&msg
);
1164 if (!IsWindow(hwndMain
))
1167 if (!ime_composition_test
.catch_result_str
)
1168 skip("WM_IME_COMPOSITION(GCS_RESULTSTR) isn't tested\n");
1169 msg_spy_flush_msgs();
1172 SetLastError(0xdeadbeef);
1173 imc
= ImmGetContext(hwnd
);
1174 ok(imc
!= 0, "ImmGetContext() failed. Last error: %lu\n", GetLastError());
1178 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
, NULL
, 0, NULL
, 0);
1181 "ImmSetCompositionStringW() failed.\n");
1183 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGEATTR
,
1185 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
1187 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGECLAUSE
,
1189 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
1191 ret
= ImmSetCompositionStringW(imc
, SCS_CHANGEATTR
| SCS_CHANGECLAUSE
,
1193 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
1195 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGEATTR
| SCS_CHANGECLAUSE
,
1197 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
1199 ImmReleaseContext(hwnd
, imc
);
1202 static void test_ImmIME(void)
1206 imc
= ImmGetContext(hwnd
);
1210 rc
= ImmConfigureIMEA(imc
, NULL
, IME_CONFIG_REGISTERWORD
, NULL
);
1211 ok (rc
== 0, "ImmConfigureIMEA did not fail\n");
1212 rc
= ImmConfigureIMEW(imc
, NULL
, IME_CONFIG_REGISTERWORD
, NULL
);
1213 ok (rc
== 0, "ImmConfigureIMEW did not fail\n");
1215 ImmReleaseContext(hwnd
,imc
);
1218 static void test_ImmAssociateContextEx(void)
1223 if (!pImmAssociateContextEx
) return;
1225 imc
= ImmGetContext(hwnd
);
1228 HIMC retimc
, newimc
;
1231 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, TRUE
);
1232 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, TRUE
);
1234 ok(GetActiveWindow() == hwnd
, "hwnd is not active\n");
1235 newimc
= ImmCreateContext();
1236 ok(newimc
!= imc
, "handles should not be the same\n");
1237 rc
= pImmAssociateContextEx(NULL
, NULL
, 0);
1238 ok(!rc
, "ImmAssociateContextEx succeeded\n");
1239 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
1240 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
1241 rc
= pImmAssociateContextEx(hwnd
, NULL
, 0);
1242 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
1243 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
1244 ok(rc
, "ImmAssociateContextEx failed\n");
1245 rc
= pImmAssociateContextEx(NULL
, imc
, 0);
1246 ok(!rc
, "ImmAssociateContextEx succeeded\n");
1248 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
1249 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
1250 rc
= pImmAssociateContextEx(hwnd
, imc
, 0);
1251 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
1252 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
1253 ok(rc
, "ImmAssociateContextEx failed\n");
1254 retimc
= ImmGetContext(hwnd
);
1255 ok(retimc
== imc
, "handles should be the same\n");
1256 ImmReleaseContext(hwnd
,retimc
);
1258 rc
= pImmAssociateContextEx(hwnd
, imc
, 0);
1259 ok(rc
, "ImmAssociateContextEx failed\n");
1261 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
1262 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
1263 rc
= pImmAssociateContextEx(hwnd
, newimc
, 0);
1264 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
1265 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
1266 ok(rc
, "ImmAssociateContextEx failed\n");
1267 retimc
= ImmGetContext(hwnd
);
1268 ok(retimc
== newimc
, "handles should be the same\n");
1269 ImmReleaseContext(hwnd
,retimc
);
1271 focus
= CreateWindowA("button", "button", 0, 0, 0, 0, 0, 0, 0, 0, 0);
1272 ok(focus
!= NULL
, "CreateWindow failed\n");
1273 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
1275 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
1276 rc
= pImmAssociateContextEx(hwnd
, imc
, 0);
1277 ok(rc
, "ImmAssociateContextEx failed\n");
1278 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
1279 DestroyWindow(focus
);
1280 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
1282 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
1284 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
1285 rc
= pImmAssociateContextEx(hwnd
, newimc
, 0);
1286 ok(rc
, "ImmAssociateContextEx failed\n");
1287 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
1289 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
1291 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
1292 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
1293 rc
= pImmAssociateContextEx(hwnd
, NULL
, IACE_DEFAULT
);
1294 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
1295 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
1296 ok(rc
, "ImmAssociateContextEx failed\n");
1298 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, FALSE
);
1299 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, FALSE
);
1301 ImmReleaseContext(hwnd
,imc
);
1304 /* similar to above, but using NtUserAssociateInputContext */
1305 static void test_NtUserAssociateInputContext(void)
1310 if (!pNtUserAssociateInputContext
)
1312 win_skip("NtUserAssociateInputContext not available\n");
1316 imc
= ImmGetContext(hwnd
);
1319 HIMC retimc
, newimc
;
1322 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, TRUE
);
1323 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, TRUE
);
1325 ok(GetActiveWindow() == hwnd
, "hwnd is not active\n");
1326 newimc
= ImmCreateContext();
1327 ok(newimc
!= imc
, "handles should not be the same\n");
1328 rc
= pNtUserAssociateInputContext(NULL
, NULL
, 0);
1329 ok(rc
== 2, "NtUserAssociateInputContext returned %x\n", rc
);
1330 rc
= pNtUserAssociateInputContext(hwnd
, NULL
, 0);
1331 ok(rc
== 1, "NtUserAssociateInputContext returned %x\n", rc
);
1332 rc
= pNtUserAssociateInputContext(NULL
, imc
, 0);
1333 ok(rc
== 2, "NtUserAssociateInputContext returned %x\n", rc
);
1335 rc
= pNtUserAssociateInputContext(hwnd
, imc
, 0);
1336 ok(rc
== 1, "NtUserAssociateInputContext returned %x\n", rc
);
1337 retimc
= ImmGetContext(hwnd
);
1338 ok(retimc
== imc
, "handles should be the same\n");
1339 ImmReleaseContext(hwnd
,retimc
);
1341 rc
= pNtUserAssociateInputContext(hwnd
, imc
, 0);
1342 ok(rc
== 0, "NtUserAssociateInputContext returned %x\n", rc
);
1344 rc
= pNtUserAssociateInputContext(hwnd
, newimc
, 0);
1345 ok(rc
== 1, "NtUserAssociateInputContext returned %x\n", rc
);
1346 retimc
= ImmGetContext(hwnd
);
1347 ok(retimc
== newimc
, "handles should be the same\n");
1348 ImmReleaseContext(hwnd
,retimc
);
1350 focus
= CreateWindowA("button", "button", 0, 0, 0, 0, 0, 0, 0, 0, 0);
1351 ok(focus
!= NULL
, "CreateWindow failed\n");
1352 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
1354 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
1355 rc
= pNtUserAssociateInputContext(hwnd
, imc
, 0);
1356 ok(rc
== 0, "NtUserAssociateInputContext returned %x\n", rc
);
1357 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
1358 DestroyWindow(focus
);
1359 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
1361 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
1363 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
1364 rc
= pNtUserAssociateInputContext(hwnd
, newimc
, 0);
1365 ok(rc
== 0, "NtUserAssociateInputContext returned %x\n", rc
);
1366 SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE
);
1368 CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE
);
1370 rc
= pNtUserAssociateInputContext(hwnd
, NULL
, IACE_DEFAULT
);
1371 ok(rc
== 1, "NtUserAssociateInputContext returned %x\n", rc
);
1373 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, FALSE
);
1374 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, FALSE
);
1376 ImmReleaseContext(hwnd
,imc
);
1379 struct test_cross_thread_himc_params
1384 INPUTCONTEXT
*contexts
[2];
1387 static DWORD WINAPI
test_cross_thread_himc_thread( void *arg
)
1389 CANDIDATEFORM candidate
= {.dwIndex
= 1, .dwStyle
= CFS_CANDIDATEPOS
};
1390 struct test_cross_thread_himc_params
*params
= arg
;
1391 COMPOSITIONFORM composition
= {0};
1392 INPUTCONTEXT
*contexts
[2];
1393 HIMC himc
[2], tmp_himc
;
1394 LOGFONTW fontW
= {0};
1395 HWND hwnd
, tmp_hwnd
;
1399 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1400 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
1401 ok_ne( NULL
, hwnd
, HWND
, "%p" );
1402 himc
[0] = ImmGetContext( hwnd
);
1403 ok_ne( NULL
, himc
[0], HIMC
, "%p" );
1404 contexts
[0] = ImmLockIMC( himc
[0] );
1405 ok_ne( NULL
, contexts
[0], INPUTCONTEXT
*, "%p" );
1406 contexts
[0]->hWnd
= hwnd
;
1408 tmp_hwnd
= CreateWindowW( L
"static", NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1409 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
1410 tmp_himc
= ImmGetContext( tmp_hwnd
);
1411 ok_eq( himc
[0], tmp_himc
, HIMC
, "%p" );
1412 ok_ret( 1, ImmReleaseContext( tmp_hwnd
, tmp_himc
) );
1413 ok_ret( 1, DestroyWindow( tmp_hwnd
) );
1415 himc
[1] = ImmCreateContext();
1416 ok_ne( NULL
, himc
[1], HIMC
, "%p" );
1417 contexts
[1] = ImmLockIMC( himc
[1] );
1418 ok_ne( NULL
, contexts
[1], INPUTCONTEXT
*, "%p" );
1419 contexts
[1]->hWnd
= hwnd
;
1421 ok_ret( 1, ImmSetOpenStatus( himc
[0], 0xdeadbeef ) );
1422 ok_ret( 1, ImmSetOpenStatus( himc
[1], 0xfeedcafe ) );
1423 ok_ret( 1, ImmSetCompositionWindow( himc
[0], &composition
) );
1424 ok_ret( 1, ImmSetCompositionWindow( himc
[1], &composition
) );
1425 ok_ret( 1, ImmSetCandidateWindow( himc
[0], &candidate
) );
1426 ok_ret( 1, ImmSetCandidateWindow( himc
[1], &candidate
) );
1427 ok_ret( 1, ImmSetStatusWindowPos( himc
[0], &pos
) );
1428 ok_ret( 1, ImmSetStatusWindowPos( himc
[1], &pos
) );
1429 ok_ret( 1, ImmSetCompositionFontW( himc
[0], &fontW
) );
1430 ok_ret( 1, ImmSetCompositionFontW( himc
[1], &fontW
) );
1432 params
->hwnd
= hwnd
;
1433 params
->himc
[0] = himc
[0];
1434 params
->himc
[1] = himc
[1];
1435 params
->contexts
[0] = contexts
[0];
1436 params
->contexts
[1] = contexts
[1];
1437 SetEvent( params
->event
);
1439 while (GetMessageW( &msg
, 0, 0, 0 ))
1441 TranslateMessage( &msg
);
1442 DispatchMessageW( &msg
);
1445 ok_ret( 1, ImmUnlockIMC( himc
[0] ) );
1446 ok_ret( 1, ImmUnlockIMC( himc
[1] ) );
1448 ok_ret( 1, ImmDestroyContext( himc
[1] ) );
1449 ok_ret( 1, ImmReleaseContext( hwnd
, himc
[0] ) );
1450 ok_ret( 0, DestroyWindow( hwnd
) );
1455 static void test_cross_thread_himc(void)
1457 static const WCHAR comp_string
[] = L
"CompString";
1458 RECONVERTSTRING reconv
= {.dwSize
= sizeof(RECONVERTSTRING
)};
1459 struct test_cross_thread_himc_params params
;
1460 COMPOSITIONFORM composition
= {0};
1461 DWORD tid
, conversion
, sentence
;
1462 IMECHARPOSITION char_pos
= {0};
1463 CANDIDATEFORM candidate
= {0};
1464 COMPOSITIONSTRING
*string
;
1465 HIMC himc
[2], tmp_himc
;
1466 INPUTCONTEXT
*tmp_ctx
;
1467 LOGFONTW fontW
= {0};
1468 LOGFONTA fontA
= {0};
1475 himc
[0] = ImmGetContext( hwnd
);
1476 ok_ne( NULL
, himc
[0], HIMC
, "%p" );
1477 ok_ne( NULL
, ImmLockIMC( himc
[0] ), INPUTCONTEXT
*, "%p" );
1478 ok_ret( 1, ImmUnlockIMC( himc
[0] ) );
1480 params
.event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
1481 ok_ne( NULL
, params
.event
, HANDLE
, "%p" );
1482 thread
= CreateThread( NULL
, 0, test_cross_thread_himc_thread
, ¶ms
, 0, &tid
);
1483 ok_ne( NULL
, thread
, HANDLE
, "%p" );
1484 WaitForSingleObject( params
.event
, INFINITE
);
1486 memset( ime_calls
, 0, sizeof(ime_calls
) );
1489 tmp_himc
= ImmGetContext( params
.hwnd
);
1490 ok_ne( himc
[0], tmp_himc
, HIMC
, "%p" );
1491 ok_eq( params
.himc
[0], tmp_himc
, HIMC
, "%p" );
1492 ok_ret( 1, ImmReleaseContext( params
.hwnd
, tmp_himc
) );
1494 himc
[1] = ImmCreateContext();
1495 ok_ne( NULL
, himc
[1], HIMC
, "%p" );
1496 tmp_ctx
= ImmLockIMC( himc
[1] );
1497 ok_ne( NULL
, tmp_ctx
, INPUTCONTEXT
*, "%p" );
1499 tmp_ctx
->hCompStr
= ImmReSizeIMCC( tmp_ctx
->hCompStr
, 512 );
1500 ok_ne( NULL
, tmp_ctx
->hCompStr
, HIMCC
, "%p" );
1501 string
= ImmLockIMCC( tmp_ctx
->hCompStr
);
1502 ok_ne( NULL
, string
, COMPOSITIONSTRING
*, "%p" );
1503 string
->dwSize
= sizeof(COMPOSITIONSTRING
);
1504 string
->dwCompStrLen
= wcslen( comp_string
);
1505 string
->dwCompStrOffset
= string
->dwSize
;
1506 dst
= (BYTE
*)string
+ string
->dwCompStrOffset
;
1507 memcpy( dst
, comp_string
, string
->dwCompStrLen
* sizeof(WCHAR
) );
1508 string
->dwSize
+= string
->dwCompStrLen
* sizeof(WCHAR
);
1510 string
->dwCompClauseLen
= 2 * sizeof(DWORD
);
1511 string
->dwCompClauseOffset
= string
->dwSize
;
1512 dst
= (BYTE
*)string
+ string
->dwCompClauseOffset
;
1513 *(DWORD
*)(dst
+ 0 * sizeof(DWORD
)) = 0;
1514 *(DWORD
*)(dst
+ 1 * sizeof(DWORD
)) = string
->dwCompStrLen
;
1515 string
->dwSize
+= 2 * sizeof(DWORD
);
1517 string
->dwCompAttrLen
= string
->dwCompStrLen
;
1518 string
->dwCompAttrOffset
= string
->dwSize
;
1519 dst
= (BYTE
*)string
+ string
->dwCompAttrOffset
;
1520 memset( dst
, ATTR_INPUT
, string
->dwCompStrLen
);
1521 string
->dwSize
+= string
->dwCompStrLen
;
1522 ok_ret( 0, ImmUnlockIMCC( tmp_ctx
->hCompStr
) );
1524 ok_ret( 1, ImmUnlockIMC( himc
[1] ) );
1526 /* ImmLockIMC should succeed with cross thread HIMC */
1528 tmp_ctx
= ImmLockIMC( params
.himc
[0] );
1529 ok_eq( params
.contexts
[0], tmp_ctx
, INPUTCONTEXT
*, "%p" );
1530 ret
= ImmGetIMCLockCount( params
.himc
[0] );
1531 ok( ret
>= 2, "got ret %u\n", ret
);
1533 tmp_ctx
->hCompStr
= ImmReSizeIMCC( tmp_ctx
->hCompStr
, 512 );
1534 ok_ne( NULL
, tmp_ctx
->hCompStr
, HIMCC
, "%p" );
1535 string
= ImmLockIMCC( tmp_ctx
->hCompStr
);
1536 ok_ne( NULL
, string
, COMPOSITIONSTRING
*, "%p" );
1537 string
->dwSize
= sizeof(COMPOSITIONSTRING
);
1538 string
->dwCompStrLen
= wcslen( comp_string
);
1539 string
->dwCompStrOffset
= string
->dwSize
;
1540 dst
= (BYTE
*)string
+ string
->dwCompStrOffset
;
1541 memcpy( dst
, comp_string
, string
->dwCompStrLen
* sizeof(WCHAR
) );
1542 string
->dwSize
+= string
->dwCompStrLen
* sizeof(WCHAR
);
1544 string
->dwCompClauseLen
= 2 * sizeof(DWORD
);
1545 string
->dwCompClauseOffset
= string
->dwSize
;
1546 dst
= (BYTE
*)string
+ string
->dwCompClauseOffset
;
1547 *(DWORD
*)(dst
+ 0 * sizeof(DWORD
)) = 0;
1548 *(DWORD
*)(dst
+ 1 * sizeof(DWORD
)) = string
->dwCompStrLen
;
1549 string
->dwSize
+= 2 * sizeof(DWORD
);
1551 string
->dwCompAttrLen
= string
->dwCompStrLen
;
1552 string
->dwCompAttrOffset
= string
->dwSize
;
1553 dst
= (BYTE
*)string
+ string
->dwCompAttrOffset
;
1554 memset( dst
, ATTR_INPUT
, string
->dwCompStrLen
);
1555 string
->dwSize
+= string
->dwCompStrLen
;
1556 ok_ret( 0, ImmUnlockIMCC( tmp_ctx
->hCompStr
) );
1558 ok_ret( 1, ImmUnlockIMC( params
.himc
[0] ) );
1560 tmp_ctx
= ImmLockIMC( params
.himc
[1] );
1561 ok_eq( params
.contexts
[1], tmp_ctx
, INPUTCONTEXT
*, "%p" );
1562 ret
= ImmGetIMCLockCount( params
.himc
[1] );
1563 ok( ret
>= 2, "got ret %u\n", ret
);
1564 ok_ret( 1, ImmUnlockIMC( params
.himc
[1] ) );
1566 /* ImmSetActiveContext should succeed with cross thread HIMC */
1568 SET_ENABLE( WM_IME_SETCONTEXT_DEACTIVATE
, TRUE
);
1569 SET_ENABLE( WM_IME_SETCONTEXT_ACTIVATE
, TRUE
);
1571 SET_EXPECT( WM_IME_SETCONTEXT_ACTIVATE
);
1572 ok_ret( 1, ImmSetActiveContext( hwnd
, params
.himc
[0], TRUE
) );
1573 CHECK_CALLED( WM_IME_SETCONTEXT_ACTIVATE
);
1575 SET_EXPECT( WM_IME_SETCONTEXT_DEACTIVATE
);
1576 ok_ret( 1, ImmSetActiveContext( hwnd
, params
.himc
[0], FALSE
) );
1577 CHECK_CALLED( WM_IME_SETCONTEXT_DEACTIVATE
);
1579 SET_ENABLE( WM_IME_SETCONTEXT_DEACTIVATE
, FALSE
);
1580 SET_ENABLE( WM_IME_SETCONTEXT_ACTIVATE
, FALSE
);
1582 /* ImmSetOpenStatus should fail with cross thread HIMC */
1584 ok_ret( 1, ImmSetOpenStatus( himc
[1], 0xdeadbeef ) );
1585 ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( himc
[1] ) );
1587 ok_ret( 0, ImmSetOpenStatus( params
.himc
[0], TRUE
) );
1588 ok_ret( 0, ImmSetOpenStatus( params
.himc
[1], TRUE
) );
1589 ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( params
.himc
[0] ) );
1590 ok_ret( (int)0xfeedcafe, ImmGetOpenStatus( params
.himc
[1] ) );
1591 ok_ret( 0, ImmSetOpenStatus( params
.himc
[0], FALSE
) );
1592 ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( params
.himc
[0] ) );
1594 /* ImmSetConversionStatus should fail with cross thread HIMC */
1596 ok_ret( 1, ImmGetConversionStatus( himc
[1], &conversion
, &sentence
) );
1597 ok_ret( 1, ImmSetConversionStatus( himc
[1], conversion
, sentence
) );
1599 ok_ret( 1, ImmGetConversionStatus( params
.himc
[0], &conversion
, &sentence
) );
1600 ok_ret( 1, ImmGetConversionStatus( params
.himc
[1], &conversion
, &sentence
) );
1601 ok_ret( 0, ImmSetConversionStatus( params
.himc
[0], conversion
, sentence
) );
1602 ok_ret( 0, ImmSetConversionStatus( params
.himc
[1], conversion
, sentence
) );
1604 /* ImmSetCompositionFont(W|A) should fail with cross thread HIMC */
1606 ok_ret( 1, ImmSetCompositionFontA( himc
[1], &fontA
) );
1607 ok_ret( 1, ImmGetCompositionFontA( himc
[1], &fontA
) );
1608 ok_ret( 1, ImmSetCompositionFontW( himc
[1], &fontW
) );
1609 ok_ret( 1, ImmGetCompositionFontW( himc
[1], &fontW
) );
1611 ok_ret( 0, ImmSetCompositionFontA( params
.himc
[0], &fontA
) );
1612 ok_ret( 0, ImmSetCompositionFontA( params
.himc
[1], &fontA
) );
1613 ok_ret( 1, ImmGetCompositionFontA( params
.himc
[0], &fontA
) );
1614 ok_ret( 1, ImmGetCompositionFontA( params
.himc
[1], &fontA
) );
1615 ok_ret( 0, ImmSetCompositionFontW( params
.himc
[0], &fontW
) );
1616 ok_ret( 0, ImmSetCompositionFontW( params
.himc
[1], &fontW
) );
1617 ok_ret( 1, ImmGetCompositionFontW( params
.himc
[0], &fontW
) );
1618 ok_ret( 1, ImmGetCompositionFontW( params
.himc
[1], &fontW
) );
1620 /* ImmRequestMessage(W|A) should fail with cross thread HIMC */
1622 ok_ret( 0, ImmRequestMessageW( himc
[1], IMR_COMPOSITIONFONT
, (LPARAM
)&fontW
) );
1623 ok_ret( 0, ImmRequestMessageA( himc
[1], IMR_COMPOSITIONFONT
, (LPARAM
)&fontA
) );
1625 ok_ret( 0, ImmRequestMessageW( params
.himc
[0], IMR_COMPOSITIONFONT
, (LPARAM
)&fontW
) );
1626 ok_ret( 0, ImmRequestMessageA( params
.himc
[0], IMR_COMPOSITIONFONT
, (LPARAM
)&fontA
) );
1627 ok_ret( 0, ImmRequestMessageW( params
.himc
[1], IMR_COMPOSITIONFONT
, (LPARAM
)&fontW
) );
1628 ok_ret( 0, ImmRequestMessageA( params
.himc
[1], IMR_COMPOSITIONFONT
, (LPARAM
)&fontA
) );
1630 ok_seq( empty_sequence
);
1632 /* ImmSetCompositionString(W|A) should fail with cross thread HIMC */
1634 ok_ret( 10, ImmGetCompositionStringA( himc
[1], GCS_COMPSTR
, buffer
, sizeof(buffer
) ) );
1635 ok_ret( 20, ImmGetCompositionStringW( himc
[1], GCS_COMPSTR
, buffer
, sizeof(buffer
) ) );
1636 ok_ret( 1, ImmSetCompositionStringA( himc
[1], SCS_SETSTR
, "a", 2, NULL
, 0 ) );
1637 ok_ret( 1, ImmSetCompositionStringW( himc
[1], SCS_SETSTR
, L
"a", 4, NULL
, 0 ) );
1639 ok_ret( 0, ImmSetCompositionStringA( params
.himc
[0], SCS_SETSTR
, "a", 2, NULL
, 0 ) );
1640 ok_ret( 0, ImmSetCompositionStringA( params
.himc
[1], SCS_SETSTR
, "a", 2, NULL
, 0 ) );
1641 ok_ret( 0, ImmSetCompositionStringW( params
.himc
[0], SCS_SETSTR
, L
"a", 4, NULL
, 0 ) );
1642 ok_ret( 0, ImmSetCompositionStringW( params
.himc
[1], SCS_SETSTR
, L
"a", 4, NULL
, 0 ) );
1643 ok_ret( 10, ImmGetCompositionStringA( params
.himc
[0], GCS_COMPSTR
, buffer
, sizeof(buffer
) ) );
1644 ok_ret( 0, ImmGetCompositionStringA( params
.himc
[1], GCS_COMPSTR
, buffer
, sizeof(buffer
) ) );
1645 ok_ret( 20, ImmGetCompositionStringW( params
.himc
[0], GCS_COMPSTR
, buffer
, sizeof(buffer
) ) );
1646 ok_ret( 0, ImmGetCompositionStringW( params
.himc
[1], GCS_COMPSTR
, buffer
, sizeof(buffer
) ) );
1648 /* ImmRequestMessage(W|A) should fail with cross thread HIMC */
1650 ok_ret( 0, ImmRequestMessageW( himc
[1], IMR_RECONVERTSTRING
, 0 ) );
1651 ok_ret( 0, ImmRequestMessageW( himc
[1], IMR_RECONVERTSTRING
, (LPARAM
)&reconv
) );
1652 ok_ret( 0, ImmRequestMessageA( himc
[1], IMR_RECONVERTSTRING
, 0 ) );
1653 ok_ret( 0, ImmRequestMessageA( himc
[1], IMR_RECONVERTSTRING
, (LPARAM
)&reconv
) );
1655 ok_ret( 0, ImmRequestMessageW( params
.himc
[0], IMR_RECONVERTSTRING
, 0 ) );
1656 ok_ret( 0, ImmRequestMessageW( params
.himc
[0], IMR_RECONVERTSTRING
, (LPARAM
)&reconv
) );
1657 ok_ret( 0, ImmRequestMessageA( params
.himc
[0], IMR_RECONVERTSTRING
, 0 ) );
1658 ok_ret( 0, ImmRequestMessageA( params
.himc
[0], IMR_RECONVERTSTRING
, (LPARAM
)&reconv
) );
1659 ok_ret( 0, ImmRequestMessageW( params
.himc
[1], IMR_RECONVERTSTRING
, 0 ) );
1660 ok_ret( 0, ImmRequestMessageW( params
.himc
[1], IMR_RECONVERTSTRING
, (LPARAM
)&reconv
) );
1661 ok_ret( 0, ImmRequestMessageA( params
.himc
[1], IMR_RECONVERTSTRING
, 0 ) );
1662 ok_ret( 0, ImmRequestMessageA( params
.himc
[1], IMR_RECONVERTSTRING
, (LPARAM
)&reconv
) );
1664 ok_ret( 0, ImmRequestMessageW( himc
[1], IMR_DOCUMENTFEED
, 0 ) );
1665 ok_ret( 0, ImmRequestMessageW( himc
[1], IMR_DOCUMENTFEED
, (LPARAM
)&reconv
) );
1666 ok_ret( 0, ImmRequestMessageA( himc
[1], IMR_DOCUMENTFEED
, 0 ) );
1667 ok_ret( 0, ImmRequestMessageA( himc
[1], IMR_DOCUMENTFEED
, (LPARAM
)&reconv
) );
1669 ok_ret( 0, ImmRequestMessageW( params
.himc
[0], IMR_DOCUMENTFEED
, 0 ) );
1670 ok_ret( 0, ImmRequestMessageW( params
.himc
[0], IMR_DOCUMENTFEED
, (LPARAM
)&reconv
) );
1671 ok_ret( 0, ImmRequestMessageA( params
.himc
[0], IMR_DOCUMENTFEED
, 0 ) );
1672 ok_ret( 0, ImmRequestMessageA( params
.himc
[0], IMR_DOCUMENTFEED
, (LPARAM
)&reconv
) );
1673 ok_ret( 0, ImmRequestMessageW( params
.himc
[1], IMR_DOCUMENTFEED
, 0 ) );
1674 ok_ret( 0, ImmRequestMessageW( params
.himc
[1], IMR_DOCUMENTFEED
, (LPARAM
)&reconv
) );
1675 ok_ret( 0, ImmRequestMessageA( params
.himc
[1], IMR_DOCUMENTFEED
, 0 ) );
1676 ok_ret( 0, ImmRequestMessageA( params
.himc
[1], IMR_DOCUMENTFEED
, (LPARAM
)&reconv
) );
1678 ok_ret( 0, ImmRequestMessageW( himc
[1], IMR_CONFIRMRECONVERTSTRING
, (LPARAM
)&reconv
) );
1679 ok_ret( 0, ImmRequestMessageA( himc
[1], IMR_CONFIRMRECONVERTSTRING
, (LPARAM
)&reconv
) );
1681 ok_ret( 0, ImmRequestMessageW( params
.himc
[0], IMR_CONFIRMRECONVERTSTRING
, (LPARAM
)&reconv
) );
1682 ok_ret( 0, ImmRequestMessageA( params
.himc
[0], IMR_CONFIRMRECONVERTSTRING
, (LPARAM
)&reconv
) );
1683 ok_ret( 0, ImmRequestMessageW( params
.himc
[1], IMR_CONFIRMRECONVERTSTRING
, (LPARAM
)&reconv
) );
1684 ok_ret( 0, ImmRequestMessageA( params
.himc
[1], IMR_CONFIRMRECONVERTSTRING
, (LPARAM
)&reconv
) );
1686 ok_seq( empty_sequence
);
1688 /* ImmSetCompositionWindow should fail with cross thread HIMC */
1690 ok_ret( 1, ImmSetCompositionWindow( himc
[1], &composition
) );
1691 ok_ret( 1, ImmGetCompositionWindow( himc
[1], &composition
) );
1693 ok_ret( 0, ImmSetCompositionWindow( params
.himc
[0], &composition
) );
1694 ok_ret( 0, ImmSetCompositionWindow( params
.himc
[1], &composition
) );
1695 ok_ret( 1, ImmGetCompositionWindow( params
.himc
[0], &composition
) );
1696 ok_ret( 1, ImmGetCompositionWindow( params
.himc
[1], &composition
) );
1698 /* ImmRequestMessage(W|A) should fail with cross thread HIMC */
1700 ok_ret( 0, ImmRequestMessageW( himc
[1], IMR_COMPOSITIONWINDOW
, (LPARAM
)&composition
) );
1701 ok_ret( 0, ImmRequestMessageA( himc
[1], IMR_COMPOSITIONWINDOW
, (LPARAM
)&composition
) );
1703 ok_ret( 0, ImmRequestMessageW( params
.himc
[0], IMR_COMPOSITIONWINDOW
, (LPARAM
)&composition
) );
1704 ok_ret( 0, ImmRequestMessageA( params
.himc
[0], IMR_COMPOSITIONWINDOW
, (LPARAM
)&composition
) );
1705 ok_ret( 0, ImmRequestMessageW( params
.himc
[1], IMR_COMPOSITIONWINDOW
, (LPARAM
)&composition
) );
1706 ok_ret( 0, ImmRequestMessageA( params
.himc
[1], IMR_COMPOSITIONWINDOW
, (LPARAM
)&composition
) );
1708 ok_seq( empty_sequence
);
1710 /* ImmSetCandidateWindow should fail with cross thread HIMC */
1712 ok_ret( 1, ImmSetCandidateWindow( himc
[1], &candidate
) );
1713 ok_ret( 1, ImmGetCandidateWindow( himc
[1], 0, &candidate
) );
1715 ok_ret( 1, ImmGetCandidateWindow( params
.himc
[0], 1, &candidate
) );
1716 ok_ret( 1, ImmGetCandidateWindow( params
.himc
[1], 1, &candidate
) );
1717 ok_ret( 0, ImmSetCandidateWindow( params
.himc
[0], &candidate
) );
1718 ok_ret( 0, ImmSetCandidateWindow( params
.himc
[1], &candidate
) );
1720 /* ImmRequestMessage(W|A) should fail with cross thread HIMC */
1722 candidate
.dwIndex
= -1;
1723 ok_ret( 0, ImmRequestMessageW( himc
[1], IMR_CANDIDATEWINDOW
, (LPARAM
)&candidate
) );
1724 ok_ret( 0, ImmRequestMessageA( himc
[1], IMR_CANDIDATEWINDOW
, (LPARAM
)&candidate
) );
1726 candidate
.dwIndex
= 0;
1727 ok_ret( 0, ImmRequestMessageW( himc
[1], IMR_CANDIDATEWINDOW
, (LPARAM
)&candidate
) );
1728 ok_ret( 0, ImmRequestMessageA( himc
[1], IMR_CANDIDATEWINDOW
, (LPARAM
)&candidate
) );
1730 ok_ret( 0, ImmRequestMessageW( params
.himc
[0], IMR_CANDIDATEWINDOW
, (LPARAM
)&candidate
) );
1731 ok_ret( 0, ImmRequestMessageA( params
.himc
[0], IMR_CANDIDATEWINDOW
, (LPARAM
)&candidate
) );
1732 ok_ret( 0, ImmRequestMessageW( params
.himc
[1], IMR_CANDIDATEWINDOW
, (LPARAM
)&candidate
) );
1733 ok_ret( 0, ImmRequestMessageA( params
.himc
[1], IMR_CANDIDATEWINDOW
, (LPARAM
)&candidate
) );
1735 ok_seq( empty_sequence
);
1737 /* ImmSetStatusWindowPos should fail with cross thread HIMC */
1739 ok_ret( 1, ImmSetStatusWindowPos( himc
[1], &pos
) );
1740 ok_ret( 1, ImmGetStatusWindowPos( himc
[1], &pos
) );
1742 ok_ret( 0, ImmSetStatusWindowPos( params
.himc
[0], &pos
) );
1743 ok_ret( 0, ImmSetStatusWindowPos( params
.himc
[1], &pos
) );
1744 ok_ret( 1, ImmGetStatusWindowPos( params
.himc
[0], &pos
) );
1745 ok_ret( 1, ImmGetStatusWindowPos( params
.himc
[1], &pos
) );
1747 /* ImmRequestMessage(W|A) should fail with cross thread HIMC */
1749 ok_ret( 0, ImmRequestMessageW( himc
[1], IMR_QUERYCHARPOSITION
, (LPARAM
)&char_pos
) );
1750 ok_ret( 0, ImmRequestMessageA( himc
[1], IMR_QUERYCHARPOSITION
, (LPARAM
)&char_pos
) );
1752 ok_ret( 0, ImmRequestMessageW( params
.himc
[0], IMR_QUERYCHARPOSITION
, (LPARAM
)&char_pos
) );
1753 ok_ret( 0, ImmRequestMessageA( params
.himc
[0], IMR_QUERYCHARPOSITION
, (LPARAM
)&char_pos
) );
1754 ok_ret( 0, ImmRequestMessageW( params
.himc
[1], IMR_QUERYCHARPOSITION
, (LPARAM
)&char_pos
) );
1755 ok_ret( 0, ImmRequestMessageA( params
.himc
[1], IMR_QUERYCHARPOSITION
, (LPARAM
)&char_pos
) );
1757 ok_seq( empty_sequence
);
1759 /* ImmGenerateMessage should fail with cross thread HIMC */
1761 ok_ret( 1, ImmGenerateMessage( himc
[1] ) );
1763 ok_ret( 0, ImmGenerateMessage( params
.himc
[0] ) );
1764 ok_ret( 0, ImmGenerateMessage( params
.himc
[1] ) );
1766 /* ImmAssociateContext should fail with cross thread HWND or HIMC */
1768 tmp_himc
= ImmAssociateContext( hwnd
, params
.himc
[0] );
1769 ok_eq( NULL
, tmp_himc
, HIMC
, "%p" );
1770 tmp_himc
= ImmGetContext( hwnd
);
1771 ok_eq( himc
[0], tmp_himc
, HIMC
, "%p" );
1772 ok_ret( 1, ImmReleaseContext( hwnd
, tmp_himc
) );
1774 tmp_himc
= ImmAssociateContext( hwnd
, params
.himc
[1] );
1775 ok_eq( NULL
, tmp_himc
, HIMC
, "%p" );
1776 tmp_himc
= ImmGetContext( hwnd
);
1777 ok_eq( himc
[0], tmp_himc
, HIMC
, "%p" );
1778 ok_ret( 1, ImmReleaseContext( hwnd
, tmp_himc
) );
1780 tmp_himc
= ImmAssociateContext( params
.hwnd
, params
.himc
[1] );
1781 ok_eq( NULL
, tmp_himc
, HIMC
, "%p" );
1782 tmp_himc
= ImmGetContext( params
.hwnd
);
1783 ok_eq( params
.himc
[0], tmp_himc
, HIMC
, "%p" );
1784 ok_ret( 1, ImmReleaseContext( params
.hwnd
, tmp_himc
) );
1786 /* ImmAssociateContext should succeed with cross thread HWND and NULL HIMC */
1788 tmp_himc
= ImmAssociateContext( params
.hwnd
, NULL
);
1789 ok_eq( params
.himc
[0], tmp_himc
, HIMC
, "%p" );
1790 tmp_himc
= ImmGetContext( params
.hwnd
);
1791 ok_eq( NULL
, tmp_himc
, HIMC
, "%p" );
1793 /* ImmReleaseContext / ImmDestroyContext should fail with cross thread HIMC */
1795 ok_ret( 1, ImmReleaseContext( params
.hwnd
, params
.himc
[0] ) );
1796 ok_ret( 0, ImmDestroyContext( params
.himc
[1] ) );
1798 /* ImmGetContext should fail with another process HWND */
1800 tmp_himc
= ImmGetContext( GetDesktopWindow() );
1801 ok_eq( NULL
, tmp_himc
, HIMC
, "%p" );
1803 ok_ret( 0, SendMessageW( params
.hwnd
, WM_CLOSE
, 0, 0 ) );
1804 ok_ret( 1, PostThreadMessageW( tid
, WM_QUIT
, 1, 0 ) );
1805 ok_ret( 0, WaitForSingleObject( thread
, 5000 ) );
1806 ok_ret( 1, CloseHandle( thread
) );
1807 ok_ret( 1, CloseHandle( params
.event
) );
1809 ok_ret( 1, ImmReleaseContext( hwnd
, himc
[0] ) );
1810 ok_ret( 1, ImmDestroyContext( himc
[1] ) );
1813 static void test_ImmIsUIMessage(void)
1821 static const struct test tests
[] =
1823 { WM_MOUSEMOVE
, FALSE
},
1824 { WM_IME_STARTCOMPOSITION
, TRUE
},
1825 { WM_IME_ENDCOMPOSITION
, TRUE
},
1826 { WM_IME_COMPOSITION
, TRUE
},
1827 { WM_IME_SETCONTEXT
, TRUE
},
1828 { WM_IME_NOTIFY
, TRUE
},
1829 { WM_IME_CONTROL
, FALSE
},
1830 { WM_IME_COMPOSITIONFULL
, TRUE
},
1831 { WM_IME_SELECT
, TRUE
},
1832 { WM_IME_CHAR
, FALSE
},
1833 { 0x287 /* FIXME */, TRUE
},
1834 { WM_IME_REQUEST
, FALSE
},
1835 { WM_IME_KEYDOWN
, FALSE
},
1836 { WM_IME_KEYUP
, FALSE
},
1837 { 0, FALSE
} /* mark the end */
1840 UINT WM_MSIME_SERVICE
= RegisterWindowMessageA("MSIMEService");
1841 UINT WM_MSIME_RECONVERTOPTIONS
= RegisterWindowMessageA("MSIMEReconvertOptions");
1842 UINT WM_MSIME_MOUSE
= RegisterWindowMessageA("MSIMEMouseOperation");
1843 UINT WM_MSIME_RECONVERTREQUEST
= RegisterWindowMessageA("MSIMEReconvertRequest");
1844 UINT WM_MSIME_RECONVERT
= RegisterWindowMessageA("MSIMEReconvert");
1845 UINT WM_MSIME_QUERYPOSITION
= RegisterWindowMessageA("MSIMEQueryPosition");
1846 UINT WM_MSIME_DOCUMENTFEED
= RegisterWindowMessageA("MSIMEDocumentFeed");
1848 const struct test
*test
;
1851 if (!pImmIsUIMessageA
) return;
1853 for (test
= tests
; test
->msg
; test
++)
1855 msg_spy_flush_msgs();
1856 ret
= pImmIsUIMessageA(NULL
, test
->msg
, 0, 0);
1857 ok(ret
== test
->ret
, "ImmIsUIMessageA returned %x for %x\n", ret
, test
->msg
);
1858 ok(!msg_spy_find_msg(test
->msg
), "Windows does not send 0x%x for NULL hwnd\n", test
->msg
);
1860 ret
= pImmIsUIMessageA(hwnd
, test
->msg
, 0, 0);
1861 ok(ret
== test
->ret
, "ImmIsUIMessageA returned %x for %x\n", ret
, test
->msg
);
1863 ok(msg_spy_find_msg(test
->msg
) != NULL
, "Windows does send 0x%x\n", test
->msg
);
1865 ok(!msg_spy_find_msg(test
->msg
), "Windows does not send 0x%x\n", test
->msg
);
1868 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_SERVICE
, 0, 0);
1869 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_SERVICE\n");
1870 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERTOPTIONS
, 0, 0);
1871 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTOPTIONS\n");
1872 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_MOUSE
, 0, 0);
1873 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_MOUSE\n");
1874 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERTREQUEST
, 0, 0);
1875 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTREQUEST\n");
1876 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERT
, 0, 0);
1877 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERT\n");
1878 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_QUERYPOSITION
, 0, 0);
1879 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_QUERYPOSITION\n");
1880 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_DOCUMENTFEED
, 0, 0);
1881 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_DOCUMENTFEED\n");
1884 static void test_ImmGetContext(void)
1889 SetLastError(0xdeadbeef);
1890 himc
= ImmGetContext((HWND
)0xffffffff);
1891 err
= GetLastError();
1892 ok(himc
== NULL
, "ImmGetContext succeeded\n");
1893 ok(err
== ERROR_INVALID_WINDOW_HANDLE
, "got %lu\n", err
);
1895 himc
= ImmGetContext(hwnd
);
1896 ok(himc
!= NULL
, "ImmGetContext failed\n");
1897 ok(ImmReleaseContext(hwnd
, himc
), "ImmReleaseContext failed\n");
1900 static LRESULT (WINAPI
*old_imm_wnd_proc
)(HWND
, UINT
, WPARAM
, LPARAM
);
1901 static LRESULT WINAPI
imm_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
1903 ok(msg
!= WM_DESTROY
, "got WM_DESTROY message\n");
1904 return old_imm_wnd_proc(hwnd
, msg
, wparam
, lparam
);
1907 static HWND thread_ime_wnd
;
1908 static DWORD WINAPI
test_ImmGetDefaultIMEWnd_thread(void *arg
)
1910 CreateWindowA("static", "static", WS_POPUP
, 0, 0, 1, 1, NULL
, NULL
, NULL
, NULL
);
1912 thread_ime_wnd
= ImmGetDefaultIMEWnd(0);
1913 ok(thread_ime_wnd
!= 0, "ImmGetDefaultIMEWnd returned NULL\n");
1914 old_imm_wnd_proc
= (void*)SetWindowLongPtrW(thread_ime_wnd
, GWLP_WNDPROC
, (LONG_PTR
)imm_wnd_proc
);
1918 static void test_ImmDefaultHwnd(void)
1920 HIMC imc1
, imc2
, imc3
;
1927 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
1928 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1929 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1931 ShowWindow(hwnd
, SW_SHOWNORMAL
);
1933 imc1
= ImmGetContext(hwnd
);
1936 win_skip("IME support not implemented\n");
1940 def1
= ImmGetDefaultIMEWnd(hwnd
);
1942 GetWindowTextA(def1
, title
, sizeof(title
));
1943 ok(!strcmp(title
, "Default IME"), "got %s\n", title
);
1944 style
= GetWindowLongA(def1
, GWL_STYLE
);
1945 ok(style
== (WS_DISABLED
| WS_POPUP
| WS_CLIPSIBLINGS
), "got %08lx\n", style
);
1946 style
= GetWindowLongA(def1
, GWL_EXSTYLE
);
1947 ok(style
== 0, "got %08lx\n", style
);
1949 imc2
= ImmCreateContext();
1950 ImmSetOpenStatus(imc2
, TRUE
);
1952 imc3
= ImmGetContext(hwnd
);
1953 def3
= ImmGetDefaultIMEWnd(hwnd
);
1955 ok(def3
== def1
, "Default IME window should not change\n");
1956 ok(imc1
== imc3
, "IME context should not change\n");
1957 ImmSetOpenStatus(imc2
, FALSE
);
1959 thread
= CreateThread(NULL
, 0, test_ImmGetDefaultIMEWnd_thread
, NULL
, 0, NULL
);
1960 WaitForSingleObject(thread
, INFINITE
);
1961 ok(thread_ime_wnd
!= def1
, "thread_ime_wnd == def1\n");
1962 ok(!IsWindow(thread_ime_wnd
), "thread_ime_wnd was not destroyed\n");
1963 CloseHandle(thread
);
1965 ImmReleaseContext(hwnd
, imc1
);
1966 ImmReleaseContext(hwnd
, imc3
);
1967 ImmDestroyContext(imc2
);
1968 DestroyWindow(hwnd
);
1971 static BOOL CALLBACK
is_ime_window_proc(HWND hWnd
, LPARAM param
)
1973 WCHAR class_nameW
[16];
1974 HWND
*ime_window
= (HWND
*)param
;
1975 if (GetClassNameW(hWnd
, class_nameW
, ARRAY_SIZE(class_nameW
)) && !lstrcmpW(class_nameW
, L
"IME"))
1983 static HWND
get_ime_window(void)
1985 HWND ime_window
= NULL
;
1986 EnumThreadWindows(GetCurrentThreadId(), is_ime_window_proc
, (LPARAM
)&ime_window
);
1990 struct testcase_ime_window
{
1992 BOOL top_level_window
;
1995 static DWORD WINAPI
test_default_ime_window_cb(void *arg
)
1997 struct testcase_ime_window
*testcase
= (struct testcase_ime_window
*)arg
;
1998 DWORD visible
= testcase
->visible
? WS_VISIBLE
: 0;
1999 HWND hwnd1
, hwnd2
, default_ime_wnd
, ime_wnd
;
2001 ok(!get_ime_window(), "Expected no IME windows\n");
2002 if (testcase
->top_level_window
) {
2003 test_phase
= FIRST_WINDOW
;
2004 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
2005 WS_OVERLAPPEDWINDOW
| visible
,
2006 CW_USEDEFAULT
, CW_USEDEFAULT
,
2007 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
2010 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
2012 CW_USEDEFAULT
, CW_USEDEFAULT
,
2013 240, 24, hwnd
, NULL
, GetModuleHandleW(NULL
), NULL
);
2015 ime_wnd
= get_ime_window();
2016 ok(ime_wnd
!= NULL
, "Expected IME window existence\n");
2017 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
2018 ok(ime_wnd
== default_ime_wnd
, "Expected %p, got %p\n", ime_wnd
, default_ime_wnd
);
2020 test_phase
= SECOND_WINDOW
;
2021 hwnd2
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
2022 WS_OVERLAPPEDWINDOW
| visible
,
2023 CW_USEDEFAULT
, CW_USEDEFAULT
,
2024 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
2025 DestroyWindow(hwnd2
);
2026 ok(IsWindow(ime_wnd
) ||
2027 broken(!testcase
->visible
/* Vista */) ||
2028 broken(!testcase
->top_level_window
/* Vista */) ,
2029 "Expected IME window existence\n");
2030 DestroyWindow(hwnd1
);
2032 ok(!IsWindow(ime_wnd
), "Expected no IME windows\n");
2036 static DWORD WINAPI
test_default_ime_window_cancel_cb(void *arg
)
2038 struct testcase_ime_window
*testcase
= (struct testcase_ime_window
*)arg
;
2039 DWORD visible
= testcase
->visible
? WS_VISIBLE
: 0;
2040 HWND hwnd1
, hwnd2
, default_ime_wnd
, ime_wnd
;
2042 ok(!get_ime_window(), "Expected no IME windows\n");
2043 test_phase
= NCCREATE_CANCEL
;
2044 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
2045 WS_OVERLAPPEDWINDOW
| visible
,
2046 CW_USEDEFAULT
, CW_USEDEFAULT
,
2047 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
2048 ok(hwnd1
== NULL
, "creation succeeded, got %p\n", hwnd1
);
2049 ok(!get_ime_window(), "Expected no IME windows\n");
2051 test_phase
= CREATE_CANCEL
;
2052 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
2053 WS_OVERLAPPEDWINDOW
| visible
,
2054 CW_USEDEFAULT
, CW_USEDEFAULT
,
2055 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
2056 ok(hwnd1
== NULL
, "creation succeeded, got %p\n", hwnd1
);
2057 ok(!get_ime_window(), "Expected no IME windows\n");
2059 test_phase
= FIRST_WINDOW
;
2060 hwnd2
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
2061 WS_OVERLAPPEDWINDOW
| visible
,
2062 CW_USEDEFAULT
, CW_USEDEFAULT
,
2063 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
2064 ime_wnd
= get_ime_window();
2065 ok(ime_wnd
!= NULL
, "Expected IME window existence\n");
2066 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd2
);
2067 ok(ime_wnd
== default_ime_wnd
, "Expected %p, got %p\n", ime_wnd
, default_ime_wnd
);
2069 DestroyWindow(hwnd2
);
2070 ok(!IsWindow(ime_wnd
), "Expected no IME windows\n");
2074 static DWORD WINAPI
test_default_ime_disabled_cb(void *arg
)
2076 HWND hWnd
, default_ime_wnd
;
2078 ok(!get_ime_window(), "Expected no IME windows\n");
2079 ImmDisableIME(GetCurrentThreadId());
2080 test_phase
= IME_DISABLED
;
2081 hWnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
2082 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
2083 CW_USEDEFAULT
, CW_USEDEFAULT
,
2084 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
2085 default_ime_wnd
= ImmGetDefaultIMEWnd(hWnd
);
2086 ok(!default_ime_wnd
, "Expected no IME windows\n");
2087 DestroyWindow(hWnd
);
2091 static DWORD WINAPI
test_default_ime_with_message_only_window_cb(void *arg
)
2093 HWND hwnd1
, hwnd2
, default_ime_wnd
;
2095 /* Message-only window doesn't create associated IME window. */
2096 test_phase
= PHASE_UNKNOWN
;
2097 hwnd1
= CreateWindowA(wndcls
, "Wine imm32.dll test",
2098 WS_OVERLAPPEDWINDOW
,
2099 CW_USEDEFAULT
, CW_USEDEFAULT
,
2100 240, 120, HWND_MESSAGE
, NULL
, GetModuleHandleW(NULL
), NULL
);
2101 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
2102 ok(!default_ime_wnd
, "Expected no IME windows, got %p\n", default_ime_wnd
);
2104 /* Setting message-only window as owner at creation,
2105 doesn't create associated IME window. */
2106 hwnd2
= CreateWindowA(wndcls
, "Wine imm32.dll test",
2107 WS_OVERLAPPEDWINDOW
,
2108 CW_USEDEFAULT
, CW_USEDEFAULT
,
2109 240, 120, hwnd1
, NULL
, GetModuleHandleW(NULL
), NULL
);
2110 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd2
);
2111 todo_wine
ok(!default_ime_wnd
|| broken(IsWindow(default_ime_wnd
)), "Expected no IME windows, got %p\n", default_ime_wnd
);
2113 DestroyWindow(hwnd2
);
2114 DestroyWindow(hwnd1
);
2116 /* Making window message-only after creation,
2117 doesn't disassociate IME window. */
2118 hwnd1
= CreateWindowA(wndcls
, "Wine imm32.dll test",
2119 WS_OVERLAPPEDWINDOW
,
2120 CW_USEDEFAULT
, CW_USEDEFAULT
,
2121 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
2122 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
2123 ok(IsWindow(default_ime_wnd
), "Expected IME window existence\n");
2124 SetParent(hwnd1
, HWND_MESSAGE
);
2125 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
2126 ok(IsWindow(default_ime_wnd
), "Expected IME window existence\n");
2127 DestroyWindow(hwnd1
);
2131 static void test_default_ime_window_creation(void)
2135 struct testcase_ime_window testcases
[] = {
2136 /* visible, top-level window */
2143 for (i
= 0; i
< ARRAY_SIZE(testcases
); i
++)
2145 thread
= CreateThread(NULL
, 0, test_default_ime_window_cb
, &testcases
[i
], 0, NULL
);
2146 ok(thread
!= NULL
, "CreateThread failed with error %lu\n", GetLastError());
2147 while (MsgWaitForMultipleObjects(1, &thread
, FALSE
, INFINITE
, QS_ALLINPUT
) == WAIT_OBJECT_0
+ 1)
2150 while (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
))
2152 TranslateMessage(&msg
);
2153 DispatchMessageA(&msg
);
2156 CloseHandle(thread
);
2158 if (testcases
[i
].top_level_window
)
2160 thread
= CreateThread(NULL
, 0, test_default_ime_window_cancel_cb
, &testcases
[i
], 0, NULL
);
2161 ok(thread
!= NULL
, "CreateThread failed with error %lu\n", GetLastError());
2162 WaitForSingleObject(thread
, INFINITE
);
2163 CloseHandle(thread
);
2167 thread
= CreateThread(NULL
, 0, test_default_ime_disabled_cb
, NULL
, 0, NULL
);
2168 WaitForSingleObject(thread
, INFINITE
);
2169 CloseHandle(thread
);
2171 thread
= CreateThread(NULL
, 0, test_default_ime_with_message_only_window_cb
, NULL
, 0, NULL
);
2172 WaitForSingleObject(thread
, INFINITE
);
2173 CloseHandle(thread
);
2175 test_phase
= PHASE_UNKNOWN
;
2178 static void test_ImmGetIMCLockCount(void)
2181 DWORD count
, ret
, i
;
2184 imc
= ImmCreateContext();
2185 ImmDestroyContext(imc
);
2186 SetLastError(0xdeadbeef);
2187 count
= ImmGetIMCLockCount((HIMC
)0xdeadcafe);
2188 ok(count
== 0, "Invalid IMC should return 0\n");
2189 ret
= GetLastError();
2190 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2191 SetLastError(0xdeadbeef);
2192 count
= ImmGetIMCLockCount(0x00000000);
2193 ok(count
== 0, "NULL IMC should return 0\n");
2194 ret
= GetLastError();
2195 ok(ret
== 0xdeadbeef, "Last Error should remain unchanged: %08lx\n",ret
);
2196 count
= ImmGetIMCLockCount(imc
);
2197 ok(count
== 0, "Destroyed IMC should return 0\n");
2198 ret
= GetLastError();
2199 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2201 imc
= ImmCreateContext();
2202 count
= ImmGetIMCLockCount(imc
);
2203 ok(count
== 0, "expect 0, returned %ld\n", count
);
2204 ic
= ImmLockIMC(imc
);
2205 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
2206 count
= ImmGetIMCLockCount(imc
);
2207 ok(count
== 1, "expect 1, returned %ld\n", count
);
2208 ret
= ImmUnlockIMC(imc
);
2209 ok(ret
== TRUE
, "expect TRUE, ret %ld\n", ret
);
2210 count
= ImmGetIMCLockCount(imc
);
2211 ok(count
== 0, "expect 0, returned %ld\n", count
);
2212 ret
= ImmUnlockIMC(imc
);
2213 ok(ret
== TRUE
, "expect TRUE, ret %ld\n", ret
);
2214 count
= ImmGetIMCLockCount(imc
);
2215 ok(count
== 0, "expect 0, returned %ld\n", count
);
2217 for (i
= 0; i
< GMEM_LOCKCOUNT
* 2; i
++)
2219 ic
= ImmLockIMC(imc
);
2220 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
2222 count
= ImmGetIMCLockCount(imc
);
2223 todo_wine
ok(count
== GMEM_LOCKCOUNT
, "expect GMEM_LOCKCOUNT, returned %ld\n", count
);
2225 for (i
= 0; i
< GMEM_LOCKCOUNT
- 1; i
++)
2227 count
= ImmGetIMCLockCount(imc
);
2228 todo_wine
ok(count
== 1, "expect 1, returned %ld\n", count
);
2230 count
= ImmGetIMCLockCount(imc
);
2231 todo_wine
ok(count
== 0, "expect 0, returned %ld\n", count
);
2233 ImmDestroyContext(imc
);
2236 static void test_ImmGetIMCCLockCount(void)
2239 DWORD count
, g_count
, i
;
2243 imcc
= ImmCreateIMCC(sizeof(CANDIDATEINFO
));
2244 count
= ImmGetIMCCLockCount(imcc
);
2245 ok(count
== 0, "expect 0, returned %ld\n", count
);
2247 count
= ImmGetIMCCLockCount(imcc
);
2248 ok(count
== 1, "expect 1, returned %ld\n", count
);
2249 ret
= ImmUnlockIMCC(imcc
);
2250 ok(ret
== FALSE
, "expect FALSE, ret %d\n", ret
);
2251 count
= ImmGetIMCCLockCount(imcc
);
2252 ok(count
== 0, "expect 0, returned %ld\n", count
);
2253 ret
= ImmUnlockIMCC(imcc
);
2254 ok(ret
== FALSE
, "expect FALSE, ret %d\n", ret
);
2255 count
= ImmGetIMCCLockCount(imcc
);
2256 ok(count
== 0, "expect 0, returned %ld\n", count
);
2258 p
= ImmLockIMCC(imcc
);
2259 ok(GlobalHandle(p
) == imcc
, "expect %p, returned %p\n", imcc
, GlobalHandle(p
));
2261 for (i
= 0; i
< GMEM_LOCKCOUNT
* 2; i
++)
2264 count
= ImmGetIMCCLockCount(imcc
);
2265 g_count
= GlobalFlags(imcc
) & GMEM_LOCKCOUNT
;
2266 ok(count
== g_count
, "count %ld, g_count %ld\n", count
, g_count
);
2268 count
= ImmGetIMCCLockCount(imcc
);
2269 ok(count
== GMEM_LOCKCOUNT
, "expect GMEM_LOCKCOUNT, returned %ld\n", count
);
2271 for (i
= 0; i
< GMEM_LOCKCOUNT
- 1; i
++)
2273 count
= ImmGetIMCCLockCount(imcc
);
2274 ok(count
== 1, "expect 1, returned %ld\n", count
);
2276 count
= ImmGetIMCCLockCount(imcc
);
2277 ok(count
== 0, "expect 0, returned %ld\n", count
);
2279 ImmDestroyIMCC(imcc
);
2282 static void test_ImmDestroyContext(void)
2288 imc
= ImmCreateContext();
2289 count
= ImmGetIMCLockCount(imc
);
2290 ok(count
== 0, "expect 0, returned %ld\n", count
);
2291 ic
= ImmLockIMC(imc
);
2292 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
2293 count
= ImmGetIMCLockCount(imc
);
2294 ok(count
== 1, "expect 1, returned %ld\n", count
);
2295 ret
= ImmDestroyContext(imc
);
2296 ok(ret
== TRUE
, "Destroy a locked IMC should success!\n");
2297 ic
= ImmLockIMC(imc
);
2298 ok(ic
== NULL
, "Lock a destroyed IMC should fail!\n");
2299 ret
= ImmUnlockIMC(imc
);
2300 ok(ret
== FALSE
, "Unlock a destroyed IMC should fail!\n");
2301 count
= ImmGetIMCLockCount(imc
);
2302 ok(count
== 0, "Get lock count of a destroyed IMC should return 0!\n");
2303 SetLastError(0xdeadbeef);
2304 ret
= ImmDestroyContext(imc
);
2305 ok(ret
== FALSE
, "Destroy a destroyed IMC should fail!\n");
2306 ret
= GetLastError();
2307 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2310 static void test_ImmDestroyIMCC(void)
2313 DWORD ret
, count
, size
;
2316 imcc
= ImmCreateIMCC(sizeof(CANDIDATEINFO
));
2317 count
= ImmGetIMCCLockCount(imcc
);
2318 ok(count
== 0, "expect 0, returned %ld\n", count
);
2319 p
= ImmLockIMCC(imcc
);
2320 ok(p
!= NULL
, "ImmLockIMCC failed!\n");
2321 count
= ImmGetIMCCLockCount(imcc
);
2322 ok(count
== 1, "expect 1, returned %ld\n", count
);
2323 size
= ImmGetIMCCSize(imcc
);
2324 ok(size
== sizeof(CANDIDATEINFO
), "returned %ld\n", size
);
2325 p
= ImmDestroyIMCC(imcc
);
2326 ok(p
== NULL
, "Destroy a locked IMCC should success!\n");
2327 p
= ImmLockIMCC(imcc
);
2328 ok(p
== NULL
, "Lock a destroyed IMCC should fail!\n");
2329 ret
= ImmUnlockIMCC(imcc
);
2330 ok(ret
== FALSE
, "Unlock a destroyed IMCC should return FALSE!\n");
2331 count
= ImmGetIMCCLockCount(imcc
);
2332 ok(count
== 0, "Get lock count of a destroyed IMCC should return 0!\n");
2333 size
= ImmGetIMCCSize(imcc
);
2334 ok(size
== 0, "Get size of a destroyed IMCC should return 0!\n");
2335 SetLastError(0xdeadbeef);
2336 p
= ImmDestroyIMCC(imcc
);
2337 ok(p
!= NULL
, "returned NULL\n");
2338 ret
= GetLastError();
2339 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2342 static void test_ImmMessages(void)
2350 LPINPUTCONTEXT lpIMC
;
2351 LPTRANSMSG lpTransMsg
;
2353 HWND hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
2354 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
2355 240, 120, NULL
, NULL
, GetModuleHandleA(NULL
), NULL
);
2357 ShowWindow(hwnd
, SW_SHOWNORMAL
);
2358 defwnd
= ImmGetDefaultIMEWnd(hwnd
);
2359 imc
= ImmGetContext(hwnd
);
2361 ImmSetOpenStatus(imc
, TRUE
);
2362 msg_spy_flush_msgs();
2363 SendMessageA(defwnd
, WM_IME_CONTROL
, IMC_GETCANDIDATEPOS
, (LPARAM
)&cf
);
2366 msg
= msg_spy_find_next_msg(WM_IME_CONTROL
,&idx
);
2367 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
2369 msg_spy_flush_msgs();
2371 lpIMC
= ImmLockIMC(imc
);
2372 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
2373 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
2374 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
2375 lpTransMsg
->message
= WM_IME_STARTCOMPOSITION
;
2376 lpTransMsg
->wParam
= 0;
2377 lpTransMsg
->lParam
= 0;
2378 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
2379 lpIMC
->dwNumMsgBuf
++;
2381 ImmGenerateMessage(imc
);
2385 msg
= msg_spy_find_next_msg(WM_IME_STARTCOMPOSITION
, &idx
);
2386 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
2388 msg_spy_flush_msgs();
2390 lpIMC
= ImmLockIMC(imc
);
2391 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
2392 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
2393 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
2394 lpTransMsg
->message
= WM_IME_COMPOSITION
;
2395 lpTransMsg
->wParam
= 0;
2396 lpTransMsg
->lParam
= 0;
2397 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
2398 lpIMC
->dwNumMsgBuf
++;
2400 ImmGenerateMessage(imc
);
2404 msg
= msg_spy_find_next_msg(WM_IME_COMPOSITION
, &idx
);
2405 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
2407 msg_spy_flush_msgs();
2409 lpIMC
= ImmLockIMC(imc
);
2410 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
2411 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
2412 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
2413 lpTransMsg
->message
= WM_IME_ENDCOMPOSITION
;
2414 lpTransMsg
->wParam
= 0;
2415 lpTransMsg
->lParam
= 0;
2416 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
2417 lpIMC
->dwNumMsgBuf
++;
2419 ImmGenerateMessage(imc
);
2423 msg
= msg_spy_find_next_msg(WM_IME_ENDCOMPOSITION
, &idx
);
2424 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
2426 msg_spy_flush_msgs();
2428 ImmSetOpenStatus(imc
, FALSE
);
2429 ImmReleaseContext(hwnd
, imc
);
2430 DestroyWindow(hwnd
);
2433 static LRESULT CALLBACK
processkey_wnd_proc( HWND hWnd
, UINT msg
, WPARAM wParam
,
2436 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2439 static void test_ime_processkey(void)
2443 HANDLE hInstance
= GetModuleHandleW(NULL
);
2444 TEST_INPUT inputs
[2];
2449 wclass
.lpszClassName
= L
"ProcessKeyTestClass";
2450 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
2451 wclass
.lpfnWndProc
= processkey_wnd_proc
;
2452 wclass
.hInstance
= hInstance
;
2453 wclass
.hIcon
= LoadIconW(0, (LPCWSTR
)IDI_APPLICATION
);
2454 wclass
.hCursor
= LoadCursorW( NULL
, (LPCWSTR
)IDC_ARROW
);
2455 wclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
2456 wclass
.lpszMenuName
= 0;
2457 wclass
.cbClsExtra
= 0;
2458 wclass
.cbWndExtra
= 0;
2459 if(!RegisterClassW(&wclass
)){
2460 win_skip("Failed to register window.\n");
2464 /* create the test window that will receive the keystrokes */
2465 hWndTest
= CreateWindowW(wclass
.lpszClassName
, L
"ProcessKey",
2466 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0, 100, 100,
2467 NULL
, NULL
, hInstance
, NULL
);
2469 ShowWindow(hWndTest
, SW_SHOW
);
2470 SetWindowPos(hWndTest
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
2471 SetForegroundWindow(hWndTest
);
2472 UpdateWindow(hWndTest
);
2474 imc
= ImmGetContext(hWndTest
);
2477 win_skip("IME not supported\n");
2478 DestroyWindow(hWndTest
);
2482 rc
= ImmSetOpenStatus(imc
, TRUE
);
2485 win_skip("Unable to open IME\n");
2486 ImmReleaseContext(hWndTest
, imc
);
2487 DestroyWindow(hWndTest
);
2491 /* flush pending messages */
2492 while (PeekMessageW(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageW(&msg
);
2496 /* init input data that never changes */
2497 inputs
[1].type
= inputs
[0].type
= INPUT_KEYBOARD
;
2498 inputs
[1].u
.ki
.dwExtraInfo
= inputs
[0].u
.ki
.dwExtraInfo
= 0;
2499 inputs
[1].u
.ki
.time
= inputs
[0].u
.ki
.time
= 0;
2501 /* Pressing a key */
2502 inputs
[0].u
.ki
.wVk
= 0x41;
2503 inputs
[0].u
.ki
.wScan
= 0x1e;
2504 inputs
[0].u
.ki
.dwFlags
= 0x0;
2506 pSendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
2508 while(PeekMessageW(&msg
, hWndTest
, 0, 0, PM_NOREMOVE
)) {
2509 if(msg
.message
!= WM_KEYDOWN
)
2510 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
2513 ok(msg
.wParam
!= VK_PROCESSKEY
,"Incorrect ProcessKey Found\n");
2514 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
2515 if(msg
.wParam
== VK_PROCESSKEY
)
2516 trace("ProcessKey was correctly found\n");
2518 TranslateMessage(&msg
);
2519 /* test calling TranslateMessage multiple times */
2520 TranslateMessage(&msg
);
2521 DispatchMessageW(&msg
);
2524 inputs
[0].u
.ki
.wVk
= 0x41;
2525 inputs
[0].u
.ki
.wScan
= 0x1e;
2526 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_KEYUP
;
2528 pSendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
2530 while(PeekMessageW(&msg
, hWndTest
, 0, 0, PM_NOREMOVE
)) {
2531 if(msg
.message
!= WM_KEYUP
)
2532 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
2535 ok(msg
.wParam
!= VK_PROCESSKEY
,"Incorrect ProcessKey Found\n");
2536 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
2537 ok(msg
.wParam
!= VK_PROCESSKEY
,"ProcessKey should still not be Found\n");
2539 TranslateMessage(&msg
);
2540 DispatchMessageW(&msg
);
2543 ImmReleaseContext(hWndTest
, imc
);
2544 ImmSetOpenStatus(imc
, FALSE
);
2545 DestroyWindow(hWndTest
);
2548 static void test_InvalidIMC(void)
2551 HIMC imc_null
= 0x00000000;
2552 HIMC imc_bad
= (HIMC
)0xdeadcafe;
2554 HIMC imc1
, imc2
, oldimc
;
2562 memset(&lf
, 0, sizeof(lf
));
2564 imc_destroy
= ImmCreateContext();
2565 ret
= ImmDestroyContext(imc_destroy
);
2566 ok(ret
== TRUE
, "Destroy an IMC should success!\n");
2568 /* Test associating destroyed imc */
2569 imc1
= ImmGetContext(hwnd
);
2570 SetLastError(0xdeadbeef);
2571 oldimc
= ImmAssociateContext(hwnd
, imc_destroy
);
2572 ok(!oldimc
, "Associating to a destroyed imc should fail!\n");
2573 ret
= GetLastError();
2574 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2575 imc2
= ImmGetContext(hwnd
);
2576 ok(imc1
== imc2
, "imc should not changed! imc1 %p, imc2 %p\n", imc1
, imc2
);
2578 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, TRUE
);
2579 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, TRUE
);
2580 r
= ImmSetActiveContext(hwnd
, imc_destroy
, TRUE
);
2581 ok(!r
, "ImmSetActiveContext succeeded\n");
2582 SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE
);
2583 r
= ImmSetActiveContext(hwnd
, imc_destroy
, FALSE
);
2584 ok(r
, "ImmSetActiveContext failed\n");
2585 CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE
);
2586 SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE
, FALSE
);
2587 SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE
, FALSE
);
2589 /* Test associating NULL imc, which is different from an invalid imc */
2590 oldimc
= ImmAssociateContext(hwnd
, imc_null
);
2591 ok(oldimc
!= NULL
, "Associating to NULL imc should success!\n");
2592 imc2
= ImmGetContext(hwnd
);
2593 ok(!imc2
, "expect NULL, returned %p\n", imc2
);
2594 oldimc
= ImmAssociateContext(hwnd
, imc1
);
2595 ok(!oldimc
, "expect NULL, returned %p\n", oldimc
);
2596 imc2
= ImmGetContext(hwnd
);
2597 ok(imc2
== imc1
, "imc should not changed! imc2 %p, imc1 %p\n", imc2
, imc1
);
2599 /* Test associating invalid imc */
2600 imc1
= ImmGetContext(hwnd
);
2601 SetLastError(0xdeadbeef);
2602 oldimc
= ImmAssociateContext(hwnd
, imc_bad
);
2603 ok(!oldimc
, "Associating to a destroyed imc should fail!\n");
2604 ret
= GetLastError();
2605 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2606 imc2
= ImmGetContext(hwnd
);
2607 ok(imc1
== imc2
, "imc should not changed! imc1 %p, imc2 %p\n", imc1
, imc2
);
2610 /* Test ImmGetCandidateListA */
2611 SetLastError(0xdeadbeef);
2612 ret
= ImmGetCandidateListA(imc_bad
, 0, NULL
, 0);
2613 ok(ret
== 0, "Bad IME should return 0\n");
2614 ret
= GetLastError();
2615 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2616 SetLastError(0xdeadbeef);
2617 ret
= ImmGetCandidateListA(imc_null
, 0, NULL
, 0);
2618 ok(ret
== 0, "NULL IME should return 0\n");
2619 ret
= GetLastError();
2620 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2621 SetLastError(0xdeadbeef);
2622 ret
= ImmGetCandidateListA(imc_destroy
, 0, NULL
, 0);
2623 ok(ret
== 0, "Destroyed IME should return 0\n");
2624 ret
= GetLastError();
2625 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2627 /* Test ImmGetCandidateListCountA*/
2628 SetLastError(0xdeadbeef);
2629 ret
= ImmGetCandidateListCountA(imc_bad
,&count
);
2630 ok(ret
== 0, "Bad IME should return 0\n");
2631 ret
= GetLastError();
2632 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2633 SetLastError(0xdeadbeef);
2634 ret
= ImmGetCandidateListCountA(imc_null
,&count
);
2635 ok(ret
== 0, "NULL IME should return 0\n");
2636 ret
= GetLastError();
2637 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2638 SetLastError(0xdeadbeef);
2639 ret
= ImmGetCandidateListCountA(imc_destroy
,&count
);
2640 ok(ret
== 0, "Destroyed IME should return 0\n");
2641 ret
= GetLastError();
2642 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2644 /* Test ImmGetCandidateWindow */
2645 SetLastError(0xdeadbeef);
2646 ret
= ImmGetCandidateWindow(imc_bad
, 0, (LPCANDIDATEFORM
)buffer
);
2647 ok(ret
== 0, "Bad IME should return 0\n");
2648 ret
= GetLastError();
2649 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2650 SetLastError(0xdeadbeef);
2651 ret
= ImmGetCandidateWindow(imc_null
, 0, (LPCANDIDATEFORM
)buffer
);
2652 ok(ret
== 0, "NULL IME should return 0\n");
2653 ret
= GetLastError();
2654 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2655 SetLastError(0xdeadbeef);
2656 ret
= ImmGetCandidateWindow(imc_destroy
, 0, (LPCANDIDATEFORM
)buffer
);
2657 ok(ret
== 0, "Destroyed IME should return 0\n");
2658 ret
= GetLastError();
2659 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2661 /* Test ImmGetCompositionFontA */
2662 SetLastError(0xdeadbeef);
2663 ret
= ImmGetCompositionFontA(imc_bad
, (LPLOGFONTA
)buffer
);
2664 ok(ret
== 0, "Bad IME should return 0\n");
2665 ret
= GetLastError();
2666 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2667 SetLastError(0xdeadbeef);
2668 ret
= ImmGetCompositionFontA(imc_null
, (LPLOGFONTA
)buffer
);
2669 ok(ret
== 0, "NULL IME should return 0\n");
2670 ret
= GetLastError();
2671 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2672 SetLastError(0xdeadbeef);
2673 ret
= ImmGetCompositionFontA(imc_destroy
, (LPLOGFONTA
)buffer
);
2674 ok(ret
== 0, "Destroyed IME should return 0\n");
2675 ret
= GetLastError();
2676 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2678 /* Test ImmGetCompositionWindow */
2679 SetLastError(0xdeadbeef);
2680 ret
= ImmGetCompositionWindow(imc_bad
, (LPCOMPOSITIONFORM
)buffer
);
2681 ok(ret
== 0, "Bad IME should return 0\n");
2682 ret
= GetLastError();
2683 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2684 SetLastError(0xdeadbeef);
2685 ret
= ImmGetCompositionWindow(imc_null
, (LPCOMPOSITIONFORM
)buffer
);
2686 ok(ret
== 0, "NULL IME should return 0\n");
2687 ret
= GetLastError();
2688 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2689 SetLastError(0xdeadbeef);
2690 ret
= ImmGetCompositionWindow(imc_destroy
, (LPCOMPOSITIONFORM
)buffer
);
2691 ok(ret
== 0, "Destroyed IME should return 0\n");
2692 ret
= GetLastError();
2693 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2695 /* Test ImmGetCompositionStringA */
2696 SetLastError(0xdeadbeef);
2697 ret
= ImmGetCompositionStringA(imc_bad
, GCS_COMPSTR
, NULL
, 0);
2698 ok(ret
== 0, "Bad IME should return 0\n");
2699 ret
= GetLastError();
2700 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2701 SetLastError(0xdeadbeef);
2702 ret
= ImmGetCompositionStringA(imc_null
, GCS_COMPSTR
, NULL
, 0);
2703 ok(ret
== 0, "NULL IME should return 0\n");
2704 ret
= GetLastError();
2705 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2706 SetLastError(0xdeadbeef);
2707 ret
= ImmGetCompositionStringA(imc_destroy
, GCS_COMPSTR
, NULL
, 0);
2708 ok(ret
== 0, "Destroyed IME should return 0\n");
2709 ret
= GetLastError();
2710 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2712 /* Test ImmSetOpenStatus */
2713 SetLastError(0xdeadbeef);
2714 ret
= ImmSetOpenStatus(imc_bad
, 1);
2715 ok(ret
== 0, "Bad IME should return 0\n");
2716 ret
= GetLastError();
2717 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2718 SetLastError(0xdeadbeef);
2719 ret
= ImmSetOpenStatus(imc_null
, 1);
2720 ok(ret
== 0, "NULL IME should return 0\n");
2721 ret
= GetLastError();
2722 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2723 SetLastError(0xdeadbeef);
2724 ret
= ImmSetOpenStatus(imc_destroy
, 1);
2725 ok(ret
== 0, "Destroyed IME should return 0\n");
2726 ret
= GetLastError();
2727 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2729 /* Test ImmGetOpenStatus */
2730 SetLastError(0xdeadbeef);
2731 ret
= ImmGetOpenStatus(imc_bad
);
2732 ok(ret
== 0, "Bad IME should return 0\n");
2733 ret
= GetLastError();
2734 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2735 SetLastError(0xdeadbeef);
2736 ret
= ImmGetOpenStatus(imc_null
);
2737 ok(ret
== 0, "NULL IME should return 0\n");
2738 ret
= GetLastError();
2739 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2740 SetLastError(0xdeadbeef);
2741 ret
= ImmGetOpenStatus(imc_destroy
);
2742 ok(ret
== 0, "Destroyed IME should return 0\n");
2743 ret
= GetLastError();
2744 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2746 /* Test ImmGetStatusWindowPos */
2747 SetLastError(0xdeadbeef);
2748 ret
= ImmGetStatusWindowPos(imc_bad
, NULL
);
2749 ok(ret
== 0, "Bad IME should return 0\n");
2750 ret
= GetLastError();
2751 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2752 SetLastError(0xdeadbeef);
2753 ret
= ImmGetStatusWindowPos(imc_null
, NULL
);
2754 ok(ret
== 0, "NULL IME should return 0\n");
2755 ret
= GetLastError();
2756 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2757 SetLastError(0xdeadbeef);
2758 ret
= ImmGetStatusWindowPos(imc_destroy
, NULL
);
2759 ok(ret
== 0, "Destroyed IME should return 0\n");
2760 ret
= GetLastError();
2761 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2763 /* Test ImmRequestMessageA */
2764 SetLastError(0xdeadbeef);
2765 ret
= ImmRequestMessageA(imc_bad
, WM_CHAR
, 0);
2766 ok(ret
== 0, "Bad IME should return 0\n");
2767 ret
= GetLastError();
2768 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2769 SetLastError(0xdeadbeef);
2770 ret
= ImmRequestMessageA(imc_null
, WM_CHAR
, 0);
2771 ok(ret
== 0, "NULL IME should return 0\n");
2772 ret
= GetLastError();
2773 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2774 SetLastError(0xdeadbeef);
2775 ret
= ImmRequestMessageA(imc_destroy
, WM_CHAR
, 0);
2776 ok(ret
== 0, "Destroyed IME should return 0\n");
2777 ret
= GetLastError();
2778 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2780 /* Test ImmSetCompositionFontA */
2781 SetLastError(0xdeadbeef);
2782 ret
= ImmSetCompositionFontA(imc_bad
, &lf
);
2783 ok(ret
== 0, "Bad IME should return 0\n");
2784 ret
= GetLastError();
2785 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2786 SetLastError(0xdeadbeef);
2787 ret
= ImmSetCompositionFontA(imc_null
, &lf
);
2788 ok(ret
== 0, "NULL IME should return 0\n");
2789 ret
= GetLastError();
2790 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2791 SetLastError(0xdeadbeef);
2792 ret
= ImmSetCompositionFontA(imc_destroy
, &lf
);
2793 ok(ret
== 0, "Destroyed IME should return 0\n");
2794 ret
= GetLastError();
2795 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2797 /* Test ImmSetCompositionWindow */
2798 SetLastError(0xdeadbeef);
2799 ret
= ImmSetCompositionWindow(imc_bad
, NULL
);
2800 ok(ret
== 0, "Bad IME should return 0\n");
2801 ret
= GetLastError();
2802 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2803 SetLastError(0xdeadbeef);
2804 ret
= ImmSetCompositionWindow(imc_null
, NULL
);
2805 ok(ret
== 0, "NULL IME should return 0\n");
2806 ret
= GetLastError();
2807 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2808 SetLastError(0xdeadbeef);
2809 ret
= ImmSetCompositionWindow(imc_destroy
, NULL
);
2810 ok(ret
== 0, "Destroyed IME should return 0\n");
2811 ret
= GetLastError();
2812 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2814 /* Test ImmSetConversionStatus */
2815 SetLastError(0xdeadbeef);
2816 ret
= ImmSetConversionStatus(imc_bad
, 0, 0);
2817 ok(ret
== 0, "Bad IME should return 0\n");
2818 ret
= GetLastError();
2819 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2820 SetLastError(0xdeadbeef);
2821 ret
= ImmSetConversionStatus(imc_null
, 0, 0);
2822 ok(ret
== 0, "NULL IME should return 0\n");
2823 ret
= GetLastError();
2824 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2825 SetLastError(0xdeadbeef);
2826 ret
= ImmSetConversionStatus(imc_destroy
, 0, 0);
2827 ok(ret
== 0, "Destroyed IME should return 0\n");
2828 ret
= GetLastError();
2829 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2831 /* Test ImmSetStatusWindowPos */
2832 SetLastError(0xdeadbeef);
2833 ret
= ImmSetStatusWindowPos(imc_bad
, 0);
2834 ok(ret
== 0, "Bad IME should return 0\n");
2835 ret
= GetLastError();
2836 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2837 SetLastError(0xdeadbeef);
2838 ret
= ImmSetStatusWindowPos(imc_null
, 0);
2839 ok(ret
== 0, "NULL IME should return 0\n");
2840 ret
= GetLastError();
2841 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2842 SetLastError(0xdeadbeef);
2843 ret
= ImmSetStatusWindowPos(imc_destroy
, 0);
2844 ok(ret
== 0, "Destroyed IME should return 0\n");
2845 ret
= GetLastError();
2846 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2848 /* Test ImmGetImeMenuItemsA */
2849 SetLastError(0xdeadbeef);
2850 ret
= ImmGetImeMenuItemsA(imc_bad
, 0, 0, NULL
, NULL
, 0);
2851 ok(ret
== 0, "Bad IME should return 0\n");
2852 ret
= GetLastError();
2853 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2854 SetLastError(0xdeadbeef);
2855 ret
= ImmGetImeMenuItemsA(imc_null
, 0, 0, NULL
, NULL
, 0);
2856 ok(ret
== 0, "NULL IME should return 0\n");
2857 ret
= GetLastError();
2858 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2859 SetLastError(0xdeadbeef);
2860 ret
= ImmGetImeMenuItemsA(imc_destroy
, 0, 0, NULL
, NULL
, 0);
2861 ok(ret
== 0, "Destroyed IME should return 0\n");
2862 ret
= GetLastError();
2863 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2865 /* Test ImmLockIMC */
2866 SetLastError(0xdeadbeef);
2867 ic
= ImmLockIMC(imc_bad
);
2868 ok(ic
== 0, "Bad IME should return 0\n");
2869 ret
= GetLastError();
2870 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2871 SetLastError(0xdeadbeef);
2872 ic
= ImmLockIMC(imc_null
);
2873 ok(ic
== 0, "NULL IME should return 0\n");
2874 ret
= GetLastError();
2875 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2876 SetLastError(0xdeadbeef);
2877 ic
= ImmLockIMC(imc_destroy
);
2878 ok(ic
== 0, "Destroyed IME should return 0\n");
2879 ret
= GetLastError();
2880 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2882 /* Test ImmUnlockIMC */
2883 SetLastError(0xdeadbeef);
2884 ret
= ImmUnlockIMC(imc_bad
);
2885 ok(ret
== 0, "Bad IME should return 0\n");
2886 ret
= GetLastError();
2887 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2888 SetLastError(0xdeadbeef);
2889 ret
= ImmUnlockIMC(imc_null
);
2890 ok(ret
== 0, "NULL IME should return 0\n");
2891 ret
= GetLastError();
2892 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08lx!\n", ret
);
2893 SetLastError(0xdeadbeef);
2894 ret
= ImmUnlockIMC(imc_destroy
);
2895 ok(ret
== 0, "Destroyed IME should return 0\n");
2896 ret
= GetLastError();
2897 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2899 /* Test ImmGenerateMessage */
2900 SetLastError(0xdeadbeef);
2901 ret
= ImmGenerateMessage(imc_bad
);
2902 ok(ret
== 0, "Bad IME should return 0\n");
2903 ret
= GetLastError();
2904 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2905 SetLastError(0xdeadbeef);
2906 ret
= ImmGenerateMessage(imc_null
);
2907 ok(ret
== 0, "NULL IME should return 0\n");
2908 ret
= GetLastError();
2909 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2910 SetLastError(0xdeadbeef);
2911 ret
= ImmGenerateMessage(imc_destroy
);
2912 ok(ret
== 0, "Destroyed IME should return 0\n");
2913 ret
= GetLastError();
2914 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08lx!\n", ret
);
2917 #define test_apttype(apttype) _test_apttype(apttype, __LINE__)
2918 static void _test_apttype(APTTYPE apttype
, unsigned int line
)
2920 APTTYPEQUALIFIER qualifier
;
2921 HRESULT hr
, hr_expected
;
2924 hr
= CoGetApartmentType(&type
, &qualifier
);
2925 hr_expected
= (apttype
== -1 ? CO_E_NOTINITIALIZED
: S_OK
);
2926 ok_(__FILE__
, line
)(hr
== hr_expected
, "CoGetApartmentType returned %lx\n", hr
);
2930 ok_(__FILE__
, line
)(type
== apttype
, "type %x\n", type
);
2931 ok_(__FILE__
, line
)(!qualifier
, "qualifier %x\n", qualifier
);
2934 static DWORD WINAPI
com_initialization_thread(void *arg
)
2940 ImmDisableIME(GetCurrentThreadId());
2941 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2942 ok(r
, "ImmSetActiveContext failed\n");
2943 test_apttype(APTTYPE_MAINSTA
);
2944 hr
= CoInitialize(NULL
);
2945 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
2949 /* Changes IMM behavior so it no longer initialized COM */
2950 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2951 ok(r
, "ImmSetActiveContext failed\n");
2952 test_apttype(APTTYPE_MAINSTA
);
2953 hr
= CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
2954 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
2955 test_apttype(APTTYPE_MTA
);
2958 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2959 ok(r
, "ImmSetActiveContext failed\n");
2964 static void test_com_initialization(void)
2966 APTTYPEQUALIFIER qualifier
;
2973 thread
= CreateThread(NULL
, 0, com_initialization_thread
, NULL
, 0, NULL
);
2974 ok(thread
!= NULL
, "CreateThread failed\n");
2975 WaitForSingleObject(thread
, INFINITE
);
2976 CloseHandle(thread
);
2979 r
= ImmSetActiveContext(NULL
, (HIMC
)0xdeadbeef, TRUE
);
2980 ok(!r
, "ImmSetActiveContext succeeded\n");
2983 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2984 ok(r
, "ImmSetActiveContext failed\n");
2985 test_apttype(APTTYPE_MAINSTA
);
2987 /* Force default IME window destruction */
2988 wnd
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
2989 ok(wnd
!= NULL
, "CreateWindow failed\n");
2993 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
2994 ok(r
, "ImmSetActiveContext failed\n");
2995 test_apttype(APTTYPE_MAINSTA
);
2996 hr
= CoInitialize(NULL
);
2997 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
3001 /* Test with default IME window created */
3002 wnd
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
3003 ok(wnd
!= NULL
, "CreateWindow failed\n");
3005 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
3006 ok(r
, "ImmSetActiveContext failed\n");
3007 test_apttype(APTTYPE_MAINSTA
);
3008 hr
= CoInitialize(NULL
);
3009 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
3011 test_apttype(APTTYPE_MAINSTA
);
3015 wnd
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
3016 ok(wnd
!= NULL
, "CreateWindow failed\n");
3017 r
= ImmSetActiveContext(NULL
, NULL
, TRUE
);
3019 hr
= CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
3020 ok(hr
== S_OK
, "CoInitialize returned %lx\n", hr
);
3021 test_apttype(APTTYPE_MTA
);
3024 hr
= CoGetApartmentType(&type
, &qualifier
);
3025 ok(hr
== CO_E_NOTINITIALIZED
|| broken(hr
== S_OK
) /* w10v22H2 */,
3026 "CoGetApartmentType returned %#lx\n", hr
);
3027 test_apttype(hr
== S_OK
? APTTYPE_MTA
: -1);
3029 wnd
= CreateWindowA("static", "static", WS_POPUP
, 0, 0, 100, 100, 0, 0, 0, 0);
3030 ok(wnd
!= NULL
, "CreateWindow failed\n");
3031 test_apttype(hr
== S_OK
? APTTYPE_MTA
: -1);
3032 ShowWindow(wnd
, SW_SHOW
);
3033 test_apttype(hr
== S_OK
? APTTYPE_MTA
: APTTYPE_MAINSTA
);
3038 static DWORD WINAPI
disable_ime_thread(void *arg
)
3044 h
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
3045 ok(h
!= NULL
, "CreateWindow failed\n");
3046 def
= ImmGetDefaultIMEWnd(h
);
3047 ok(def
!= NULL
, "ImmGetDefaultIMEWnd returned NULL\n");
3049 r
= ImmDisableIME(arg
? GetCurrentThreadId() : 0);
3050 ok(r
, "ImmDisableIME failed\n");
3054 def
= ImmGetDefaultIMEWnd(h
);
3055 todo_wine
ok(def
!= NULL
, "ImmGetDefaultIMEWnd returned NULL\n");
3056 while(PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
3057 DispatchMessageA(&msg
);
3059 def
= ImmGetDefaultIMEWnd(h
);
3060 ok(!def
, "ImmGetDefaultIMEWnd returned %p\n", def
);
3064 static DWORD WINAPI
check_not_disabled_ime_thread(void *arg
)
3068 WaitForSingleObject(arg
, INFINITE
);
3069 hwnd
= CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
3070 ok(hwnd
!= NULL
, "CreateWindow failed\n");
3071 def
= ImmGetDefaultIMEWnd(hwnd
);
3072 ok(def
!= NULL
, "ImmGetDefaultIMEWnd returned %p\n", def
);
3076 static DWORD WINAPI
disable_ime_process(void *arg
)
3078 BOOL r
= ImmDisableIME(-1);
3079 ok(r
, "ImmDisableIME failed\n");
3083 static void test_ImmDisableIME(void)
3085 HANDLE thread
, event
;
3090 def
= ImmGetDefaultIMEWnd(hwnd
);
3091 ok(def
!= NULL
, "ImmGetDefaultIMEWnd(hwnd) returned NULL\n");
3093 event
= CreateEventW(NULL
, TRUE
, FALSE
, FALSE
);
3094 thread
= CreateThread(NULL
, 0, check_not_disabled_ime_thread
, event
, 0, &tid
);
3095 ok(thread
!= NULL
, "CreateThread failed\n");
3096 r
= ImmDisableIME(tid
);
3097 ok(!r
, "ImmDisableIME(tid) succeeded\n");
3099 WaitForSingleObject(thread
, INFINITE
);
3100 CloseHandle(thread
);
3103 thread
= CreateThread(NULL
, 0, disable_ime_thread
, 0, 0, NULL
);
3104 ok(thread
!= NULL
, "CreateThread failed\n");
3105 WaitForSingleObject(thread
, INFINITE
);
3106 CloseHandle(thread
);
3108 thread
= CreateThread(NULL
, 0, disable_ime_thread
, (void*)1, 0, NULL
);
3109 ok(thread
!= NULL
, "CreateThread failed\n");
3110 WaitForSingleObject(thread
, INFINITE
);
3111 CloseHandle(thread
);
3113 msg_spy_pump_msg_queue();
3114 thread
= CreateThread(NULL
, 0, disable_ime_process
, 0, 0, NULL
);
3115 ok(thread
!= NULL
, "CreateThread failed\n");
3116 WaitForSingleObject(thread
, INFINITE
);
3117 CloseHandle(thread
);
3119 ok(IsWindow(def
), "not a window\n");
3120 def2
= ImmGetDefaultIMEWnd(hwnd
);
3121 ok(def2
== def
, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def2
);
3122 ok(IsWindow(def
), "not a window\n");
3123 msg_spy_pump_msg_queue();
3124 ok(!IsWindow(def
), "window is still valid\n");
3125 def
= ImmGetDefaultIMEWnd(hwnd
);
3126 ok(!def
, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def
);
3128 r
= ImmDisableIME(-1);
3129 ok(r
, "ImmDisableIME(-1) failed\n");
3130 def
= ImmGetDefaultIMEWnd(hwnd
);
3131 ok(!def
, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def
);
3134 static BOOL WINAPI
ime_ImeConfigure( HKL hkl
, HWND hwnd
, DWORD mode
, void *data
)
3136 ime_trace( "hkl %p, hwnd %p, mode %lu, data %p\n", hkl
, hwnd
, mode
, data
);
3137 ok( 0, "unexpected call\n" );
3141 static DWORD WINAPI
ime_ImeConversionList( HIMC himc
, const WCHAR
*source
, CANDIDATELIST
*dest
,
3142 DWORD dest_len
, UINT flag
)
3144 ime_trace( "himc %p, source %s, dest %p, dest_len %lu, flag %#x\n",
3145 himc
, debugstr_w(source
), dest
, dest_len
, flag
);
3146 ok( 0, "unexpected call\n" );
3150 static BOOL WINAPI
ime_ImeDestroy( UINT force
)
3152 ime_trace( "force %u\n", force
);
3154 todo_wine_if( todo_ImeDestroy
)
3155 CHECK_EXPECT( ImeDestroy
);
3157 ok( !force
, "got force %u\n", force
);
3162 static UINT WINAPI
ime_ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc
, const WCHAR
*reading
, DWORD style
,
3163 const WCHAR
*string
, void *data
)
3165 ime_trace( "proc %p, reading %s, style %lu, string %s, data %p\n",
3166 proc
, debugstr_w(reading
), style
, debugstr_w(string
), data
);
3168 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
3169 CHECK_EXPECT( ImeEnumRegisterWord
);
3173 ok_eq( 0, reading
, const void *, "%p" );
3174 ok_eq( 0, string
, const void *, "%p" );
3176 else if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
3178 ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
3179 ok_wcs( L
"Reading", reading
);
3180 ok_wcs( L
"String", string
);
3184 ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
3185 ok_str( "Reading", (char *)reading
);
3186 ok_str( "String", (char *)string
);
3189 if (style
) return proc( reading
, style
, string
, data
);
3193 static LRESULT WINAPI
ime_ImeEscape( HIMC himc
, UINT escape
, void *data
)
3195 ime_trace( "himc %p, escape %#x, data %p\n", himc
, escape
, data
);
3197 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
3198 CHECK_EXPECT( ImeEscape
);
3202 case IME_ESC_SET_EUDC_DICTIONARY
:
3203 if (!data
) return 4;
3204 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
3205 ok_wcs( L
"EscapeIme", data
);
3207 ok_str( "EscapeIme", data
);
3209 case IME_ESC_QUERY_SUPPORT
:
3210 case IME_ESC_SEQUENCE_TO_INTERNAL
:
3211 case IME_ESC_GET_EUDC_DICTIONARY
:
3212 case IME_ESC_MAX_KEY
:
3213 case IME_ESC_IME_NAME
:
3214 case IME_ESC_HANJA_MODE
:
3215 case IME_ESC_GETHELPFILENAME
:
3216 if (!data
) return 4;
3217 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
) wcscpy( data
, L
"ImeEscape" );
3218 else strcpy( data
, "ImeEscape" );
3222 ok_eq( 0xdeadbeef, escape
, UINT
, "%#x" );
3223 ok_eq( NULL
, data
, void *, "%p" );
3228 static DWORD WINAPI
ime_ImeGetImeMenuItems( HIMC himc
, DWORD flags
, DWORD type
, IMEMENUITEMINFOW
*parent
,
3229 IMEMENUITEMINFOW
*menu
, DWORD size
)
3231 ime_trace( "himc %p, flags %#lx, type %lu, parent %p, menu %p, size %#lx\n",
3232 himc
, flags
, type
, parent
, menu
, size
);
3233 ok( 0, "unexpected call\n" );
3237 static UINT WINAPI
ime_ImeGetRegisterWordStyle( UINT item
, STYLEBUFW
*style
)
3239 ime_trace( "item %u, style %p\n", item
, style
);
3241 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
3242 CHECK_EXPECT( ImeGetRegisterWordStyle
);
3245 ok_eq( 16, item
, UINT
, "%u" );
3246 else if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
3248 STYLEBUFW
*styleW
= style
;
3249 styleW
->dwStyle
= 0xdeadbeef;
3250 wcscpy( styleW
->szDescription
, L
"StyleDescription" );
3254 STYLEBUFA
*styleA
= (STYLEBUFA
*)style
;
3255 styleA
->dwStyle
= 0xdeadbeef;
3256 strcpy( styleA
->szDescription
, "StyleDescription" );
3262 static BOOL WINAPI
ime_ImeInquire( IMEINFO
*info
, WCHAR
*ui_class
, DWORD flags
)
3264 ime_trace( "info %p, ui_class %p, flags %#lx\n", info
, ui_class
, flags
);
3266 todo_wine_if( todo_ImeInquire
)
3267 CHECK_EXPECT( ImeInquire
);
3269 ok( !!info
, "got info %p\n", info
);
3270 ok( !!ui_class
, "got ui_class %p\n", ui_class
);
3271 ok( !flags
, "got flags %#lx\n", flags
);
3275 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
3276 wcscpy( ui_class
, ime_ui_class
.lpszClassName
);
3278 WideCharToMultiByte( CP_ACP
, 0, ime_ui_class
.lpszClassName
, -1,
3279 (char *)ui_class
, 17, NULL
, NULL
);
3284 static BOOL WINAPI
ime_ImeProcessKey( HIMC himc
, UINT vkey
, LPARAM lparam
, BYTE
*state
)
3286 struct ime_call call
=
3288 .hkl
= GetKeyboardLayout( 0 ), .himc
= himc
,
3289 .func
= IME_PROCESS_KEY
, .process_key
= {.vkey
= vkey
, .lparam
= lparam
}
3291 ime_trace( "himc %p, vkey %u, lparam %#Ix, state %p\n",
3292 himc
, vkey
, lparam
, state
);
3293 ime_calls
[ime_call_count
++] = call
;
3294 return LOWORD(lparam
);
3297 static BOOL WINAPI
ime_ImeRegisterWord( const WCHAR
*reading
, DWORD style
, const WCHAR
*string
)
3299 ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading
), style
, debugstr_w(string
) );
3301 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
3302 CHECK_EXPECT( ImeRegisterWord
);
3304 if (style
) ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
3305 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
3307 if (reading
) ok_wcs( L
"Reading", reading
);
3308 if (string
) ok_wcs( L
"String", string
);
3312 if (reading
) ok_str( "Reading", (char *)reading
);
3313 if (string
) ok_str( "String", (char *)string
);
3319 static BOOL WINAPI
ime_ImeSelect( HIMC himc
, BOOL select
)
3321 struct ime_call call
=
3323 .hkl
= GetKeyboardLayout( 0 ), .himc
= himc
,
3324 .func
= IME_SELECT
, .select
= select
3328 ime_trace( "himc %p, select %d\n", himc
, select
);
3329 ime_calls
[ime_call_count
++] = call
;
3331 if (ImeSelect_init_status
&& select
)
3333 ctx
= ImmLockIMC( himc
);
3334 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
3336 ctx
->fdwConversion
= ~0;
3337 ctx
->fdwSentence
= ~0;
3338 ImmUnlockIMC( himc
);
3344 static BOOL WINAPI
ime_ImeSetActiveContext( HIMC himc
, BOOL flag
)
3346 struct ime_call call
=
3348 .hkl
= GetKeyboardLayout( 0 ), .himc
= himc
,
3349 .func
= IME_SET_ACTIVE_CONTEXT
, .set_active_context
= {.flag
= flag
}
3351 ime_trace( "himc %p, flag %#x\n", himc
, flag
);
3352 ime_calls
[ime_call_count
++] = call
;
3356 static BOOL WINAPI
ime_ImeSetCompositionString( HIMC himc
, DWORD index
, const void *comp
, DWORD comp_len
,
3357 const void *read
, DWORD read_len
)
3359 ime_trace( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu\n",
3360 himc
, index
, comp
, comp_len
, read
, read_len
);
3361 CHECK_EXPECT( ImeSetCompositionString
);
3363 ok_eq( expect_ime
, GetKeyboardLayout( 0 ), HKL
, "%p" );
3364 ok_ne( default_himc
, himc
, HIMC
, "%p" );
3366 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
3371 todo_wine_if( todo_ImeSetCompositionString
)
3372 ok_eq( 22, comp_len
, UINT
, "%#x" );
3373 ok_wcs( L
"CompString", comp
);
3375 case SCS_CHANGECLAUSE
:
3377 const UINT
*clause
= comp
;
3378 ok_eq( 8, comp_len
, UINT
, "%#x" );
3379 ok_eq( 0, clause
[0], UINT
, "%#x" );
3380 todo_wine_if( todo_ImeSetCompositionString
)
3381 ok_eq( 1, clause
[1], UINT
, "%#x");
3384 case SCS_CHANGEATTR
:
3386 const BYTE
*attr
= comp
;
3387 todo_wine_if( todo_ImeSetCompositionString
&& comp_len
!= 4 )
3388 ok_eq( 4, comp_len
, UINT
, "%#x" );
3389 todo_wine_if( todo_ImeSetCompositionString
&& attr
[0] != 0xcd )
3390 ok_eq( 0xcd, attr
[0], UINT
, "%#x" );
3391 todo_wine_if( todo_ImeSetCompositionString
)
3392 ok_eq( 0xcd, attr
[1], UINT
, "%#x" );
3396 ok( 0, "unexpected index %#lx\n", index
);
3405 todo_wine_if( todo_ImeSetCompositionString
)
3406 ok_eq( 11, comp_len
, UINT
, "%#x" );
3407 ok_str( "CompString", comp
);
3409 case SCS_CHANGECLAUSE
:
3411 const UINT
*clause
= comp
;
3412 ok_eq( 8, comp_len
, UINT
, "%#x" );
3413 todo_wine_if( todo_ImeSetCompositionString
)
3414 ok_eq( 0, clause
[0], UINT
, "%#x" );
3415 todo_wine_if( todo_ImeSetCompositionString
)
3416 ok_eq( 1, clause
[1], UINT
, "%#x");
3419 case SCS_CHANGEATTR
:
3421 const BYTE
*attr
= comp
;
3422 todo_wine_if( todo_ImeSetCompositionString
&& comp_len
!= 4 )
3423 ok_eq( 4, comp_len
, UINT
, "%#x" );
3424 todo_wine_if( todo_ImeSetCompositionString
)
3425 ok_eq( 0xcd, attr
[0], UINT
, "%#x" );
3426 todo_wine_if( todo_ImeSetCompositionString
)
3427 ok_eq( 0xcd, attr
[1], UINT
, "%#x" );
3431 ok( 0, "unexpected index %#lx\n", index
);
3436 ok_eq( NULL
, read
, const void *, "%p" );
3437 ok_eq( 0, read_len
, UINT
, "%#x" );
3442 static UINT WINAPI
ime_ImeToAsciiEx( UINT vkey
, UINT vsc
, BYTE
*state
, TRANSMSGLIST
*msgs
, UINT flags
, HIMC himc
)
3444 struct ime_call call
=
3446 .hkl
= GetKeyboardLayout( 0 ), .himc
= himc
,
3447 .func
= IME_TO_ASCII_EX
, .to_ascii_ex
= {.vkey
= vkey
, .vsc
= vsc
, .flags
= flags
}
3452 ime_trace( "vkey %#x, vsc %#x, state %p, msgs %p, flags %#x, himc %p\n",
3453 vkey
, vsc
, state
, msgs
, flags
, himc
);
3454 ime_calls
[ime_call_count
++] = call
;
3456 ok_ne( NULL
, msgs
, TRANSMSGLIST
*, "%p" );
3457 todo_wine
ok_eq( 256, msgs
->uMsgCount
, UINT
, "%u" );
3459 ctx
= ImmLockIMC( himc
);
3460 todo_wine
ok_ret( VK_PROCESSKEY
, ImmGetVirtualKey( ctx
->hWnd
) );
3464 msgs
->TransMsg
[0].message
= WM_IME_STARTCOMPOSITION
;
3465 msgs
->TransMsg
[0].wParam
= 1;
3466 msgs
->TransMsg
[0].lParam
= 0;
3468 msgs
->TransMsg
[1].message
= WM_IME_ENDCOMPOSITION
;
3469 msgs
->TransMsg
[1].wParam
= 1;
3470 msgs
->TransMsg
[1].lParam
= 0;
3478 ctx
= ImmLockIMC( himc
);
3479 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
3481 ok_ne( NULL
, ctx
->hMsgBuf
, HIMCC
, "%p" );
3482 ok_eq( 0, ctx
->dwNumMsgBuf
, UINT
, "%u" );
3484 ctx
->hMsgBuf
= ImmReSizeIMCC( ctx
->hMsgBuf
, 64 * sizeof(*msgs
) );
3485 ok_ne( NULL
, ctx
->hMsgBuf
, HIMCC
, "%p" );
3487 msgs
= ImmLockIMCC( ctx
->hMsgBuf
);
3488 ok_ne( NULL
, msgs
, TRANSMSG
*, "%p" );
3490 msgs
[ctx
->dwNumMsgBuf
].message
= WM_IME_STARTCOMPOSITION
;
3491 msgs
[ctx
->dwNumMsgBuf
].wParam
= 2;
3492 msgs
[ctx
->dwNumMsgBuf
].lParam
= 0;
3494 msgs
[ctx
->dwNumMsgBuf
].message
= WM_IME_ENDCOMPOSITION
;
3495 msgs
[ctx
->dwNumMsgBuf
].wParam
= 2;
3496 msgs
[ctx
->dwNumMsgBuf
].lParam
= 0;
3499 ok_ret( 0, ImmUnlockIMCC( ctx
->hMsgBuf
) );
3502 ok_ret( 1, ImmUnlockIMC( himc
) );
3504 if (vsc
& 0x800) count
= ~0;
3508 static BOOL WINAPI
ime_ImeUnregisterWord( const WCHAR
*reading
, DWORD style
, const WCHAR
*string
)
3510 ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading
), style
, debugstr_w(string
) );
3512 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
3513 CHECK_EXPECT( ImeUnregisterWord
);
3515 if (style
) ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
3516 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
3518 if (reading
) ok_wcs( L
"Reading", reading
);
3519 if (string
) ok_wcs( L
"String", string
);
3523 if (reading
) ok_str( "Reading", (char *)reading
);
3524 if (string
) ok_str( "String", (char *)string
);
3530 static BOOL WINAPI
ime_NotifyIME( HIMC himc
, DWORD action
, DWORD index
, DWORD value
)
3532 struct ime_call call
=
3534 .hkl
= GetKeyboardLayout( 0 ), .himc
= himc
,
3535 .func
= IME_NOTIFY
, .notify
= {.action
= action
, .index
= index
, .value
= value
}
3537 ime_trace( "himc %p, action %#lx, index %lu, value %lu\n", himc
, action
, index
, value
);
3538 ime_calls
[ime_call_count
++] = call
;
3542 static BOOL WINAPI
ime_DllMain( HINSTANCE instance
, DWORD reason
, LPVOID reserved
)
3544 ime_trace( "instance %p, reason %lu, reserved %p.\n", instance
, reason
, reserved
);
3548 case DLL_PROCESS_ATTACH
:
3549 DisableThreadLibraryCalls( instance
);
3550 ime_ui_class
.hInstance
= instance
;
3551 RegisterClassExW( &ime_ui_class
);
3552 todo_wine_if(todo_IME_DLL_PROCESS_ATTACH
)
3553 CHECK_EXPECT( IME_DLL_PROCESS_ATTACH
);
3556 case DLL_PROCESS_DETACH
:
3557 UnregisterClassW( ime_ui_class
.lpszClassName
, instance
);
3558 todo_wine_if(todo_IME_DLL_PROCESS_DETACH
)
3559 CHECK_EXPECT( IME_DLL_PROCESS_DETACH
);
3566 static struct ime_functions ime_functions
=
3569 ime_ImeConversionList
,
3571 ime_ImeEnumRegisterWord
,
3573 ime_ImeGetImeMenuItems
,
3574 ime_ImeGetRegisterWordStyle
,
3577 ime_ImeRegisterWord
,
3579 ime_ImeSetActiveContext
,
3580 ime_ImeSetCompositionString
,
3582 ime_ImeUnregisterWord
,
3587 static HKL
ime_install(void)
3589 WCHAR buffer
[MAX_PATH
];
3595 /* IME module gets cached and won't reload from disk as soon as a window has
3596 * loaded it. To workaround the issue we load the module first as a DLL,
3597 * set its function pointers from the test, and later when the cached IME
3598 * gets loaded, read the function pointers from the separately loaded DLL.
3601 load_resource( L
"ime_wrapper.dll", buffer
);
3603 SetLastError( 0xdeadbeef );
3604 ret
= MoveFileW( buffer
, L
"c:\\windows\\system32\\winetest_ime.dll" );
3607 ok( GetLastError() == ERROR_ACCESS_DENIED
, "got error %lu\n", GetLastError() );
3608 win_skip( "Failed to copy DLL to system directory\n" );
3612 module
= LoadLibraryW( L
"c:\\windows\\system32\\winetest_ime.dll" );
3613 ok( !!module
, "LoadLibraryW failed, error %lu\n", GetLastError() );
3614 *(struct ime_functions
*)GetProcAddress( module
, "ime_functions" ) = ime_functions
;
3616 /* install the actual IME module, it will lookup the functions from the DLL */
3617 load_resource( L
"ime_wrapper.dll", buffer
);
3619 SetLastError( 0xdeadbeef );
3620 swprintf( ime_path
, ARRAY_SIZE(ime_path
), L
"c:\\windows\\system32\\wine%04x.ime", ime_count
++ );
3621 ret
= MoveFileW( buffer
, ime_path
);
3622 todo_wine_if( GetLastError() == ERROR_ALREADY_EXISTS
)
3623 ok( ret
|| broken( !ret
) /* sometimes still in use */,
3624 "MoveFileW failed, error %lu\n", GetLastError() );
3626 hkl
= ImmInstallIMEW( ime_path
, L
"WineTest IME" );
3627 ok( hkl
== expect_ime
, "ImmInstallIMEW returned %p, error %lu\n", hkl
, GetLastError() );
3629 swprintf( buffer
, ARRAY_SIZE(buffer
), L
"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl
);
3630 ret
= RegOpenKeyW( HKEY_LOCAL_MACHINE
, buffer
, &hkey
);
3631 ok( !ret
, "RegOpenKeyW returned %#lx, error %lu\n", ret
, GetLastError() );
3633 len
= sizeof(buffer
);
3634 memset( buffer
, 0xcd, sizeof(buffer
) );
3635 ret
= RegQueryValueExW( hkey
, L
"Ime File", NULL
, NULL
, (BYTE
*)buffer
, &len
);
3636 ok( !ret
, "RegQueryValueExW returned %#lx, error %lu\n", ret
, GetLastError() );
3637 ok( !wcsicmp( buffer
, wcsrchr( ime_path
, '\\' ) + 1 ), "got Ime File %s\n", debugstr_w(buffer
) );
3639 len
= sizeof(buffer
);
3640 memset( buffer
, 0xcd, sizeof(buffer
) );
3641 ret
= RegQueryValueExW( hkey
, L
"Layout Text", NULL
, NULL
, (BYTE
*)buffer
, &len
);
3642 ok( !ret
, "RegQueryValueExW returned %#lx, error %lu\n", ret
, GetLastError() );
3643 ok( !wcscmp( buffer
, L
"WineTest IME" ), "got Layout Text %s\n", debugstr_w(buffer
) );
3645 len
= sizeof(buffer
);
3646 memset( buffer
, 0, sizeof(buffer
) );
3647 ret
= RegQueryValueExW( hkey
, L
"Layout File", NULL
, NULL
, (BYTE
*)buffer
, &len
);
3649 ok( !ret
, "RegQueryValueExW returned %#lx, error %lu\n", ret
, GetLastError() );
3651 ok( !wcscmp( buffer
, L
"kbdus.dll" ), "got Layout File %s\n", debugstr_w(buffer
) );
3653 ret
= RegCloseKey( hkey
);
3654 ok( !ret
, "RegCloseKey returned %#lx, error %lu\n", ret
, GetLastError() );
3659 static void ime_cleanup( HKL hkl
, BOOL free
)
3661 HMODULE module
= GetModuleHandleW( L
"winetest_ime.dll" );
3662 WCHAR buffer
[MAX_PATH
], value
[MAX_PATH
];
3663 DWORD i
, buffer_len
, value_len
, ret
;
3666 ret
= UnloadKeyboardLayout( hkl
);
3668 ok( ret
, "UnloadKeyboardLayout failed, error %lu\n", GetLastError() );
3670 if (free
) ok_ret( 1, ImmFreeLayout( hkl
) );
3672 swprintf( buffer
, ARRAY_SIZE(buffer
), L
"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl
);
3673 ret
= RegDeleteKeyW( HKEY_LOCAL_MACHINE
, buffer
);
3674 ok( !ret
, "RegDeleteKeyW returned %#lx, error %lu\n", ret
, GetLastError() );
3676 ret
= RegOpenKeyW( HKEY_CURRENT_USER
, L
"Keyboard Layout\\Preload", &hkey
);
3677 ok( !ret
, "RegOpenKeyW returned %#lx, error %lu\n", ret
, GetLastError() );
3679 value_len
= ARRAY_SIZE(value
);
3680 buffer_len
= sizeof(buffer
);
3681 for (i
= 0; !RegEnumValueW( hkey
, i
, value
, &value_len
, NULL
, NULL
, (void *)buffer
, &buffer_len
); i
++)
3683 value_len
= ARRAY_SIZE(value
);
3684 buffer_len
= sizeof(buffer
);
3685 if (hkl
!= UlongToHandle( wcstoul( buffer
, NULL
, 16 ) )) continue;
3686 ret
= RegDeleteValueW( hkey
, value
);
3687 ok( !ret
, "RegDeleteValueW returned %#lx, error %lu\n", ret
, GetLastError() );
3690 ret
= RegCloseKey( hkey
);
3691 ok( !ret
, "RegCloseKey returned %#lx, error %lu\n", ret
, GetLastError() );
3693 ret
= DeleteFileW( ime_path
);
3694 todo_wine_if( GetLastError() == ERROR_ACCESS_DENIED
)
3695 ok( ret
|| broken( !ret
) /* sometimes still in use */,
3696 "DeleteFileW failed, error %lu\n", GetLastError() );
3698 ret
= FreeLibrary( module
);
3699 ok( ret
, "FreeLibrary failed, error %lu\n", GetLastError() );
3701 ret
= DeleteFileW( L
"c:\\windows\\system32\\winetest_ime.dll" );
3702 ok( ret
, "DeleteFileW failed, error %lu\n", GetLastError() );
3705 static BOOL CALLBACK
enum_get_context( HIMC himc
, LPARAM lparam
)
3707 ime_trace( "himc %p\n", himc
);
3708 *(HIMC
*)lparam
= himc
;
3712 static BOOL CALLBACK
enum_find_context( HIMC himc
, LPARAM lparam
)
3714 ime_trace( "himc %p\n", himc
);
3715 if (lparam
&& lparam
== (LPARAM
)himc
) return FALSE
;
3719 static void test_ImmEnumInputContext(void)
3723 ok_ret( 1, ImmEnumInputContext( 0, enum_get_context
, (LPARAM
)&default_himc
) );
3724 ok_ret( 1, ImmEnumInputContext( -1, enum_find_context
, 0 ) );
3725 ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context
, 0 ) );
3728 ok_ret( 0, ImmEnumInputContext( 1, enum_find_context
, 0 ) );
3730 ok_ret( 0, ImmEnumInputContext( GetCurrentProcessId(), enum_find_context
, 0 ) );
3732 himc
= ImmCreateContext();
3733 ok_ne( NULL
, himc
, HIMC
, "%p" );
3734 ok_ret( 0, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context
, (LPARAM
)himc
) );
3735 ok_ret( 1, ImmDestroyContext( himc
) );
3736 ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context
, (LPARAM
)himc
) );
3739 static void test_ImmInstallIME(void)
3744 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, TRUE
);
3745 SET_ENABLE( ImeInquire
, TRUE
);
3746 SET_ENABLE( ImeDestroy
, TRUE
);
3747 SET_ENABLE( IME_DLL_PROCESS_DETACH
, TRUE
);
3749 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3750 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3752 if (!(hkl
= ime_install())) goto cleanup
;
3754 SET_EXPECT( IME_DLL_PROCESS_ATTACH
);
3755 SET_EXPECT( ImeInquire
);
3756 ret
= ImmLoadIME( hkl
);
3757 ok( ret
, "ImmLoadIME returned %#x\n", ret
);
3758 CHECK_CALLED( IME_DLL_PROCESS_ATTACH
);
3759 CHECK_CALLED( ImeInquire
);
3761 ret
= ImmLoadIME( hkl
);
3762 ok( ret
, "ImmLoadIME returned %#x\n", ret
);
3764 SET_EXPECT( ImeDestroy
);
3765 SET_EXPECT( IME_DLL_PROCESS_DETACH
);
3766 ret
= ImmFreeLayout( hkl
);
3767 ok( ret
, "ImmFreeLayout returned %#x\n", ret
);
3768 CHECK_CALLED( ImeDestroy
);
3769 CHECK_CALLED( IME_DLL_PROCESS_DETACH
);
3771 ret
= ImmFreeLayout( hkl
);
3772 ok( ret
, "ImmFreeLayout returned %#x\n", ret
);
3774 ime_info
.fdwProperty
= 0;
3776 SET_EXPECT( IME_DLL_PROCESS_ATTACH
);
3777 SET_EXPECT( ImeInquire
);
3778 ret
= ImmLoadIME( hkl
);
3779 ok( ret
, "ImmLoadIME returned %#x\n", ret
);
3780 CHECK_CALLED( IME_DLL_PROCESS_ATTACH
);
3781 CHECK_CALLED( ImeInquire
);
3783 ret
= ImmLoadIME( hkl
);
3784 ok( ret
, "ImmLoadIME returned %#x\n", ret
);
3786 SET_EXPECT( ImeDestroy
);
3787 SET_EXPECT( IME_DLL_PROCESS_DETACH
);
3788 ret
= ImmFreeLayout( hkl
);
3789 ok( ret
, "ImmFreeLayout returned %#x\n", ret
);
3790 CHECK_CALLED( ImeDestroy
);
3791 CHECK_CALLED( IME_DLL_PROCESS_DETACH
);
3793 ret
= ImmFreeLayout( hkl
);
3794 ok( ret
, "ImmFreeLayout returned %#x\n", ret
);
3796 ime_cleanup( hkl
, FALSE
);
3799 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, FALSE
);
3800 SET_ENABLE( ImeInquire
, FALSE
);
3801 SET_ENABLE( ImeDestroy
, FALSE
);
3802 SET_ENABLE( IME_DLL_PROCESS_DETACH
, FALSE
);
3805 static void test_ImmIsIME(void)
3807 HKL hkl
= GetKeyboardLayout( 0 );
3809 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, TRUE
);
3810 SET_ENABLE( ImeInquire
, TRUE
);
3811 SET_ENABLE( ImeDestroy
, TRUE
);
3812 SET_ENABLE( IME_DLL_PROCESS_DETACH
, TRUE
);
3814 SetLastError( 0xdeadbeef );
3815 ok_ret( 0, ImmIsIME( 0 ) );
3816 ok_ret( 0xdeadbeef, GetLastError() );
3817 ok_ret( 1, ImmIsIME( hkl
) );
3819 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3820 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3822 if (!(hkl
= wineime_hkl
)) goto cleanup
;
3824 todo_ImeInquire
= TRUE
;
3825 todo_ImeDestroy
= TRUE
;
3826 todo_IME_DLL_PROCESS_ATTACH
= TRUE
;
3827 todo_IME_DLL_PROCESS_DETACH
= TRUE
;
3828 ok_ret( 1, ImmIsIME( hkl
) );
3829 todo_IME_DLL_PROCESS_ATTACH
= FALSE
;
3830 todo_IME_DLL_PROCESS_DETACH
= FALSE
;
3831 todo_ImeInquire
= FALSE
;
3832 todo_ImeDestroy
= FALSE
;
3835 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, FALSE
);
3836 SET_ENABLE( ImeInquire
, FALSE
);
3837 SET_ENABLE( ImeDestroy
, FALSE
);
3838 SET_ENABLE( IME_DLL_PROCESS_DETACH
, FALSE
);
3841 static void test_ImmGetProperty(void)
3843 static const IMEINFO expect_ime_info
=
3845 .fdwProperty
= IME_PROP_UNICODE
| IME_PROP_AT_CARET
,
3847 static const IMEINFO expect_ime_info_0411
= /* MS Japanese IME */
3849 .fdwProperty
= IME_PROP_CANDLIST_START_FROM_1
| IME_PROP_UNICODE
| IME_PROP_AT_CARET
| 0xa,
3850 .fdwConversionCaps
= IME_CMODE_NATIVE
| IME_CMODE_FULLSHAPE
| IME_CMODE_KATAKANA
,
3851 .fdwSentenceCaps
= IME_SMODE_PLAURALCLAUSE
| IME_SMODE_CONVERSATION
,
3852 .fdwSCSCaps
= SCS_CAP_COMPSTR
| SCS_CAP_SETRECONVERTSTRING
| SCS_CAP_MAKEREAD
,
3853 .fdwSelectCaps
= SELECT_CAP_CONVERSION
| SELECT_CAP_SENTENCE
,
3854 .fdwUICaps
= UI_CAP_ROT90
,
3856 static const IMEINFO expect_ime_info_0412
= /* MS Korean IME */
3858 .fdwProperty
= IME_PROP_CANDLIST_START_FROM_1
| IME_PROP_UNICODE
| IME_PROP_AT_CARET
| 0xa,
3859 .fdwConversionCaps
= IME_CMODE_NATIVE
| IME_CMODE_FULLSHAPE
,
3860 .fdwSentenceCaps
= IME_SMODE_NONE
,
3861 .fdwSCSCaps
= SCS_CAP_COMPSTR
| SCS_CAP_SETRECONVERTSTRING
,
3862 .fdwSelectCaps
= SELECT_CAP_CONVERSION
,
3863 .fdwUICaps
= UI_CAP_ROT90
,
3865 static const IMEINFO expect_ime_info_0804
= /* MS Chinese IME */
3867 .fdwProperty
= IME_PROP_CANDLIST_START_FROM_1
| IME_PROP_UNICODE
| IME_PROP_AT_CARET
| 0xa,
3868 .fdwConversionCaps
= IME_CMODE_NATIVE
| IME_CMODE_FULLSHAPE
,
3869 .fdwSentenceCaps
= IME_SMODE_PLAURALCLAUSE
,
3870 .fdwSCSCaps
= SCS_CAP_COMPSTR
| SCS_CAP_SETRECONVERTSTRING
| SCS_CAP_MAKEREAD
,
3871 .fdwUICaps
= UI_CAP_ROT90
,
3873 HKL hkl
= GetKeyboardLayout( 0 );
3874 const IMEINFO
*expect
;
3876 SET_ENABLE( ImeInquire
, TRUE
);
3877 SET_ENABLE( ImeDestroy
, TRUE
);
3879 SetLastError( 0xdeadbeef );
3880 ok_ret( 0, ImmGetProperty( 0, 0 ) );
3881 ok_ret( 0, ImmGetProperty( hkl
, 0 ) );
3883 if (hkl
== (HKL
)0x04110411) expect
= &expect_ime_info_0411
;
3884 else if (hkl
== (HKL
)0x04120412) expect
= &expect_ime_info_0412
;
3885 else if (hkl
== (HKL
)0x08040804) expect
= &expect_ime_info_0804
;
3886 else expect
= &expect_ime_info
;
3888 /* IME_PROP_COMPLETE_ON_UNSELECT seems to be somtimes set on CJK locales IMEs, sometimes not */
3889 ok_ret( expect
->fdwProperty
, ImmGetProperty( hkl
, IGP_PROPERTY
) & ~IME_PROP_COMPLETE_ON_UNSELECT
);
3891 ok_ret( expect
->fdwConversionCaps
, ImmGetProperty( hkl
, IGP_CONVERSION
) );
3893 ok_ret( expect
->fdwSentenceCaps
, ImmGetProperty( hkl
, IGP_SENTENCE
) );
3894 ok_ret( expect
->fdwSCSCaps
, ImmGetProperty( hkl
, IGP_SETCOMPSTR
) );
3896 ok_ret( expect
->fdwSelectCaps
, ImmGetProperty( hkl
, IGP_SELECT
) );
3897 ok_ret( IMEVER_0400
, ImmGetProperty( hkl
, IGP_GETIMEVERSION
) );
3898 ok_ret( expect
->fdwUICaps
, ImmGetProperty( hkl
, IGP_UI
) );
3900 ok_ret( 0xdeadbeef, GetLastError() );
3902 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
3903 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
3905 if (!(hkl
= wineime_hkl
)) goto cleanup
;
3907 SET_EXPECT( ImeInquire
);
3908 SET_EXPECT( ImeDestroy
);
3909 ok_ret( 0, ImmGetProperty( hkl
, 0 ) );
3910 CHECK_CALLED( ImeInquire
);
3911 CHECK_CALLED( ImeDestroy
);
3914 todo_ImeInquire
= TRUE
;
3915 todo_ImeDestroy
= TRUE
;
3916 ok_ret( expect
->fdwProperty
, ImmGetProperty( hkl
, IGP_PROPERTY
) );
3917 ok_ret( expect
->fdwConversionCaps
, ImmGetProperty( hkl
, IGP_CONVERSION
) );
3918 ok_ret( expect
->fdwSentenceCaps
, ImmGetProperty( hkl
, IGP_SENTENCE
) );
3919 ok_ret( expect
->fdwSCSCaps
, ImmGetProperty( hkl
, IGP_SETCOMPSTR
) );
3920 ok_ret( expect
->fdwSelectCaps
, ImmGetProperty( hkl
, IGP_SELECT
) );
3921 ok_ret( IMEVER_0400
, ImmGetProperty( hkl
, IGP_GETIMEVERSION
) );
3922 ok_ret( expect
->fdwUICaps
, ImmGetProperty( hkl
, IGP_UI
) );
3923 todo_ImeInquire
= FALSE
;
3924 called_ImeInquire
= FALSE
;
3925 todo_ImeDestroy
= FALSE
;
3926 called_ImeDestroy
= FALSE
;
3929 SET_ENABLE( ImeInquire
, FALSE
);
3930 SET_ENABLE( ImeDestroy
, FALSE
);
3933 static void test_ImmGetDescription(void)
3935 HKL hkl
= GetKeyboardLayout( 0 );
3936 WCHAR bufferW
[MAX_PATH
];
3937 char bufferA
[MAX_PATH
];
3940 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, TRUE
);
3941 SET_ENABLE( ImeInquire
, TRUE
);
3942 SET_ENABLE( ImeDestroy
, TRUE
);
3943 SET_ENABLE( IME_DLL_PROCESS_DETACH
, TRUE
);
3945 SetLastError( 0xdeadbeef );
3946 ret
= ImmGetDescriptionW( NULL
, NULL
, 0 );
3947 ok( !ret
, "ImmGetDescriptionW returned %lu\n", ret
);
3948 ret
= ImmGetDescriptionA( NULL
, NULL
, 0 );
3949 ok( !ret
, "ImmGetDescriptionA returned %lu\n", ret
);
3950 ret
= ImmGetDescriptionW( NULL
, NULL
, 100 );
3951 ok( !ret
, "ImmGetDescriptionW returned %lu\n", ret
);
3952 ret
= ImmGetDescriptionA( NULL
, NULL
, 100 );
3953 ok( !ret
, "ImmGetDescriptionA returned %lu\n", ret
);
3954 ret
= ImmGetDescriptionW( hkl
, bufferW
, 100 );
3955 ok( !ret
, "ImmGetDescriptionW returned %lu\n", ret
);
3956 ret
= ImmGetDescriptionA( hkl
, bufferA
, 100 );
3957 ok( !ret
, "ImmGetDescriptionA returned %lu\n", ret
);
3958 ret
= GetLastError();
3959 ok( ret
== 0xdeadbeef, "got error %lu\n", ret
);
3961 if (!(hkl
= wineime_hkl
)) goto cleanup
;
3963 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3964 ret
= ImmGetDescriptionW( hkl
, bufferW
, 2 );
3965 ok( ret
== 1, "ImmGetDescriptionW returned %lu\n", ret
);
3966 ok( !wcscmp( bufferW
, L
"W" ), "got bufferW %s\n", debugstr_w(bufferW
) );
3967 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3968 ret
= ImmGetDescriptionA( hkl
, bufferA
, 2 );
3969 ok( ret
== 0, "ImmGetDescriptionA returned %lu\n", ret
);
3970 ok( !strcmp( bufferA
, "" ), "got bufferA %s\n", debugstr_a(bufferA
) );
3972 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3973 ret
= ImmGetDescriptionW( hkl
, bufferW
, 11 );
3974 ok( ret
== 10, "ImmGetDescriptionW returned %lu\n", ret
);
3975 ok( !wcscmp( bufferW
, L
"WineTest I" ), "got bufferW %s\n", debugstr_w(bufferW
) );
3976 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3977 ret
= ImmGetDescriptionA( hkl
, bufferA
, 11 );
3978 ok( ret
== 0, "ImmGetDescriptionA returned %lu\n", ret
);
3979 ok( !strcmp( bufferA
, "" ), "got bufferA %s\n", debugstr_a(bufferA
) );
3981 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3982 ret
= ImmGetDescriptionW( hkl
, bufferW
, 12 );
3983 ok( ret
== 11, "ImmGetDescriptionW returned %lu\n", ret
);
3984 ok( !wcscmp( bufferW
, L
"WineTest IM" ), "got bufferW %s\n", debugstr_w(bufferW
) );
3985 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3986 ret
= ImmGetDescriptionA( hkl
, bufferA
, 12 );
3987 ok( ret
== 12, "ImmGetDescriptionA returned %lu\n", ret
);
3988 ok( !strcmp( bufferA
, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA
) );
3990 memset( bufferW
, 0xcd, sizeof(bufferW
) );
3991 ret
= ImmGetDescriptionW( hkl
, bufferW
, 13 );
3992 ok( ret
== 12, "ImmGetDescriptionW returned %lu\n", ret
);
3993 ok( !wcscmp( bufferW
, L
"WineTest IME" ), "got bufferW %s\n", debugstr_w(bufferW
) );
3994 memset( bufferA
, 0xcd, sizeof(bufferA
) );
3995 ret
= ImmGetDescriptionA( hkl
, bufferA
, 13 );
3996 ok( ret
== 12, "ImmGetDescriptionA returned %lu\n", ret
);
3997 ok( !strcmp( bufferA
, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA
) );
4000 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, FALSE
);
4001 SET_ENABLE( ImeInquire
, FALSE
);
4002 SET_ENABLE( ImeDestroy
, FALSE
);
4003 SET_ENABLE( IME_DLL_PROCESS_DETACH
, FALSE
);
4006 static void test_ImmGetIMEFileName(void)
4008 HKL hkl
= GetKeyboardLayout( 0 );
4009 WCHAR bufferW
[MAX_PATH
], expectW
[16];
4010 char bufferA
[MAX_PATH
], expectA
[16];
4013 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, TRUE
);
4014 SET_ENABLE( ImeInquire
, TRUE
);
4015 SET_ENABLE( ImeDestroy
, TRUE
);
4016 SET_ENABLE( IME_DLL_PROCESS_DETACH
, TRUE
);
4018 SetLastError( 0xdeadbeef );
4019 ret
= ImmGetIMEFileNameW( NULL
, NULL
, 0 );
4020 ok( !ret
, "ImmGetIMEFileNameW returned %lu\n", ret
);
4021 ret
= ImmGetIMEFileNameA( NULL
, NULL
, 0 );
4022 ok( !ret
, "ImmGetIMEFileNameA returned %lu\n", ret
);
4023 ret
= ImmGetIMEFileNameW( NULL
, NULL
, 100 );
4024 ok( !ret
, "ImmGetIMEFileNameW returned %lu\n", ret
);
4025 ret
= ImmGetIMEFileNameA( NULL
, NULL
, 100 );
4026 ok( !ret
, "ImmGetIMEFileNameA returned %lu\n", ret
);
4027 ret
= ImmGetIMEFileNameW( hkl
, bufferW
, 100 );
4028 ok( !ret
, "ImmGetIMEFileNameW returned %lu\n", ret
);
4029 ret
= ImmGetIMEFileNameA( hkl
, bufferA
, 100 );
4030 ok( !ret
, "ImmGetIMEFileNameA returned %lu\n", ret
);
4031 ret
= GetLastError();
4032 ok( ret
== 0xdeadbeef, "got error %lu\n", ret
);
4034 if (!(hkl
= wineime_hkl
)) goto cleanup
;
4036 memset( bufferW
, 0xcd, sizeof(bufferW
) );
4037 ret
= ImmGetIMEFileNameW( hkl
, bufferW
, 2 );
4038 ok( ret
== 1, "ImmGetIMEFileNameW returned %lu\n", ret
);
4039 ok( !wcscmp( bufferW
, L
"W" ), "got bufferW %s\n", debugstr_w(bufferW
) );
4040 memset( bufferA
, 0xcd, sizeof(bufferA
) );
4041 ret
= ImmGetIMEFileNameA( hkl
, bufferA
, 2 );
4042 ok( ret
== 0, "ImmGetIMEFileNameA returned %lu\n", ret
);
4043 ok( !strcmp( bufferA
, "" ), "got bufferA %s\n", debugstr_a(bufferA
) );
4045 swprintf( expectW
, ARRAY_SIZE(expectW
), L
"WINE%04X.I", ime_count
- 1 );
4046 memset( bufferW
, 0xcd, sizeof(bufferW
) );
4047 ret
= ImmGetIMEFileNameW( hkl
, bufferW
, 11 );
4048 ok( ret
== 10, "ImmGetIMEFileNameW returned %lu\n", ret
);
4049 ok( !wcscmp( bufferW
, expectW
), "got bufferW %s\n", debugstr_w(bufferW
) );
4050 memset( bufferA
, 0xcd, sizeof(bufferA
) );
4051 ret
= ImmGetIMEFileNameA( hkl
, bufferA
, 11 );
4052 ok( ret
== 0, "ImmGetIMEFileNameA returned %lu\n", ret
);
4053 ok( !strcmp( bufferA
, "" ), "got bufferA %s\n", debugstr_a(bufferA
) );
4055 swprintf( expectW
, ARRAY_SIZE(expectW
), L
"WINE%04X.IM", ime_count
- 1 );
4056 memset( bufferW
, 0xcd, sizeof(bufferW
) );
4057 ret
= ImmGetIMEFileNameW( hkl
, bufferW
, 12 );
4058 ok( ret
== 11, "ImmGetIMEFileNameW returned %lu\n", ret
);
4059 ok( !wcscmp( bufferW
, expectW
), "got bufferW %s\n", debugstr_w(bufferW
) );
4060 snprintf( expectA
, ARRAY_SIZE(expectA
), "WINE%04X.IME", ime_count
- 1 );
4061 memset( bufferA
, 0xcd, sizeof(bufferA
) );
4062 ret
= ImmGetIMEFileNameA( hkl
, bufferA
, 12 );
4063 ok( ret
== 12, "ImmGetIMEFileNameA returned %lu\n", ret
);
4064 ok( !strcmp( bufferA
, expectA
), "got bufferA %s\n", debugstr_a(bufferA
) );
4066 swprintf( expectW
, ARRAY_SIZE(expectW
), L
"WINE%04X.IME", ime_count
- 1 );
4067 memset( bufferW
, 0xcd, sizeof(bufferW
) );
4068 ret
= ImmGetIMEFileNameW( hkl
, bufferW
, 13 );
4069 ok( ret
== 12, "ImmGetIMEFileNameW returned %lu\n", ret
);
4070 ok( !wcscmp( bufferW
, expectW
), "got bufferW %s\n", debugstr_w(bufferW
) );
4071 memset( bufferA
, 0xcd, sizeof(bufferA
) );
4072 ret
= ImmGetIMEFileNameA( hkl
, bufferA
, 13 );
4073 ok( ret
== 12, "ImmGetIMEFileNameA returned %lu\n", ret
);
4074 ok( !strcmp( bufferA
, expectA
), "got bufferA %s\n", debugstr_a(bufferA
) );
4077 SET_ENABLE( IME_DLL_PROCESS_ATTACH
, FALSE
);
4078 SET_ENABLE( ImeInquire
, FALSE
);
4079 SET_ENABLE( ImeDestroy
, FALSE
);
4080 SET_ENABLE( IME_DLL_PROCESS_DETACH
, FALSE
);
4083 static void test_ImmEscape( BOOL unicode
)
4085 HKL hkl
= GetKeyboardLayout( 0 );
4088 IME_ESC_QUERY_SUPPORT
,
4089 IME_ESC_SEQUENCE_TO_INTERNAL
,
4090 IME_ESC_GET_EUDC_DICTIONARY
,
4091 IME_ESC_SET_EUDC_DICTIONARY
,
4095 IME_ESC_GETHELPFILENAME
,
4100 SET_ENABLE( ImeEscape
, TRUE
);
4102 winetest_push_context( unicode
? "unicode" : "ansi" );
4104 ok_ret( 0, ImmEscapeW( hkl
, 0, 0, NULL
) );
4105 ok_ret( 0, ImmEscapeA( hkl
, 0, 0, NULL
) );
4107 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
4108 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
4109 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
4111 if (!(hkl
= wineime_hkl
)) goto cleanup
;
4113 for (i
= 0; i
< ARRAY_SIZE(codes
); ++i
)
4115 winetest_push_context( "esc %#lx", codes
[i
] );
4117 SET_EXPECT( ImeEscape
);
4118 ok_ret( 4, ImmEscapeW( hkl
, 0, codes
[i
], NULL
) );
4119 CHECK_CALLED( ImeEscape
);
4121 SET_EXPECT( ImeEscape
);
4122 memset( bufferW
, 0xcd, sizeof(bufferW
) );
4123 if (codes
[i
] == IME_ESC_SET_EUDC_DICTIONARY
) wcscpy( bufferW
, L
"EscapeIme" );
4124 ok_ret( 4, ImmEscapeW( hkl
, 0, codes
[i
], bufferW
) );
4125 if (unicode
|| codes
[i
] == IME_ESC_GET_EUDC_DICTIONARY
|| codes
[i
] == IME_ESC_IME_NAME
||
4126 codes
[i
] == IME_ESC_GETHELPFILENAME
)
4128 ok_wcs( L
"ImeEscape", bufferW
);
4129 ok_eq( 0xcdcd, bufferW
[10], WORD
, "%#x" );
4131 else if (codes
[i
] == IME_ESC_SET_EUDC_DICTIONARY
)
4133 ok_wcs( L
"EscapeIme", bufferW
);
4134 ok_eq( 0xcdcd, bufferW
[10], WORD
, "%#x" );
4136 else if (codes
[i
] == IME_ESC_HANJA_MODE
)
4139 ok_eq( 0xcdcd, bufferW
[0], WORD
, "%#x" );
4143 ok( !memcmp( bufferW
, "ImeEscape", 10 ), "got bufferW %s\n", debugstr_w(bufferW
) );
4144 ok_eq( 0xcdcd, bufferW
[5], WORD
, "%#x" );
4146 CHECK_CALLED( ImeEscape
);
4148 SET_EXPECT( ImeEscape
);
4149 ok_ret( 4, ImmEscapeA( hkl
, 0, codes
[i
], NULL
) );
4150 CHECK_CALLED( ImeEscape
);
4152 SET_EXPECT( ImeEscape
);
4153 memset( bufferA
, 0xcd, sizeof(bufferA
) );
4154 if (codes
[i
] == IME_ESC_SET_EUDC_DICTIONARY
) strcpy( bufferA
, "EscapeIme" );
4155 ok_ret( 4, ImmEscapeA( hkl
, 0, codes
[i
], bufferA
) );
4156 if (!unicode
|| codes
[i
] == IME_ESC_GET_EUDC_DICTIONARY
|| codes
[i
] == IME_ESC_IME_NAME
||
4157 codes
[i
] == IME_ESC_GETHELPFILENAME
)
4159 ok_str( "ImeEscape", bufferA
);
4160 ok_eq( 0xcd, bufferA
[10], BYTE
, "%#x" );
4162 else if (codes
[i
] == IME_ESC_SET_EUDC_DICTIONARY
)
4164 ok_str( "EscapeIme", bufferA
);
4165 ok_eq( 0xcd, bufferA
[10], BYTE
, "%#x" );
4167 else if (codes
[i
] == IME_ESC_HANJA_MODE
)
4170 ok_eq( 0xcd, bufferA
[0], BYTE
, "%#x" );
4174 ok( !memcmp( bufferA
, L
"ImeEscape", 10 * sizeof(WCHAR
) ), "got bufferA %s\n", debugstr_a(bufferA
) );
4175 ok_eq( 0xcd, bufferA
[20], BYTE
, "%#x" );
4177 CHECK_CALLED( ImeEscape
);
4179 winetest_pop_context();
4183 SET_ENABLE( ImeEscape
, FALSE
);
4185 winetest_pop_context();
4188 static int CALLBACK
enum_register_wordA( const char *reading
, DWORD style
, const char *string
, void *user
)
4190 ime_trace( "reading %s, style %#lx, string %s, user %p\n", debugstr_a(reading
), style
, debugstr_a(string
), user
);
4192 ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
4193 ok_str( "Reading", reading
);
4194 ok_str( "String", string
);
4199 static int CALLBACK
enum_register_wordW( const WCHAR
*reading
, DWORD style
, const WCHAR
*string
, void *user
)
4201 ime_trace( "reading %s, style %#lx, string %s, user %p\n", debugstr_w(reading
), style
, debugstr_w(string
), user
);
4203 ok_eq( 0xdeadbeef, style
, UINT
, "%#x" );
4204 ok_wcs( L
"Reading", reading
);
4205 ok_wcs( L
"String", string
);
4210 static void test_ImmEnumRegisterWord( BOOL unicode
)
4212 HKL hkl
= GetKeyboardLayout( 0 );
4214 winetest_push_context( unicode
? "unicode" : "ansi" );
4216 SET_ENABLE( ImeEnumRegisterWord
, TRUE
);
4218 SetLastError( 0xdeadbeef );
4219 ok_ret( 0, ImmEnumRegisterWordW( NULL
, enum_register_wordW
, NULL
, 0, NULL
, NULL
) );
4220 ok_ret( 0, ImmEnumRegisterWordA( NULL
, enum_register_wordA
, NULL
, 0, NULL
, NULL
) );
4221 ok_ret( 0, ImmEnumRegisterWordW( hkl
, enum_register_wordW
, NULL
, 0, NULL
, NULL
) );
4222 ok_ret( 0, ImmEnumRegisterWordA( hkl
, enum_register_wordA
, NULL
, 0, NULL
, NULL
) );
4224 ok_ret( 0xdeadbeef, GetLastError() );
4226 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
4227 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
4228 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
4230 if (!(hkl
= wineime_hkl
)) goto cleanup
;
4232 SET_EXPECT( ImeEnumRegisterWord
);
4233 ok_ret( 0, ImmEnumRegisterWordW( hkl
, enum_register_wordW
, NULL
, 0, NULL
, NULL
) );
4234 CHECK_CALLED( ImeEnumRegisterWord
);
4236 SET_EXPECT( ImeEnumRegisterWord
);
4237 ok_ret( 0, ImmEnumRegisterWordA( hkl
, enum_register_wordA
, NULL
, 0, NULL
, NULL
) );
4238 CHECK_CALLED( ImeEnumRegisterWord
);
4240 SET_EXPECT( ImeEnumRegisterWord
);
4241 ok_ret( 0xdeadbeef, ImmEnumRegisterWordW( hkl
, enum_register_wordW
, L
"Reading", 0xdeadbeef, L
"String", NULL
) );
4242 CHECK_CALLED( ImeEnumRegisterWord
);
4244 SET_EXPECT( ImeEnumRegisterWord
);
4245 ok_ret( 0xdeadbeef, ImmEnumRegisterWordA( hkl
, enum_register_wordA
, "Reading", 0xdeadbeef, "String", NULL
) );
4246 CHECK_CALLED( ImeEnumRegisterWord
);
4249 SET_ENABLE( ImeEnumRegisterWord
, FALSE
);
4251 winetest_pop_context();
4254 static void test_ImmRegisterWord( BOOL unicode
)
4256 HKL hkl
= GetKeyboardLayout( 0 );
4258 SET_ENABLE( ImeRegisterWord
, TRUE
);
4260 winetest_push_context( unicode
? "unicode" : "ansi" );
4262 SetLastError( 0xdeadbeef );
4263 ok_ret( 0, ImmRegisterWordW( NULL
, NULL
, 0, NULL
) );
4264 ok_ret( 0, ImmRegisterWordA( NULL
, NULL
, 0, NULL
) );
4265 ok_ret( 0, ImmRegisterWordW( hkl
, NULL
, 0, NULL
) );
4266 ok_ret( 0, ImmRegisterWordA( hkl
, NULL
, 0, NULL
) );
4268 ok_ret( 0xdeadbeef, GetLastError() );
4270 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
4271 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
4272 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
4274 if (!(hkl
= wineime_hkl
)) goto cleanup
;
4276 SET_EXPECT( ImeRegisterWord
);
4277 ok_ret( 0, ImmRegisterWordW( hkl
, NULL
, 0, NULL
) );
4278 CHECK_CALLED( ImeRegisterWord
);
4280 SET_EXPECT( ImeRegisterWord
);
4281 ok_ret( 0, ImmRegisterWordA( hkl
, NULL
, 0, NULL
) );
4282 CHECK_CALLED( ImeRegisterWord
);
4284 SET_EXPECT( ImeRegisterWord
);
4285 ok_ret( 0, ImmRegisterWordW( hkl
, L
"Reading", 0, NULL
) );
4286 CHECK_CALLED( ImeRegisterWord
);
4288 SET_EXPECT( ImeRegisterWord
);
4289 ok_ret( 0, ImmRegisterWordA( hkl
, "Reading", 0, NULL
) );
4290 CHECK_CALLED( ImeRegisterWord
);
4292 SET_EXPECT( ImeRegisterWord
);
4293 ok_ret( 0, ImmRegisterWordW( hkl
, NULL
, 0xdeadbeef, NULL
) );
4294 CHECK_CALLED( ImeRegisterWord
);
4296 SET_EXPECT( ImeRegisterWord
);
4297 ok_ret( 0, ImmRegisterWordA( hkl
, NULL
, 0xdeadbeef, NULL
) );
4298 CHECK_CALLED( ImeRegisterWord
);
4300 SET_EXPECT( ImeRegisterWord
);
4301 ok_ret( 0, ImmRegisterWordW( hkl
, NULL
, 0, L
"String" ) );
4302 CHECK_CALLED( ImeRegisterWord
);
4304 SET_EXPECT( ImeRegisterWord
);
4305 ok_ret( 0, ImmRegisterWordA( hkl
, NULL
, 0, "String" ) );
4306 CHECK_CALLED( ImeRegisterWord
);
4309 SET_ENABLE( ImeRegisterWord
, FALSE
);
4311 winetest_pop_context();
4314 static void test_ImmGetRegisterWordStyle( BOOL unicode
)
4316 HKL hkl
= GetKeyboardLayout( 0 );
4320 winetest_push_context( unicode
? "unicode" : "ansi" );
4322 SET_ENABLE( ImeGetRegisterWordStyle
, TRUE
);
4324 SetLastError( 0xdeadbeef );
4325 ok_ret( 0, ImmGetRegisterWordStyleW( NULL
, 0, &styleW
) );
4326 ok_ret( 0, ImmGetRegisterWordStyleA( NULL
, 0, &styleA
) );
4327 ok_ret( 0, ImmGetRegisterWordStyleW( hkl
, 0, &styleW
) );
4328 ok_ret( 0, ImmGetRegisterWordStyleA( hkl
, 0, &styleA
) );
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 if (!strcmp( winetest_platform
, "wine" )) goto skip_null
;
4340 SET_EXPECT( ImeGetRegisterWordStyle
);
4341 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleW( hkl
, 16, NULL
) );
4342 CHECK_CALLED( ImeGetRegisterWordStyle
);
4344 SET_EXPECT( ImeGetRegisterWordStyle
);
4345 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleA( hkl
, 16, NULL
) );
4346 CHECK_CALLED( ImeGetRegisterWordStyle
);
4349 SET_EXPECT( ImeGetRegisterWordStyle
);
4350 memset( &styleW
, 0xcd, sizeof(styleW
) );
4351 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleW( hkl
, 1, &styleW
) );
4352 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
4354 ok_eq( 0xdeadbeef, styleW
.dwStyle
, UINT
, "%#x" );
4355 ok_wcs( L
"StyleDescription", styleW
.szDescription
);
4360 ok_eq( 0xcdcdcdcd, styleW
.dwStyle
, UINT
, "%#x" );
4362 ok_eq( 0xcdcd, styleW
.szDescription
[0], WORD
, "%#x" );
4364 CHECK_CALLED( ImeGetRegisterWordStyle
);
4366 SET_EXPECT( ImeGetRegisterWordStyle
);
4367 memset( &styleA
, 0xcd, sizeof(styleA
) );
4368 ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleA( hkl
, 1, &styleA
) );
4369 if (ime_info
.fdwProperty
& IME_PROP_UNICODE
)
4372 ok_eq( 0xcdcdcdcd, styleA
.dwStyle
, UINT
, "%#x" );
4374 ok_eq( 0xcd, styleA
.szDescription
[0], BYTE
, "%#x" );
4378 ok_eq( 0xdeadbeef, styleA
.dwStyle
, UINT
, "%#x" );
4379 ok_str( "StyleDescription", styleA
.szDescription
);
4381 CHECK_CALLED( ImeGetRegisterWordStyle
);
4384 SET_ENABLE( ImeGetRegisterWordStyle
, FALSE
);
4386 winetest_pop_context();
4389 static void test_ImmUnregisterWord( BOOL unicode
)
4391 HKL hkl
= GetKeyboardLayout( 0 );
4393 winetest_push_context( unicode
? "unicode" : "ansi" );
4395 SET_ENABLE( ImeUnregisterWord
, TRUE
);
4397 SetLastError( 0xdeadbeef );
4398 ok_ret( 0, ImmUnregisterWordW( NULL
, NULL
, 0, NULL
) );
4399 ok_ret( 0, ImmUnregisterWordA( NULL
, NULL
, 0, NULL
) );
4400 ok_ret( 0, ImmUnregisterWordW( hkl
, NULL
, 0, NULL
) );
4401 ok_ret( 0, ImmUnregisterWordA( hkl
, NULL
, 0, NULL
) );
4403 ok_ret( 0xdeadbeef, GetLastError() );
4405 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
4406 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
4407 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
4409 if (!(hkl
= wineime_hkl
)) goto cleanup
;
4411 SET_EXPECT( ImeUnregisterWord
);
4412 ok_ret( 0, ImmUnregisterWordW( hkl
, NULL
, 0, NULL
) );
4413 CHECK_CALLED( ImeUnregisterWord
);
4415 SET_EXPECT( ImeUnregisterWord
);
4416 ok_ret( 0, ImmUnregisterWordA( hkl
, NULL
, 0, NULL
) );
4417 CHECK_CALLED( ImeUnregisterWord
);
4419 SET_EXPECT( ImeUnregisterWord
);
4420 ok_ret( 0, ImmUnregisterWordW( hkl
, L
"Reading", 0, NULL
) );
4421 CHECK_CALLED( ImeUnregisterWord
);
4423 SET_EXPECT( ImeUnregisterWord
);
4424 ok_ret( 0, ImmUnregisterWordA( hkl
, "Reading", 0, NULL
) );
4425 CHECK_CALLED( ImeUnregisterWord
);
4427 SET_EXPECT( ImeUnregisterWord
);
4428 ok_ret( 0, ImmUnregisterWordW( hkl
, NULL
, 0xdeadbeef, NULL
) );
4429 CHECK_CALLED( ImeUnregisterWord
);
4431 SET_EXPECT( ImeUnregisterWord
);
4432 ok_ret( 0, ImmUnregisterWordA( hkl
, NULL
, 0xdeadbeef, NULL
) );
4433 CHECK_CALLED( ImeUnregisterWord
);
4435 SET_EXPECT( ImeUnregisterWord
);
4436 ok_ret( 0, ImmUnregisterWordW( hkl
, NULL
, 0, L
"String" ) );
4437 CHECK_CALLED( ImeUnregisterWord
);
4439 SET_EXPECT( ImeUnregisterWord
);
4440 ok_ret( 0, ImmUnregisterWordA( hkl
, NULL
, 0, "String" ) );
4441 CHECK_CALLED( ImeUnregisterWord
);
4444 SET_ENABLE( ImeUnregisterWord
, FALSE
);
4446 winetest_pop_context();
4455 static BOOL CALLBACK
enum_thread_ime_windows( HWND hwnd
, LPARAM lparam
)
4457 struct ime_windows
*params
= (void *)lparam
;
4461 ime_trace( "hwnd %p, lparam %#Ix\n", hwnd
, lparam
);
4463 ret
= RealGetWindowClassW( hwnd
, buffer
, ARRAY_SIZE(buffer
) );
4464 ok( ret
, "RealGetWindowClassW returned %#x\n", ret
);
4466 if (!wcscmp( buffer
, L
"IME" ))
4468 ok( !params
->ime_hwnd
, "Found extra IME window %p\n", hwnd
);
4469 params
->ime_hwnd
= hwnd
;
4471 if (!wcscmp( buffer
, ime_ui_class
.lpszClassName
))
4473 ok( !params
->ime_ui_hwnd
, "Found extra IME UI window %p\n", hwnd
);
4474 params
->ime_ui_hwnd
= hwnd
;
4480 static void test_ImmSetConversionStatus(void)
4482 const struct ime_call set_conversion_status_0_seq
[] =
4485 .hkl
= expect_ime
, .himc
= default_himc
,
4486 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETCONVERSIONMODE
},
4489 .hkl
= expect_ime
, .himc
= default_himc
,
4490 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCONVERSIONMODE
},
4493 .hkl
= expect_ime
, .himc
= default_himc
,
4494 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCONVERSIONMODE
},
4497 .hkl
= expect_ime
, .himc
= default_himc
,
4498 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETSENTENCEMODE
},
4501 .hkl
= expect_ime
, .himc
= default_himc
,
4502 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETSENTENCEMODE
},
4505 .hkl
= expect_ime
, .himc
= default_himc
,
4506 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETSENTENCEMODE
},
4510 const struct ime_call set_conversion_status_1_seq
[] =
4513 .hkl
= expect_ime
, .himc
= default_himc
,
4514 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0xdeadbeef, .value
= IMC_SETCONVERSIONMODE
},
4518 const struct ime_call set_conversion_status_2_seq
[] =
4521 .hkl
= expect_ime
, .himc
= default_himc
,
4522 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETCONVERSIONMODE
},
4525 .hkl
= expect_ime
, .himc
= default_himc
,
4526 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCONVERSIONMODE
},
4529 .hkl
= expect_ime
, .himc
= default_himc
,
4530 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCONVERSIONMODE
},
4533 .hkl
= expect_ime
, .himc
= default_himc
,
4534 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0xfeedcafe, .value
= IMC_SETSENTENCEMODE
},
4537 .hkl
= expect_ime
, .himc
= default_himc
,
4538 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETSENTENCEMODE
},
4541 .hkl
= expect_ime
, .himc
= default_himc
,
4542 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETSENTENCEMODE
},
4546 DWORD old_conversion
, old_sentence
, conversion
, sentence
;
4550 ok_ret( 0, ImmGetConversionStatus( 0, &old_conversion
, &old_sentence
) );
4551 ok_ret( 1, ImmGetConversionStatus( default_himc
, &old_conversion
, &old_sentence
) );
4553 ctx
= ImmLockIMC( default_himc
);
4554 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
4555 ok_eq( old_conversion
, ctx
->fdwConversion
, UINT
, "%#x" );
4556 ok_eq( old_sentence
, ctx
->fdwSentence
, UINT
, "%#x" );
4558 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
4559 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
4560 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
4563 ok_ret( 1, ImmGetConversionStatus( default_himc
, &conversion
, &sentence
) );
4564 ok_eq( old_conversion
, conversion
, UINT
, "%#x" );
4565 ok_eq( old_sentence
, sentence
, UINT
, "%#x" );
4566 ok_eq( old_conversion
, ctx
->fdwConversion
, UINT
, "%#x" );
4567 ok_eq( old_sentence
, ctx
->fdwSentence
, UINT
, "%#x" );
4569 ok_ret( 1, ImmSetConversionStatus( default_himc
, 0, 0 ) );
4570 ok_ret( 1, ImmGetConversionStatus( default_himc
, &conversion
, &sentence
) );
4571 ok_eq( 0, conversion
, UINT
, "%#x" );
4572 ok_eq( 0, sentence
, UINT
, "%#x" );
4573 ok_eq( 0, ctx
->fdwConversion
, UINT
, "%#x" );
4574 ok_eq( 0, ctx
->fdwSentence
, UINT
, "%#x" );
4576 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
4578 if (!(hkl
= wineime_hkl
)) goto cleanup
;
4580 ok_ret( 1, ImmActivateLayout( hkl
) );
4581 ok_ret( 1, ImmLoadIME( hkl
) );
4583 /* initial values are dependent on both old and new IME */
4584 ok_ret( 1, ImmSetConversionStatus( default_himc
, 0, 0 ) );
4585 memset( ime_calls
, 0, sizeof(ime_calls
) );
4588 ok_ret( 1, ImmGetConversionStatus( default_himc
, &conversion
, &sentence
) );
4589 ok_eq( 0, conversion
, UINT
, "%#x" );
4590 ok_eq( 0, sentence
, UINT
, "%#x" );
4591 ok_eq( 0, ctx
->fdwConversion
, UINT
, "%#x" );
4592 ok_eq( 0, ctx
->fdwSentence
, UINT
, "%#x" );
4594 ok_seq( empty_sequence
);
4595 ok_ret( 1, ImmSetConversionStatus( default_himc
, 0xdeadbeef, 0xfeedcafe ) );
4596 ok_seq( set_conversion_status_0_seq
);
4598 ok_ret( 1, ImmGetConversionStatus( default_himc
, &conversion
, &sentence
) );
4599 ok_eq( 0xdeadbeef, conversion
, UINT
, "%#x" );
4600 ok_eq( 0xfeedcafe, sentence
, UINT
, "%#x" );
4601 ok_eq( 0xdeadbeef, ctx
->fdwConversion
, UINT
, "%#x" );
4602 ok_eq( 0xfeedcafe, ctx
->fdwSentence
, UINT
, "%#x" );
4604 ok_ret( 1, ImmSetConversionStatus( default_himc
, 0xdeadbeef, 0xfeedcafe ) );
4605 ok_seq( empty_sequence
);
4607 ok_ret( 1, ImmGetConversionStatus( default_himc
, &conversion
, NULL
) );
4608 ok_eq( 0xdeadbeef, conversion
, UINT
, "%#x" );
4609 ok_eq( 0xdeadbeef, ctx
->fdwConversion
, UINT
, "%#x" );
4610 ok_eq( 0xfeedcafe, ctx
->fdwSentence
, UINT
, "%#x" );
4613 ok_seq( empty_sequence
);
4614 ok_ret( 1, ImmSetConversionStatus( default_himc
, 0, 0xfeedcafe ) );
4615 ok_seq( set_conversion_status_1_seq
);
4617 ok_ret( 1, ImmGetConversionStatus( default_himc
, &conversion
, &sentence
) );
4618 ok_eq( 0, conversion
, UINT
, "%#x" );
4619 ok_eq( 0xfeedcafe, sentence
, UINT
, "%#x" );
4620 ok_eq( 0, ctx
->fdwConversion
, UINT
, "%#x" );
4621 ok_eq( 0xfeedcafe, ctx
->fdwSentence
, UINT
, "%#x" );
4624 ok_seq( empty_sequence
);
4625 ok_ret( 1, ImmSetConversionStatus( default_himc
, ~0, ~0 ) );
4626 ok_seq( set_conversion_status_2_seq
);
4628 ok_ret( 1, ImmGetConversionStatus( default_himc
, NULL
, &sentence
) );
4629 ok_eq( ~0, sentence
, UINT
, "%#x" );
4630 ok_eq( ~0, ctx
->fdwConversion
, UINT
, "%#x" );
4631 ok_eq( ~0, ctx
->fdwSentence
, UINT
, "%#x" );
4633 ok_ret( 1, ImmSetConversionStatus( default_himc
, ~0, ~0 ) );
4634 ok_seq( empty_sequence
);
4636 ok_ret( 1, ImmGetConversionStatus( default_himc
, &conversion
, &sentence
) );
4637 ok_eq( ~0, conversion
, UINT
, "%#x" );
4638 ok_eq( ~0, sentence
, UINT
, "%#x" );
4639 ok_eq( ~0, ctx
->fdwConversion
, UINT
, "%#x" );
4640 ok_eq( ~0, ctx
->fdwSentence
, UINT
, "%#x" );
4642 /* status is cached and some bits are kept from the previous active IME */
4643 ok_ret( 1, ImmActivateLayout( default_hkl
) );
4644 todo_wine
ok_eq( 0x200, ctx
->fdwConversion
, UINT
, "%#x" );
4645 ok_eq( old_sentence
, ctx
->fdwSentence
, UINT
, "%#x" );
4646 ok_ret( 1, ImmActivateLayout( hkl
) );
4647 ok_eq( ~0, ctx
->fdwConversion
, UINT
, "%#x" );
4648 ok_eq( ~0, ctx
->fdwSentence
, UINT
, "%#x" );
4649 ok_ret( 1, ImmActivateLayout( default_hkl
) );
4650 todo_wine
ok_eq( 0x200, ctx
->fdwConversion
, UINT
, "%#x" );
4651 ok_eq( old_sentence
, ctx
->fdwSentence
, UINT
, "%#x" );
4653 ok_ret( 1, ImmFreeLayout( hkl
) );
4656 /* sanitize conversion status to some sane default */
4657 ok_ret( 1, ImmSetConversionStatus( default_himc
, 0, 0 ) );
4658 ok_ret( 1, ImmGetConversionStatus( default_himc
, &conversion
, &sentence
) );
4659 ok_eq( 0, conversion
, UINT
, "%#x" );
4660 ok_eq( 0, sentence
, UINT
, "%#x" );
4661 ok_eq( 0, ctx
->fdwConversion
, UINT
, "%#x" );
4662 ok_eq( 0, ctx
->fdwSentence
, UINT
, "%#x" );
4664 ok_ret( 1, DestroyWindow( hwnd
) );
4666 memset( ime_calls
, 0, sizeof(ime_calls
) );
4669 ok_ret( 1, ImmUnlockIMC( default_himc
) );
4672 static void test_ImmSetOpenStatus(void)
4674 const struct ime_call set_open_status_0_seq
[] =
4677 .hkl
= expect_ime
, .himc
= default_himc
,
4678 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETOPENSTATUS
},
4681 .hkl
= expect_ime
, .himc
= default_himc
,
4682 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETOPENSTATUS
},
4685 .hkl
= expect_ime
, .himc
= default_himc
,
4686 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETOPENSTATUS
},
4690 const struct ime_call set_open_status_1_seq
[] =
4693 .hkl
= expect_ime
, .himc
= default_himc
,
4694 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETOPENSTATUS
},
4698 const struct ime_call set_open_status_2_seq
[] =
4701 .hkl
= expect_ime
, .himc
= default_himc
,
4702 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETOPENSTATUS
},
4705 .hkl
= expect_ime
, .himc
= default_himc
,
4706 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETOPENSTATUS
},
4709 .hkl
= expect_ime
, .himc
= default_himc
,
4710 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETOPENSTATUS
},
4715 struct ime_windows ime_windows
= {0};
4716 DWORD old_status
, status
;
4720 ok_ret( 0, ImmGetOpenStatus( 0 ) );
4721 old_status
= ImmGetOpenStatus( default_himc
);
4723 ctx
= ImmLockIMC( default_himc
);
4724 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
4725 ok_eq( old_status
, ctx
->fOpen
, UINT
, "%#x" );
4727 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
4728 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
4729 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
4732 status
= ImmGetOpenStatus( default_himc
);
4733 ok_eq( old_status
, status
, UINT
, "%#x" );
4734 ok_eq( old_status
, ctx
->fOpen
, UINT
, "%#x" );
4736 ok_ret( 1, ImmSetOpenStatus( default_himc
, 0 ) );
4737 status
= ImmGetOpenStatus( default_himc
);
4738 ok_eq( 0, status
, UINT
, "%#x" );
4739 ok_eq( 0, ctx
->fOpen
, UINT
, "%#x" );
4741 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
4743 if (!(hkl
= wineime_hkl
)) goto cleanup
;
4745 ok_ret( 1, ImmActivateLayout( hkl
) );
4746 ok_ret( 1, ImmLoadIME( hkl
) );
4748 /* initial values are dependent on both old and new IME */
4749 ok_ret( 1, ImmSetOpenStatus( default_himc
, 0 ) );
4750 memset( ime_calls
, 0, sizeof(ime_calls
) );
4753 status
= ImmGetOpenStatus( default_himc
);
4754 ok_eq( 0, status
, UINT
, "%#x" );
4755 ok_eq( 0, ctx
->fOpen
, UINT
, "%#x" );
4757 ok_seq( empty_sequence
);
4758 ok_ret( 1, ImmSetOpenStatus( default_himc
, 0xdeadbeef ) );
4759 ok_seq( set_open_status_0_seq
);
4761 status
= ImmGetOpenStatus( default_himc
);
4762 ok_eq( 0xdeadbeef, status
, UINT
, "%#x" );
4763 ok_eq( 0xdeadbeef, ctx
->fOpen
, UINT
, "%#x" );
4766 himc
= ImmCreateContext();
4767 ok_ne( NULL
, himc
, HIMC
, "%p" );
4768 ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows
, (LPARAM
)&ime_windows
) );
4769 ok_ne( NULL
, ime_windows
.ime_hwnd
, HWND
, "%p" );
4770 ok_ne( NULL
, ime_windows
.ime_ui_hwnd
, HWND
, "%p" );
4771 ok_eq( default_himc
, (HIMC
)GetWindowLongPtrW( ime_windows
.ime_ui_hwnd
, IMMGWL_IMC
), HIMC
, "%p" );
4772 ok_ret( 1, ImmSetOpenStatus( himc
, TRUE
) );
4773 ok_eq( default_himc
, (HIMC
)GetWindowLongPtrW( ime_windows
.ime_ui_hwnd
, IMMGWL_IMC
), HIMC
, "%p" );
4774 ok_ret( 1, ImmSetOpenStatus( himc
, FALSE
) );
4775 ok_eq( default_himc
, (HIMC
)GetWindowLongPtrW( ime_windows
.ime_ui_hwnd
, IMMGWL_IMC
), HIMC
, "%p" );
4776 ok_ret( 1, ImmDestroyContext( himc
) );
4777 memset( ime_calls
, 0, sizeof(ime_calls
) );
4781 ok_ret( 1, ImmSetOpenStatus( default_himc
, 0xdeadbeef ) );
4782 ok_seq( empty_sequence
);
4784 status
= ImmGetOpenStatus( default_himc
);
4785 ok_eq( 0xdeadbeef, status
, UINT
, "%#x" );
4786 ok_eq( 0xdeadbeef, ctx
->fOpen
, UINT
, "%#x" );
4789 ok_ret( 1, ImmSetOpenStatus( default_himc
, 0xfeedcafe ) );
4790 ok_seq( set_open_status_1_seq
);
4792 status
= ImmGetOpenStatus( default_himc
);
4793 ok_eq( 0xfeedcafe, status
, UINT
, "%#x" );
4794 ok_eq( 0xfeedcafe, ctx
->fOpen
, UINT
, "%#x" );
4797 ok_seq( empty_sequence
);
4798 ok_ret( 1, ImmSetOpenStatus( default_himc
, ~0 ) );
4799 ok_seq( set_open_status_2_seq
);
4801 status
= ImmGetOpenStatus( default_himc
);
4802 ok_eq( ~0, status
, UINT
, "%#x" );
4803 ok_eq( ~0, ctx
->fOpen
, UINT
, "%#x" );
4805 ok_ret( 1, ImmSetOpenStatus( default_himc
, ~0 ) );
4806 ok_seq( empty_sequence
);
4808 status
= ImmGetOpenStatus( default_himc
);
4809 ok_eq( ~0, status
, UINT
, "%#x" );
4810 ok_eq( ~0, ctx
->fOpen
, UINT
, "%#x" );
4812 /* status is cached between IME activations */
4814 ok_ret( 1, ImmActivateLayout( default_hkl
) );
4815 status
= ImmGetOpenStatus( default_himc
);
4816 ok_eq( old_status
, status
, UINT
, "%#x" );
4817 ok_eq( old_status
, ctx
->fOpen
, UINT
, "%#x" );
4818 ok_ret( 1, ImmActivateLayout( hkl
) );
4819 status
= ImmGetOpenStatus( default_himc
);
4820 todo_wine
ok_eq( 1, status
, UINT
, "%#x" );
4821 todo_wine
ok_eq( 1, ctx
->fOpen
, UINT
, "%#x" );
4822 ok_ret( 1, ImmSetOpenStatus( default_himc
, 0 ) );
4823 ok_ret( 1, ImmActivateLayout( default_hkl
) );
4824 status
= ImmGetOpenStatus( default_himc
);
4825 ok_eq( old_status
, status
, UINT
, "%#x" );
4826 ok_eq( old_status
, ctx
->fOpen
, UINT
, "%#x" );
4828 ok_ret( 1, ImmFreeLayout( hkl
) );
4831 /* sanitize open status to some sane default */
4832 ok_ret( 1, ImmSetOpenStatus( default_himc
, 0 ) );
4833 status
= ImmGetOpenStatus( default_himc
);
4834 ok_eq( 0, status
, UINT
, "%#x" );
4835 ok_eq( 0, ctx
->fOpen
, UINT
, "%#x" );
4837 ok_ret( 1, DestroyWindow( hwnd
) );
4839 memset( ime_calls
, 0, sizeof(ime_calls
) );
4842 ok_ret( 1, ImmUnlockIMC( default_himc
) );
4845 static void test_ImmProcessKey(void)
4847 const struct ime_call process_key_0
[] =
4850 .hkl
= expect_ime
, .himc
= default_himc
,
4851 .func
= IME_PROCESS_KEY
, .process_key
= {.vkey
= 'A', .lparam
= MAKELONG(0, 0x1e)},
4855 const struct ime_call process_key_1
[] =
4858 .hkl
= expect_ime
, .himc
= default_himc
,
4859 .func
= IME_PROCESS_KEY
, .process_key
= {.vkey
= 'A', .lparam
= MAKELONG(1, 0x1e)},
4863 const struct ime_call process_key_2
[] =
4866 .hkl
= expect_ime
, .himc
= default_himc
,
4867 .func
= IME_PROCESS_KEY
, .process_key
= {.vkey
= 'A', .lparam
= MAKELONG(2, 0x1e)},
4875 hwnd
= CreateWindowW( L
"static", NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
4876 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
4877 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
4880 ok_ret( 0, ImmProcessKey( hwnd
, default_hkl
, 'A', MAKELONG(1, 0x1e), 0 ) );
4881 ok_seq( empty_sequence
);
4883 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
4885 if (!(hkl
= wineime_hkl
)) goto cleanup
;
4887 ok_ret( 1, ImmActivateLayout( hkl
) );
4888 ok_ret( 1, ImmLoadIME( hkl
) );
4890 memset( ime_calls
, 0, sizeof(ime_calls
) );
4893 ok_ret( 0, ImmProcessKey( 0, hkl
, 'A', MAKELONG(1, 0x1e), 0 ) );
4894 ok_seq( empty_sequence
);
4896 ok_ret( 0, ImmProcessKey( hwnd
, hkl
, 'A', MAKELONG(0, 0x1e), 0 ) );
4897 ok_seq( process_key_0
);
4898 ret
= ImmProcessKey( hwnd
, hkl
, 'A', MAKELONG(1, 0x1e), 0 );
4901 ok_seq( process_key_1
);
4902 ok_ret( 2, ImmProcessKey( hwnd
, hkl
, 'A', MAKELONG(2, 0x1e), 0 ) );
4903 ok_seq( process_key_2
);
4905 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4906 ok_ret( 0, ImmProcessKey( hwnd
, default_hkl
, 'A', MAKELONG(1, 0x1e), 0 ) );
4907 ok_seq( empty_sequence
);
4908 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
4910 himc
= ImmCreateContext();
4911 ok_ne( NULL
, himc
, HIMC
, "%p" );
4912 ok_ret( 'A', ImmGetVirtualKey( hwnd
) );
4913 ok_eq( default_himc
, ImmAssociateContext( hwnd
, himc
), HIMC
, "%p" );
4914 todo_wine
ok_ret( VK_PROCESSKEY
, ImmGetVirtualKey( hwnd
) );
4915 ok_eq( himc
, ImmAssociateContext( hwnd
, default_himc
), HIMC
, "%p" );
4916 ok_ret( 'A', ImmGetVirtualKey( hwnd
) );
4917 ImmDestroyContext( himc
);
4919 ok_ret( 0, ImmTranslateMessage( hwnd
, WM_KEYUP
, 'A', 0 ) );
4920 ok_ret( VK_PROCESSKEY
, ImmGetVirtualKey( hwnd
) );
4922 ok_ret( 1, ImmActivateLayout( default_hkl
) );
4924 ok_ret( 1, ImmFreeLayout( hkl
) );
4926 memset( ime_calls
, 0, sizeof(ime_calls
) );
4930 ok_ret( 1, DestroyWindow( hwnd
) );
4933 static void test_ImmActivateLayout(void)
4935 const struct ime_call activate_seq
[] =
4938 .hkl
= expect_ime
, .himc
= default_himc
,
4939 .func
= IME_SELECT
, .select
= 1,
4943 const struct ime_call deactivate_seq
[] =
4946 .hkl
= expect_ime
, .himc
= default_himc
,
4947 .func
= IME_NOTIFY
, .notify
= {.action
= NI_COMPOSITIONSTR
, .index
= CPS_CANCEL
, .value
= 0},
4951 .hkl
= default_hkl
, .himc
= default_himc
,
4952 .func
= IME_SELECT
, .select
= 0,
4956 struct ime_call activate_with_window_seq
[] =
4959 .hkl
= expect_ime
, .himc
= default_himc
,
4960 .func
= IME_SELECT
, .select
= 1,
4964 .hkl
= expect_ime
, .himc
= 0/*himc*/,
4965 .func
= IME_SELECT
, .select
= 1,
4969 .hkl
= expect_ime
, .himc
= default_himc
,
4970 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SELECT
, .wparam
= 1, .lparam
= (LPARAM
)expect_ime
},
4973 .hkl
= expect_ime
, .himc
= default_himc
,
4974 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_OPENSTATUSWINDOW
},
4978 .hkl
= expect_ime
, .himc
= default_himc
,
4979 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETOPENSTATUS
},
4983 .hkl
= expect_ime
, .himc
= default_himc
,
4984 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCONVERSIONMODE
},
4988 .hkl
= expect_ime
, .himc
= default_himc
,
4989 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETSENTENCEMODE
},
4994 struct ime_call deactivate_with_window_seq
[] =
4997 .hkl
= expect_ime
, .himc
= default_himc
,
4998 .func
= IME_NOTIFY
, .notify
= {.action
= NI_COMPOSITIONSTR
, .index
= CPS_CANCEL
, .value
= 0},
4999 .todo
= TRUE
, .flaky_himc
= TRUE
,
5002 .hkl
= expect_ime
, .himc
= 0/*himc*/,
5003 .func
= IME_NOTIFY
, .notify
= {.action
= NI_COMPOSITIONSTR
, .index
= CPS_CANCEL
, .value
= 0},
5004 .todo
= TRUE
, .flaky_himc
= TRUE
,
5007 .hkl
= expect_ime
, .himc
= default_himc
,
5008 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_CLOSESTATUSWINDOW
},
5012 .hkl
= expect_ime
, .himc
= default_himc
,
5013 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SELECT
, .wparam
= 0, .lparam
= (LPARAM
)expect_ime
},
5016 .hkl
= default_hkl
, .himc
= default_himc
,
5017 .func
= IME_SELECT
, .select
= 0,
5021 .hkl
= default_hkl
, .himc
= 0/*himc*/,
5022 .func
= IME_SELECT
, .select
= 0,
5028 struct ime_windows ime_windows
= {0};
5032 SET_ENABLE( ImeInquire
, TRUE
);
5033 SET_ENABLE( ImeDestroy
, TRUE
);
5035 ok_ret( 1, ImmActivateLayout( default_hkl
) );
5037 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
5039 if (!(hkl
= wineime_hkl
)) goto cleanup
;
5041 /* ActivateKeyboardLayout doesn't call ImeInquire / ImeDestroy */
5043 ok_seq( empty_sequence
);
5044 ok_eq( default_hkl
, ActivateKeyboardLayout( hkl
, 0 ), HKL
, "%p" );
5045 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
5046 ok_eq( hkl
, ActivateKeyboardLayout( default_hkl
, 0 ), HKL
, "%p" );
5047 ok_seq( empty_sequence
);
5048 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
5051 /* ImmActivateLayout changes active HKL */
5053 SET_EXPECT( ImeInquire
);
5054 ok_ret( 1, ImmActivateLayout( hkl
) );
5055 ok_seq( activate_seq
);
5056 CHECK_CALLED( ImeInquire
);
5057 ok_ret( 1, ImmLoadIME( hkl
) );
5059 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
5061 ok_ret( 1, ImmActivateLayout( hkl
) );
5062 ok_seq( empty_sequence
);
5064 ok_ret( 1, ImmActivateLayout( default_hkl
) );
5065 ok_seq( deactivate_seq
);
5067 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
5070 /* ImmActivateLayout leaks the IME, we need to free it manually */
5072 SET_EXPECT( ImeDestroy
);
5073 ret
= ImmFreeLayout( hkl
);
5074 ok( ret
, "ImmFreeLayout returned %u\n", ret
);
5075 CHECK_CALLED( ImeDestroy
);
5076 ok_seq( empty_sequence
);
5079 /* when there's a window, ActivateKeyboardLayout calls ImeInquire */
5081 hwnd
= CreateWindowW( L
"static", NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
5082 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
5083 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
5085 ok_seq( empty_sequence
);
5087 himc
= ImmCreateContext();
5088 ok( !!himc
, "got himc %p\n", himc
);
5089 ok_seq( empty_sequence
);
5091 SET_EXPECT( ImeInquire
);
5092 ok_eq( default_hkl
, ActivateKeyboardLayout( hkl
, 0 ), HKL
, "%p" );
5093 CHECK_CALLED( ImeInquire
);
5094 activate_with_window_seq
[1].himc
= himc
;
5095 ok_seq( activate_with_window_seq
);
5096 ok_ret( 1, ImmLoadIME( hkl
) );
5098 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
5100 /* FIXME: ignore spurious VK_CONTROL ImeProcessKey / ImeToAsciiEx calls */
5102 memset( ime_calls
, 0, sizeof(ime_calls
) );
5105 ok_eq( hkl
, ActivateKeyboardLayout( default_hkl
, 0 ), HKL
, "%p" );
5106 deactivate_with_window_seq
[1].himc
= himc
;
5107 deactivate_with_window_seq
[5].himc
= himc
;
5108 ok_seq( deactivate_with_window_seq
);
5110 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
5112 ok_ret( 1, ImmDestroyContext( himc
) );
5113 ok_seq( empty_sequence
);
5116 ok_eq( default_hkl
, ActivateKeyboardLayout( hkl
, 0 ), HKL
, "%p" );
5117 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
5119 ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows
, (LPARAM
)&ime_windows
) );
5120 ok( !!ime_windows
.ime_hwnd
, "missing IME window\n" );
5121 ok( !!ime_windows
.ime_ui_hwnd
, "missing IME UI window\n" );
5122 ok_ret( (UINT_PTR
)ime_windows
.ime_hwnd
, (UINT_PTR
)GetParent( ime_windows
.ime_ui_hwnd
) );
5124 ok_eq( hkl
, ActivateKeyboardLayout( default_hkl
, 0 ), HKL
, "%p" );
5125 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
5129 SET_EXPECT( ImeDestroy
);
5130 ok_ret( 1, ImmFreeLayout( hkl
) );
5131 CHECK_CALLED( ImeDestroy
);
5133 ok_ret( 1, DestroyWindow( hwnd
) );
5135 memset( ime_calls
, 0, sizeof(ime_calls
) );
5140 SET_ENABLE( ImeInquire
, FALSE
);
5141 SET_ENABLE( ImeDestroy
, FALSE
);
5144 static void test_ImmCreateInputContext(void)
5146 struct ime_call activate_seq
[] =
5149 .hkl
= expect_ime
, .himc
= default_himc
,
5150 .func
= IME_SELECT
, .select
= 1,
5154 .hkl
= expect_ime
, .himc
= 0/*himc[0]*/,
5155 .func
= IME_SELECT
, .select
= 1,
5159 .hkl
= expect_ime
, .himc
= default_himc
,
5160 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SELECT
, .wparam
= 1, .lparam
= (LPARAM
)expect_ime
},
5163 .hkl
= expect_ime
, .himc
= default_himc
,
5164 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_OPENSTATUSWINDOW
},
5169 struct ime_call select1_seq
[] =
5172 .hkl
= expect_ime
, .himc
= 0/*himc[0]*/,
5173 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETOPENSTATUS
},
5174 .todo
= TRUE
, .flaky_himc
= TRUE
, .broken
= TRUE
/* sometimes */,
5177 .hkl
= expect_ime
, .himc
= default_himc
,
5178 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETOPENSTATUS
},
5179 .todo
= TRUE
, .flaky_himc
= TRUE
, .broken
= TRUE
/* sometimes */,
5182 .hkl
= expect_ime
, .himc
= default_himc
,
5183 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETOPENSTATUS
},
5184 .todo
= TRUE
, .broken
= TRUE
/* sometimes */,
5187 .hkl
= expect_ime
, .himc
= default_himc
,
5188 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCONVERSIONMODE
},
5189 .todo
= TRUE
, .broken
= TRUE
/* sometimes */,
5192 .hkl
= expect_ime
, .himc
= 0/*himc[1]*/,
5193 .func
= IME_SELECT
, .select
= 1,
5197 struct ime_call select0_seq
[] =
5200 .hkl
= expect_ime
, .himc
= 0/*himc[1]*/,
5201 .func
= IME_SELECT
, .select
= 0,
5205 struct ime_call deactivate_seq
[] =
5208 .hkl
= expect_ime
, .himc
= default_himc
,
5209 .func
= IME_NOTIFY
, .notify
= {.action
= NI_COMPOSITIONSTR
, .index
= CPS_CANCEL
, .value
= 0},
5210 .todo
= TRUE
, .flaky_himc
= TRUE
,
5213 .hkl
= expect_ime
, .himc
= 0/*himc[0]*/,
5214 .func
= IME_NOTIFY
, .notify
= {.action
= NI_COMPOSITIONSTR
, .index
= CPS_CANCEL
, .value
= 0},
5215 .todo
= TRUE
, .flaky_himc
= TRUE
,
5218 .hkl
= expect_ime
, .himc
= default_himc
,
5219 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_CLOSESTATUSWINDOW
},
5223 .hkl
= expect_ime
, .himc
= default_himc
,
5224 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SELECT
, .wparam
= 0, .lparam
= (LPARAM
)expect_ime
},
5227 .hkl
= default_hkl
, .himc
= default_himc
,
5228 .func
= IME_SELECT
, .select
= 0,
5232 .hkl
= default_hkl
, .himc
= 0/*himc[0]*/,
5233 .func
= IME_SELECT
, .select
= 0,
5243 ctx
= ImmLockIMC( default_himc
);
5244 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
5245 ok_ret( 0, IsWindow( ctx
->hWnd
) );
5246 ok_ret( 1, ImmUnlockIMC( default_himc
) );
5249 /* new input contexts cannot be locked before IME window has been created */
5251 himc
[0] = ImmCreateContext();
5252 ok( !!himc
[0], "ImmCreateContext failed, error %lu\n", GetLastError() );
5253 ctx
= ImmLockIMC( himc
[0] );
5255 ok( !ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
5256 if (ctx
) ImmUnlockIMCC( himc
[0] );
5258 hwnd
= CreateWindowW( L
"static", NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
5259 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
5260 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
5263 ctx
= ImmLockIMC( default_himc
);
5264 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
5265 ok_ret( 1, ImmUnlockIMC( default_himc
) );
5267 ctx
= ImmLockIMC( himc
[0] );
5268 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
5269 ok_ret( 1, ImmUnlockIMC( himc
[0] ) );
5272 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
5273 ime_info
.dwPrivateDataSize
= 123;
5275 if (!(hkl
= wineime_hkl
)) goto cleanup
;
5277 ok_ret( 1, ImmLoadIME( hkl
) );
5279 /* Activating the layout calls ImeSelect 1 on existing HIMC */
5281 ok_seq( empty_sequence
);
5282 ok_ret( 1, ImmActivateLayout( hkl
) );
5283 activate_seq
[1].himc
= himc
[0];
5284 ok_seq( activate_seq
);
5286 ok_eq( hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
5288 ctx
= ImmLockIMC( default_himc
);
5289 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
5290 ok_ret( 1, ImmUnlockIMC( default_himc
) );
5292 ctx
= ImmLockIMC( himc
[0] );
5293 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
5294 ok_ret( 1, ImmUnlockIMC( himc
[0] ) );
5297 /* ImmLockIMC triggers the ImeSelect call, to allocate private data */
5299 himc
[1] = ImmCreateContext();
5300 ok( !!himc
[1], "ImmCreateContext failed, error %lu\n", GetLastError() );
5302 ok_seq( empty_sequence
);
5303 ctx
= ImmLockIMC( himc
[1] );
5304 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
5305 select1_seq
[0].himc
= himc
[0];
5306 select1_seq
[4].himc
= himc
[1];
5307 ok_seq( select1_seq
);
5309 ok_ret( 1, ImmUnlockIMC( himc
[1] ) );
5311 ok_seq( empty_sequence
);
5312 ok_ret( 1, ImmDestroyContext( himc
[1] ) );
5313 select0_seq
[0].himc
= himc
[1];
5314 ok_seq( select0_seq
);
5317 /* Deactivating the layout calls ImeSelect 0 on existing HIMC */
5319 ok_ret( 1, ImmActivateLayout( default_hkl
) );
5320 deactivate_seq
[1].himc
= himc
[0];
5321 deactivate_seq
[5].himc
= himc
[0];
5322 ok_seq( deactivate_seq
);
5324 ok_eq( default_hkl
, GetKeyboardLayout( 0 ), HKL
, "%p" );
5326 ok_ret( 1, ImmFreeLayout( hkl
) );
5327 ok_seq( empty_sequence
);
5330 ok_ret( 1, ImmDestroyContext( himc
[0] ) );
5331 ok_ret( 1, DestroyWindow( hwnd
) );
5333 memset( ime_calls
, 0, sizeof(ime_calls
) );
5336 ime_info
.dwPrivateDataSize
= 0;
5339 static void test_DefWindowProc(void)
5341 const struct ime_call start_composition_seq
[] =
5343 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_STARTCOMPOSITION
}},
5346 const struct ime_call end_composition_seq
[] =
5348 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_ENDCOMPOSITION
}},
5351 const struct ime_call composition_seq
[] =
5353 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_COMPOSITION
}},
5356 const struct ime_call set_context_seq
[] =
5358 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SETCONTEXT
}},
5361 const struct ime_call notify_seq
[] =
5363 {.hkl
= expect_ime
, .himc
= default_himc
, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
}},
5369 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
5371 if (!(hkl
= wineime_hkl
)) return;
5373 hwnd
= CreateWindowW( L
"static", NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
5374 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
5375 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
5377 ok_ret( 1, ImmActivateLayout( hkl
) );
5378 ok_ret( 1, ImmLoadIME( hkl
) );
5380 memset( ime_calls
, 0, sizeof(ime_calls
) );
5383 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_STARTCOMPOSITION
, 0, 0 ) );
5384 ok_seq( start_composition_seq
);
5385 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_ENDCOMPOSITION
, 0, 0 ) );
5386 ok_seq( end_composition_seq
);
5387 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_COMPOSITION
, 0, 0 ) );
5388 ok_seq( composition_seq
);
5389 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_SETCONTEXT
, 0, 0 ) );
5390 ok_seq( set_context_seq
);
5391 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_NOTIFY
, 0, 0 ) );
5392 ok_seq( notify_seq
);
5393 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_CONTROL
, 0, 0 ) );
5394 ok_seq( empty_sequence
);
5395 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_COMPOSITIONFULL
, 0, 0 ) );
5396 ok_seq( empty_sequence
);
5397 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_SELECT
, 0, 0 ) );
5398 ok_seq( empty_sequence
);
5399 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_CHAR
, 0, 0 ) );
5400 ok_seq( empty_sequence
);
5401 ok_ret( 0, DefWindowProcW( hwnd
, 0x287, 0, 0 ) );
5402 ok_seq( empty_sequence
);
5403 ok_ret( 0, DefWindowProcW( hwnd
, WM_IME_REQUEST
, 0, 0 ) );
5404 ok_seq( empty_sequence
);
5405 ret
= DefWindowProcW( hwnd
, WM_IME_KEYDOWN
, 0, 0 );
5408 ok_seq( empty_sequence
);
5409 ret
= DefWindowProcW( hwnd
, WM_IME_KEYUP
, 0, 0 );
5412 ok_seq( empty_sequence
);
5414 ok_ret( 1, ImmActivateLayout( default_hkl
) );
5415 ok_ret( 1, DestroyWindow( hwnd
) );
5418 ok_ret( 1, ImmFreeLayout( hkl
) );
5419 memset( ime_calls
, 0, sizeof(ime_calls
) );
5423 static void test_ImmSetActiveContext(void)
5425 const struct ime_call activate_0_seq
[] =
5428 .hkl
= expect_ime
, .himc
= default_himc
,
5429 .func
= IME_SET_ACTIVE_CONTEXT
, .set_active_context
= {.flag
= 1}
5432 .hkl
= expect_ime
, .himc
= default_himc
,
5433 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SETCONTEXT
, .wparam
= 1, .lparam
= ISC_SHOWUIALL
}
5437 const struct ime_call deactivate_0_seq
[] =
5440 .hkl
= expect_ime
, .himc
= default_himc
,
5441 .func
= IME_SET_ACTIVE_CONTEXT
, .set_active_context
= {.flag
= 0}
5444 .hkl
= expect_ime
, .himc
= default_himc
,
5445 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SETCONTEXT
, .wparam
= 0, .lparam
= ISC_SHOWUIALL
}
5449 struct ime_call deactivate_1_seq
[] =
5452 .hkl
= expect_ime
, .himc
= default_himc
,
5453 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETOPENSTATUS
},
5454 .todo
= TRUE
, .flaky_himc
= TRUE
, .broken
= TRUE
/* sometimes */,
5457 .hkl
= expect_ime
, .himc
= default_himc
,
5458 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETOPENSTATUS
},
5459 .todo
= TRUE
, .broken
= TRUE
/* sometimes */,
5462 .hkl
= expect_ime
, .himc
= default_himc
,
5463 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCONVERSIONMODE
},
5464 .todo
= TRUE
, .broken
= TRUE
/* sometimes */,
5467 .hkl
= expect_ime
, .himc
= 0/*himc*/,
5468 .func
= IME_SELECT
, .select
= 1,
5471 .hkl
= expect_ime
, .himc
= 0/*himc*/,
5472 .func
= IME_SET_ACTIVE_CONTEXT
, .set_active_context
= {.flag
= 0}
5475 .hkl
= expect_ime
, .himc
= default_himc
,
5476 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SETCONTEXT
, .wparam
= 0, .lparam
= ISC_SHOWUIALL
}
5480 struct ime_call deactivate_2_seq
[] =
5483 .hkl
= expect_ime
, .himc
= 0/*himc*/,
5484 .func
= IME_SET_ACTIVE_CONTEXT
, .set_active_context
= {.flag
= 0}
5487 .hkl
= expect_ime
, .himc
= default_himc
,
5488 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SETCONTEXT
, .wparam
= 0, .lparam
= ISC_SHOWUIALL
}
5492 struct ime_call activate_1_seq
[] =
5495 .hkl
= expect_ime
, .himc
= 0/*himc*/,
5496 .func
= IME_SET_ACTIVE_CONTEXT
, .set_active_context
= {.flag
= 1}
5499 .hkl
= expect_ime
, .himc
= default_himc
,
5500 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_SETCONTEXT
, .wparam
= 1, .lparam
= ISC_SHOWUIALL
}
5505 struct ime_windows ime_windows
= {0};
5509 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
5511 if (!(hkl
= wineime_hkl
)) return;
5513 hwnd
= CreateWindowW( L
"static", NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
5514 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
5515 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
5517 ok_ret( 1, ImmActivateLayout( hkl
) );
5518 ok_ret( 1, ImmLoadIME( hkl
) );
5520 memset( ime_calls
, 0, sizeof(ime_calls
) );
5523 ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows
, (LPARAM
)&ime_windows
) );
5524 ok_ne( NULL
, ime_windows
.ime_hwnd
, HWND
, "%p" );
5525 ok_ne( NULL
, ime_windows
.ime_ui_hwnd
, HWND
, "%p" );
5526 ok_ret( 0, IsWindowVisible( ime_windows
.ime_ui_hwnd
) );
5528 SetLastError( 0xdeadbeef );
5529 ok_ret( 1, ImmSetActiveContext( hwnd
, default_himc
, TRUE
) );
5530 ok_seq( activate_0_seq
);
5531 ok_ret( 0, GetLastError() );
5532 ok_ret( 0, IsWindowVisible( ime_windows
.ime_ui_hwnd
) );
5533 ok_ret( 1, ImmSetActiveContext( hwnd
, default_himc
, TRUE
) );
5534 ok_seq( activate_0_seq
);
5535 ok_ret( 1, ImmSetActiveContext( hwnd
, default_himc
, FALSE
) );
5536 ok_seq( deactivate_0_seq
);
5538 himc
= ImmCreateContext();
5539 ok_ne( NULL
, himc
, HIMC
, "%p" );
5540 ctx
= ImmLockIMC( himc
);
5541 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
5542 ok_eq( 0, ctx
->hWnd
, HWND
, "%p" );
5544 ok_ret( 1, ImmSetActiveContext( hwnd
, himc
, FALSE
) );
5545 deactivate_1_seq
[3].himc
= himc
;
5546 deactivate_1_seq
[4].himc
= himc
;
5547 ok_seq( deactivate_1_seq
);
5548 ok_ret( 1, ImmSetActiveContext( hwnd
, himc
, TRUE
) );
5549 activate_1_seq
[0].himc
= himc
;
5550 ok_seq( activate_1_seq
);
5552 ctx
->hWnd
= (HWND
)0xdeadbeef;
5553 ok_ret( 1, ImmSetActiveContext( hwnd
, himc
, FALSE
) );
5554 ok_eq( (HWND
)0xdeadbeef, ctx
->hWnd
, HWND
, "%p" );
5555 deactivate_2_seq
[0].himc
= himc
;
5556 ok_seq( deactivate_2_seq
);
5559 ok_ret( 1, ImmSetActiveContext( hwnd
, himc
, TRUE
) );
5560 ok_eq( hwnd
, ctx
->hWnd
, HWND
, "%p" );
5561 activate_1_seq
[0].himc
= himc
;
5562 ok_seq( activate_1_seq
);
5564 ok_eq( default_himc
, (HIMC
)GetWindowLongPtrW( ime_windows
.ime_ui_hwnd
, IMMGWL_IMC
), HIMC
, "%p" );
5565 ok_ret( 1, ImmSetActiveContext( hwnd
, himc
, TRUE
) );
5566 ok_ret( 0, IsWindowVisible( ime_windows
.ime_ui_hwnd
) );
5567 ok_eq( default_himc
, (HIMC
)GetWindowLongPtrW( ime_windows
.ime_ui_hwnd
, IMMGWL_IMC
), HIMC
, "%p" );
5570 ok_eq( default_himc
, ImmAssociateContext( hwnd
, himc
), HIMC
, "%p" );
5571 ok_eq( himc
, (HIMC
)GetWindowLongPtrW( ime_windows
.ime_ui_hwnd
, IMMGWL_IMC
), HIMC
, "%p" );
5572 ok_ret( 0, IsWindowVisible( ime_windows
.ime_ui_hwnd
) );
5573 ok_eq( hwnd
, ctx
->hWnd
, HWND
, "%p" );
5575 ctx
->hWnd
= (HWND
)0xdeadbeef;
5576 ok_eq( himc
, ImmGetContext( hwnd
), HIMC
, "%p" );
5577 ok_eq( (HWND
)0xdeadbeef, ctx
->hWnd
, HWND
, "%p" );
5578 ok_ret( 1, ImmReleaseContext( hwnd
, himc
) );
5580 ok_ret( 1, ImmUnlockIMC( himc
) );
5581 ok_ret( 1, ImmDestroyContext( himc
) );
5583 ok_ret( 1, ImmActivateLayout( default_hkl
) );
5584 ok_ret( 1, DestroyWindow( hwnd
) );
5587 ok_ret( 1, ImmFreeLayout( hkl
) );
5588 memset( ime_calls
, 0, sizeof(ime_calls
) );
5592 static void test_ImmRequestMessage(void)
5594 struct ime_call composition_window_seq
[] =
5597 .hkl
= expect_ime
, .himc
= default_himc
,
5598 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_REQUEST
, .wparam
= IMR_COMPOSITIONWINDOW
, .lparam
= 0/*&comp_form*/}
5602 struct ime_call candidate_window_seq
[] =
5605 .hkl
= expect_ime
, .himc
= default_himc
,
5606 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_REQUEST
, .wparam
= IMR_CANDIDATEWINDOW
, .lparam
= 0/*&cand_form*/}
5610 struct ime_call composition_font_seq
[] =
5613 .hkl
= expect_ime
, .himc
= default_himc
,
5614 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_REQUEST
, .wparam
= IMR_COMPOSITIONFONT
, .lparam
= 0/*&log_font*/}
5618 struct ime_call reconvert_string_seq
[] =
5621 .hkl
= expect_ime
, .himc
= default_himc
,
5622 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_REQUEST
, .wparam
= IMR_RECONVERTSTRING
, .lparam
= 0/*&reconv*/}
5626 struct ime_call confirm_reconvert_string_seq
[] =
5629 .hkl
= expect_ime
, .himc
= default_himc
,
5630 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_REQUEST
, .wparam
= IMR_CONFIRMRECONVERTSTRING
, .lparam
= 0/*&reconv*/}
5634 struct ime_call query_char_position_seq
[] =
5637 .hkl
= expect_ime
, .himc
= default_himc
,
5638 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_REQUEST
, .wparam
= IMR_QUERYCHARPOSITION
, .lparam
= 0/*&char_pos*/}
5642 struct ime_call document_feed_seq
[] =
5645 .hkl
= expect_ime
, .himc
= default_himc
,
5646 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_REQUEST
, .wparam
= IMR_DOCUMENTFEED
, .lparam
= 0/*&reconv*/}
5651 COMPOSITIONFORM comp_form
= {0};
5652 IMECHARPOSITION char_pos
= {0};
5653 RECONVERTSTRING reconv
= {0};
5654 CANDIDATEFORM cand_form
= {0};
5655 LOGFONTW log_font
= {0};
5659 if (!(hkl
= wineime_hkl
)) return;
5661 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
5662 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
5663 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
5665 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
5667 ok_ret( 1, ImmActivateLayout( hkl
) );
5668 ok_ret( 1, ImmLoadIME( hkl
) );
5669 himc
= ImmCreateContext();
5670 ok_ne( NULL
, himc
, HIMC
, "%p" );
5671 ctx
= ImmLockIMC( himc
);
5672 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
5674 memset( ime_calls
, 0, sizeof(ime_calls
) );
5677 ok_ret( 0, ImmRequestMessageW( default_himc
, 0xdeadbeef, 0 ) );
5678 todo_wine
ok_seq( empty_sequence
);
5679 ok_ret( 0, ImmRequestMessageW( default_himc
, IMR_COMPOSITIONWINDOW
, (LPARAM
)&comp_form
) );
5680 composition_window_seq
[0].message
.lparam
= (LPARAM
)&comp_form
;
5681 ok_seq( composition_window_seq
);
5682 ok_ret( 0, ImmRequestMessageW( default_himc
, IMR_CANDIDATEWINDOW
, (LPARAM
)&cand_form
) );
5683 candidate_window_seq
[0].message
.lparam
= (LPARAM
)&cand_form
;
5684 ok_seq( candidate_window_seq
);
5685 ok_ret( 0, ImmRequestMessageW( default_himc
, IMR_COMPOSITIONFONT
, (LPARAM
)&log_font
) );
5686 composition_font_seq
[0].message
.lparam
= (LPARAM
)&log_font
;
5687 ok_seq( composition_font_seq
);
5688 ok_ret( 0, ImmRequestMessageW( default_himc
, IMR_RECONVERTSTRING
, (LPARAM
)&reconv
) );
5689 todo_wine
ok_seq( empty_sequence
);
5690 reconv
.dwSize
= sizeof(RECONVERTSTRING
);
5691 ok_ret( 0, ImmRequestMessageW( default_himc
, IMR_RECONVERTSTRING
, (LPARAM
)&reconv
) );
5692 reconvert_string_seq
[0].message
.lparam
= (LPARAM
)&reconv
;
5693 ok_seq( reconvert_string_seq
);
5694 ok_ret( 0, ImmRequestMessageW( default_himc
, IMR_CONFIRMRECONVERTSTRING
, (LPARAM
)&reconv
) );
5695 confirm_reconvert_string_seq
[0].message
.lparam
= (LPARAM
)&reconv
;
5696 ok_seq( confirm_reconvert_string_seq
);
5697 ok_ret( 0, ImmRequestMessageW( default_himc
, IMR_QUERYCHARPOSITION
, (LPARAM
)&char_pos
) );
5698 query_char_position_seq
[0].message
.lparam
= (LPARAM
)&char_pos
;
5699 ok_seq( query_char_position_seq
);
5700 ok_ret( 0, ImmRequestMessageW( default_himc
, IMR_DOCUMENTFEED
, (LPARAM
)&reconv
) );
5701 document_feed_seq
[0].message
.lparam
= (LPARAM
)&reconv
;
5702 ok_seq( document_feed_seq
);
5704 ok_ret( 0, ImmRequestMessageW( himc
, IMR_CANDIDATEWINDOW
, (LPARAM
)&cand_form
) );
5705 ok_seq( empty_sequence
);
5706 ok_ret( 1, ImmSetActiveContext( hwnd
, himc
, TRUE
) );
5707 memset( ime_calls
, 0, sizeof(ime_calls
) );
5709 ok_ret( 0, ImmRequestMessageW( himc
, IMR_CANDIDATEWINDOW
, (LPARAM
)&cand_form
) );
5710 candidate_window_seq
[0].message
.lparam
= (LPARAM
)&cand_form
;
5711 ok_seq( candidate_window_seq
);
5712 ok_ret( 0, ImmRequestMessageW( default_himc
, IMR_CANDIDATEWINDOW
, (LPARAM
)&cand_form
) );
5713 ok_seq( candidate_window_seq
);
5715 ok_ret( 1, ImmUnlockIMC( himc
) );
5716 ok_ret( 1, ImmDestroyContext( himc
) );
5718 ok_ret( 1, ImmActivateLayout( default_hkl
) );
5719 ok_ret( 1, DestroyWindow( hwnd
) );
5722 ok_ret( 1, ImmFreeLayout( hkl
) );
5723 memset( ime_calls
, 0, sizeof(ime_calls
) );
5727 static void test_ImmGetCandidateList( BOOL unicode
)
5729 char buffer
[512], expect_bufW
[512] = {0}, expect_bufA
[512] = {0};
5730 CANDIDATELIST
*cand_list
= (CANDIDATELIST
*)buffer
, *expect_listW
, *expect_listA
;
5732 CANDIDATEINFO
*cand_info
;
5736 expect_listW
= (CANDIDATELIST
*)expect_bufW
;
5737 expect_listW
->dwSize
= offsetof(CANDIDATELIST
, dwOffset
[2]) + 32 * sizeof(WCHAR
);
5738 expect_listW
->dwStyle
= 0xdeadbeef;
5739 expect_listW
->dwCount
= 2;
5740 expect_listW
->dwSelection
= 3;
5741 expect_listW
->dwPageStart
= 4;
5742 expect_listW
->dwPageSize
= 5;
5743 expect_listW
->dwOffset
[0] = offsetof(CANDIDATELIST
, dwOffset
[2]) + 2 * sizeof(WCHAR
);
5744 expect_listW
->dwOffset
[1] = offsetof(CANDIDATELIST
, dwOffset
[2]) + 16 * sizeof(WCHAR
);
5745 wcscpy( (WCHAR
*)(expect_bufW
+ expect_listW
->dwOffset
[0]), L
"Candidate 1" );
5746 wcscpy( (WCHAR
*)(expect_bufW
+ expect_listW
->dwOffset
[1]), L
"Candidate 2" );
5748 expect_listA
= (CANDIDATELIST
*)expect_bufA
;
5749 expect_listA
->dwSize
= offsetof(CANDIDATELIST
, dwOffset
[2]) + 32;
5750 expect_listA
->dwStyle
= 0xdeadbeef;
5751 expect_listA
->dwCount
= 2;
5752 expect_listA
->dwSelection
= 3;
5753 expect_listA
->dwPageStart
= 4;
5754 expect_listA
->dwPageSize
= 5;
5755 expect_listA
->dwOffset
[0] = offsetof(CANDIDATELIST
, dwOffset
[2]) + 2;
5756 expect_listA
->dwOffset
[1] = offsetof(CANDIDATELIST
, dwOffset
[2]) + 16;
5757 strcpy( (char *)(expect_bufA
+ expect_listA
->dwOffset
[0]), "Candidate 1" );
5758 strcpy( (char *)(expect_bufA
+ expect_listA
->dwOffset
[1]), "Candidate 2" );
5760 winetest_push_context( unicode
? "unicode" : "ansi" );
5762 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
5763 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
5764 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
5766 if (!(hkl
= wineime_hkl
)) goto cleanup
;
5768 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
5769 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
5770 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
5772 ok_ret( 1, ImmActivateLayout( hkl
) );
5773 ok_ret( 1, ImmLoadIME( hkl
) );
5774 himc
= ImmCreateContext();
5775 ok_ne( NULL
, himc
, HIMC
, "%p" );
5776 ctx
= ImmLockIMC( himc
);
5777 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
5779 memset( ime_calls
, 0, sizeof(ime_calls
) );
5782 ok_ret( 0, ImmGetCandidateListW( default_himc
, 0, NULL
, 0 ) );
5783 ok_seq( empty_sequence
);
5784 ok_ret( 0, ImmGetCandidateListW( default_himc
, 1, NULL
, 0 ) );
5785 ok_seq( empty_sequence
);
5786 ok_ret( 0, ImmGetCandidateListW( default_himc
, 0, cand_list
, sizeof(buffer
) ) );
5787 ok_seq( empty_sequence
);
5789 ok_ret( 0, ImmGetCandidateListW( himc
, 0, cand_list
, sizeof(buffer
) ) );
5790 ok_seq( empty_sequence
);
5792 todo_wine
ok_seq( empty_sequence
);
5793 ctx
->hCandInfo
= ImmReSizeIMCC( ctx
->hCandInfo
, sizeof(*cand_info
) + sizeof(buffer
) );
5794 ok( !!ctx
->hCandInfo
, "ImmReSizeIMCC failed, error %lu\n", GetLastError() );
5796 cand_info
= ImmLockIMCC( ctx
->hCandInfo
);
5797 ok( !!cand_info
, "ImmLockIMCC failed, error %lu\n", GetLastError() );
5798 cand_info
->dwCount
= 1;
5799 cand_info
->dwOffset
[0] = sizeof(*cand_info
);
5800 if (unicode
) memcpy( cand_info
+ 1, expect_bufW
, sizeof(expect_bufW
) );
5801 else memcpy( cand_info
+ 1, expect_bufA
, sizeof(expect_bufA
) );
5802 ok_ret( 0, ImmUnlockIMCC( ctx
->hCandInfo
) );
5804 ok_ret( (unicode
? 96 : 80), ImmGetCandidateListW( himc
, 0, NULL
, 0 ) );
5805 ok_seq( empty_sequence
);
5806 ok_ret( 0, ImmGetCandidateListW( himc
, 1, NULL
, 0 ) );
5807 ok_seq( empty_sequence
);
5808 memset( buffer
, 0xcd, sizeof(buffer
) );
5809 ok_ret( (unicode
? 96 : 80), ImmGetCandidateListW( himc
, 0, cand_list
, sizeof(buffer
) ) );
5810 ok_seq( empty_sequence
);
5814 expect_listW
->dwSize
= offsetof(CANDIDATELIST
, dwOffset
[2]) + 24 * sizeof(WCHAR
);
5815 expect_listW
->dwOffset
[0] = offsetof(CANDIDATELIST
, dwOffset
[2]);
5816 expect_listW
->dwOffset
[1] = offsetof(CANDIDATELIST
, dwOffset
[2]) + 12 * sizeof(WCHAR
);
5817 wcscpy( (WCHAR
*)(expect_bufW
+ expect_listW
->dwOffset
[0]), L
"Candidate 1" );
5818 wcscpy( (WCHAR
*)(expect_bufW
+ expect_listW
->dwOffset
[1]), L
"Candidate 2" );
5820 check_candidate_list_( __LINE__
, cand_list
, expect_listW
, TRUE
);
5822 ok_ret( (unicode
? 56 : 64), ImmGetCandidateListA( himc
, 0, NULL
, 0 ) );
5823 ok_seq( empty_sequence
);
5824 ok_ret( 0, ImmGetCandidateListA( himc
, 1, NULL
, 0 ) );
5825 ok_seq( empty_sequence
);
5826 memset( buffer
, 0xcd, sizeof(buffer
) );
5827 ok_ret( (unicode
? 56 : 64), ImmGetCandidateListA( himc
, 0, cand_list
, sizeof(buffer
) ) );
5828 ok_seq( empty_sequence
);
5832 expect_listA
->dwSize
= offsetof(CANDIDATELIST
, dwOffset
[2]) + 24;
5833 expect_listA
->dwOffset
[0] = offsetof(CANDIDATELIST
, dwOffset
[2]);
5834 expect_listA
->dwOffset
[1] = offsetof(CANDIDATELIST
, dwOffset
[2]) + 12;
5835 strcpy( (char *)(expect_bufA
+ expect_listA
->dwOffset
[0]), "Candidate 1" );
5836 strcpy( (char *)(expect_bufA
+ expect_listA
->dwOffset
[1]), "Candidate 2" );
5838 check_candidate_list_( __LINE__
, cand_list
, expect_listA
, FALSE
);
5840 ok_ret( 1, ImmUnlockIMC( himc
) );
5841 ok_ret( 1, ImmDestroyContext( himc
) );
5843 ok_ret( 1, ImmActivateLayout( default_hkl
) );
5844 ok_ret( 1, DestroyWindow( hwnd
) );
5847 ok_ret( 1, ImmFreeLayout( hkl
) );
5848 memset( ime_calls
, 0, sizeof(ime_calls
) );
5852 winetest_pop_context();
5855 static void test_ImmGetCandidateListCount( BOOL unicode
)
5858 CANDIDATEINFO
*cand_info
;
5863 winetest_push_context( unicode
? "unicode" : "ansi" );
5865 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
5866 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
5867 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
5869 if (!(hkl
= wineime_hkl
)) goto cleanup
;
5871 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
5872 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
5873 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
5875 ok_ret( 1, ImmActivateLayout( hkl
) );
5876 ok_ret( 1, ImmLoadIME( hkl
) );
5877 himc
= ImmCreateContext();
5878 ok_ne( NULL
, himc
, HIMC
, "%p" );
5879 ctx
= ImmLockIMC( himc
);
5880 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
5882 memset( ime_calls
, 0, sizeof(ime_calls
) );
5885 ok_ret( 144, ImmGetCandidateListCountW( default_himc
, &count
) );
5886 ok_eq( 0, count
, UINT
, "%u" );
5887 ok_seq( empty_sequence
);
5888 ok_ret( 144, ImmGetCandidateListCountA( default_himc
, &count
) );
5889 ok_eq( 0, count
, UINT
, "%u" );
5890 ok_seq( empty_sequence
);
5892 ok_ret( 144, ImmGetCandidateListCountW( himc
, &count
) );
5893 ok_eq( 0, count
, UINT
, "%u" );
5894 ok_seq( empty_sequence
);
5895 ok_ret( 144, ImmGetCandidateListCountA( himc
, &count
) );
5896 ok_eq( 0, count
, UINT
, "%u" );
5897 ok_seq( empty_sequence
);
5899 cand_info
= ImmLockIMCC( ctx
->hCandInfo
);
5900 ok( !!cand_info
, "ImmLockIMCC failed, error %lu\n", GetLastError() );
5901 cand_info
->dwCount
= 1;
5902 ok_ret( 0, ImmUnlockIMCC( ctx
->hCandInfo
) );
5904 todo_wine_if(!unicode
)
5905 ok_ret( (unicode
? 144 : 172), ImmGetCandidateListCountW( himc
, &count
) );
5906 ok_eq( 1, count
, UINT
, "%u" );
5907 ok_seq( empty_sequence
);
5908 todo_wine_if(unicode
)
5909 ok_ret( (unicode
? 172 : 144), ImmGetCandidateListCountA( himc
, &count
) );
5910 ok_eq( 1, count
, UINT
, "%u" );
5911 ok_seq( empty_sequence
);
5913 ok_ret( 1, ImmUnlockIMC( himc
) );
5914 ok_ret( 1, ImmDestroyContext( himc
) );
5916 ok_ret( 1, ImmActivateLayout( default_hkl
) );
5917 ok_ret( 1, DestroyWindow( hwnd
) );
5920 ok_ret( 1, ImmFreeLayout( hkl
) );
5921 memset( ime_calls
, 0, sizeof(ime_calls
) );
5925 winetest_pop_context();
5928 static void test_ImmGetCandidateWindow(void)
5931 const CANDIDATEFORM expect_form
=
5933 .dwIndex
= 0xdeadbeef,
5934 .dwStyle
= 0xfeedcafe,
5935 .ptCurrentPos
= {.x
= 123, .y
= 456},
5936 .rcArea
= {.left
= 1, .top
= 2, .right
= 3, .bottom
= 4},
5938 CANDIDATEFORM cand_form
;
5942 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
5944 if (!(hkl
= wineime_hkl
)) return;
5946 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
5947 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
5948 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
5950 ok_ret( 1, ImmActivateLayout( hkl
) );
5951 ok_ret( 1, ImmLoadIME( hkl
) );
5952 himc
= ImmCreateContext();
5953 ok_ne( NULL
, himc
, HIMC
, "%p" );
5954 ctx
= ImmLockIMC( himc
);
5955 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
5957 memset( ime_calls
, 0, sizeof(ime_calls
) );
5960 memset( &cand_form
, 0xcd, sizeof(cand_form
) );
5961 ok_ret( 0, ImmGetCandidateWindow( default_himc
, 0, &cand_form
) );
5962 ok_eq( 0xcdcdcdcd, cand_form
.dwIndex
, UINT
, "%u" );
5963 ok_ret( 0, ImmGetCandidateWindow( default_himc
, 1, &cand_form
) );
5964 ok_eq( 0xcdcdcdcd, cand_form
.dwIndex
, UINT
, "%u" );
5965 ok_ret( 0, ImmGetCandidateWindow( default_himc
, 2, &cand_form
) );
5966 ok_eq( 0xcdcdcdcd, cand_form
.dwIndex
, UINT
, "%u" );
5967 ok_ret( 0, ImmGetCandidateWindow( default_himc
, 3, &cand_form
) );
5968 ok_eq( 0xcdcdcdcd, cand_form
.dwIndex
, UINT
, "%u" );
5969 ok_ret( 1, ImmGetCandidateWindow( default_himc
, 4, &cand_form
) );
5970 ok_seq( empty_sequence
);
5972 ok_ret( 0, ImmGetCandidateWindow( himc
, 0, &cand_form
) );
5973 ok_seq( empty_sequence
);
5975 ok_seq( empty_sequence
);
5976 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
5977 ctx
->cfCandForm
[0] = expect_form
;
5979 ok_ret( 1, ImmGetCandidateWindow( himc
, 0, &cand_form
) );
5980 check_candidate_form( &cand_form
, &expect_form
);
5981 ok_seq( empty_sequence
);
5983 ok_seq( empty_sequence
);
5984 ok( !!ctx
, "ImmLockIMC failed, error %lu\n", GetLastError() );
5985 ctx
->cfCandForm
[0].dwIndex
= -1;
5987 ok_ret( 0, ImmGetCandidateWindow( himc
, 0, &cand_form
) );
5988 ok_seq( empty_sequence
);
5990 ok_ret( 1, ImmUnlockIMC( himc
) );
5991 ok_ret( 1, ImmDestroyContext( himc
) );
5993 ok_ret( 1, ImmActivateLayout( default_hkl
) );
5994 ok_ret( 1, DestroyWindow( hwnd
) );
5997 ok_ret( 1, ImmFreeLayout( hkl
) );
5998 memset( ime_calls
, 0, sizeof(ime_calls
) );
6002 static void test_ImmGetCompositionString( BOOL unicode
)
6004 static COMPOSITIONSTRING expect_string_empty
= {.dwSize
= sizeof(COMPOSITIONSTRING
)};
6005 static COMPOSITIONSTRING expect_stringA
=
6008 .dwCompReadAttrLen
= 8,
6009 .dwCompReadAttrOffset
= 116,
6010 .dwCompReadClauseLen
= 8,
6011 .dwCompReadClauseOffset
= 108,
6012 .dwCompReadStrLen
= 8,
6013 .dwCompReadStrOffset
= 100,
6015 .dwCompAttrOffset
= 136,
6016 .dwCompClauseLen
= 8,
6017 .dwCompClauseOffset
= 128,
6019 .dwCompStrOffset
= 124,
6022 .dwResultReadClauseLen
= 8,
6023 .dwResultReadClauseOffset
= 150,
6024 .dwResultReadStrLen
= 10,
6025 .dwResultReadStrOffset
= 140,
6026 .dwResultClauseLen
= 8,
6027 .dwResultClauseOffset
= 164,
6028 .dwResultStrLen
= 6,
6029 .dwResultStrOffset
= 158,
6031 .dwPrivateOffset
= 172,
6033 static const COMPOSITIONSTRING expect_stringW
=
6036 .dwCompReadAttrLen
= 8,
6037 .dwCompReadAttrOffset
= 124,
6038 .dwCompReadClauseLen
= 8,
6039 .dwCompReadClauseOffset
= 116,
6040 .dwCompReadStrLen
= 8,
6041 .dwCompReadStrOffset
= 100,
6043 .dwCompAttrOffset
= 148,
6044 .dwCompClauseLen
= 8,
6045 .dwCompClauseOffset
= 140,
6047 .dwCompStrOffset
= 132,
6050 .dwResultReadClauseLen
= 8,
6051 .dwResultReadClauseOffset
= 172,
6052 .dwResultReadStrLen
= 10,
6053 .dwResultReadStrOffset
= 152,
6054 .dwResultClauseLen
= 8,
6055 .dwResultClauseOffset
= 192,
6056 .dwResultStrLen
= 6,
6057 .dwResultStrOffset
= 180,
6059 .dwPrivateOffset
= 200,
6061 static const UINT gcs_indexes
[] =
6072 GCS_RESULTREADCLAUSE
,
6076 static const UINT scs_indexes
[] =
6082 static const UINT expect_retW
[ARRAY_SIZE(gcs_indexes
)] = {16, 8, 8, 8, 4, 8, 3, 1, 20, 8, 12, 8};
6083 static const UINT expect_retA
[ARRAY_SIZE(gcs_indexes
)] = {8, 8, 8, 4, 4, 8, 3, 1, 10, 8, 6, 8};
6085 COMPOSITIONSTRING
*string
;
6087 INPUTCONTEXT
*old_ctx
, *ctx
;
6094 SET_ENABLE( ImeSetCompositionString
, TRUE
);
6096 winetest_push_context( unicode
? "unicode" : "ansi" );
6098 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
6099 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
6100 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
6102 if (!(hkl
= wineime_hkl
)) goto cleanup
;
6104 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
6105 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
6106 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
6108 ok_ret( 1, ImmActivateLayout( hkl
) );
6109 ok_ret( 1, ImmLoadIME( hkl
) );
6110 himc
= ImmCreateContext();
6111 ok_ne( NULL
, himc
, HIMC
, "%p" );
6112 ctx
= ImmLockIMC( himc
);
6113 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
6115 memset( ime_calls
, 0, sizeof(ime_calls
) );
6118 memset( buffer
, 0xcd, sizeof(buffer
) );
6119 todo_wine
ok_ret( -2, ImmGetCompositionStringW( default_himc
, GCS_COMPSTR
| GCS_COMPATTR
, buffer
, sizeof(buffer
) ) );
6120 memset( buffer
, 0xcd, sizeof(buffer
) );
6121 todo_wine
ok_ret( -2, ImmGetCompositionStringA( default_himc
, GCS_COMPSTR
| GCS_COMPATTR
, buffer
, sizeof(buffer
) ) );
6123 for (i
= 0; i
< ARRAY_SIZE(gcs_indexes
); ++i
)
6125 memset( buffer
, 0xcd, sizeof(buffer
) );
6126 ok_ret( 0, ImmGetCompositionStringW( default_himc
, gcs_indexes
[i
], buffer
, sizeof(buffer
) ) );
6127 memset( buffer
, 0xcd, sizeof(buffer
) );
6128 ok_ret( 0, ImmGetCompositionStringA( default_himc
, gcs_indexes
[i
], buffer
, sizeof(buffer
) ) );
6130 memset( buffer
, 0xcd, sizeof(buffer
) );
6131 ok_ret( 0, ImmGetCompositionStringW( himc
, gcs_indexes
[i
], buffer
, sizeof(buffer
) ) );
6132 memset( buffer
, 0xcd, sizeof(buffer
) );
6133 ok_ret( 0, ImmGetCompositionStringA( himc
, gcs_indexes
[i
], buffer
, sizeof(buffer
) ) );
6136 ctx
->hCompStr
= ImmReSizeIMCC( ctx
->hCompStr
, unicode
? expect_stringW
.dwSize
: expect_stringA
.dwSize
);
6137 string
= ImmLockIMCC( ctx
->hCompStr
);
6138 ok( !!string
, "ImmLockIMCC failed, error %lu\n", GetLastError() );
6139 check_composition_string( string
, &expect_string_empty
);
6141 string
->dwCursorPos
= 3;
6142 string
->dwDeltaStart
= 1;
6144 if (unicode
) str
= L
"ReadComp";
6145 else str
= "ReadComp";
6146 len
= unicode
? wcslen( str
) : strlen( str
);
6148 string
->dwCompReadStrLen
= len
;
6149 string
->dwCompReadStrOffset
= string
->dwSize
;
6150 dst
= (BYTE
*)string
+ string
->dwCompReadStrOffset
;
6151 memcpy( dst
, str
, len
* (unicode
? sizeof(WCHAR
) : 1) );
6152 string
->dwSize
+= len
* (unicode
? sizeof(WCHAR
) : 1);
6154 string
->dwCompReadClauseLen
= 2 * sizeof(DWORD
);
6155 string
->dwCompReadClauseOffset
= string
->dwSize
;
6156 dst
= (BYTE
*)string
+ string
->dwCompReadClauseOffset
;
6157 *(DWORD
*)(dst
+ 0 * sizeof(DWORD
)) = 0;
6158 *(DWORD
*)(dst
+ 1 * sizeof(DWORD
)) = len
;
6159 string
->dwSize
+= 2 * sizeof(DWORD
);
6161 string
->dwCompReadAttrLen
= len
;
6162 string
->dwCompReadAttrOffset
= string
->dwSize
;
6163 dst
= (BYTE
*)string
+ string
->dwCompReadAttrOffset
;
6164 memset( dst
, ATTR_INPUT
, len
);
6165 string
->dwSize
+= len
;
6167 if (unicode
) str
= L
"Comp";
6169 len
= unicode
? wcslen( str
) : strlen( str
);
6171 string
->dwCompStrLen
= len
;
6172 string
->dwCompStrOffset
= string
->dwSize
;
6173 dst
= (BYTE
*)string
+ string
->dwCompStrOffset
;
6174 memcpy( dst
, str
, len
* (unicode
? sizeof(WCHAR
) : 1) );
6175 string
->dwSize
+= len
* (unicode
? sizeof(WCHAR
) : 1);
6177 string
->dwCompClauseLen
= 2 * sizeof(DWORD
);
6178 string
->dwCompClauseOffset
= string
->dwSize
;
6179 dst
= (BYTE
*)string
+ string
->dwCompClauseOffset
;
6180 *(DWORD
*)(dst
+ 0 * sizeof(DWORD
)) = 0;
6181 *(DWORD
*)(dst
+ 1 * sizeof(DWORD
)) = len
;
6182 string
->dwSize
+= 2 * sizeof(DWORD
);
6184 string
->dwCompAttrLen
= len
;
6185 string
->dwCompAttrOffset
= string
->dwSize
;
6186 dst
= (BYTE
*)string
+ string
->dwCompAttrOffset
;
6187 memset( dst
, ATTR_INPUT
, len
);
6188 string
->dwSize
+= len
;
6190 if (unicode
) str
= L
"ReadResult";
6191 else str
= "ReadResult";
6192 len
= unicode
? wcslen( str
) : strlen( str
);
6194 string
->dwResultReadStrLen
= len
;
6195 string
->dwResultReadStrOffset
= string
->dwSize
;
6196 dst
= (BYTE
*)string
+ string
->dwResultReadStrOffset
;
6197 memcpy( dst
, str
, len
* (unicode
? sizeof(WCHAR
) : 1) );
6198 string
->dwSize
+= len
* (unicode
? sizeof(WCHAR
) : 1);
6200 string
->dwResultReadClauseLen
= 2 * sizeof(DWORD
);
6201 string
->dwResultReadClauseOffset
= string
->dwSize
;
6202 dst
= (BYTE
*)string
+ string
->dwResultReadClauseOffset
;
6203 *(DWORD
*)(dst
+ 0 * sizeof(DWORD
)) = 0;
6204 *(DWORD
*)(dst
+ 1 * sizeof(DWORD
)) = len
;
6205 string
->dwSize
+= 2 * sizeof(DWORD
);
6207 if (unicode
) str
= L
"Result";
6208 else str
= "Result";
6209 len
= unicode
? wcslen( str
) : strlen( str
);
6211 string
->dwResultStrLen
= len
;
6212 string
->dwResultStrOffset
= string
->dwSize
;
6213 dst
= (BYTE
*)string
+ string
->dwResultStrOffset
;
6214 memcpy( dst
, str
, len
* (unicode
? sizeof(WCHAR
) : 1) );
6215 string
->dwSize
+= len
* (unicode
? sizeof(WCHAR
) : 1);
6217 string
->dwResultClauseLen
= 2 * sizeof(DWORD
);
6218 string
->dwResultClauseOffset
= string
->dwSize
;
6219 dst
= (BYTE
*)string
+ string
->dwResultClauseOffset
;
6220 *(DWORD
*)(dst
+ 0 * sizeof(DWORD
)) = 0;
6221 *(DWORD
*)(dst
+ 1 * sizeof(DWORD
)) = len
;
6222 string
->dwSize
+= 2 * sizeof(DWORD
);
6224 string
->dwPrivateSize
= 4;
6225 string
->dwPrivateOffset
= string
->dwSize
;
6226 dst
= (BYTE
*)string
+ string
->dwPrivateOffset
;
6227 memset( dst
, 0xa5, string
->dwPrivateSize
);
6228 string
->dwSize
+= 4;
6230 check_composition_string( string
, unicode
? &expect_stringW
: &expect_stringA
);
6231 ok_ret( 0, ImmUnlockIMCC( ctx
->hCompStr
) );
6232 old_himcc
= ctx
->hCompStr
;
6234 for (i
= 0; i
< ARRAY_SIZE(gcs_indexes
); ++i
)
6238 winetest_push_context( "%u", i
);
6240 memset( buffer
, 0xcd, sizeof(buffer
) );
6241 expect
= expect_retW
[i
];
6242 ok_ret( expect
, ImmGetCompositionStringW( himc
, gcs_indexes
[i
], buffer
, sizeof(buffer
) ) );
6243 memset( buffer
+ expect
, 0, 4 );
6245 if (i
== 0) ok_wcs( L
"ReadComp", (WCHAR
*)buffer
);
6246 else if (i
== 3) ok_wcs( L
"Comp", (WCHAR
*)buffer
);
6247 else if (i
== 8) ok_wcs( L
"ReadResult", (WCHAR
*)buffer
);
6248 else if (i
== 10) ok_wcs( L
"Result", (WCHAR
*)buffer
);
6249 else if (i
!= 6 && i
!= 7) ok_wcs( L
"", (WCHAR
*)buffer
);
6251 memset( buffer
, 0xcd, sizeof(buffer
) );
6252 expect
= expect_retA
[i
];
6253 ok_ret( expect
, ImmGetCompositionStringA( himc
, gcs_indexes
[i
], buffer
, sizeof(buffer
) ) );
6254 memset( buffer
+ expect
, 0, 4 );
6256 if (i
== 0) ok_str( "ReadComp", (char *)buffer
);
6257 else if (i
== 3) ok_str( "Comp", (char *)buffer
);
6258 else if (i
== 8) ok_str( "ReadResult", (char *)buffer
);
6259 else if (i
== 10) ok_str( "Result", (char *)buffer
);
6260 else if (i
!= 6 && i
!= 7) ok_str( "", (char *)buffer
);
6262 winetest_pop_context();
6265 for (i
= 0; i
< ARRAY_SIZE(gcs_indexes
); ++i
)
6267 winetest_push_context( "%u", i
);
6268 ok_ret( 0, ImmSetCompositionStringW( himc
, gcs_indexes
[i
], buffer
, sizeof(buffer
), NULL
, 0 ) );
6269 ok_ret( 0, ImmSetCompositionStringA( himc
, gcs_indexes
[i
], buffer
, sizeof(buffer
), NULL
, 0 ) );
6270 winetest_pop_context();
6272 ok_ret( 0, ImmSetCompositionStringW( himc
, SCS_SETSTR
| SCS_CHANGEATTR
, buffer
, sizeof(buffer
), NULL
, 0 ) );
6273 ok_ret( 0, ImmSetCompositionStringA( himc
, SCS_SETSTR
| SCS_CHANGEATTR
, buffer
, sizeof(buffer
), NULL
, 0 ) );
6274 ok_ret( 0, ImmSetCompositionStringW( himc
, SCS_CHANGECLAUSE
| SCS_CHANGEATTR
, buffer
, sizeof(buffer
), NULL
, 0 ) );
6275 ok_ret( 0, ImmSetCompositionStringA( himc
, SCS_CHANGECLAUSE
| SCS_CHANGEATTR
, buffer
, sizeof(buffer
), NULL
, 0 ) );
6277 for (i
= 0; i
< ARRAY_SIZE(scs_indexes
); ++i
)
6279 winetest_push_context( "%u", i
);
6281 if (scs_indexes
[i
] == SCS_CHANGECLAUSE
)
6283 memset( buffer
, 0, sizeof(buffer
) );
6284 *((DWORD
*)buffer
+ 1) = 1;
6285 len
= 2 * sizeof(DWORD
);
6287 else if (scs_indexes
[i
] == SCS_CHANGEATTR
)
6289 memset( buffer
, 0xcd, sizeof(buffer
) );
6290 len
= expect_stringW
.dwCompAttrLen
;
6292 else if (scs_indexes
[i
] == SCS_SETSTR
)
6294 wcscpy( (WCHAR
*)buffer
, L
"CompString" );
6295 len
= 11 * sizeof(WCHAR
);
6298 todo_ImeSetCompositionString
= !unicode
;
6299 SET_EXPECT( ImeSetCompositionString
);
6300 ok_ret( 1, ImmSetCompositionStringW( himc
, scs_indexes
[i
], buffer
, len
, NULL
, 0 ) );
6301 CHECK_CALLED( ImeSetCompositionString
);
6302 todo_ImeSetCompositionString
= FALSE
;
6303 ok_seq( empty_sequence
);
6305 string
= ImmLockIMCC( ctx
->hCompStr
);
6306 ok_ne( NULL
, string
, COMPOSITIONSTRING
*, "%p" );
6307 check_composition_string( string
, unicode
? &expect_stringW
: &expect_stringA
);
6308 ok_ret( 0, ImmUnlockIMCC( ctx
->hCompStr
) );
6310 if (scs_indexes
[i
] == SCS_CHANGECLAUSE
)
6312 memset( buffer
, 0, sizeof(buffer
) );
6313 *((DWORD
*)buffer
+ 1) = 1;
6314 len
= 2 * sizeof(DWORD
);
6316 else if (scs_indexes
[i
] == SCS_CHANGEATTR
)
6318 memset( buffer
, 0xcd, sizeof(buffer
) );
6319 len
= expect_stringA
.dwCompAttrLen
;
6321 else if (scs_indexes
[i
] == SCS_SETSTR
)
6323 strcpy( buffer
, "CompString" );
6327 todo_ImeSetCompositionString
= unicode
;
6328 SET_EXPECT( ImeSetCompositionString
);
6329 ok_ret( 1, ImmSetCompositionStringA( himc
, scs_indexes
[i
], buffer
, len
, NULL
, 0 ) );
6330 CHECK_CALLED( ImeSetCompositionString
);
6331 todo_ImeSetCompositionString
= FALSE
;
6332 ok_seq( empty_sequence
);
6334 string
= ImmLockIMCC( ctx
->hCompStr
);
6335 ok_ne( NULL
, string
, COMPOSITIONSTRING
*, "%p" );
6336 check_composition_string( string
, unicode
? &expect_stringW
: &expect_stringA
);
6337 ok_ret( 0, ImmUnlockIMCC( ctx
->hCompStr
) );
6339 winetest_pop_context();
6341 ok_seq( empty_sequence
);
6344 ok_ret( 1, ImmUnlockIMC( himc
) );
6346 /* composition strings are kept between IME selections */
6347 ok_ret( 1, ImmActivateLayout( default_hkl
) );
6348 ctx
= ImmLockIMC( himc
);
6349 ok_eq( old_ctx
, ctx
, INPUTCONTEXT
*, "%p" );
6350 ok_eq( old_himcc
, ctx
->hCompStr
, HIMCC
, "%p" );
6351 string
= ImmLockIMCC( ctx
->hCompStr
);
6352 ok_ne( NULL
, string
, COMPOSITIONSTRING
*, "%p" );
6353 *string
= expect_string_empty
;
6354 ok_ret( 0, ImmUnlockIMCC( ctx
->hCompStr
) );
6355 ok_ret( 1, ImmActivateLayout( hkl
) );
6356 ok_eq( old_himcc
, ctx
->hCompStr
, HIMCC
, "%p" );
6357 check_composition_string( string
, &expect_string_empty
);
6358 ok_ret( 1, ImmActivateLayout( default_hkl
) );
6359 ok_eq( old_himcc
, ctx
->hCompStr
, HIMCC
, "%p" );
6360 check_composition_string( string
, &expect_string_empty
);
6362 ok_ret( 1, ImmUnlockIMC( himc
) );
6363 ok_ret( 1, ImmDestroyContext( himc
) );
6365 ok_ret( 1, ImmActivateLayout( default_hkl
) );
6366 ok_ret( 1, DestroyWindow( hwnd
) );
6369 ok_ret( 1, ImmFreeLayout( hkl
) );
6370 memset( ime_calls
, 0, sizeof(ime_calls
) );
6374 winetest_pop_context();
6375 SET_ENABLE( ImeSetCompositionString
, FALSE
);
6378 static void test_ImmSetCompositionWindow(void)
6380 struct ime_call set_composition_window_0_seq
[] =
6383 .hkl
= expect_ime
, .himc
= 0/*himc*/,
6384 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETCOMPOSITIONWINDOW
},
6387 .hkl
= expect_ime
, .himc
= default_himc
,
6388 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCOMPOSITIONWINDOW
},
6391 .hkl
= expect_ime
, .himc
= default_himc
,
6392 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCOMPOSITIONWINDOW
},
6396 struct ime_call set_composition_window_1_seq
[] =
6399 .hkl
= expect_ime
, .himc
= 0/*himc*/,
6400 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETCOMPOSITIONWINDOW
},
6404 COMPOSITIONFORM comp_form
, expect_form
=
6406 .dwStyle
= 0xfeedcafe,
6407 .ptCurrentPos
= {.x
= 123, .y
= 456},
6408 .rcArea
= {.left
= 1, .top
= 2, .right
= 3, .bottom
= 4},
6410 struct ime_windows ime_windows
= {0};
6415 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
6417 if (!(hkl
= wineime_hkl
)) return;
6419 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
6420 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
6421 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
6423 ok_ret( 1, ImmActivateLayout( hkl
) );
6424 ok_ret( 1, ImmLoadIME( hkl
) );
6425 himc
= ImmCreateContext();
6426 ok_ne( NULL
, himc
, HIMC
, "%p" );
6427 ctx
= ImmLockIMC( himc
);
6428 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
6430 memset( ime_calls
, 0, sizeof(ime_calls
) );
6433 set_composition_window_0_seq
[0].himc
= himc
;
6434 set_composition_window_1_seq
[0].himc
= himc
;
6436 ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows
, (LPARAM
)&ime_windows
) );
6437 ok_ne( NULL
, ime_windows
.ime_hwnd
, HWND
, "%p" );
6438 ok_ne( NULL
, ime_windows
.ime_ui_hwnd
, HWND
, "%p" );
6440 ctx
->cfCompForm
= expect_form
;
6441 ctx
->fdwInit
= ~INIT_COMPFORM
;
6442 memset( &comp_form
, 0xcd, sizeof(comp_form
) );
6443 ok_ret( 0, ImmGetCompositionWindow( himc
, &comp_form
) );
6444 ok_eq( 0xcdcdcdcd, comp_form
.dwStyle
, UINT
, "%#x" );
6445 ctx
->fdwInit
= INIT_COMPFORM
;
6446 ok_ret( 1, ImmGetCompositionWindow( himc
, &comp_form
) );
6447 check_composition_form( &comp_form
, &expect_form
);
6448 ok_seq( empty_sequence
);
6449 ok_ret( 0, IsWindowVisible( ime_windows
.ime_ui_hwnd
) );
6451 ok_ret( 0, ShowWindow( ime_windows
.ime_ui_hwnd
, SW_SHOWNOACTIVATE
) );
6453 ok_seq( empty_sequence
);
6454 check_WM_SHOWWINDOW
= TRUE
;
6458 memset( &comp_form
, 0xcd, sizeof(comp_form
) );
6459 ok_ret( 1, ImmSetCompositionWindow( himc
, &comp_form
) );
6461 ok_seq( set_composition_window_0_seq
);
6462 ok_eq( INIT_COMPFORM
, ctx
->fdwInit
, UINT
, "%u" );
6463 check_composition_form( &ctx
->cfCompForm
, &comp_form
);
6464 ok_ret( 1, IsWindowVisible( ime_windows
.ime_ui_hwnd
) );
6465 check_WM_SHOWWINDOW
= FALSE
;
6467 ShowWindow( ime_windows
.ime_ui_hwnd
, SW_HIDE
);
6469 ok_seq( empty_sequence
);
6471 ok_ret( 1, ImmSetCompositionWindow( himc
, &expect_form
) );
6472 ok_seq( set_composition_window_0_seq
);
6473 check_composition_form( &ctx
->cfCompForm
, &expect_form
);
6475 ctx
->cfCompForm
= expect_form
;
6476 ok_ret( 1, ImmGetCompositionWindow( himc
, &comp_form
) );
6477 check_composition_form( &comp_form
, &expect_form
);
6478 ok_seq( empty_sequence
);
6481 memset( &comp_form
, 0xcd, sizeof(comp_form
) );
6482 ok_ret( 1, ImmSetCompositionWindow( himc
, &comp_form
) );
6483 ok_seq( set_composition_window_1_seq
);
6484 check_composition_form( &ctx
->cfCompForm
, &comp_form
);
6486 ok_ret( 1, ImmUnlockIMC( himc
) );
6487 ok_ret( 1, ImmDestroyContext( himc
) );
6489 ok_ret( 1, ImmActivateLayout( default_hkl
) );
6490 ok_ret( 1, DestroyWindow( hwnd
) );
6493 ok_ret( 1, ImmFreeLayout( hkl
) );
6494 memset( ime_calls
, 0, sizeof(ime_calls
) );
6498 static void test_ImmSetStatusWindowPos(void)
6500 struct ime_call set_status_window_pos_0_seq
[] =
6503 .hkl
= expect_ime
, .himc
= 0/*himc*/,
6504 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETSTATUSWINDOWPOS
},
6507 .hkl
= expect_ime
, .himc
= default_himc
,
6508 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETSTATUSWINDOWPOS
},
6511 .hkl
= expect_ime
, .himc
= default_himc
,
6512 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETSTATUSWINDOWPOS
},
6516 struct ime_call set_status_window_pos_1_seq
[] =
6519 .hkl
= expect_ime
, .himc
= 0/*himc*/,
6520 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETSTATUSWINDOWPOS
},
6529 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
6531 if (!(hkl
= wineime_hkl
)) return;
6533 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
6534 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
6535 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
6537 ok_ret( 1, ImmActivateLayout( hkl
) );
6538 ok_ret( 1, ImmLoadIME( hkl
) );
6539 himc
= ImmCreateContext();
6540 ok_ne( NULL
, himc
, HIMC
, "%p" );
6541 ctx
= ImmLockIMC( himc
);
6542 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
6544 memset( ime_calls
, 0, sizeof(ime_calls
) );
6547 set_status_window_pos_0_seq
[0].himc
= himc
;
6548 set_status_window_pos_1_seq
[0].himc
= himc
;
6550 memset( &pos
, 0xcd, sizeof(pos
) );
6551 ctx
->ptStatusWndPos
.x
= 0xdeadbeef;
6552 ctx
->ptStatusWndPos
.y
= 0xfeedcafe;
6553 ctx
->fdwInit
= ~INIT_STATUSWNDPOS
;
6554 ok_ret( 0, ImmGetStatusWindowPos( himc
, &pos
) );
6555 ok_eq( 0xcdcdcdcd, pos
.x
, UINT
, "%u" );
6556 ok_eq( 0xcdcdcdcd, pos
.y
, UINT
, "%u" );
6557 ctx
->fdwInit
= INIT_STATUSWNDPOS
;
6558 ok_ret( 1, ImmGetStatusWindowPos( himc
, &pos
) );
6559 ok_eq( 0xdeadbeef, pos
.x
, UINT
, "%u" );
6560 ok_eq( 0xfeedcafe, pos
.y
, UINT
, "%u" );
6561 ok_seq( empty_sequence
);
6567 ok_ret( 1, ImmSetStatusWindowPos( himc
, &pos
) );
6568 ok_seq( set_status_window_pos_0_seq
);
6569 ok_eq( INIT_STATUSWNDPOS
, ctx
->fdwInit
, UINT
, "%u" );
6571 ok_ret( 1, ImmSetStatusWindowPos( himc
, &pos
) );
6572 ok_seq( set_status_window_pos_0_seq
);
6573 ok_ret( 1, ImmGetStatusWindowPos( himc
, &pos
) );
6574 ok_eq( 123, pos
.x
, UINT
, "%u" );
6575 ok_eq( 123, ctx
->ptStatusWndPos
.x
, UINT
, "%u" );
6576 ok_eq( 456, pos
.y
, UINT
, "%u" );
6577 ok_eq( 456, ctx
->ptStatusWndPos
.y
, UINT
, "%u" );
6578 ok_seq( empty_sequence
);
6581 ok_ret( 1, ImmSetStatusWindowPos( himc
, &pos
) );
6582 ok_seq( set_status_window_pos_1_seq
);
6584 ok_ret( 1, ImmUnlockIMC( himc
) );
6585 ok_ret( 1, ImmDestroyContext( himc
) );
6587 ok_ret( 1, ImmActivateLayout( default_hkl
) );
6588 ok_ret( 1, DestroyWindow( hwnd
) );
6591 ok_ret( 1, ImmFreeLayout( hkl
) );
6592 memset( ime_calls
, 0, sizeof(ime_calls
) );
6596 static void test_ImmSetCompositionFont( BOOL unicode
)
6598 struct ime_call set_composition_font_0_seq
[] =
6601 .hkl
= expect_ime
, .himc
= 0/*himc*/,
6602 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETCOMPOSITIONFONT
},
6605 .hkl
= expect_ime
, .himc
= default_himc
,
6606 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCOMPOSITIONFONT
},
6609 .hkl
= expect_ime
, .himc
= default_himc
,
6610 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCOMPOSITIONFONT
},
6614 struct ime_call set_composition_font_1_seq
[] =
6617 .hkl
= expect_ime
, .himc
= 0/*himc*/,
6618 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETCOMPOSITIONFONT
},
6622 LOGFONTW fontW
, expect_fontW
=
6633 .lfOutPrecision
= 10,
6634 .lfClipPrecision
= 11,
6636 .lfPitchAndFamily
= 13,
6637 .lfFaceName
= L
"FontFace",
6639 LOGFONTA fontA
, expect_fontA
=
6650 .lfOutPrecision
= 10,
6651 .lfClipPrecision
= 11,
6653 .lfPitchAndFamily
= 13,
6654 .lfFaceName
= "FontFace",
6660 winetest_push_context( unicode
? "unicode" : "ansi" );
6662 /* IME_PROP_END_UNLOAD for the IME to unload / reload. */
6663 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
;
6664 if (unicode
) ime_info
.fdwProperty
|= IME_PROP_UNICODE
;
6666 if (!(hkl
= wineime_hkl
)) goto cleanup
;
6668 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
6669 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
6670 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
6672 ok_ret( 1, ImmActivateLayout( hkl
) );
6673 ok_ret( 1, ImmLoadIME( hkl
) );
6674 himc
= ImmCreateContext();
6675 ok_ne( NULL
, himc
, HIMC
, "%p" );
6676 ctx
= ImmLockIMC( himc
);
6677 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
6679 memset( ime_calls
, 0, sizeof(ime_calls
) );
6682 set_composition_font_0_seq
[0].himc
= himc
;
6683 set_composition_font_1_seq
[0].himc
= himc
;
6685 memset( &fontW
, 0xcd, sizeof(fontW
) );
6686 memset( &fontA
, 0xcd, sizeof(fontA
) );
6688 if (unicode
) ctx
->lfFont
.W
= expect_fontW
;
6689 else ctx
->lfFont
.A
= expect_fontA
;
6690 ctx
->fdwInit
= ~INIT_LOGFONT
;
6691 ok_ret( 0, ImmGetCompositionFontW( himc
, &fontW
) );
6692 ok_ret( 0, ImmGetCompositionFontA( himc
, &fontA
) );
6693 ctx
->fdwInit
= INIT_LOGFONT
;
6694 ok_ret( 1, ImmGetCompositionFontW( himc
, &fontW
) );
6695 check_logfont_w( &fontW
, &expect_fontW
);
6696 ok_ret( 1, ImmGetCompositionFontA( himc
, &fontA
) );
6697 check_logfont_a( &fontA
, &expect_fontA
);
6701 memset( &ctx
->lfFont
, 0xcd, sizeof(ctx
->lfFont
) );
6702 ok_ret( 1, ImmSetCompositionFontW( himc
, &expect_fontW
) );
6703 ok_eq( INIT_LOGFONT
, ctx
->fdwInit
, UINT
, "%u" );
6704 ok_seq( set_composition_font_0_seq
);
6705 ok_ret( 1, ImmSetCompositionFontW( himc
, &expect_fontW
) );
6706 ok_seq( set_composition_font_0_seq
);
6707 if (unicode
) check_logfont_w( &ctx
->lfFont
.W
, &expect_fontW
);
6708 else check_logfont_a( &ctx
->lfFont
.A
, &expect_fontA
);
6710 ok_ret( 1, ImmGetCompositionFontW( himc
, &fontW
) );
6711 check_logfont_w( &fontW
, &expect_fontW
);
6712 ok_ret( 1, ImmGetCompositionFontA( himc
, &fontA
) );
6713 check_logfont_a( &fontA
, &expect_fontA
);
6717 memset( &ctx
->lfFont
, 0xcd, sizeof(ctx
->lfFont
) );
6718 ok_ret( 1, ImmSetCompositionFontA( himc
, &expect_fontA
) );
6719 ok_eq( INIT_LOGFONT
, ctx
->fdwInit
, UINT
, "%u" );
6720 ok_seq( set_composition_font_0_seq
);
6721 ok_ret( 1, ImmSetCompositionFontA( himc
, &expect_fontA
) );
6722 ok_seq( set_composition_font_0_seq
);
6723 if (unicode
) check_logfont_w( &ctx
->lfFont
.W
, &expect_fontW
);
6724 else check_logfont_a( &ctx
->lfFont
.A
, &expect_fontA
);
6726 ok_ret( 1, ImmGetCompositionFontW( himc
, &fontW
) );
6727 check_logfont_w( &fontW
, &expect_fontW
);
6728 ok_ret( 1, ImmGetCompositionFontA( himc
, &fontA
) );
6729 check_logfont_a( &fontA
, &expect_fontA
);
6732 ok_ret( 1, ImmSetCompositionFontW( himc
, &expect_fontW
) );
6733 ok_seq( set_composition_font_1_seq
);
6734 ok_ret( 1, ImmSetCompositionFontA( himc
, &expect_fontA
) );
6735 ok_seq( set_composition_font_1_seq
);
6737 ok_ret( 1, ImmUnlockIMC( himc
) );
6738 ok_ret( 1, ImmDestroyContext( himc
) );
6740 ok_ret( 1, ImmActivateLayout( default_hkl
) );
6741 ok_ret( 1, DestroyWindow( hwnd
) );
6744 ok_ret( 1, ImmFreeLayout( hkl
) );
6745 memset( ime_calls
, 0, sizeof(ime_calls
) );
6749 winetest_pop_context();
6752 static void test_ImmSetCandidateWindow(void)
6754 struct ime_call set_candidate_window_0_seq
[] =
6757 .hkl
= expect_ime
, .himc
= 0/*himc*/,
6758 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETCANDIDATEPOS
},
6761 .hkl
= expect_ime
, .himc
= default_himc
,
6762 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCANDIDATEPOS
, .lparam
= 4},
6765 .hkl
= expect_ime
, .himc
= default_himc
,
6766 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_NOTIFY
, .wparam
= IMN_SETCANDIDATEPOS
, .lparam
= 4},
6770 struct ime_call set_candidate_window_1_seq
[] =
6773 .hkl
= expect_ime
, .himc
= 0/*himc*/,
6774 .func
= IME_NOTIFY
, .notify
= {.action
= NI_CONTEXTUPDATED
, .index
= 0, .value
= IMC_SETCANDIDATEPOS
},
6778 CANDIDATEFORM cand_form
, expect_form
=
6780 .dwIndex
= 2, .dwStyle
= 0xfeedcafe,
6781 .ptCurrentPos
= {.x
= 123, .y
= 456},
6782 .rcArea
= {.left
= 1, .top
= 2, .right
= 3, .bottom
= 4},
6788 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
6790 if (!(hkl
= wineime_hkl
)) return;
6792 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
6793 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
6794 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
6796 ok_ret( 1, ImmActivateLayout( hkl
) );
6797 ok_ret( 1, ImmLoadIME( hkl
) );
6798 himc
= ImmCreateContext();
6799 ok_ne( NULL
, himc
, HIMC
, "%p" );
6800 ctx
= ImmLockIMC( himc
);
6801 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
6803 memset( ime_calls
, 0, sizeof(ime_calls
) );
6806 set_candidate_window_0_seq
[0].himc
= himc
;
6807 set_candidate_window_1_seq
[0].himc
= himc
;
6809 ctx
->cfCandForm
[1] = expect_form
;
6810 ctx
->cfCandForm
[2] = expect_form
;
6812 memset( &cand_form
, 0xcd, sizeof(cand_form
) );
6813 ok_ret( 0, ImmGetCandidateWindow( himc
, 0, &cand_form
) );
6814 ok_eq( 0xcdcdcdcd, cand_form
.dwStyle
, UINT
, "%#x" );
6815 ok_ret( 1, ImmGetCandidateWindow( himc
, 1, &cand_form
) );
6816 check_candidate_form( &cand_form
, &expect_form
);
6817 ok_ret( 1, ImmGetCandidateWindow( himc
, 2, &cand_form
) );
6818 check_candidate_form( &cand_form
, &expect_form
);
6819 ok_seq( empty_sequence
);
6822 memset( &cand_form
, 0xcd, sizeof(cand_form
) );
6823 cand_form
.dwIndex
= 2;
6824 ok_ret( 1, ImmSetCandidateWindow( himc
, &cand_form
) );
6825 ok_seq( set_candidate_window_0_seq
);
6826 check_candidate_form( &ctx
->cfCandForm
[2], &cand_form
);
6827 ok_eq( 0, ctx
->fdwInit
, UINT
, "%u" );
6829 ok_ret( 1, ImmSetCandidateWindow( himc
, &expect_form
) );
6830 ok_seq( set_candidate_window_0_seq
);
6831 check_candidate_form( &ctx
->cfCandForm
[2], &expect_form
);
6834 memset( &cand_form
, 0xcd, sizeof(cand_form
) );
6835 cand_form
.dwIndex
= 2;
6836 ok_ret( 1, ImmSetCandidateWindow( himc
, &cand_form
) );
6837 ok_seq( set_candidate_window_1_seq
);
6838 check_candidate_form( &ctx
->cfCandForm
[2], &cand_form
);
6840 ok_ret( 1, ImmUnlockIMC( himc
) );
6841 ok_ret( 1, ImmDestroyContext( himc
) );
6843 ok_ret( 1, ImmActivateLayout( default_hkl
) );
6844 ok_ret( 1, DestroyWindow( hwnd
) );
6847 ok_ret( 1, ImmFreeLayout( hkl
) );
6848 memset( ime_calls
, 0, sizeof(ime_calls
) );
6852 static void test_ImmGenerateMessage(void)
6854 const struct ime_call generate_sequence
[] =
6857 .hkl
= expect_ime
, .himc
= default_himc
,
6858 .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_COMPOSITION
, .wparam
= 0, .lparam
= GCS_COMPSTR
},
6861 .hkl
= expect_ime
, .himc
= default_himc
,
6862 .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_COMPOSITION
, .wparam
= 0, .lparam
= GCS_COMPSTR
},
6866 TRANSMSG
*msgs
, *tmp_msgs
;
6871 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
6873 if (!(hkl
= wineime_hkl
)) return;
6875 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
6876 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
6877 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
6879 ok_ret( 1, ImmActivateLayout( hkl
) );
6880 ok_ret( 1, ImmLoadIME( hkl
) );
6881 himc
= ImmCreateContext();
6882 ok_ne( NULL
, himc
, HIMC
, "%p" );
6883 ctx
= ImmLockIMC( himc
);
6884 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
6886 memset( ime_calls
, 0, sizeof(ime_calls
) );
6889 todo_wine
ok_ret( 4, ImmGetIMCCSize( ctx
->hMsgBuf
) );
6890 ctx
->hMsgBuf
= ImmReSizeIMCC( ctx
->hMsgBuf
, sizeof(*msgs
) );
6891 ok_ne( NULL
, ctx
->hMsgBuf
, HIMCC
, "%p" );
6893 msgs
= ImmLockIMCC( ctx
->hMsgBuf
);
6894 ok_ne( NULL
, msgs
, TRANSMSG
*, "%p" );
6895 msgs
[0].message
= WM_IME_COMPOSITION
;
6897 msgs
[0].lParam
= GCS_COMPSTR
;
6898 ok_ret( 0, ImmUnlockIMCC( ctx
->hMsgBuf
) );
6901 ctx
->dwNumMsgBuf
= 0;
6902 ok_ret( 1, ImmGenerateMessage( himc
) );
6903 ok_seq( empty_sequence
);
6904 ok_ret( sizeof(*msgs
), ImmGetIMCCSize( ctx
->hMsgBuf
) );
6905 tmp_msgs
= ImmLockIMCC( ctx
->hMsgBuf
);
6906 ok_eq( msgs
, tmp_msgs
, TRANSMSG
*, "%p" );
6907 ok_ret( 0, ImmUnlockIMCC( ctx
->hMsgBuf
) );
6909 ctx
->dwNumMsgBuf
= 1;
6910 ok_ret( 1, ImmGenerateMessage( himc
) );
6911 ok_seq( empty_sequence
);
6912 ok_eq( 0, ctx
->dwNumMsgBuf
, UINT
, "%u" );
6913 ok_ret( sizeof(*msgs
), ImmGetIMCCSize( ctx
->hMsgBuf
) );
6914 tmp_msgs
= ImmLockIMCC( ctx
->hMsgBuf
);
6915 ok_eq( msgs
, tmp_msgs
, TRANSMSG
*, "%p" );
6916 ok_ret( 0, ImmUnlockIMCC( ctx
->hMsgBuf
) );
6919 ctx
->dwNumMsgBuf
= 0;
6920 ok_ret( 1, ImmGenerateMessage( himc
) );
6921 ok_seq( empty_sequence
);
6922 ok_ret( sizeof(*msgs
), ImmGetIMCCSize( ctx
->hMsgBuf
) );
6923 tmp_msgs
= ImmLockIMCC( ctx
->hMsgBuf
);
6924 ok_eq( msgs
, tmp_msgs
, TRANSMSG
*, "%p" );
6925 ok_ret( 0, ImmUnlockIMCC( ctx
->hMsgBuf
) );
6927 ctx
->dwNumMsgBuf
= 1;
6928 ok_ret( 1, ImmGenerateMessage( himc
) );
6929 ok_seq( generate_sequence
);
6930 ok_eq( 0, ctx
->dwNumMsgBuf
, UINT
, "%u" );
6931 ok_ret( sizeof(*msgs
), ImmGetIMCCSize( ctx
->hMsgBuf
) );
6932 tmp_msgs
= ImmLockIMCC( ctx
->hMsgBuf
);
6933 ok_eq( msgs
, tmp_msgs
, TRANSMSG
*, "%p" );
6934 ok_ret( 0, ImmUnlockIMCC( ctx
->hMsgBuf
) );
6936 tmp_msgs
= ImmLockIMCC( ctx
->hMsgBuf
);
6937 ok_eq( msgs
, tmp_msgs
, TRANSMSG
*, "%p" );
6938 ok_ret( 0, ImmUnlockIMCC( ctx
->hMsgBuf
) );
6940 ok_ret( 1, ImmUnlockIMC( himc
) );
6941 ok_ret( 1, ImmDestroyContext( himc
) );
6943 ok_ret( 1, ImmActivateLayout( default_hkl
) );
6944 ok_ret( 1, DestroyWindow( hwnd
) );
6947 ok_ret( 1, ImmFreeLayout( hkl
) );
6948 memset( ime_calls
, 0, sizeof(ime_calls
) );
6952 static void test_ImmTranslateMessage( BOOL kbd_char_first
)
6954 const struct ime_call process_key_seq
[] =
6957 .hkl
= expect_ime
, .himc
= default_himc
, .func
= IME_PROCESS_KEY
,
6958 .process_key
= {.vkey
= 'Q', .lparam
= MAKELONG(2, 0x10)},
6961 .hkl
= expect_ime
, .himc
= default_himc
, .func
= IME_PROCESS_KEY
,
6962 .process_key
= {.vkey
= 'Q', .lparam
= MAKELONG(2, 0xc010)},
6966 const struct ime_call to_ascii_ex_0
[] =
6969 .hkl
= expect_ime
, .himc
= default_himc
, .func
= IME_TO_ASCII_EX
,
6970 .to_ascii_ex
= {.vkey
= kbd_char_first
? MAKELONG('Q', 'q') : 'Q', .vsc
= 0x10},
6974 const struct ime_call to_ascii_ex_1
[] =
6977 .hkl
= expect_ime
, .himc
= default_himc
, .func
= IME_PROCESS_KEY
,
6978 .process_key
= {.vkey
= 'Q', .lparam
= MAKELONG(2, 0xc010)},
6981 .hkl
= expect_ime
, .himc
= default_himc
, .func
= IME_TO_ASCII_EX
,
6982 /* FIXME what happened to kbd_char_first here!? */
6983 .to_ascii_ex
= {.vkey
= 'Q', .vsc
= 0xc010},
6988 struct ime_call to_ascii_ex_2
[] =
6991 .hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= IME_PROCESS_KEY
,
6992 .process_key
= {.vkey
= 'Q', .lparam
= MAKELONG(2, 0x210)},
6995 .hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= IME_TO_ASCII_EX
,
6996 .to_ascii_ex
= {.vkey
= kbd_char_first
? MAKELONG('Q', 'q') : 'Q', .vsc
= 0x210},
7000 .hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= IME_PROCESS_KEY
,
7001 .process_key
= {.vkey
= 'Q', .lparam
= MAKELONG(2, 0x410)},
7004 .hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= IME_TO_ASCII_EX
,
7005 .to_ascii_ex
= {.vkey
= kbd_char_first
? MAKELONG('Q', 'q') : 'Q', .vsc
= 0x410},
7010 struct ime_call to_ascii_ex_3
[] =
7013 .hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= IME_PROCESS_KEY
,
7014 .process_key
= {.vkey
= 'Q', .lparam
= MAKELONG(2, 0xa10)},
7017 .hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= IME_TO_ASCII_EX
,
7018 .to_ascii_ex
= {.vkey
= kbd_char_first
? MAKELONG('Q', 'q') : 'Q', .vsc
= 0xa10},
7022 .hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= IME_PROCESS_KEY
,
7023 .process_key
= {.vkey
= 'Q', .lparam
= MAKELONG(2, 0xc10)},
7026 .hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= IME_TO_ASCII_EX
,
7027 .to_ascii_ex
= {.vkey
= kbd_char_first
? MAKELONG('Q', 'q') : 'Q', .vsc
= 0xc10},
7032 struct ime_call post_messages
[] =
7034 {.hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_STARTCOMPOSITION
, .wparam
= 1}},
7035 {.hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_STARTCOMPOSITION
, .wparam
= 1}},
7036 {.hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_ENDCOMPOSITION
, .wparam
= 1}},
7037 {.hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_ENDCOMPOSITION
, .wparam
= 1}},
7040 struct ime_call sent_messages
[] =
7042 {.hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_STARTCOMPOSITION
, .wparam
= 2}},
7043 {.hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_STARTCOMPOSITION
, .wparam
= 2}},
7044 {.hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= MSG_TEST_WIN
, .message
= {.msg
= WM_IME_ENDCOMPOSITION
, .wparam
= 2}},
7045 {.hkl
= expect_ime
, .himc
= 0/*himc*/, .func
= MSG_IME_UI
, .message
= {.msg
= WM_IME_ENDCOMPOSITION
, .wparam
= 2}},
7048 HWND hwnd
, other_hwnd
;
7054 ime_info
.fdwProperty
= IME_PROP_END_UNLOAD
| IME_PROP_UNICODE
;
7055 if (kbd_char_first
) ime_info
.fdwProperty
|= IME_PROP_KBD_CHAR_FIRST
;
7057 winetest_push_context( kbd_char_first
? "kbd_char_first" : "default" );
7059 if (!(hkl
= wineime_hkl
)) goto cleanup
;
7061 other_hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
7062 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
7063 ok( !!other_hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
7066 hwnd
= CreateWindowW( test_class
.lpszClassName
, NULL
, WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
7067 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
7068 ok( !!hwnd
, "CreateWindowW failed, error %lu\n", GetLastError() );
7071 ok_ret( 1, ImmActivateLayout( hkl
) );
7072 ok_ret( 1, ImmLoadIME( hkl
) );
7073 himc
= ImmCreateContext();
7074 ok_ne( NULL
, himc
, HIMC
, "%p" );
7075 ctx
= ImmLockIMC( himc
);
7076 ok_ne( NULL
, ctx
, INPUTCONTEXT
*, "%p" );
7078 memset( ime_calls
, 0, sizeof(ime_calls
) );
7081 ok_ret( 2, ImmProcessKey( hwnd
, expect_ime
, 'Q', MAKELONG(2, 0x10), 0 ) );
7082 ok_ret( 2, ImmProcessKey( hwnd
, expect_ime
, 'Q', MAKELONG(2, 0xc010), 0 ) );
7084 ok_ret( 0, ImmTranslateMessage( hwnd
, 0, 0, 0 ) );
7085 ok_ret( 'Q', ImmGetVirtualKey( hwnd
) );
7086 ok_seq( process_key_seq
);
7088 ok_ret( 0, ImmTranslateMessage( hwnd
, WM_KEYDOWN
, 'Q', MAKELONG(2, 0x10) ) );
7089 ok_ret( VK_PROCESSKEY
, ImmGetVirtualKey( hwnd
) );
7090 ok_seq( to_ascii_ex_0
);
7092 ok_ret( 0, ImmTranslateMessage( hwnd
, WM_KEYUP
, 'Q', MAKELONG(2, 0xc010) ) );
7093 ok_seq( empty_sequence
);
7095 ok_ret( 2, ImmProcessKey( hwnd
, expect_ime
, 'Q', MAKELONG(2, 0xc010), 0 ) );
7096 ok_ret( 0, ImmTranslateMessage( hwnd
, WM_KEYUP
, 'Q', MAKELONG(2, 0xc010) ) );
7097 ok_ret( VK_PROCESSKEY
, ImmGetVirtualKey( hwnd
) );
7098 ok_seq( to_ascii_ex_1
);
7100 ok_eq( default_himc
, ImmAssociateContext( hwnd
, himc
), HIMC
, "%p" );
7101 ok_eq( default_himc
, ImmAssociateContext( other_hwnd
, himc
), HIMC
, "%p" );
7102 for (i
= 0; i
< ARRAY_SIZE(to_ascii_ex_2
); i
++) to_ascii_ex_2
[i
].himc
= himc
;
7103 for (i
= 0; i
< ARRAY_SIZE(to_ascii_ex_3
); i
++) to_ascii_ex_3
[i
].himc
= himc
;
7104 for (i
= 0; i
< ARRAY_SIZE(post_messages
); i
++) post_messages
[i
].himc
= himc
;
7105 for (i
= 0; i
< ARRAY_SIZE(sent_messages
); i
++) sent_messages
[i
].himc
= himc
;
7106 memset( ime_calls
, 0, sizeof(ime_calls
) );
7110 ok_ret( 2, ImmProcessKey( hwnd
, expect_ime
, 'Q', MAKELONG(2, 0x210), 0 ) );
7111 ret
= ImmTranslateMessage( hwnd
, WM_KEYUP
, 'Q', MAKELONG(2, 0x210) );
7112 todo_wine
ok_eq( 1, ret
, UINT
, "%u" );
7113 ok_ret( 2, ImmProcessKey( hwnd
, expect_ime
, 'Q', MAKELONG(2, 0x410), 0 ) );
7114 ok_ret( 0, ImmTranslateMessage( hwnd
, WM_KEYUP
, 'Q', MAKELONG(2, 0x410) ) );
7115 ok_ret( VK_PROCESSKEY
, ImmGetVirtualKey( hwnd
) );
7116 ok_seq( to_ascii_ex_2
);
7118 todo_wine
ok_seq( post_messages
);
7119 ok_ret( 1, ImmGenerateMessage( himc
) );
7120 todo_wine
ok_seq( sent_messages
);
7122 ok_ret( 2, ImmProcessKey( hwnd
, expect_ime
, 'Q', MAKELONG(2, 0xa10), 0 ) );
7123 ok_ret( 0, ImmTranslateMessage( hwnd
, WM_KEYUP
, 'Q', MAKELONG(2, 0xa10) ) );
7124 ok_ret( 2, ImmProcessKey( hwnd
, expect_ime
, 'Q', MAKELONG(2, 0xc10), 0 ) );
7125 ok_ret( 0, ImmTranslateMessage( hwnd
, WM_KEYUP
, 'Q', MAKELONG(2, 0xc10) ) );
7126 ok_ret( VK_PROCESSKEY
, ImmGetVirtualKey( hwnd
) );
7127 ok_seq( to_ascii_ex_3
);
7129 ok_seq( empty_sequence
);
7130 ok_ret( 1, ImmGenerateMessage( himc
) );
7131 todo_wine
ok_seq( sent_messages
);
7134 ok_ret( 2, ImmProcessKey( other_hwnd
, expect_ime
, 'Q', MAKELONG(2, 0x210), 0 ) );
7135 ret
= ImmTranslateMessage( other_hwnd
, WM_KEYUP
, 'Q', MAKELONG(2, 0x210) );
7136 todo_wine
ok_eq( 1, ret
, UINT
, "%u" );
7137 ok_ret( 2, ImmProcessKey( other_hwnd
, expect_ime
, 'Q', MAKELONG(2, 0x410), 0 ) );
7138 ok_ret( 0, ImmTranslateMessage( other_hwnd
, WM_KEYUP
, 'Q', MAKELONG(2, 0x410) ) );
7139 ok_ret( VK_PROCESSKEY
, ImmGetVirtualKey( other_hwnd
) );
7140 ok_seq( to_ascii_ex_2
);
7141 process_messages_( hwnd
);
7142 ok_seq( empty_sequence
);
7143 process_messages_( other_hwnd
);
7144 todo_wine
ok_seq( post_messages
);
7145 ok_ret( 1, ImmGenerateMessage( himc
) );
7146 ok_seq( empty_sequence
);
7148 ok_ret( 1, ImmUnlockIMC( himc
) );
7149 ok_ret( 1, ImmDestroyContext( himc
) );
7151 ok_ret( 1, ImmActivateLayout( default_hkl
) );
7152 ok_ret( 1, DestroyWindow( other_hwnd
) );
7153 ok_ret( 1, DestroyWindow( hwnd
) );
7156 ok_ret( 1, ImmFreeLayout( hkl
) );
7157 memset( ime_calls
, 0, sizeof(ime_calls
) );
7161 winetest_pop_context();
7166 default_hkl
= GetKeyboardLayout( 0 );
7168 test_class
.hInstance
= GetModuleHandleW( NULL
);
7169 RegisterClassExW( &test_class
);
7171 if (!is_ime_enabled())
7173 win_skip("IME support not implemented\n");
7177 test_com_initialization();
7179 test_ImmEnumInputContext();
7181 test_ImmInstallIME();
7182 wineime_hkl
= ime_install();
7184 test_ImmGetDescription();
7185 test_ImmGetIMEFileName();
7187 test_ImmGetProperty();
7189 test_ImmEscape( FALSE
);
7190 test_ImmEscape( TRUE
);
7191 test_ImmEnumRegisterWord( FALSE
);
7192 test_ImmEnumRegisterWord( TRUE
);
7193 test_ImmRegisterWord( FALSE
);
7194 test_ImmRegisterWord( TRUE
);
7195 test_ImmGetRegisterWordStyle( FALSE
);
7196 test_ImmGetRegisterWordStyle( TRUE
);
7197 test_ImmUnregisterWord( FALSE
);
7198 test_ImmUnregisterWord( TRUE
);
7200 /* test these first to sanitize conversion / open statuses */
7201 test_ImmSetConversionStatus();
7202 test_ImmSetOpenStatus();
7203 ImeSelect_init_status
= TRUE
;
7205 test_ImmActivateLayout();
7206 test_ImmCreateInputContext();
7207 test_ImmProcessKey();
7208 test_DefWindowProc();
7209 test_ImmSetActiveContext();
7210 test_ImmRequestMessage();
7212 test_ImmGetCandidateList( TRUE
);
7213 test_ImmGetCandidateList( FALSE
);
7214 test_ImmGetCandidateListCount( TRUE
);
7215 test_ImmGetCandidateListCount( FALSE
);
7216 test_ImmGetCandidateWindow();
7218 test_ImmGetCompositionString( TRUE
);
7219 test_ImmGetCompositionString( FALSE
);
7220 test_ImmSetCompositionWindow();
7221 test_ImmSetStatusWindowPos();
7222 test_ImmSetCompositionFont( TRUE
);
7223 test_ImmSetCompositionFont( FALSE
);
7224 test_ImmSetCandidateWindow();
7226 test_ImmGenerateMessage();
7227 test_ImmTranslateMessage( FALSE
);
7228 test_ImmTranslateMessage( TRUE
);
7230 if (wineime_hkl
) ime_cleanup( wineime_hkl
, TRUE
);
7234 test_ImmNotifyIME();
7237 test_ImmAssociateContextEx();
7238 test_NtUserAssociateInputContext();
7239 test_cross_thread_himc();
7240 test_ImmIsUIMessage();
7241 test_ImmGetContext();
7242 test_ImmDefaultHwnd();
7243 test_default_ime_window_creation();
7244 test_ImmGetIMCLockCount();
7245 test_ImmGetIMCCLockCount();
7246 test_ImmDestroyContext();
7247 test_ImmDestroyIMCC();
7250 /* Reinitialize the hooks to capture all windows */
7255 test_ime_processkey();
7256 else win_skip("SendInput is not available\n");
7258 /* there's no way of enabling IME - keep the test last */
7259 test_ImmDisableIME();
7263 UnregisterClassW( test_class
.lpszClassName
, test_class
.hInstance
);