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
23 #include "wine/test.h"
28 #include "ddk/immdev.h"
33 static BOOL (WINAPI
*pImmAssociateContextEx
)(HWND
,HIMC
,DWORD
);
34 static BOOL (WINAPI
*pImmIsUIMessageA
)(HWND
,UINT
,WPARAM
,LPARAM
);
35 static UINT (WINAPI
*pSendInput
) (UINT
, INPUT
*, size_t);
38 * msgspy - record and analyse message traces sent to a certain window
40 typedef struct _msgs
{
45 static struct _msg_spy
{
48 HHOOK call_wnd_proc_hook
;
64 typedef struct _tagTRANSMSG
{
68 } TRANSMSG
, *LPTRANSMSG
;
70 static UINT (WINAPI
*pSendInput
) (UINT
, INPUT
*, size_t);
72 static LRESULT CALLBACK
get_msg_filter(int nCode
, WPARAM wParam
, LPARAM lParam
)
74 if (HC_ACTION
== nCode
) {
75 MSG
*msg
= (MSG
*)lParam
;
77 if ((msg
->hwnd
== msg_spy
.hwnd
|| msg_spy
.hwnd
== NULL
) &&
78 (msg_spy
.i_msg
< ARRAY_SIZE(msg_spy
.msgs
)))
80 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.hwnd
= msg
->hwnd
;
81 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.message
= msg
->message
;
82 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.wParam
= msg
->wParam
;
83 msg_spy
.msgs
[msg_spy
.i_msg
].msg
.lParam
= msg
->lParam
;
84 msg_spy
.msgs
[msg_spy
.i_msg
].post
= TRUE
;
89 return CallNextHookEx(msg_spy
.get_msg_hook
, nCode
, wParam
, lParam
);
92 static LRESULT CALLBACK
call_wnd_proc_filter(int nCode
, WPARAM wParam
,
95 if (HC_ACTION
== nCode
) {
96 CWPSTRUCT
*cwp
= (CWPSTRUCT
*)lParam
;
98 if (((cwp
->hwnd
== msg_spy
.hwnd
|| msg_spy
.hwnd
== NULL
)) &&
99 (msg_spy
.i_msg
< ARRAY_SIZE(msg_spy
.msgs
)))
101 memcpy(&msg_spy
.msgs
[msg_spy
.i_msg
].msg
, cwp
, sizeof(msg_spy
.msgs
[0].msg
));
102 msg_spy
.msgs
[msg_spy
.i_msg
].post
= FALSE
;
107 return CallNextHookEx(msg_spy
.call_wnd_proc_hook
, nCode
, wParam
, lParam
);
110 static void msg_spy_pump_msg_queue(void) {
113 while(PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
114 TranslateMessage(&msg
);
115 DispatchMessageW(&msg
);
121 static void msg_spy_flush_msgs(void) {
122 msg_spy_pump_msg_queue();
126 static imm_msgs
* msg_spy_find_next_msg(UINT message
, UINT
*start
) {
129 msg_spy_pump_msg_queue();
131 if (msg_spy
.i_msg
>= ARRAY_SIZE(msg_spy
.msgs
))
132 fprintf(stdout
, "%s:%d: msg_spy: message buffer overflow!\n",
135 for (i
= *start
; i
< msg_spy
.i_msg
; i
++)
136 if (msg_spy
.msgs
[i
].msg
.message
== message
)
139 return &msg_spy
.msgs
[i
];
145 static imm_msgs
* msg_spy_find_msg(UINT message
) {
148 return msg_spy_find_next_msg(message
, &i
);
151 static void msg_spy_init(HWND hwnd
) {
153 msg_spy
.get_msg_hook
=
154 SetWindowsHookExW(WH_GETMESSAGE
, get_msg_filter
, GetModuleHandleW(NULL
),
155 GetCurrentThreadId());
156 msg_spy
.call_wnd_proc_hook
=
157 SetWindowsHookExW(WH_CALLWNDPROC
, call_wnd_proc_filter
,
158 GetModuleHandleW(NULL
), GetCurrentThreadId());
161 msg_spy_flush_msgs();
164 static void msg_spy_cleanup(void) {
165 if (msg_spy
.get_msg_hook
)
166 UnhookWindowsHookEx(msg_spy
.get_msg_hook
);
167 if (msg_spy
.call_wnd_proc_hook
)
168 UnhookWindowsHookEx(msg_spy
.call_wnd_proc_hook
);
169 memset(&msg_spy
, 0, sizeof(msg_spy
));
173 * imm32 test cases - Issue some IMM commands on a dummy window and analyse the
174 * messages being sent to this window in response.
176 static const char wndcls
[] = "winetest_imm32_wndcls";
177 static enum { PHASE_UNKNOWN
, FIRST_WINDOW
, SECOND_WINDOW
,
178 CREATE_CANCEL
, NCCREATE_CANCEL
, IME_DISABLED
} test_phase
;
181 static HWND
get_ime_window(void);
183 static LRESULT WINAPI
wndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
185 HWND default_ime_wnd
;
188 case WM_IME_SETCONTEXT
:
191 default_ime_wnd
= get_ime_window();
195 ok(!default_ime_wnd
, "expected no IME windows\n");
198 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
201 break; /* do nothing */
203 if (test_phase
== NCCREATE_CANCEL
)
207 default_ime_wnd
= get_ime_window();
212 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
215 ok(!default_ime_wnd
, "expected no IME windows\n");
218 break; /* do nothing */
222 default_ime_wnd
= get_ime_window();
227 ok(default_ime_wnd
!= NULL
, "expected IME window existence\n");
230 ok(!default_ime_wnd
, "expected no IME windows\n");
233 break; /* do nothing */
235 if (test_phase
== CREATE_CANCEL
)
240 return DefWindowProcA(hWnd
,msg
,wParam
,lParam
);
243 static BOOL
init(void) {
248 hmod
= GetModuleHandleA("imm32.dll");
249 huser
= GetModuleHandleA("user32");
250 pImmAssociateContextEx
= (void*)GetProcAddress(hmod
, "ImmAssociateContextEx");
251 pImmIsUIMessageA
= (void*)GetProcAddress(hmod
, "ImmIsUIMessageA");
252 pSendInput
= (void*)GetProcAddress(huser
, "SendInput");
254 wc
.cbSize
= sizeof(WNDCLASSEXA
);
256 wc
.lpfnWndProc
= wndProc
;
259 wc
.hInstance
= GetModuleHandleA(NULL
);
260 wc
.hIcon
= LoadIconA(NULL
, (LPCSTR
)IDI_APPLICATION
);
261 wc
.hCursor
= LoadCursorA(NULL
, (LPCSTR
)IDC_ARROW
);
262 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+1);
263 wc
.lpszMenuName
= NULL
;
264 wc
.lpszClassName
= wndcls
;
265 wc
.hIconSm
= LoadIconA(NULL
, (LPCSTR
)IDI_APPLICATION
);
267 if (!RegisterClassExA(&wc
))
270 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
271 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
272 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
276 imc
= ImmGetContext(hwnd
);
279 win_skip("IME support not implemented\n");
282 ImmReleaseContext(hwnd
, imc
);
284 ShowWindow(hwnd
, SW_SHOWNORMAL
);
292 static void cleanup(void) {
296 UnregisterClassA(wndcls
, GetModuleHandleW(NULL
));
299 static void test_ImmNotifyIME(void) {
301 static char string
[] = "wine";
303 static const char string
[] = "wine";
305 char resstr
[16] = "";
309 imc
= ImmGetContext(hwnd
);
310 msg_spy_flush_msgs();
312 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
315 "Canceling an empty composition string should succeed.\n");
316 ok(!msg_spy_find_msg(WM_IME_COMPOSITION
), "Windows does not post "
317 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
318 "the composition string being canceled is empty.\n");
320 ImmSetCompositionStringA(imc
, SCS_SETSTR
, string
, sizeof(string
), NULL
, 0);
321 msg_spy_flush_msgs();
323 ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
324 msg_spy_flush_msgs();
326 /* behavior differs between win9x and NT */
327 ret
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, resstr
, sizeof(resstr
));
328 ok(!ret
, "After being cancelled the composition string is empty.\n");
330 msg_spy_flush_msgs();
332 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
335 "Canceling an empty composition string should succeed.\n");
336 ok(!msg_spy_find_msg(WM_IME_COMPOSITION
), "Windows does not post "
337 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
338 "the composition string being canceled is empty.\n");
340 msg_spy_flush_msgs();
341 ImmReleaseContext(hwnd
, imc
);
343 imc
= ImmCreateContext();
344 ImmDestroyContext(imc
);
346 SetLastError(0xdeadbeef);
347 ret
= ImmNotifyIME((HIMC
)0xdeadcafe, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
348 ok (ret
== 0, "Bad IME should return 0\n");
349 ret
= GetLastError();
350 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
351 SetLastError(0xdeadbeef);
352 ret
= ImmNotifyIME(0x00000000, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
353 ok (ret
== 0, "NULL IME should return 0\n");
354 ret
= GetLastError();
355 ok(ret
== ERROR_SUCCESS
, "wrong last error %08x!\n", ret
);
356 SetLastError(0xdeadbeef);
357 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_CANCEL
, 0);
358 ok (ret
== 0, "Destroyed IME should return 0\n");
359 ret
= GetLastError();
360 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
365 WNDPROC old_wnd_proc
;
366 BOOL catch_result_str
;
370 } ime_composition_test
;
372 static LRESULT WINAPI
test_ime_wnd_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
376 case WM_IME_COMPOSITION
:
377 if ((lParam
& GCS_RESULTSTR
) && !ime_composition_test
.catch_result_str
) {
384 hwndIme
= ImmGetDefaultIMEWnd(hWnd
);
385 ok(hwndIme
!= NULL
, "expected IME window existence\n");
387 ok(!ime_composition_test
.catch_ime_char
, "WM_IME_CHAR is sent\n");
388 ret
= CallWindowProcA(ime_composition_test
.old_wnd_proc
,
389 hWnd
, msg
, wParam
, lParam
);
390 ok(ime_composition_test
.catch_ime_char
, "WM_IME_CHAR isn't sent\n");
392 ime_composition_test
.catch_ime_char
= FALSE
;
393 SendMessageA(hwndIme
, msg
, wParam
, lParam
);
394 ok(!ime_composition_test
.catch_ime_char
, "WM_IME_CHAR is sent\n");
396 imc
= ImmGetContext(hWnd
);
397 size
= ImmGetCompositionStringW(imc
, GCS_RESULTSTR
,
398 wstring
, sizeof(wstring
));
399 ok(size
> 0, "ImmGetCompositionString(GCS_RESULTSTR) is %d\n", size
);
400 ImmReleaseContext(hwnd
, imc
);
402 ime_composition_test
.catch_result_str
= TRUE
;
407 if (!ime_composition_test
.catch_result_str
)
408 ime_composition_test
.catch_ime_char
= TRUE
;
411 if (wParam
== ime_composition_test
.timer_id
) {
412 HWND parent
= GetParent(hWnd
);
414 int left
= 20 - (GetTickCount() - ime_composition_test
.start
) / 1000;
415 wsprintfA(title
, "%sLeft %d sec. - IME composition test",
416 ime_composition_test
.catch_result_str
? "[*] " : "", left
);
417 SetWindowTextA(parent
, title
);
419 DestroyWindow(parent
);
421 SetTimer(hWnd
, wParam
, 100, NULL
);
426 return CallWindowProcA(ime_composition_test
.old_wnd_proc
,
427 hWnd
, msg
, wParam
, lParam
);
430 static void test_ImmGetCompositionString(void)
434 static WCHAR string
[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e};
436 static const WCHAR string
[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e};
445 imc
= ImmGetContext(hwnd
);
446 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
, string
, sizeof(string
), NULL
,0);
448 win_skip("Composition isn't supported\n");
449 ImmReleaseContext(hwnd
, imc
);
452 msg_spy_flush_msgs();
454 alen
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, 20);
455 wlen
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, 20);
456 /* windows machines without any IME installed just return 0 above */
459 len
= ImmGetCompositionStringW(imc
, GCS_COMPATTR
, NULL
, 0);
460 ok(len
*sizeof(WCHAR
)==wlen
,"GCS_COMPATTR(W) not returning correct count\n");
461 len
= ImmGetCompositionStringA(imc
, GCS_COMPATTR
, NULL
, 0);
462 ok(len
==alen
,"GCS_COMPATTR(A) not returning correct count\n");
464 /* Get strings with exactly matching buffer sizes. */
465 memset(wstring
, 0x1a, sizeof(wstring
));
466 memset(cstring
, 0x1a, sizeof(cstring
));
468 len
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, alen
);
469 ok(len
== alen
, "Unexpected length %d.\n", len
);
470 ok(cstring
[alen
] == 0x1a, "Unexpected buffer contents.\n");
472 len
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, wlen
);
473 ok(len
== wlen
, "Unexpected length %d.\n", len
);
474 ok(wstring
[wlen
/sizeof(WCHAR
)] == 0x1a1a, "Unexpected buffer contents.\n");
476 /* Get strings with exactly smaller buffer sizes. */
477 memset(wstring
, 0x1a, sizeof(wstring
));
478 memset(cstring
, 0x1a, sizeof(cstring
));
480 /* Returns 0 but still fills buffer. */
481 len
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, alen
- 1);
482 ok(!len
, "Unexpected length %d.\n", len
);
483 ok(cstring
[0] == 'w', "Unexpected buffer contents %s.\n", cstring
);
485 len
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, wlen
- 1);
486 ok(len
== wlen
- 1, "Unexpected length %d.\n", len
);
487 ok(!memcmp(wstring
, string
, wlen
- 1), "Unexpected buffer contents.\n");
489 /* Get the size of the required output buffer. */
490 memset(wstring
, 0x1a, sizeof(wstring
));
491 memset(cstring
, 0x1a, sizeof(cstring
));
493 len
= ImmGetCompositionStringA(imc
, GCS_COMPSTR
, cstring
, 0);
494 ok(len
== alen
, "Unexpected length %d.\n", len
);
495 ok(cstring
[0] == 0x1a, "Unexpected buffer contents %s.\n", cstring
);
497 len
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
, wstring
, 0);
498 ok(len
== wlen
, "Unexpected length %d.\n", len
);
499 ok(wstring
[0] == 0x1a1a, "Unexpected buffer contents.\n");
502 win_skip("Composition string isn't available\n");
504 ImmReleaseContext(hwnd
, imc
);
506 /* Test composition results input by IMM API */
507 prop
= ImmGetProperty(GetKeyboardLayout(0), IGP_SETCOMPSTR
);
508 if (!(prop
& SCS_CAP_COMPSTR
)) {
509 /* Wine's IME doesn't support SCS_SETSTR in ImmSetCompositionString */
510 skip("This IME doesn't support SCS_SETSTR\n");
513 ime_composition_test
.old_wnd_proc
=
514 (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
515 (LONG_PTR
)test_ime_wnd_proc
);
516 imc
= ImmGetContext(hwnd
);
517 msg_spy_flush_msgs();
519 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
,
520 string
, sizeof(string
), NULL
,0);
521 ok(ret
, "ImmSetCompositionStringW failed\n");
522 wlen
= ImmGetCompositionStringW(imc
, GCS_COMPSTR
,
523 wstring
, sizeof(wstring
));
525 ret
= ImmNotifyIME(imc
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
526 ok(ret
, "ImmNotifyIME(CPS_COMPLETE) failed\n");
527 msg_spy_flush_msgs();
528 ok(ime_composition_test
.catch_result_str
,
529 "WM_IME_COMPOSITION(GCS_RESULTSTR) isn't sent\n");
532 win_skip("Composition string isn't available\n");
533 ImmReleaseContext(hwnd
, imc
);
534 SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
535 (LONG_PTR
)ime_composition_test
.old_wnd_proc
);
536 msg_spy_flush_msgs();
539 /* Test composition results input by hand */
540 memset(&ime_composition_test
, 0, sizeof(ime_composition_test
));
541 if (winetest_interactive
) {
542 HWND hwndMain
, hwndChild
;
544 const DWORD MY_TIMER
= 0xcaffe;
546 hwndMain
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
,
547 "IME composition test",
548 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
549 CW_USEDEFAULT
, CW_USEDEFAULT
, 320, 160,
550 NULL
, NULL
, GetModuleHandleA(NULL
), NULL
);
551 hwndChild
= CreateWindowExA(0, "static",
552 "Input a DBCS character here using IME.",
553 WS_CHILD
| WS_VISIBLE
,
554 0, 0, 320, 100, hwndMain
, NULL
,
555 GetModuleHandleA(NULL
), NULL
);
557 ime_composition_test
.old_wnd_proc
=
558 (WNDPROC
)SetWindowLongPtrA(hwndChild
, GWLP_WNDPROC
,
559 (LONG_PTR
)test_ime_wnd_proc
);
563 ime_composition_test
.timer_id
= MY_TIMER
;
564 ime_composition_test
.start
= GetTickCount();
565 SetTimer(hwndChild
, ime_composition_test
.timer_id
, 100, NULL
);
566 while (GetMessageA(&msg
, NULL
, 0, 0)) {
567 TranslateMessage(&msg
);
568 DispatchMessageA(&msg
);
569 if (!IsWindow(hwndMain
))
572 if (!ime_composition_test
.catch_result_str
)
573 skip("WM_IME_COMPOSITION(GCS_RESULTSTR) isn't tested\n");
574 msg_spy_flush_msgs();
578 static void test_ImmSetCompositionString(void)
583 SetLastError(0xdeadbeef);
584 imc
= ImmGetContext(hwnd
);
585 ok(imc
!= 0, "ImmGetContext() failed. Last error: %u\n", GetLastError());
589 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
, NULL
, 0, NULL
, 0);
592 "ImmSetCompositionStringW() failed.\n");
594 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGEATTR
,
596 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
598 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGECLAUSE
,
600 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
602 ret
= ImmSetCompositionStringW(imc
, SCS_CHANGEATTR
| SCS_CHANGECLAUSE
,
604 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
606 ret
= ImmSetCompositionStringW(imc
, SCS_SETSTR
| SCS_CHANGEATTR
| SCS_CHANGECLAUSE
,
608 ok(!ret
, "ImmSetCompositionStringW() succeeded.\n");
610 ImmReleaseContext(hwnd
, imc
);
613 static void test_ImmIME(void)
617 imc
= ImmGetContext(hwnd
);
622 rc
= ImmConfigureIMEA((HKL
)imc
, NULL
, IME_CONFIG_REGISTERWORD
, NULL
);
624 rc
= ImmConfigureIMEA(imc
, NULL
, IME_CONFIG_REGISTERWORD
, NULL
);
626 ok (rc
== 0, "ImmConfigureIMEA did not fail\n");
628 rc
= ImmConfigureIMEW((HKL
)imc
, NULL
, IME_CONFIG_REGISTERWORD
, NULL
);
630 rc
= ImmConfigureIMEW(imc
, NULL
, IME_CONFIG_REGISTERWORD
, NULL
);
632 ok (rc
== 0, "ImmConfigureIMEW did not fail\n");
634 ImmReleaseContext(hwnd
,imc
);
637 static void test_ImmAssociateContextEx(void)
642 if (!pImmAssociateContextEx
) return;
644 imc
= ImmGetContext(hwnd
);
649 newimc
= ImmCreateContext();
650 ok(newimc
!= imc
, "handles should not be the same\n");
651 rc
= pImmAssociateContextEx(NULL
, NULL
, 0);
652 ok(!rc
, "ImmAssociateContextEx succeeded\n");
653 rc
= pImmAssociateContextEx(hwnd
, NULL
, 0);
654 ok(rc
, "ImmAssociateContextEx failed\n");
655 rc
= pImmAssociateContextEx(NULL
, imc
, 0);
656 ok(!rc
, "ImmAssociateContextEx succeeded\n");
658 rc
= pImmAssociateContextEx(hwnd
, imc
, 0);
659 ok(rc
, "ImmAssociateContextEx failed\n");
660 retimc
= ImmGetContext(hwnd
);
661 ok(retimc
== imc
, "handles should be the same\n");
662 ImmReleaseContext(hwnd
,retimc
);
664 rc
= pImmAssociateContextEx(hwnd
, newimc
, 0);
665 ok(rc
, "ImmAssociateContextEx failed\n");
666 retimc
= ImmGetContext(hwnd
);
667 ok(retimc
== newimc
, "handles should be the same\n");
668 ImmReleaseContext(hwnd
,retimc
);
670 rc
= pImmAssociateContextEx(hwnd
, NULL
, IACE_DEFAULT
);
671 ok(rc
, "ImmAssociateContextEx failed\n");
673 ImmReleaseContext(hwnd
,imc
);
676 typedef struct _igc_threadinfo
{
684 static DWORD WINAPI
ImmGetContextThreadFunc( LPVOID lpParam
)
693 igc_threadinfo
*info
= (igc_threadinfo
*)lpParam
;
694 info
->hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
695 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
696 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
698 h1
= ImmGetContext(hwnd
);
699 ok(info
->himc
== h1
, "hwnd context changed in new thread\n");
700 h2
= ImmGetContext(info
->hwnd
);
701 ok(h2
!= h1
, "new hwnd in new thread should have different context\n");
703 ImmReleaseContext(hwnd
,h1
);
705 hwnd2
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
706 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
707 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
708 h1
= ImmGetContext(hwnd2
);
710 ok(h1
== h2
, "Windows in same thread should have same default context\n");
711 ImmReleaseContext(hwnd2
,h1
);
712 ImmReleaseContext(info
->hwnd
,h2
);
713 DestroyWindow(hwnd2
);
715 /* priming for later tests */
716 ImmSetCompositionWindow(h1
, &cf
);
717 ImmSetStatusWindowPos(h1
, &pt
);
718 info
->u_himc
= ImmCreateContext();
719 ImmSetOpenStatus(info
->u_himc
, TRUE
);
721 cdf
.dwStyle
= CFS_CANDIDATEPOS
;
722 cdf
.ptCurrentPos
.x
= 0;
723 cdf
.ptCurrentPos
.y
= 0;
724 ImmSetCandidateWindow(info
->u_himc
, &cdf
);
726 SetEvent(info
->event
);
728 while(GetMessageW(&msg
, 0, 0, 0))
730 TranslateMessage(&msg
);
731 DispatchMessageW(&msg
);
736 static void test_ImmThreads(void)
738 HIMC himc
, otherHimc
, h1
;
739 igc_threadinfo threadinfo
;
746 DWORD status
, sentence
;
749 himc
= ImmGetContext(hwnd
);
750 threadinfo
.event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
751 threadinfo
.himc
= himc
;
752 hThread
= CreateThread(NULL
, 0, ImmGetContextThreadFunc
, &threadinfo
, 0, &dwThreadId
);
753 WaitForSingleObject(threadinfo
.event
, INFINITE
);
755 otherHimc
= ImmGetContext(threadinfo
.hwnd
);
757 ok(himc
!= otherHimc
, "Windows from other threads should have different himc\n");
758 ok(otherHimc
== threadinfo
.himc
, "Context from other thread should not change in main thread\n");
760 h1
= ImmAssociateContext(hwnd
,otherHimc
);
761 ok(h1
== NULL
, "Should fail to be able to Associate a default context from a different thread\n");
762 h1
= ImmGetContext(hwnd
);
763 ok(h1
== himc
, "Context for window should remain unchanged\n");
764 ImmReleaseContext(hwnd
,h1
);
766 h1
= ImmAssociateContext(hwnd
, threadinfo
.u_himc
);
767 ok (h1
== NULL
, "Should fail to associate a context from a different thread\n");
768 h1
= ImmGetContext(hwnd
);
769 ok(h1
== himc
, "Context for window should remain unchanged\n");
770 ImmReleaseContext(hwnd
,h1
);
772 h1
= ImmAssociateContext(threadinfo
.hwnd
, threadinfo
.u_himc
);
773 ok (h1
== NULL
, "Should fail to associate a context from a different thread into a window from that thread.\n");
774 h1
= ImmGetContext(threadinfo
.hwnd
);
775 ok(h1
== threadinfo
.himc
, "Context for window should remain unchanged\n");
776 ImmReleaseContext(threadinfo
.hwnd
,h1
);
779 rc
= ImmSetOpenStatus(himc
, TRUE
);
780 ok(rc
!= 0, "ImmSetOpenStatus failed\n");
781 rc
= ImmGetOpenStatus(himc
);
782 ok(rc
!= 0, "ImmGetOpenStatus failed\n");
783 rc
= ImmSetOpenStatus(himc
, FALSE
);
784 ok(rc
!= 0, "ImmSetOpenStatus failed\n");
785 rc
= ImmGetOpenStatus(himc
);
786 ok(rc
== 0, "ImmGetOpenStatus failed\n");
788 rc
= ImmSetOpenStatus(otherHimc
, TRUE
);
789 ok(rc
== 0, "ImmSetOpenStatus should fail\n");
790 rc
= ImmSetOpenStatus(threadinfo
.u_himc
, TRUE
);
791 ok(rc
== 0, "ImmSetOpenStatus should fail\n");
792 rc
= ImmGetOpenStatus(otherHimc
);
793 ok(rc
== 0, "ImmGetOpenStatus failed\n");
794 rc
= ImmGetOpenStatus(threadinfo
.u_himc
);
795 ok (rc
== 1 || broken(rc
== 0), "ImmGetOpenStatus should return 1\n");
796 rc
= ImmSetOpenStatus(otherHimc
, FALSE
);
797 ok(rc
== 0, "ImmSetOpenStatus should fail\n");
798 rc
= ImmGetOpenStatus(otherHimc
);
799 ok(rc
== 0, "ImmGetOpenStatus failed\n");
801 /* CompositionFont */
802 rc
= ImmGetCompositionFontA(himc
, &lf
);
803 ok(rc
!= 0, "ImmGetCompositionFont failed\n");
804 rc
= ImmSetCompositionFontA(himc
, &lf
);
805 ok(rc
!= 0, "ImmSetCompositionFont failed\n");
807 rc
= ImmGetCompositionFontA(otherHimc
, &lf
);
808 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionFont failed\n");
809 rc
= ImmGetCompositionFontA(threadinfo
.u_himc
, &lf
);
810 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionFont user himc failed\n");
811 rc
= ImmSetCompositionFontA(otherHimc
, &lf
);
812 ok(rc
== 0, "ImmSetCompositionFont should fail\n");
813 rc
= ImmSetCompositionFontA(threadinfo
.u_himc
, &lf
);
814 ok(rc
== 0, "ImmSetCompositionFont should fail\n");
816 /* CompositionWindow */
817 rc
= ImmSetCompositionWindow(himc
, &cf
);
818 ok(rc
!= 0, "ImmSetCompositionWindow failed\n");
819 rc
= ImmGetCompositionWindow(himc
, &cf
);
820 ok(rc
!= 0, "ImmGetCompositionWindow failed\n");
822 rc
= ImmSetCompositionWindow(otherHimc
, &cf
);
823 ok(rc
== 0, "ImmSetCompositionWindow should fail\n");
824 rc
= ImmSetCompositionWindow(threadinfo
.u_himc
, &cf
);
825 ok(rc
== 0, "ImmSetCompositionWindow should fail\n");
826 rc
= ImmGetCompositionWindow(otherHimc
, &cf
);
827 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionWindow failed\n");
828 rc
= ImmGetCompositionWindow(threadinfo
.u_himc
, &cf
);
829 ok(rc
!= 0 || broken(rc
== 0), "ImmGetCompositionWindow failed\n");
831 /* ConversionStatus */
832 rc
= ImmGetConversionStatus(himc
, &status
, &sentence
);
833 ok(rc
!= 0, "ImmGetConversionStatus failed\n");
834 rc
= ImmSetConversionStatus(himc
, status
, sentence
);
835 ok(rc
!= 0, "ImmSetConversionStatus failed\n");
837 rc
= ImmGetConversionStatus(otherHimc
, &status
, &sentence
);
838 ok(rc
!= 0 || broken(rc
== 0), "ImmGetConversionStatus failed\n");
839 rc
= ImmGetConversionStatus(threadinfo
.u_himc
, &status
, &sentence
);
840 ok(rc
!= 0 || broken(rc
== 0), "ImmGetConversionStatus failed\n");
841 rc
= ImmSetConversionStatus(otherHimc
, status
, sentence
);
842 ok(rc
== 0, "ImmSetConversionStatus should fail\n");
843 rc
= ImmSetConversionStatus(threadinfo
.u_himc
, status
, sentence
);
844 ok(rc
== 0, "ImmSetConversionStatus should fail\n");
846 /* StatusWindowPos */
847 rc
= ImmSetStatusWindowPos(himc
, &pt
);
848 ok(rc
!= 0, "ImmSetStatusWindowPos failed\n");
849 rc
= ImmGetStatusWindowPos(himc
, &pt
);
850 ok(rc
!= 0, "ImmGetStatusWindowPos failed\n");
852 rc
= ImmSetStatusWindowPos(otherHimc
, &pt
);
853 ok(rc
== 0, "ImmSetStatusWindowPos should fail\n");
854 rc
= ImmSetStatusWindowPos(threadinfo
.u_himc
, &pt
);
855 ok(rc
== 0, "ImmSetStatusWindowPos should fail\n");
856 rc
= ImmGetStatusWindowPos(otherHimc
, &pt
);
857 ok(rc
!= 0 || broken(rc
== 0), "ImmGetStatusWindowPos failed\n");
858 rc
= ImmGetStatusWindowPos(threadinfo
.u_himc
, &pt
);
859 ok(rc
!= 0 || broken(rc
== 0), "ImmGetStatusWindowPos failed\n");
861 h1
= ImmAssociateContext(threadinfo
.hwnd
, NULL
);
862 ok (h1
== otherHimc
, "ImmAssociateContext cross thread with NULL should work\n");
863 h1
= ImmGetContext(threadinfo
.hwnd
);
864 ok (h1
== NULL
, "CrossThread window context should be NULL\n");
865 h1
= ImmAssociateContext(threadinfo
.hwnd
, h1
);
866 ok (h1
== NULL
, "Resetting cross thread context should fail\n");
867 h1
= ImmGetContext(threadinfo
.hwnd
);
868 ok (h1
== NULL
, "CrossThread window context should still be NULL\n");
870 rc
= ImmDestroyContext(threadinfo
.u_himc
);
871 ok (rc
== 0, "ImmDestroyContext Cross Thread should fail\n");
873 /* Candidate Window */
874 rc
= ImmGetCandidateWindow(himc
, 0, &cdf
);
875 ok (rc
== 0, "ImmGetCandidateWindow should fail\n");
877 cdf
.dwStyle
= CFS_CANDIDATEPOS
;
878 cdf
.ptCurrentPos
.x
= 0;
879 cdf
.ptCurrentPos
.y
= 0;
880 rc
= ImmSetCandidateWindow(himc
, &cdf
);
881 ok (rc
== 1, "ImmSetCandidateWindow should succeed\n");
882 rc
= ImmGetCandidateWindow(himc
, 0, &cdf
);
883 ok (rc
== 1, "ImmGetCandidateWindow should succeed\n");
885 rc
= ImmGetCandidateWindow(otherHimc
, 0, &cdf
);
886 ok (rc
== 0, "ImmGetCandidateWindow should fail\n");
887 rc
= ImmSetCandidateWindow(otherHimc
, &cdf
);
888 ok (rc
== 0, "ImmSetCandidateWindow should fail\n");
889 rc
= ImmGetCandidateWindow(threadinfo
.u_himc
, 0, &cdf
);
890 ok (rc
== 1 || broken( rc
== 0), "ImmGetCandidateWindow should succeed\n");
891 rc
= ImmSetCandidateWindow(threadinfo
.u_himc
, &cdf
);
892 ok (rc
== 0, "ImmSetCandidateWindow should fail\n");
894 ImmReleaseContext(threadinfo
.hwnd
,otherHimc
);
895 ImmReleaseContext(hwnd
,himc
);
897 SendMessageA(threadinfo
.hwnd
, WM_CLOSE
, 0, 0);
898 rc
= PostThreadMessageA(dwThreadId
, WM_QUIT
, 1, 0);
899 ok(rc
== 1, "PostThreadMessage should succeed\n");
900 WaitForSingleObject(hThread
, INFINITE
);
901 CloseHandle(hThread
);
903 himc
= ImmGetContext(GetDesktopWindow());
904 ok(himc
== NULL
, "Should not be able to get himc from other process window\n");
907 static void test_ImmIsUIMessage(void)
915 static const struct test tests
[] =
917 { WM_MOUSEMOVE
, FALSE
},
918 { WM_IME_STARTCOMPOSITION
, TRUE
},
919 { WM_IME_ENDCOMPOSITION
, TRUE
},
920 { WM_IME_COMPOSITION
, TRUE
},
921 { WM_IME_SETCONTEXT
, TRUE
},
922 { WM_IME_NOTIFY
, TRUE
},
923 { WM_IME_CONTROL
, FALSE
},
924 { WM_IME_COMPOSITIONFULL
, TRUE
},
925 { WM_IME_SELECT
, TRUE
},
926 { WM_IME_CHAR
, FALSE
},
927 { 0x287 /* FIXME */, TRUE
},
928 { WM_IME_REQUEST
, FALSE
},
929 { WM_IME_KEYDOWN
, FALSE
},
930 { WM_IME_KEYUP
, FALSE
},
931 { 0, FALSE
} /* mark the end */
934 UINT WM_MSIME_SERVICE
= RegisterWindowMessageA("MSIMEService");
935 UINT WM_MSIME_RECONVERTOPTIONS
= RegisterWindowMessageA("MSIMEReconvertOptions");
936 UINT WM_MSIME_MOUSE
= RegisterWindowMessageA("MSIMEMouseOperation");
937 UINT WM_MSIME_RECONVERTREQUEST
= RegisterWindowMessageA("MSIMEReconvertRequest");
938 UINT WM_MSIME_RECONVERT
= RegisterWindowMessageA("MSIMEReconvert");
939 UINT WM_MSIME_QUERYPOSITION
= RegisterWindowMessageA("MSIMEQueryPosition");
940 UINT WM_MSIME_DOCUMENTFEED
= RegisterWindowMessageA("MSIMEDocumentFeed");
942 const struct test
*test
;
945 if (!pImmIsUIMessageA
) return;
947 for (test
= tests
; test
->msg
; test
++)
949 msg_spy_flush_msgs();
950 ret
= pImmIsUIMessageA(NULL
, test
->msg
, 0, 0);
951 ok(ret
== test
->ret
, "ImmIsUIMessageA returned %x for %x\n", ret
, test
->msg
);
952 ok(!msg_spy_find_msg(test
->msg
), "Windows does not send 0x%x for NULL hwnd\n", test
->msg
);
954 ret
= pImmIsUIMessageA(hwnd
, test
->msg
, 0, 0);
955 ok(ret
== test
->ret
, "ImmIsUIMessageA returned %x for %x\n", ret
, test
->msg
);
957 ok(msg_spy_find_msg(test
->msg
) != NULL
, "Windows does send 0x%x\n", test
->msg
);
959 ok(!msg_spy_find_msg(test
->msg
), "Windows does not send 0x%x\n", test
->msg
);
962 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_SERVICE
, 0, 0);
963 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_SERVICE\n");
964 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERTOPTIONS
, 0, 0);
965 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTOPTIONS\n");
966 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_MOUSE
, 0, 0);
967 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_MOUSE\n");
968 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERTREQUEST
, 0, 0);
969 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERTREQUEST\n");
970 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_RECONVERT
, 0, 0);
971 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_RECONVERT\n");
972 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_QUERYPOSITION
, 0, 0);
973 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_QUERYPOSITION\n");
974 ret
= pImmIsUIMessageA(NULL
, WM_MSIME_DOCUMENTFEED
, 0, 0);
975 ok(!ret
, "ImmIsUIMessageA returned TRUE for WM_MSIME_DOCUMENTFEED\n");
978 static void test_ImmGetContext(void)
983 SetLastError(0xdeadbeef);
984 himc
= ImmGetContext((HWND
)0xffffffff);
985 err
= GetLastError();
986 ok(himc
== NULL
, "ImmGetContext succeeded\n");
987 ok(err
== ERROR_INVALID_WINDOW_HANDLE
, "got %u\n", err
);
989 himc
= ImmGetContext(hwnd
);
990 ok(himc
!= NULL
, "ImmGetContext failed\n");
991 ok(ImmReleaseContext(hwnd
, himc
), "ImmReleaseContext failed\n");
994 static void test_ImmGetDescription(void)
1001 /* FIXME: invalid keyboard layouts should not pass */
1002 ret
= ImmGetDescriptionW(NULL
, NULL
, 0);
1003 ok(!ret
, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret
);
1004 ret
= ImmGetDescriptionA(NULL
, NULL
, 0);
1005 ok(!ret
, "ImmGetDescriptionA failed, expected 0 received %d.\n", ret
);
1007 /* load a language with valid IMM descriptions */
1008 hkl
= GetKeyboardLayout(0);
1009 ok(hkl
!= 0, "GetKeyboardLayout failed, expected != 0.\n");
1011 ret
= ImmGetDescriptionW(hkl
, NULL
, 0);
1014 win_skip("ImmGetDescriptionW is not working for current loaded keyboard.\n");
1018 SetLastError(0xdeadcafe);
1019 ret
= ImmGetDescriptionW(0, NULL
, 100);
1020 ok (ret
== 0, "ImmGetDescriptionW with 0 hkl should return 0\n");
1021 ret
= GetLastError();
1022 ok (ret
== 0xdeadcafe, "Last Error should remain unchanged\n");
1024 ret
= ImmGetDescriptionW(hkl
, descW
, 0);
1025 ok(ret
, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
1027 lret
= ImmGetDescriptionW(hkl
, descW
, ret
+ 1);
1028 ok(lret
, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
1029 ok(lret
== ret
, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret
, lret
);
1031 lret
= ImmGetDescriptionA(hkl
, descA
, ret
+ 1);
1032 ok(lret
, "ImmGetDescriptionA failed, expected != 0 received 0.\n");
1033 ok(lret
== ret
, "ImmGetDescriptionA failed to return the correct amount of data. Expected %d, got %d.\n", ret
, lret
);
1035 ret
/= 2; /* try to copy partially */
1036 lret
= ImmGetDescriptionW(hkl
, descW
, ret
+ 1);
1037 ok(lret
, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
1038 ok(lret
== ret
, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret
, lret
);
1040 lret
= ImmGetDescriptionA(hkl
, descA
, ret
+ 1);
1041 ok(!lret
, "ImmGetDescriptionA should fail\n");
1043 ret
= ImmGetDescriptionW(hkl
, descW
, 1);
1044 ok(!ret
, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret
);
1046 UnloadKeyboardLayout(hkl
);
1049 static LRESULT (WINAPI
*old_imm_wnd_proc
)(HWND
, UINT
, WPARAM
, LPARAM
);
1050 static LRESULT WINAPI
imm_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
1052 ok(msg
!= WM_DESTROY
, "got WM_DESTROY message\n");
1053 return old_imm_wnd_proc(hwnd
, msg
, wparam
, lparam
);
1056 static HWND thread_ime_wnd
;
1057 static DWORD WINAPI
test_ImmGetDefaultIMEWnd_thread(void *arg
)
1059 CreateWindowA("static", "static", WS_POPUP
, 0, 0, 1, 1, NULL
, NULL
, NULL
, NULL
);
1061 thread_ime_wnd
= ImmGetDefaultIMEWnd(0);
1062 ok(thread_ime_wnd
!= 0, "ImmGetDefaultIMEWnd returned NULL\n");
1063 old_imm_wnd_proc
= (void*)SetWindowLongPtrW(thread_ime_wnd
, GWLP_WNDPROC
, (LONG_PTR
)imm_wnd_proc
);
1067 static void test_ImmDefaultHwnd(void)
1069 HIMC imc1
, imc2
, imc3
;
1076 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
1077 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1078 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1080 ShowWindow(hwnd
, SW_SHOWNORMAL
);
1082 imc1
= ImmGetContext(hwnd
);
1085 win_skip("IME support not implemented\n");
1089 def1
= ImmGetDefaultIMEWnd(hwnd
);
1091 GetWindowTextA(def1
, title
, sizeof(title
));
1092 ok(!strcmp(title
, "Default IME"), "got %s\n", title
);
1093 style
= GetWindowLongA(def1
, GWL_STYLE
);
1094 ok(style
== (WS_DISABLED
| WS_POPUP
| WS_CLIPSIBLINGS
), "got %08x\n", style
);
1095 style
= GetWindowLongA(def1
, GWL_EXSTYLE
);
1096 ok(style
== 0, "got %08x\n", style
);
1098 imc2
= ImmCreateContext();
1099 ImmSetOpenStatus(imc2
, TRUE
);
1101 imc3
= ImmGetContext(hwnd
);
1102 def3
= ImmGetDefaultIMEWnd(hwnd
);
1104 ok(def3
== def1
, "Default IME window should not change\n");
1105 ok(imc1
== imc3
, "IME context should not change\n");
1106 ImmSetOpenStatus(imc2
, FALSE
);
1108 thread
= CreateThread(NULL
, 0, test_ImmGetDefaultIMEWnd_thread
, NULL
, 0, NULL
);
1109 WaitForSingleObject(thread
, INFINITE
);
1110 ok(thread_ime_wnd
!= def1
, "thread_ime_wnd == def1\n");
1111 ok(!IsWindow(thread_ime_wnd
), "thread_ime_wnd was not destroyed\n");
1112 CloseHandle(thread
);
1114 ImmReleaseContext(hwnd
, imc1
);
1115 ImmReleaseContext(hwnd
, imc3
);
1116 ImmDestroyContext(imc2
);
1117 DestroyWindow(hwnd
);
1120 static BOOL CALLBACK
is_ime_window_proc(HWND hWnd
, LPARAM param
)
1122 static const WCHAR imeW
[] = {'I','M','E',0};
1123 WCHAR class_nameW
[16];
1124 HWND
*ime_window
= (HWND
*)param
;
1125 if (GetClassNameW(hWnd
, class_nameW
, ARRAY_SIZE(class_nameW
)) && !lstrcmpW(class_nameW
, imeW
))
1133 static HWND
get_ime_window(void)
1135 HWND ime_window
= NULL
;
1136 EnumThreadWindows(GetCurrentThreadId(), is_ime_window_proc
, (LPARAM
)&ime_window
);
1140 struct testcase_ime_window
{
1142 BOOL top_level_window
;
1145 static DWORD WINAPI
test_default_ime_window_cb(void *arg
)
1147 struct testcase_ime_window
*testcase
= (struct testcase_ime_window
*)arg
;
1148 DWORD visible
= testcase
->visible
? WS_VISIBLE
: 0;
1149 HWND hwnd1
, hwnd2
, default_ime_wnd
, ime_wnd
;
1151 ok(!get_ime_window(), "Expected no IME windows\n");
1152 if (testcase
->top_level_window
) {
1153 test_phase
= FIRST_WINDOW
;
1154 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1155 WS_OVERLAPPEDWINDOW
| visible
,
1156 CW_USEDEFAULT
, CW_USEDEFAULT
,
1157 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1160 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
1162 CW_USEDEFAULT
, CW_USEDEFAULT
,
1163 240, 24, hwnd
, NULL
, GetModuleHandleW(NULL
), NULL
);
1165 ime_wnd
= get_ime_window();
1166 ok(ime_wnd
!= NULL
, "Expected IME window existence\n");
1167 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1168 ok(ime_wnd
== default_ime_wnd
, "Expected %p, got %p\n", ime_wnd
, default_ime_wnd
);
1170 test_phase
= SECOND_WINDOW
;
1171 hwnd2
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1172 WS_OVERLAPPEDWINDOW
| visible
,
1173 CW_USEDEFAULT
, CW_USEDEFAULT
,
1174 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1175 DestroyWindow(hwnd2
);
1176 ok(IsWindow(ime_wnd
) ||
1177 broken(!testcase
->visible
/* Vista */) ||
1178 broken(!testcase
->top_level_window
/* Vista */) ,
1179 "Expected IME window existence\n");
1180 DestroyWindow(hwnd1
);
1181 ok(!IsWindow(ime_wnd
), "Expected no IME windows\n");
1185 static DWORD WINAPI
test_default_ime_window_cancel_cb(void *arg
)
1187 struct testcase_ime_window
*testcase
= (struct testcase_ime_window
*)arg
;
1188 DWORD visible
= testcase
->visible
? WS_VISIBLE
: 0;
1189 HWND hwnd1
, hwnd2
, default_ime_wnd
, ime_wnd
;
1191 ok(!get_ime_window(), "Expected no IME windows\n");
1192 test_phase
= NCCREATE_CANCEL
;
1193 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1194 WS_OVERLAPPEDWINDOW
| visible
,
1195 CW_USEDEFAULT
, CW_USEDEFAULT
,
1196 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1197 ok(hwnd1
== NULL
, "creation succeeded, got %p\n", hwnd1
);
1198 ok(!get_ime_window(), "Expected no IME windows\n");
1200 test_phase
= CREATE_CANCEL
;
1201 hwnd1
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1202 WS_OVERLAPPEDWINDOW
| visible
,
1203 CW_USEDEFAULT
, CW_USEDEFAULT
,
1204 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1205 ok(hwnd1
== NULL
, "creation succeeded, got %p\n", hwnd1
);
1206 ok(!get_ime_window(), "Expected no IME windows\n");
1208 test_phase
= FIRST_WINDOW
;
1209 hwnd2
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1210 WS_OVERLAPPEDWINDOW
| visible
,
1211 CW_USEDEFAULT
, CW_USEDEFAULT
,
1212 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1213 ime_wnd
= get_ime_window();
1214 ok(ime_wnd
!= NULL
, "Expected IME window existence\n");
1215 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd2
);
1216 ok(ime_wnd
== default_ime_wnd
, "Expected %p, got %p\n", ime_wnd
, default_ime_wnd
);
1218 DestroyWindow(hwnd2
);
1219 ok(!IsWindow(ime_wnd
), "Expected no IME windows\n");
1223 static DWORD WINAPI
test_default_ime_disabled_cb(void *arg
)
1225 HWND hWnd
, default_ime_wnd
;
1227 ok(!get_ime_window(), "Expected no IME windows\n");
1228 ImmDisableIME(GetCurrentThreadId());
1229 test_phase
= IME_DISABLED
;
1230 hWnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, wndcls
, "Wine imm32.dll test",
1231 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1232 CW_USEDEFAULT
, CW_USEDEFAULT
,
1233 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1234 default_ime_wnd
= ImmGetDefaultIMEWnd(hWnd
);
1235 ok(!default_ime_wnd
, "Expected no IME windows\n");
1236 DestroyWindow(hWnd
);
1240 static DWORD WINAPI
test_default_ime_with_message_only_window_cb(void *arg
)
1242 HWND hwnd1
, hwnd2
, default_ime_wnd
;
1244 test_phase
= PHASE_UNKNOWN
;
1245 hwnd1
= CreateWindowA(wndcls
, "Wine imm32.dll test",
1246 WS_OVERLAPPEDWINDOW
,
1247 CW_USEDEFAULT
, CW_USEDEFAULT
,
1248 240, 120, HWND_MESSAGE
, NULL
, GetModuleHandleW(NULL
), NULL
);
1249 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1250 ok(!IsWindow(default_ime_wnd
), "Expected no IME windows, got %p\n", default_ime_wnd
);
1252 hwnd2
= CreateWindowA(wndcls
, "Wine imm32.dll test",
1253 WS_OVERLAPPEDWINDOW
,
1254 CW_USEDEFAULT
, CW_USEDEFAULT
,
1255 240, 120, hwnd1
, NULL
, GetModuleHandleW(NULL
), NULL
);
1256 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd2
);
1257 ok(IsWindow(default_ime_wnd
), "Expected IME window existence\n");
1259 DestroyWindow(hwnd2
);
1260 DestroyWindow(hwnd1
);
1262 hwnd1
= CreateWindowA(wndcls
, "Wine imm32.dll test",
1263 WS_OVERLAPPEDWINDOW
,
1264 CW_USEDEFAULT
, CW_USEDEFAULT
,
1265 240, 120, NULL
, NULL
, GetModuleHandleW(NULL
), NULL
);
1266 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1267 ok(IsWindow(default_ime_wnd
), "Expected IME window existence\n");
1268 SetParent(hwnd1
, HWND_MESSAGE
);
1269 default_ime_wnd
= ImmGetDefaultIMEWnd(hwnd1
);
1270 ok(IsWindow(default_ime_wnd
), "Expected IME window existence\n");
1271 DestroyWindow(hwnd1
);
1275 static void test_default_ime_window_creation(void)
1279 struct testcase_ime_window testcases
[] = {
1280 /* visible, top-level window */
1287 for (i
= 0; i
< ARRAY_SIZE(testcases
); i
++)
1289 thread
= CreateThread(NULL
, 0, test_default_ime_window_cb
, &testcases
[i
], 0, NULL
);
1290 ok(thread
!= NULL
, "CreateThread failed with error %u\n", GetLastError());
1291 while (MsgWaitForMultipleObjects(1, &thread
, FALSE
, INFINITE
, QS_ALLINPUT
) == WAIT_OBJECT_0
+ 1)
1294 while (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
))
1296 TranslateMessage(&msg
);
1297 DispatchMessageA(&msg
);
1300 CloseHandle(thread
);
1302 if (testcases
[i
].top_level_window
)
1304 thread
= CreateThread(NULL
, 0, test_default_ime_window_cancel_cb
, &testcases
[i
], 0, NULL
);
1305 ok(thread
!= NULL
, "CreateThread failed with error %u\n", GetLastError());
1306 WaitForSingleObject(thread
, INFINITE
);
1307 CloseHandle(thread
);
1311 thread
= CreateThread(NULL
, 0, test_default_ime_disabled_cb
, NULL
, 0, NULL
);
1312 WaitForSingleObject(thread
, INFINITE
);
1313 CloseHandle(thread
);
1315 thread
= CreateThread(NULL
, 0, test_default_ime_with_message_only_window_cb
, NULL
, 0, NULL
);
1316 WaitForSingleObject(thread
, INFINITE
);
1317 CloseHandle(thread
);
1319 test_phase
= PHASE_UNKNOWN
;
1322 static void test_ImmGetIMCLockCount(void)
1325 DWORD count
, ret
, i
;
1328 imc
= ImmCreateContext();
1329 ImmDestroyContext(imc
);
1330 SetLastError(0xdeadbeef);
1331 count
= ImmGetIMCLockCount((HIMC
)0xdeadcafe);
1332 ok(count
== 0, "Invalid IMC should return 0\n");
1333 ret
= GetLastError();
1334 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1335 SetLastError(0xdeadbeef);
1336 count
= ImmGetIMCLockCount(0x00000000);
1337 ok(count
== 0, "NULL IMC should return 0\n");
1338 ret
= GetLastError();
1339 ok(ret
== 0xdeadbeef, "Last Error should remain unchanged: %08x\n",ret
);
1340 count
= ImmGetIMCLockCount(imc
);
1341 ok(count
== 0, "Destroyed IMC should return 0\n");
1342 ret
= GetLastError();
1343 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1345 imc
= ImmCreateContext();
1346 count
= ImmGetIMCLockCount(imc
);
1347 ok(count
== 0, "expect 0, returned %d\n", count
);
1348 ic
= ImmLockIMC(imc
);
1349 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
1350 count
= ImmGetIMCLockCount(imc
);
1351 ok(count
== 1, "expect 1, returned %d\n", count
);
1352 ret
= ImmUnlockIMC(imc
);
1353 ok(ret
== TRUE
, "expect TRUE, ret %d\n", ret
);
1354 count
= ImmGetIMCLockCount(imc
);
1355 ok(count
== 0, "expect 0, returned %d\n", count
);
1356 ret
= ImmUnlockIMC(imc
);
1357 ok(ret
== TRUE
, "expect TRUE, ret %d\n", ret
);
1358 count
= ImmGetIMCLockCount(imc
);
1359 ok(count
== 0, "expect 0, returned %d\n", count
);
1361 for (i
= 0; i
< GMEM_LOCKCOUNT
* 2; i
++)
1363 ic
= ImmLockIMC(imc
);
1364 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
1366 count
= ImmGetIMCLockCount(imc
);
1367 todo_wine
ok(count
== GMEM_LOCKCOUNT
, "expect GMEM_LOCKCOUNT, returned %d\n", count
);
1369 for (i
= 0; i
< GMEM_LOCKCOUNT
- 1; i
++)
1371 count
= ImmGetIMCLockCount(imc
);
1372 todo_wine
ok(count
== 1, "expect 1, returned %d\n", count
);
1374 count
= ImmGetIMCLockCount(imc
);
1375 todo_wine
ok(count
== 0, "expect 0, returned %d\n", count
);
1377 ImmDestroyContext(imc
);
1380 static void test_ImmGetIMCCLockCount(void)
1383 DWORD count
, g_count
, i
;
1387 imcc
= ImmCreateIMCC(sizeof(CANDIDATEINFO
));
1388 count
= ImmGetIMCCLockCount(imcc
);
1389 ok(count
== 0, "expect 0, returned %d\n", count
);
1391 count
= ImmGetIMCCLockCount(imcc
);
1392 ok(count
== 1, "expect 1, returned %d\n", count
);
1393 ret
= ImmUnlockIMCC(imcc
);
1394 ok(ret
== FALSE
, "expect FALSE, ret %d\n", ret
);
1395 count
= ImmGetIMCCLockCount(imcc
);
1396 ok(count
== 0, "expect 0, returned %d\n", count
);
1397 ret
= ImmUnlockIMCC(imcc
);
1398 ok(ret
== FALSE
, "expect FALSE, ret %d\n", ret
);
1399 count
= ImmGetIMCCLockCount(imcc
);
1400 ok(count
== 0, "expect 0, returned %d\n", count
);
1402 p
= ImmLockIMCC(imcc
);
1403 ok(GlobalHandle(p
) == imcc
, "expect %p, returned %p\n", imcc
, GlobalHandle(p
));
1405 for (i
= 0; i
< GMEM_LOCKCOUNT
* 2; i
++)
1408 count
= ImmGetIMCCLockCount(imcc
);
1409 g_count
= GlobalFlags(imcc
) & GMEM_LOCKCOUNT
;
1410 ok(count
== g_count
, "count %d, g_count %d\n", count
, g_count
);
1412 count
= ImmGetIMCCLockCount(imcc
);
1413 ok(count
== GMEM_LOCKCOUNT
, "expect GMEM_LOCKCOUNT, returned %d\n", count
);
1415 for (i
= 0; i
< GMEM_LOCKCOUNT
- 1; i
++)
1417 count
= ImmGetIMCCLockCount(imcc
);
1418 ok(count
== 1, "expect 1, returned %d\n", count
);
1420 count
= ImmGetIMCCLockCount(imcc
);
1421 ok(count
== 0, "expect 0, returned %d\n", count
);
1423 ImmDestroyIMCC(imcc
);
1426 static void test_ImmDestroyContext(void)
1432 imc
= ImmCreateContext();
1433 count
= ImmGetIMCLockCount(imc
);
1434 ok(count
== 0, "expect 0, returned %d\n", count
);
1435 ic
= ImmLockIMC(imc
);
1436 ok(ic
!= NULL
, "ImmLockIMC failed!\n");
1437 count
= ImmGetIMCLockCount(imc
);
1438 ok(count
== 1, "expect 1, returned %d\n", count
);
1439 ret
= ImmDestroyContext(imc
);
1440 ok(ret
== TRUE
, "Destroy a locked IMC should success!\n");
1441 ic
= ImmLockIMC(imc
);
1442 ok(ic
== NULL
, "Lock a destroyed IMC should fail!\n");
1443 ret
= ImmUnlockIMC(imc
);
1444 ok(ret
== FALSE
, "Unlock a destroyed IMC should fail!\n");
1445 count
= ImmGetIMCLockCount(imc
);
1446 ok(count
== 0, "Get lock count of a destroyed IMC should return 0!\n");
1447 SetLastError(0xdeadbeef);
1448 ret
= ImmDestroyContext(imc
);
1449 ok(ret
== FALSE
, "Destroy a destroyed IMC should fail!\n");
1450 ret
= GetLastError();
1451 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1454 static void test_ImmDestroyIMCC(void)
1457 DWORD ret
, count
, size
;
1460 imcc
= ImmCreateIMCC(sizeof(CANDIDATEINFO
));
1461 count
= ImmGetIMCCLockCount(imcc
);
1462 ok(count
== 0, "expect 0, returned %d\n", count
);
1463 p
= ImmLockIMCC(imcc
);
1464 ok(p
!= NULL
, "ImmLockIMCC failed!\n");
1465 count
= ImmGetIMCCLockCount(imcc
);
1466 ok(count
== 1, "expect 1, returned %d\n", count
);
1467 size
= ImmGetIMCCSize(imcc
);
1468 ok(size
== sizeof(CANDIDATEINFO
), "returned %d\n", size
);
1469 p
= ImmDestroyIMCC(imcc
);
1470 ok(p
== NULL
, "Destroy a locked IMCC should success!\n");
1471 p
= ImmLockIMCC(imcc
);
1472 ok(p
== NULL
, "Lock a destroyed IMCC should fail!\n");
1473 ret
= ImmUnlockIMCC(imcc
);
1474 ok(ret
== FALSE
, "Unlock a destroyed IMCC should return FALSE!\n");
1475 count
= ImmGetIMCCLockCount(imcc
);
1476 ok(count
== 0, "Get lock count of a destroyed IMCC should return 0!\n");
1477 size
= ImmGetIMCCSize(imcc
);
1478 ok(size
== 0, "Get size of a destroyed IMCC should return 0!\n");
1479 SetLastError(0xdeadbeef);
1480 p
= ImmDestroyIMCC(imcc
);
1481 ok(p
!= NULL
, "returned NULL\n");
1482 ret
= GetLastError();
1483 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1486 static void test_ImmMessages(void)
1494 LPINPUTCONTEXT lpIMC
;
1495 LPTRANSMSG lpTransMsg
;
1497 HWND hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, "EDIT", "Wine imm32.dll test",
1498 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1499 240, 120, NULL
, NULL
, GetModuleHandleA(NULL
), NULL
);
1501 ShowWindow(hwnd
, SW_SHOWNORMAL
);
1502 defwnd
= ImmGetDefaultIMEWnd(hwnd
);
1503 imc
= ImmGetContext(hwnd
);
1505 ImmSetOpenStatus(imc
, TRUE
);
1506 msg_spy_flush_msgs();
1507 SendMessageA(defwnd
, WM_IME_CONTROL
, IMC_GETCANDIDATEPOS
, (LPARAM
)&cf
);
1510 msg
= msg_spy_find_next_msg(WM_IME_CONTROL
,&idx
);
1511 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1513 msg_spy_flush_msgs();
1515 lpIMC
= ImmLockIMC(imc
);
1516 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
1517 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
1518 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
1519 lpTransMsg
->message
= WM_IME_STARTCOMPOSITION
;
1520 lpTransMsg
->wParam
= 0;
1521 lpTransMsg
->lParam
= 0;
1522 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
1523 lpIMC
->dwNumMsgBuf
++;
1525 ImmGenerateMessage(imc
);
1529 msg
= msg_spy_find_next_msg(WM_IME_STARTCOMPOSITION
, &idx
);
1530 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1532 msg_spy_flush_msgs();
1534 lpIMC
= ImmLockIMC(imc
);
1535 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
1536 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
1537 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
1538 lpTransMsg
->message
= WM_IME_COMPOSITION
;
1539 lpTransMsg
->wParam
= 0;
1540 lpTransMsg
->lParam
= 0;
1541 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
1542 lpIMC
->dwNumMsgBuf
++;
1544 ImmGenerateMessage(imc
);
1548 msg
= msg_spy_find_next_msg(WM_IME_COMPOSITION
, &idx
);
1549 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1551 msg_spy_flush_msgs();
1553 lpIMC
= ImmLockIMC(imc
);
1554 lpIMC
->hMsgBuf
= ImmReSizeIMCC(lpIMC
->hMsgBuf
, (lpIMC
->dwNumMsgBuf
+ 1) * sizeof(TRANSMSG
));
1555 lpTransMsg
= ImmLockIMCC(lpIMC
->hMsgBuf
);
1556 lpTransMsg
+= lpIMC
->dwNumMsgBuf
;
1557 lpTransMsg
->message
= WM_IME_ENDCOMPOSITION
;
1558 lpTransMsg
->wParam
= 0;
1559 lpTransMsg
->lParam
= 0;
1560 ImmUnlockIMCC(lpIMC
->hMsgBuf
);
1561 lpIMC
->dwNumMsgBuf
++;
1563 ImmGenerateMessage(imc
);
1567 msg
= msg_spy_find_next_msg(WM_IME_ENDCOMPOSITION
, &idx
);
1568 if (msg
) ok(!msg
->post
, "Message should not be posted\n");
1570 msg_spy_flush_msgs();
1572 ImmSetOpenStatus(imc
, FALSE
);
1573 ImmReleaseContext(hwnd
, imc
);
1574 DestroyWindow(hwnd
);
1577 static LRESULT CALLBACK
processkey_wnd_proc( HWND hWnd
, UINT msg
, WPARAM wParam
,
1580 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1583 static void test_ime_processkey(void)
1585 WCHAR classNameW
[] = {'P','r','o','c','e','s','s', 'K','e','y','T','e','s','t','C','l','a','s','s',0};
1586 WCHAR windowNameW
[] = {'P','r','o','c','e','s','s', 'K','e','y',0};
1590 HANDLE hInstance
= GetModuleHandleW(NULL
);
1591 TEST_INPUT inputs
[2];
1596 wclass
.lpszClassName
= classNameW
;
1597 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1598 wclass
.lpfnWndProc
= processkey_wnd_proc
;
1599 wclass
.hInstance
= hInstance
;
1600 wclass
.hIcon
= LoadIconW(0, (LPCWSTR
)IDI_APPLICATION
);
1601 wclass
.hCursor
= LoadCursorW( NULL
, (LPCWSTR
)IDC_ARROW
);
1602 wclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1603 wclass
.lpszMenuName
= 0;
1604 wclass
.cbClsExtra
= 0;
1605 wclass
.cbWndExtra
= 0;
1606 if(!RegisterClassW(&wclass
)){
1607 win_skip("Failed to register window.\n");
1611 /* create the test window that will receive the keystrokes */
1612 hWndTest
= CreateWindowW(wclass
.lpszClassName
, windowNameW
,
1613 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0, 100, 100,
1614 NULL
, NULL
, hInstance
, NULL
);
1616 ShowWindow(hWndTest
, SW_SHOW
);
1617 SetWindowPos(hWndTest
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
1618 SetForegroundWindow(hWndTest
);
1619 UpdateWindow(hWndTest
);
1621 imc
= ImmGetContext(hWndTest
);
1624 win_skip("IME not supported\n");
1625 DestroyWindow(hWndTest
);
1629 rc
= ImmSetOpenStatus(imc
, TRUE
);
1632 win_skip("Unable to open IME\n");
1633 ImmReleaseContext(hWndTest
, imc
);
1634 DestroyWindow(hWndTest
);
1638 /* flush pending messages */
1639 while (PeekMessageW(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageW(&msg
);
1643 /* init input data that never changes */
1644 inputs
[1].type
= inputs
[0].type
= INPUT_KEYBOARD
;
1645 inputs
[1].u
.ki
.dwExtraInfo
= inputs
[0].u
.ki
.dwExtraInfo
= 0;
1646 inputs
[1].u
.ki
.time
= inputs
[0].u
.ki
.time
= 0;
1648 /* Pressing a key */
1649 inputs
[0].u
.ki
.wVk
= 0x41;
1650 inputs
[0].u
.ki
.wScan
= 0x1e;
1651 inputs
[0].u
.ki
.dwFlags
= 0x0;
1653 pSendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
1655 while(PeekMessageW(&msg
, hWndTest
, 0, 0, PM_NOREMOVE
)) {
1656 if(msg
.message
!= WM_KEYDOWN
)
1657 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1660 ok(msg
.wParam
!= VK_PROCESSKEY
,"Incorrect ProcessKey Found\n");
1661 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1662 if(msg
.wParam
== VK_PROCESSKEY
)
1663 trace("ProcessKey was correctly found\n");
1665 TranslateMessage(&msg
);
1666 DispatchMessageW(&msg
);
1669 inputs
[0].u
.ki
.wVk
= 0x41;
1670 inputs
[0].u
.ki
.wScan
= 0x1e;
1671 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_KEYUP
;
1673 pSendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
1675 while(PeekMessageW(&msg
, hWndTest
, 0, 0, PM_NOREMOVE
)) {
1676 if(msg
.message
!= WM_KEYUP
)
1677 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1680 ok(msg
.wParam
!= VK_PROCESSKEY
,"Incorrect ProcessKey Found\n");
1681 PeekMessageW(&msg
, hWndTest
, 0, 0, PM_REMOVE
);
1682 ok(msg
.wParam
!= VK_PROCESSKEY
,"ProcessKey should still not be Found\n");
1684 TranslateMessage(&msg
);
1685 DispatchMessageW(&msg
);
1688 ImmReleaseContext(hWndTest
, imc
);
1689 ImmSetOpenStatus(imc
, FALSE
);
1690 DestroyWindow(hWndTest
);
1693 static void test_InvalidIMC(void)
1696 HIMC imc_null
= 0x00000000;
1697 HIMC imc_bad
= (HIMC
)0xdeadcafe;
1699 HIMC imc1
, imc2
, oldimc
;
1706 memset(&lf
, 0, sizeof(lf
));
1708 imc_destroy
= ImmCreateContext();
1709 ret
= ImmDestroyContext(imc_destroy
);
1710 ok(ret
== TRUE
, "Destroy an IMC should success!\n");
1712 /* Test associating destroyed imc */
1713 imc1
= ImmGetContext(hwnd
);
1714 SetLastError(0xdeadbeef);
1715 oldimc
= ImmAssociateContext(hwnd
, imc_destroy
);
1716 ok(!oldimc
, "Associating to a destroyed imc should fail!\n");
1717 ret
= GetLastError();
1718 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1719 imc2
= ImmGetContext(hwnd
);
1720 ok(imc1
== imc2
, "imc should not changed! imc1 %p, imc2 %p\n", imc1
, imc2
);
1722 /* Test associating NULL imc, which is different from an invalid imc */
1723 oldimc
= ImmAssociateContext(hwnd
, imc_null
);
1724 ok(oldimc
!= NULL
, "Associating to NULL imc should success!\n");
1725 imc2
= ImmGetContext(hwnd
);
1726 ok(!imc2
, "expect NULL, returned %p\n", imc2
);
1727 oldimc
= ImmAssociateContext(hwnd
, imc1
);
1728 ok(!oldimc
, "expect NULL, returned %p\n", oldimc
);
1729 imc2
= ImmGetContext(hwnd
);
1730 ok(imc2
== imc1
, "imc should not changed! imc2 %p, imc1 %p\n", imc2
, imc1
);
1732 /* Test associating invalid imc */
1733 imc1
= ImmGetContext(hwnd
);
1734 SetLastError(0xdeadbeef);
1735 oldimc
= ImmAssociateContext(hwnd
, imc_bad
);
1736 ok(!oldimc
, "Associating to a destroyed imc should fail!\n");
1737 ret
= GetLastError();
1738 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1739 imc2
= ImmGetContext(hwnd
);
1740 ok(imc1
== imc2
, "imc should not changed! imc1 %p, imc2 %p\n", imc1
, imc2
);
1743 /* Test ImmGetCandidateListA */
1744 SetLastError(0xdeadbeef);
1745 ret
= ImmGetCandidateListA(imc_bad
, 0, NULL
, 0);
1746 ok(ret
== 0, "Bad IME should return 0\n");
1747 ret
= GetLastError();
1748 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1749 SetLastError(0xdeadbeef);
1750 ret
= ImmGetCandidateListA(imc_null
, 0, NULL
, 0);
1751 ok(ret
== 0, "NULL IME should return 0\n");
1752 ret
= GetLastError();
1753 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1754 SetLastError(0xdeadbeef);
1755 ret
= ImmGetCandidateListA(imc_destroy
, 0, NULL
, 0);
1756 ok(ret
== 0, "Destroyed IME should return 0\n");
1757 ret
= GetLastError();
1758 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1760 /* Test ImmGetCandidateListCountA*/
1761 SetLastError(0xdeadbeef);
1762 ret
= ImmGetCandidateListCountA(imc_bad
,&count
);
1763 ok(ret
== 0, "Bad IME should return 0\n");
1764 ret
= GetLastError();
1765 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1766 SetLastError(0xdeadbeef);
1767 ret
= ImmGetCandidateListCountA(imc_null
,&count
);
1768 ok(ret
== 0, "NULL IME should return 0\n");
1769 ret
= GetLastError();
1770 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1771 SetLastError(0xdeadbeef);
1772 ret
= ImmGetCandidateListCountA(imc_destroy
,&count
);
1773 ok(ret
== 0, "Destroyed IME should return 0\n");
1774 ret
= GetLastError();
1775 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1777 /* Test ImmGetCandidateWindow */
1778 SetLastError(0xdeadbeef);
1779 ret
= ImmGetCandidateWindow(imc_bad
, 0, (LPCANDIDATEFORM
)buffer
);
1780 ok(ret
== 0, "Bad IME should return 0\n");
1781 ret
= GetLastError();
1782 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1783 SetLastError(0xdeadbeef);
1784 ret
= ImmGetCandidateWindow(imc_null
, 0, (LPCANDIDATEFORM
)buffer
);
1785 ok(ret
== 0, "NULL IME should return 0\n");
1786 ret
= GetLastError();
1787 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1788 SetLastError(0xdeadbeef);
1789 ret
= ImmGetCandidateWindow(imc_destroy
, 0, (LPCANDIDATEFORM
)buffer
);
1790 ok(ret
== 0, "Destroyed IME should return 0\n");
1791 ret
= GetLastError();
1792 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1794 /* Test ImmGetCompositionFontA */
1795 SetLastError(0xdeadbeef);
1796 ret
= ImmGetCompositionFontA(imc_bad
, (LPLOGFONTA
)buffer
);
1797 ok(ret
== 0, "Bad IME should return 0\n");
1798 ret
= GetLastError();
1799 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1800 SetLastError(0xdeadbeef);
1801 ret
= ImmGetCompositionFontA(imc_null
, (LPLOGFONTA
)buffer
);
1802 ok(ret
== 0, "NULL IME should return 0\n");
1803 ret
= GetLastError();
1804 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1805 SetLastError(0xdeadbeef);
1806 ret
= ImmGetCompositionFontA(imc_destroy
, (LPLOGFONTA
)buffer
);
1807 ok(ret
== 0, "Destroyed IME should return 0\n");
1808 ret
= GetLastError();
1809 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1811 /* Test ImmGetCompositionWindow */
1812 SetLastError(0xdeadbeef);
1813 ret
= ImmGetCompositionWindow(imc_bad
, (LPCOMPOSITIONFORM
)buffer
);
1814 ok(ret
== 0, "Bad IME should return 0\n");
1815 ret
= GetLastError();
1816 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1817 SetLastError(0xdeadbeef);
1818 ret
= ImmGetCompositionWindow(imc_null
, (LPCOMPOSITIONFORM
)buffer
);
1819 ok(ret
== 0, "NULL IME should return 0\n");
1820 ret
= GetLastError();
1821 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1822 SetLastError(0xdeadbeef);
1823 ret
= ImmGetCompositionWindow(imc_destroy
, (LPCOMPOSITIONFORM
)buffer
);
1824 ok(ret
== 0, "Destroyed IME should return 0\n");
1825 ret
= GetLastError();
1826 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1828 /* Test ImmGetCompositionStringA */
1829 SetLastError(0xdeadbeef);
1830 ret
= ImmGetCompositionStringA(imc_bad
, GCS_COMPSTR
, NULL
, 0);
1831 ok(ret
== 0, "Bad IME should return 0\n");
1832 ret
= GetLastError();
1833 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1834 SetLastError(0xdeadbeef);
1835 ret
= ImmGetCompositionStringA(imc_null
, GCS_COMPSTR
, NULL
, 0);
1836 ok(ret
== 0, "NULL IME should return 0\n");
1837 ret
= GetLastError();
1838 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1839 SetLastError(0xdeadbeef);
1840 ret
= ImmGetCompositionStringA(imc_destroy
, GCS_COMPSTR
, NULL
, 0);
1841 ok(ret
== 0, "Destroyed IME should return 0\n");
1842 ret
= GetLastError();
1843 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1845 /* Test ImmSetOpenStatus */
1846 SetLastError(0xdeadbeef);
1847 ret
= ImmSetOpenStatus(imc_bad
, 1);
1848 ok(ret
== 0, "Bad IME should return 0\n");
1849 ret
= GetLastError();
1850 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1851 SetLastError(0xdeadbeef);
1852 ret
= ImmSetOpenStatus(imc_null
, 1);
1853 ok(ret
== 0, "NULL IME should return 0\n");
1854 ret
= GetLastError();
1855 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1856 SetLastError(0xdeadbeef);
1857 ret
= ImmSetOpenStatus(imc_destroy
, 1);
1858 ok(ret
== 0, "Destroyed IME should return 0\n");
1859 ret
= GetLastError();
1860 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1862 /* Test ImmGetOpenStatus */
1863 SetLastError(0xdeadbeef);
1864 ret
= ImmGetOpenStatus(imc_bad
);
1865 ok(ret
== 0, "Bad IME should return 0\n");
1866 ret
= GetLastError();
1867 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1868 SetLastError(0xdeadbeef);
1869 ret
= ImmGetOpenStatus(imc_null
);
1870 ok(ret
== 0, "NULL IME should return 0\n");
1871 ret
= GetLastError();
1872 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1873 SetLastError(0xdeadbeef);
1874 ret
= ImmGetOpenStatus(imc_destroy
);
1875 ok(ret
== 0, "Destroyed IME should return 0\n");
1876 ret
= GetLastError();
1877 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1879 /* Test ImmGetStatusWindowPos */
1880 SetLastError(0xdeadbeef);
1881 ret
= ImmGetStatusWindowPos(imc_bad
, NULL
);
1882 ok(ret
== 0, "Bad IME should return 0\n");
1883 ret
= GetLastError();
1884 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1885 SetLastError(0xdeadbeef);
1886 ret
= ImmGetStatusWindowPos(imc_null
, NULL
);
1887 ok(ret
== 0, "NULL IME should return 0\n");
1888 ret
= GetLastError();
1889 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
1890 SetLastError(0xdeadbeef);
1891 ret
= ImmGetStatusWindowPos(imc_destroy
, NULL
);
1892 ok(ret
== 0, "Destroyed IME should return 0\n");
1893 ret
= GetLastError();
1894 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1896 /* Test ImmRequestMessageA */
1897 SetLastError(0xdeadbeef);
1898 ret
= ImmRequestMessageA(imc_bad
, WM_CHAR
, 0);
1899 ok(ret
== 0, "Bad IME should return 0\n");
1900 ret
= GetLastError();
1901 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1902 SetLastError(0xdeadbeef);
1903 ret
= ImmRequestMessageA(imc_null
, WM_CHAR
, 0);
1904 ok(ret
== 0, "NULL IME should return 0\n");
1905 ret
= GetLastError();
1906 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1907 SetLastError(0xdeadbeef);
1908 ret
= ImmRequestMessageA(imc_destroy
, WM_CHAR
, 0);
1909 ok(ret
== 0, "Destroyed IME should return 0\n");
1910 ret
= GetLastError();
1911 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1913 /* Test ImmSetCompositionFontA */
1914 SetLastError(0xdeadbeef);
1915 ret
= ImmSetCompositionFontA(imc_bad
, &lf
);
1916 ok(ret
== 0, "Bad IME should return 0\n");
1917 ret
= GetLastError();
1918 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1919 SetLastError(0xdeadbeef);
1920 ret
= ImmSetCompositionFontA(imc_null
, &lf
);
1921 ok(ret
== 0, "NULL IME should return 0\n");
1922 ret
= GetLastError();
1923 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1924 SetLastError(0xdeadbeef);
1925 ret
= ImmSetCompositionFontA(imc_destroy
, &lf
);
1926 ok(ret
== 0, "Destroyed IME should return 0\n");
1927 ret
= GetLastError();
1928 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1930 /* Test ImmSetCompositionWindow */
1931 SetLastError(0xdeadbeef);
1932 ret
= ImmSetCompositionWindow(imc_bad
, NULL
);
1933 ok(ret
== 0, "Bad IME should return 0\n");
1934 ret
= GetLastError();
1935 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1936 SetLastError(0xdeadbeef);
1937 ret
= ImmSetCompositionWindow(imc_null
, NULL
);
1938 ok(ret
== 0, "NULL IME should return 0\n");
1939 ret
= GetLastError();
1940 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1941 SetLastError(0xdeadbeef);
1942 ret
= ImmSetCompositionWindow(imc_destroy
, NULL
);
1943 ok(ret
== 0, "Destroyed IME should return 0\n");
1944 ret
= GetLastError();
1945 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1947 /* Test ImmSetConversionStatus */
1948 SetLastError(0xdeadbeef);
1949 ret
= ImmSetConversionStatus(imc_bad
, 0, 0);
1950 ok(ret
== 0, "Bad IME should return 0\n");
1951 ret
= GetLastError();
1952 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1953 SetLastError(0xdeadbeef);
1954 ret
= ImmSetConversionStatus(imc_null
, 0, 0);
1955 ok(ret
== 0, "NULL IME should return 0\n");
1956 ret
= GetLastError();
1957 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1958 SetLastError(0xdeadbeef);
1959 ret
= ImmSetConversionStatus(imc_destroy
, 0, 0);
1960 ok(ret
== 0, "Destroyed IME should return 0\n");
1961 ret
= GetLastError();
1962 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1964 /* Test ImmSetStatusWindowPos */
1965 SetLastError(0xdeadbeef);
1966 ret
= ImmSetStatusWindowPos(imc_bad
, 0);
1967 ok(ret
== 0, "Bad IME should return 0\n");
1968 ret
= GetLastError();
1969 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1970 SetLastError(0xdeadbeef);
1971 ret
= ImmSetStatusWindowPos(imc_null
, 0);
1972 ok(ret
== 0, "NULL IME should return 0\n");
1973 ret
= GetLastError();
1974 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1975 SetLastError(0xdeadbeef);
1976 ret
= ImmSetStatusWindowPos(imc_destroy
, 0);
1977 ok(ret
== 0, "Destroyed IME should return 0\n");
1978 ret
= GetLastError();
1979 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1981 /* Test ImmGetImeMenuItemsA */
1982 SetLastError(0xdeadbeef);
1983 ret
= ImmGetImeMenuItemsA(imc_bad
, 0, 0, NULL
, NULL
, 0);
1984 ok(ret
== 0, "Bad IME should return 0\n");
1985 ret
= GetLastError();
1986 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1987 SetLastError(0xdeadbeef);
1988 ret
= ImmGetImeMenuItemsA(imc_null
, 0, 0, NULL
, NULL
, 0);
1989 ok(ret
== 0, "NULL IME should return 0\n");
1990 ret
= GetLastError();
1991 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1992 SetLastError(0xdeadbeef);
1993 ret
= ImmGetImeMenuItemsA(imc_destroy
, 0, 0, NULL
, NULL
, 0);
1994 ok(ret
== 0, "Destroyed IME should return 0\n");
1995 ret
= GetLastError();
1996 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
1998 /* Test ImmLockIMC */
1999 SetLastError(0xdeadbeef);
2000 ic
= ImmLockIMC(imc_bad
);
2001 ok(ic
== 0, "Bad IME should return 0\n");
2002 ret
= GetLastError();
2003 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
2004 SetLastError(0xdeadbeef);
2005 ic
= ImmLockIMC(imc_null
);
2006 ok(ic
== 0, "NULL IME should return 0\n");
2007 ret
= GetLastError();
2008 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
2009 SetLastError(0xdeadbeef);
2010 ic
= ImmLockIMC(imc_destroy
);
2011 ok(ic
== 0, "Destroyed IME should return 0\n");
2012 ret
= GetLastError();
2013 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
2015 /* Test ImmUnlockIMC */
2016 SetLastError(0xdeadbeef);
2017 ret
= ImmUnlockIMC(imc_bad
);
2018 ok(ret
== 0, "Bad IME should return 0\n");
2019 ret
= GetLastError();
2020 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
2021 SetLastError(0xdeadbeef);
2022 ret
= ImmUnlockIMC(imc_null
);
2023 ok(ret
== 0, "NULL IME should return 0\n");
2024 ret
= GetLastError();
2025 ok(ret
== 0xdeadbeef, "last error should remain unchanged %08x!\n", ret
);
2026 SetLastError(0xdeadbeef);
2027 ret
= ImmUnlockIMC(imc_destroy
);
2028 ok(ret
== 0, "Destroyed IME should return 0\n");
2029 ret
= GetLastError();
2030 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
2032 /* Test ImmGenerateMessage */
2033 SetLastError(0xdeadbeef);
2034 ret
= ImmGenerateMessage(imc_bad
);
2035 ok(ret
== 0, "Bad IME should return 0\n");
2036 ret
= GetLastError();
2037 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
2038 SetLastError(0xdeadbeef);
2039 ret
= ImmGenerateMessage(imc_null
);
2040 ok(ret
== 0, "NULL IME should return 0\n");
2041 ret
= GetLastError();
2042 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
2043 SetLastError(0xdeadbeef);
2044 ret
= ImmGenerateMessage(imc_destroy
);
2045 ok(ret
== 0, "Destroyed IME should return 0\n");
2046 ret
= GetLastError();
2047 ok(ret
== ERROR_INVALID_HANDLE
, "wrong last error %08x!\n", ret
);
2053 test_ImmNotifyIME();
2054 test_ImmGetCompositionString();
2055 test_ImmSetCompositionString();
2057 test_ImmAssociateContextEx();
2059 test_ImmIsUIMessage();
2060 test_ImmGetContext();
2061 test_ImmGetDescription();
2062 test_ImmDefaultHwnd();
2063 test_default_ime_window_creation();
2064 test_ImmGetIMCLockCount();
2065 test_ImmGetIMCCLockCount();
2066 test_ImmDestroyContext();
2067 test_ImmDestroyIMCC();
2070 /* Reinitialize the hooks to capture all windows */
2075 test_ime_processkey();
2076 else win_skip("SendInput is not available\n");