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 #define NUMELEMS(array) (sizeof((array))/sizeof((array)[0]))
30 static BOOL (WINAPI *pImmAssociateContextEx)(HWND,HIMC,DWORD);
31 static BOOL (WINAPI *pImmIsUIMessageA)(HWND,UINT,WPARAM,LPARAM);
32 static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t);
35 * msgspy - record and analyse message traces sent to a certain window
37 typedef struct _msgs {
42 static struct _msg_spy {
45 HHOOK call_wnd_proc_hook;
61 static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t);
63 static LRESULT CALLBACK get_msg_filter(int nCode, WPARAM wParam, LPARAM lParam)
65 if (HC_ACTION == nCode) {
66 MSG *msg = (MSG*)lParam;
68 if ((msg->hwnd == msg_spy.hwnd || msg_spy.hwnd == NULL) &&
69 (msg_spy.i_msg < NUMELEMS(msg_spy.msgs)))
71 msg_spy.msgs[msg_spy.i_msg].msg.hwnd = msg->hwnd;
72 msg_spy.msgs[msg_spy.i_msg].msg.message = msg->message;
73 msg_spy.msgs[msg_spy.i_msg].msg.wParam = msg->wParam;
74 msg_spy.msgs[msg_spy.i_msg].msg.lParam = msg->lParam;
75 msg_spy.msgs[msg_spy.i_msg].post = TRUE;
80 return CallNextHookEx(msg_spy.get_msg_hook, nCode, wParam, lParam);
83 static LRESULT CALLBACK call_wnd_proc_filter(int nCode, WPARAM wParam,
86 if (HC_ACTION == nCode) {
87 CWPSTRUCT *cwp = (CWPSTRUCT*)lParam;
89 if (((cwp->hwnd == msg_spy.hwnd || msg_spy.hwnd == NULL)) &&
90 (msg_spy.i_msg < NUMELEMS(msg_spy.msgs)))
92 memcpy(&msg_spy.msgs[msg_spy.i_msg].msg, cwp, sizeof(msg_spy.msgs[0].msg));
93 msg_spy.msgs[msg_spy.i_msg].post = FALSE;
98 return CallNextHookEx(msg_spy.call_wnd_proc_hook, nCode, wParam, lParam);
101 static void msg_spy_pump_msg_queue(void) {
104 while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
105 TranslateMessage(&msg);
106 DispatchMessage(&msg);
112 static void msg_spy_flush_msgs(void) {
113 msg_spy_pump_msg_queue();
117 static imm_msgs* msg_spy_find_next_msg(UINT message, UINT *start) {
120 msg_spy_pump_msg_queue();
122 if (msg_spy.i_msg >= NUMELEMS(msg_spy.msgs))
123 fprintf(stdout, "%s:%d: msg_spy: message buffer overflow!\n",
126 for (i = *start; i < msg_spy.i_msg; i++)
127 if (msg_spy.msgs[i].msg.message == message)
130 return &msg_spy.msgs[i];
136 static imm_msgs* msg_spy_find_msg(UINT message) {
139 return msg_spy_find_next_msg(message, &i);
142 static void msg_spy_init(HWND hwnd) {
144 msg_spy.get_msg_hook =
145 SetWindowsHookEx(WH_GETMESSAGE, get_msg_filter, GetModuleHandle(0),
146 GetCurrentThreadId());
147 msg_spy.call_wnd_proc_hook =
148 SetWindowsHookEx(WH_CALLWNDPROC, call_wnd_proc_filter,
149 GetModuleHandle(0), GetCurrentThreadId());
152 msg_spy_flush_msgs();
155 static void msg_spy_cleanup(void) {
156 if (msg_spy.get_msg_hook)
157 UnhookWindowsHookEx(msg_spy.get_msg_hook);
158 if (msg_spy.call_wnd_proc_hook)
159 UnhookWindowsHookEx(msg_spy.call_wnd_proc_hook);
160 memset(&msg_spy, 0, sizeof(msg_spy));
164 * imm32 test cases - Issue some IMM commands on a dummy window and analyse the
165 * messages being sent to this window in response.
167 static const char wndcls[] = "winetest_imm32_wndcls";
170 static LRESULT WINAPI wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
174 case WM_IME_SETCONTEXT:
180 return DefWindowProcA(hwnd,msg,wParam,lParam);
183 static BOOL init(void) {
188 hmod = GetModuleHandleA("imm32.dll");
189 huser = GetModuleHandleA("user32");
190 pImmAssociateContextEx = (void*)GetProcAddress(hmod, "ImmAssociateContextEx");
191 pImmIsUIMessageA = (void*)GetProcAddress(hmod, "ImmIsUIMessageA");
192 pSendInput = (void*)GetProcAddress(huser, "SendInput");
194 wc.cbSize = sizeof(WNDCLASSEX);
196 wc.lpfnWndProc = wndProc;
199 wc.hInstance = GetModuleHandle(0);
200 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
201 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
202 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
203 wc.lpszMenuName = NULL;
204 wc.lpszClassName = wndcls;
205 wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
207 if (!RegisterClassExA(&wc))
210 hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
211 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
212 240, 120, NULL, NULL, GetModuleHandle(0), NULL);
216 imc = ImmGetContext(hwnd);
219 win_skip("IME support not implemented\n");
222 ImmReleaseContext(hwnd, imc);
224 ShowWindow(hwnd, SW_SHOWNORMAL);
232 static void cleanup(void) {
236 UnregisterClass(wndcls, GetModuleHandle(0));
239 static void test_ImmNotifyIME(void) {
240 static const char string[] = "wine";
241 char resstr[16] = "";
245 imc = ImmGetContext(hwnd);
246 msg_spy_flush_msgs();
248 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
251 "Canceling an empty composition string should succeed.\n");
252 ok(!msg_spy_find_msg(WM_IME_COMPOSITION), "Windows does not post "
253 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
254 "the composition string being canceled is empty.\n");
256 ImmSetCompositionString(imc, SCS_SETSTR, string, sizeof(string), NULL, 0);
257 msg_spy_flush_msgs();
259 ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
260 msg_spy_flush_msgs();
262 /* behavior differs between win9x and NT */
263 ret = ImmGetCompositionString(imc, GCS_COMPSTR, resstr, sizeof(resstr));
264 ok(!ret, "After being cancelled the composition string is empty.\n");
266 msg_spy_flush_msgs();
268 ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
271 "Canceling an empty composition string should succeed.\n");
272 ok(!msg_spy_find_msg(WM_IME_COMPOSITION), "Windows does not post "
273 "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if "
274 "the composition string being canceled is empty.\n");
276 msg_spy_flush_msgs();
277 ImmReleaseContext(hwnd, imc);
280 static void test_ImmGetCompositionString(void)
283 static const WCHAR string[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e};
289 imc = ImmGetContext(hwnd);
290 ImmSetCompositionStringW(imc, SCS_SETSTR, string, sizeof(string), NULL,0);
291 alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20);
292 wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 20);
293 /* windows machines without any IME installed just return 0 above */
296 len = ImmGetCompositionStringW(imc, GCS_COMPATTR, NULL, 0);
297 ok(len*sizeof(WCHAR)==wlen,"GCS_COMPATTR(W) not returning correct count\n");
298 len = ImmGetCompositionStringA(imc, GCS_COMPATTR, NULL, 0);
299 ok(len==alen,"GCS_COMPATTR(A) not returning correct count\n");
301 ImmReleaseContext(hwnd, imc);
304 static void test_ImmSetCompositionString(void)
309 SetLastError(0xdeadbeef);
310 imc = ImmGetContext(hwnd);
311 ok(imc != 0, "ImmGetContext() failed. Last error: %u\n", GetLastError());
315 ret = ImmSetCompositionStringW(imc, SCS_SETSTR, NULL, 0, NULL, 0);
318 "ImmSetCompositionStringW() failed.\n");
320 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR,
322 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
324 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGECLAUSE,
326 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
328 ret = ImmSetCompositionStringW(imc, SCS_CHANGEATTR | SCS_CHANGECLAUSE,
330 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
332 ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR | SCS_CHANGECLAUSE,
334 ok(!ret, "ImmSetCompositionStringW() succeeded.\n");
336 ImmReleaseContext(hwnd, imc);
339 static void test_ImmIME(void)
343 imc = ImmGetContext(hwnd);
347 rc = ImmConfigureIMEA(imc, NULL, IME_CONFIG_REGISTERWORD, NULL);
348 ok (rc == 0, "ImmConfigureIMEA did not fail\n");
349 rc = ImmConfigureIMEW(imc, NULL, IME_CONFIG_REGISTERWORD, NULL);
350 ok (rc == 0, "ImmConfigureIMEW did not fail\n");
352 ImmReleaseContext(hwnd,imc);
355 static void test_ImmAssociateContextEx(void)
360 if (!pImmAssociateContextEx) return;
362 imc = ImmGetContext(hwnd);
367 newimc = ImmCreateContext();
368 ok(newimc != imc, "handles should not be the same\n");
369 rc = pImmAssociateContextEx(NULL, NULL, 0);
370 ok(!rc, "ImmAssociateContextEx succeeded\n");
371 rc = pImmAssociateContextEx(hwnd, NULL, 0);
372 ok(rc, "ImmAssociateContextEx failed\n");
373 rc = pImmAssociateContextEx(NULL, imc, 0);
374 ok(!rc, "ImmAssociateContextEx succeeded\n");
376 rc = pImmAssociateContextEx(hwnd, imc, 0);
377 ok(rc, "ImmAssociateContextEx failed\n");
378 retimc = ImmGetContext(hwnd);
379 ok(retimc == imc, "handles should be the same\n");
380 ImmReleaseContext(hwnd,retimc);
382 rc = pImmAssociateContextEx(hwnd, newimc, 0);
383 ok(rc, "ImmAssociateContextEx failed\n");
384 retimc = ImmGetContext(hwnd);
385 ok(retimc == newimc, "handles should be the same\n");
386 ImmReleaseContext(hwnd,retimc);
388 rc = pImmAssociateContextEx(hwnd, NULL, IACE_DEFAULT);
389 ok(rc, "ImmAssociateContextEx failed\n");
391 ImmReleaseContext(hwnd,imc);
394 typedef struct _igc_threadinfo {
401 static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam)
407 igc_threadinfo *info= (igc_threadinfo*)lpParam;
408 info->hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
409 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
410 240, 120, NULL, NULL, GetModuleHandle(0), NULL);
412 h1 = ImmGetContext(hwnd);
413 todo_wine ok(info->himc == h1, "hwnd context changed in new thread\n");
414 h2 = ImmGetContext(info->hwnd);
415 todo_wine ok(h2 != h1, "new hwnd in new thread should have different context\n");
417 ImmReleaseContext(hwnd,h1);
419 hwnd2 = CreateWindowEx(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
420 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
421 240, 120, NULL, NULL, GetModuleHandle(0), NULL);
422 h1 = ImmGetContext(hwnd2);
424 ok(h1 == h2, "Windows in same thread should have same default context\n");
425 ImmReleaseContext(hwnd2,h1);
426 ImmReleaseContext(info->hwnd,h2);
427 DestroyWindow(hwnd2);
429 /* priming for later tests */
430 ImmSetCompositionWindow(h1, &cf);
431 ImmSetStatusWindowPos(h1, &pt);
433 SetEvent(info->event);
438 static void test_ImmThreads(void)
440 HIMC himc, otherHimc, h1;
441 igc_threadinfo threadinfo;
447 DWORD status, sentence;
450 himc = ImmGetContext(hwnd);
451 threadinfo.event = CreateEvent(NULL, TRUE, FALSE, NULL);
452 threadinfo.himc = himc;
453 hThread = CreateThread(NULL, 0, ImmGetContextThreadFunc, &threadinfo, 0, &dwThreadId );
454 WaitForSingleObject(threadinfo.event, INFINITE);
456 otherHimc = ImmGetContext(threadinfo.hwnd);
458 todo_wine ok(himc != otherHimc, "Windows from other threads should have different himc\n");
459 todo_wine ok(otherHimc == threadinfo.himc, "Context from other thread should not change in main thread\n");
461 if (0) /* FIXME: Causes wine to hang */
463 h1 = ImmAssociateContext(hwnd,otherHimc);
464 ok(h1 == NULL, "Should fail to be able to Associate a default context from a different thread\n");
465 h1 = ImmGetContext(hwnd);
466 ok(h1 == himc, "Context for window should remain unchanged\n");
467 ImmReleaseContext(hwnd,h1);
472 rc = ImmSetOpenStatus(himc, TRUE);
473 ok(rc != 0, "ImmSetOpenStatus failed\n");
474 rc = ImmGetOpenStatus(himc);
475 ok(rc != 0, "ImmGetOpenStatus failed\n");
476 rc = ImmSetOpenStatus(himc, FALSE);
477 ok(rc != 0, "ImmSetOpenStatus failed\n");
478 rc = ImmGetOpenStatus(himc);
479 ok(rc == 0, "ImmGetOpenStatus failed\n");
481 rc = ImmSetOpenStatus(otherHimc, TRUE);
482 todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
483 rc = ImmGetOpenStatus(otherHimc);
484 todo_wine ok(rc == 0, "ImmGetOpenStatus failed\n");
485 rc = ImmSetOpenStatus(otherHimc, FALSE);
486 todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
487 rc = ImmGetOpenStatus(otherHimc);
488 ok(rc == 0, "ImmGetOpenStatus failed\n");
490 /* CompositionFont */
491 rc = ImmGetCompositionFont(himc, &lf);
492 ok(rc != 0, "ImmGetCompositionFont failed\n");
493 rc = ImmSetCompositionFont(himc, &lf);
494 ok(rc != 0, "ImmSetCompositionFont failed\n");
496 rc = ImmGetCompositionFont(otherHimc, &lf);
497 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont failed\n");
498 rc = ImmSetCompositionFont(otherHimc, &lf);
499 todo_wine ok(rc == 0, "ImmSetCompositionFont should fail\n");
501 /* CompositionWindow */
502 rc = ImmSetCompositionWindow(himc, &cf);
503 ok(rc != 0, "ImmSetCompositionWindow failed\n");
504 rc = ImmGetCompositionWindow(himc, &cf);
505 ok(rc != 0, "ImmGetCompositionWindow failed\n");
507 rc = ImmSetCompositionWindow(otherHimc, &cf);
508 todo_wine ok(rc == 0, "ImmSetCompositionWindow should fail\n");
509 rc = ImmGetCompositionWindow(otherHimc, &cf);
510 ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n");
512 /* ConversionStatus */
513 rc = ImmGetConversionStatus(himc, &status, &sentence);
514 ok(rc != 0, "ImmGetConversionStatus failed\n");
515 rc = ImmSetConversionStatus(himc, status, sentence);
516 ok(rc != 0, "ImmSetConversionStatus failed\n");
518 rc = ImmGetConversionStatus(otherHimc, &status, &sentence);
519 ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n");
520 rc = ImmSetConversionStatus(otherHimc, status, sentence);
521 todo_wine ok(rc == 0, "ImmSetConversionStatus should fail\n");
523 /* StatusWindowPos */
524 rc = ImmSetStatusWindowPos(himc, &pt);
525 ok(rc != 0, "ImmSetStatusWindowPos failed\n");
526 rc = ImmGetStatusWindowPos(himc, &pt);
527 ok(rc != 0, "ImmGetStatusWindowPos failed\n");
529 rc = ImmSetStatusWindowPos(otherHimc, &pt);
530 todo_wine ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
531 rc = ImmGetStatusWindowPos(otherHimc, &pt);
532 ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n");
534 ImmReleaseContext(threadinfo.hwnd,otherHimc);
535 ImmReleaseContext(hwnd,himc);
537 DestroyWindow(threadinfo.hwnd);
538 TerminateThread(hThread, 1);
540 himc = ImmGetContext(GetDesktopWindow());
541 todo_wine ok(himc == NULL, "Should not be able to get himc from other process window\n");
544 static void test_ImmIsUIMessage(void)
552 static const struct test tests[] =
554 { WM_MOUSEMOVE, FALSE },
555 { WM_IME_STARTCOMPOSITION, TRUE },
556 { WM_IME_ENDCOMPOSITION, TRUE },
557 { WM_IME_COMPOSITION, TRUE },
558 { WM_IME_SETCONTEXT, TRUE },
559 { WM_IME_NOTIFY, TRUE },
560 { WM_IME_CONTROL, FALSE },
561 { WM_IME_COMPOSITIONFULL, TRUE },
562 { WM_IME_SELECT, TRUE },
563 { WM_IME_CHAR, FALSE },
564 { 0x287 /* FIXME */, TRUE },
565 { WM_IME_REQUEST, FALSE },
566 { WM_IME_KEYDOWN, FALSE },
567 { WM_IME_KEYUP, FALSE },
568 { 0, FALSE } /* mark the end */
571 const struct test *test;
574 if (!pImmIsUIMessageA) return;
576 for (test = tests; test->msg; test++)
578 msg_spy_flush_msgs();
579 ret = pImmIsUIMessageA(NULL, test->msg, 0, 0);
580 ok(ret == test->ret, "ImmIsUIMessageA returned %x for %x\n", ret, test->msg);
581 ok(!msg_spy_find_msg(test->msg), "Windows does not send 0x%x for NULL hwnd\n", test->msg);
583 ret = pImmIsUIMessageA(hwnd, test->msg, 0, 0);
584 ok(ret == test->ret, "ImmIsUIMessageA returned %x for %x\n", ret, test->msg);
586 ok(msg_spy_find_msg(test->msg) != NULL, "Windows does send 0x%x\n", test->msg);
588 ok(!msg_spy_find_msg(test->msg), "Windows does not send 0x%x\n", test->msg);
592 static void test_ImmGetContext(void)
597 SetLastError(0xdeadbeef);
598 himc = ImmGetContext((HWND)0xffffffff);
599 err = GetLastError();
600 ok(himc == NULL, "ImmGetContext succeeded\n");
601 ok(err == ERROR_INVALID_WINDOW_HANDLE, "got %u\n", err);
603 himc = ImmGetContext(hwnd);
604 ok(himc != NULL, "ImmGetContext failed\n");
605 ok(ImmReleaseContext(hwnd, himc), "ImmReleaseContext failed\n");
608 static void test_ImmGetDescription(void)
611 WCHAR japime[] = { 'E', '0', '0', '1', '0', '4', '1', '1', 0 };
616 /* FIXME: invalid keyboard layouts should not pass */
617 ret = ImmGetDescriptionW(NULL, NULL, 0);
618 todo_wine ok(!ret, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret);
620 /* load a language with valid IMM descriptions */
621 hkl = LoadKeyboardLayoutW(japime, KLF_ACTIVATE);
622 todo_wine ok(hkl != 0, "LoadKeyboardLayoutW failed, expected != 0.\n");
624 ret = ImmGetDescriptionW(hkl, NULL, 0);
627 win_skip("ImmGetDescriptionW is not working for current loaded keyboard.\n");
631 ret = ImmGetDescriptionW(hkl, descW, 0);
632 ok(ret, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
634 lret = ImmGetDescriptionW(hkl, descW, ret + 1);
635 ok(lret, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
636 ok(lret == ret, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret);
638 lret = ImmGetDescriptionA(hkl, descA, ret + 1);
639 ok(lret, "ImmGetDescriptionA failed, expected != 0 received 0.\n");
640 todo_wine ok(lret == ret, "ImmGetDescriptionA failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret);
642 ret /= 2; /* try to copy partially */
643 lret = ImmGetDescriptionW(hkl, descW, ret + 1);
644 ok(lret, "ImmGetDescriptionW failed, expected != 0 received 0.\n");
645 ok(lret == ret, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret);
647 ret = ImmGetDescriptionW(hkl, descW, 1);
648 ok(!ret, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret);
650 UnloadKeyboardLayout(hkl);
653 static void test_ImmDefaultHwnd(void)
655 HIMC imc1, imc2, imc3;
659 hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test",
660 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
661 240, 120, NULL, NULL, GetModuleHandle(0), NULL);
663 ShowWindow(hwnd, SW_SHOWNORMAL);
665 imc1 = ImmGetContext(hwnd);
668 win_skip("IME support not implemented\n");
672 def1 = ImmGetDefaultIMEWnd(hwnd);
674 imc2 = ImmCreateContext();
675 ImmSetOpenStatus(imc2, TRUE);
677 imc3 = ImmGetContext(hwnd);
678 def3 = ImmGetDefaultIMEWnd(hwnd);
680 ok(def3 == def1, "Default IME window should not change\n");
681 ok(imc1 == imc3, "IME context should not change\n");
682 ImmSetOpenStatus(imc2, FALSE);
684 ImmReleaseContext(hwnd, imc1);
685 ImmReleaseContext(hwnd, imc3);
686 ImmDestroyContext(imc2);
690 static void test_ImmMessages(void)
698 HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "Wine imm32.dll test",
699 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
700 240, 120, NULL, NULL, GetModuleHandle(0), NULL);
702 ShowWindow(hwnd, SW_SHOWNORMAL);
703 defwnd = ImmGetDefaultIMEWnd(hwnd);
704 imc = ImmGetContext(hwnd);
706 ImmSetOpenStatus(imc, TRUE);
707 msg_spy_flush_msgs();
708 SendMessage(defwnd, WM_IME_CONTROL, IMC_GETCANDIDATEPOS, (LPARAM)&cf );
711 msg = msg_spy_find_next_msg(WM_IME_CONTROL,&idx);
712 if (msg) ok(!msg->post, "Message should not be posted\n");
714 msg_spy_flush_msgs();
715 ImmSetOpenStatus(imc, FALSE);
716 ImmReleaseContext(hwnd, imc);
720 static LRESULT CALLBACK processkey_wnd_proc( HWND hWnd, UINT msg, WPARAM wParam,
723 return DefWindowProcW(hWnd, msg, wParam, lParam);
726 static void test_ime_processkey(void)
728 WCHAR classNameW[] = {'P','r','o','c','e','s','s', 'K','e','y','T','e','s','t','C','l','a','s','s',0};
729 WCHAR windowNameW[] = {'P','r','o','c','e','s','s', 'K','e','y',0};
733 HANDLE hInstance = GetModuleHandleW(NULL);
734 TEST_INPUT inputs[2];
739 wclass.lpszClassName = classNameW;
740 wclass.style = CS_HREDRAW | CS_VREDRAW;
741 wclass.lpfnWndProc = processkey_wnd_proc;
742 wclass.hInstance = hInstance;
743 wclass.hIcon = LoadIcon(0, IDI_APPLICATION);
744 wclass.hCursor = LoadCursor( NULL, IDC_ARROW);
745 wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
746 wclass.lpszMenuName = 0;
747 wclass.cbClsExtra = 0;
748 wclass.cbWndExtra = 0;
749 if(!RegisterClassW(&wclass)){
750 win_skip("Failed to register window.\n");
754 /* create the test window that will receive the keystrokes */
755 hWndTest = CreateWindowW(wclass.lpszClassName, windowNameW,
756 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100,
757 NULL, NULL, hInstance, NULL);
759 ShowWindow(hWndTest, SW_SHOW);
760 SetWindowPos(hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
761 SetForegroundWindow(hWndTest);
762 UpdateWindow(hWndTest);
764 imc = ImmGetContext(hWndTest);
767 win_skip("IME not supported\n");
768 DestroyWindow(hWndTest);
772 rc = ImmSetOpenStatus(imc, TRUE);
775 win_skip("Unable to open IME\n");
776 ImmReleaseContext(hWndTest, imc);
777 DestroyWindow(hWndTest);
781 /* flush pending messages */
782 while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageW(&msg);
786 /* init input data that never changes */
787 inputs[1].type = inputs[0].type = INPUT_KEYBOARD;
788 inputs[1].u.ki.dwExtraInfo = inputs[0].u.ki.dwExtraInfo = 0;
789 inputs[1].u.ki.time = inputs[0].u.ki.time = 0;
792 inputs[0].u.ki.wVk = 0x41;
793 inputs[0].u.ki.wScan = 0x1e;
794 inputs[0].u.ki.dwFlags = 0x0;
796 pSendInput(1, (INPUT*)inputs, sizeof(INPUT));
798 while(PeekMessageW(&msg, hWndTest, 0, 0, PM_NOREMOVE)) {
799 if(msg.message != WM_KEYDOWN)
800 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
803 ok(msg.wParam != VK_PROCESSKEY,"Incorrect ProcessKey Found\n");
804 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
805 if(msg.wParam == VK_PROCESSKEY)
806 trace("ProcessKey was correctly found\n");
808 TranslateMessage(&msg);
809 DispatchMessageW(&msg);
812 inputs[0].u.ki.wVk = 0x41;
813 inputs[0].u.ki.wScan = 0x1e;
814 inputs[0].u.ki.dwFlags = KEYEVENTF_KEYUP;
816 pSendInput(1, (INPUT*)inputs, sizeof(INPUT));
818 while(PeekMessageW(&msg, hWndTest, 0, 0, PM_NOREMOVE)) {
819 if(msg.message != WM_KEYUP)
820 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
823 ok(msg.wParam != VK_PROCESSKEY,"Incorrect ProcessKey Found\n");
824 PeekMessageW(&msg, hWndTest, 0, 0, PM_REMOVE);
825 ok(msg.wParam != VK_PROCESSKEY,"ProcessKey should still not be Found\n");
827 TranslateMessage(&msg);
828 DispatchMessageW(&msg);
831 ImmReleaseContext(hWndTest, imc);
832 ImmSetOpenStatus(imc, FALSE);
833 DestroyWindow(hWndTest);
840 test_ImmGetCompositionString();
841 test_ImmSetCompositionString();
843 test_ImmAssociateContextEx();
845 test_ImmIsUIMessage();
846 test_ImmGetContext();
847 test_ImmGetDescription();
848 test_ImmDefaultHwnd();
850 /* Reinitialize the hooks to capture all windows */
855 test_ime_processkey();
856 else win_skip("SendInput is not available\n");