https://git.reactos.org/?p=reactos.git;a=commitdiff;h=fb58782012d5d0b3ba95b…
commit fb58782012d5d0b3ba95b388731fa43a262cfea4
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sat Oct 29 13:49:28 2022 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Sat Oct 29 13:49:28 2022 +0900
[IMM32_APITEST] Add JapanImeConvTestA/W testcases (#4820)
Add IME conversion tests to verify IMM/IME support. CORE-11700
---
modules/rostests/apitests/imm32/CMakeLists.txt | 5 +-
modules/rostests/apitests/imm32/JapanImeConvTest.h | 284 +++++++++++++++++++++
.../rostests/apitests/imm32/JapanImeConvTestA.c | 9 +
.../rostests/apitests/imm32/JapanImeConvTestW.c | 9 +
modules/rostests/apitests/imm32/resource.rc | 16 ++
modules/rostests/apitests/imm32/testlist.c | 4 +
6 files changed, 326 insertions(+), 1 deletion(-)
diff --git a/modules/rostests/apitests/imm32/CMakeLists.txt
b/modules/rostests/apitests/imm32/CMakeLists.txt
index 30b7dd66a8e..9c6486a8508 100644
--- a/modules/rostests/apitests/imm32/CMakeLists.txt
+++ b/modules/rostests/apitests/imm32/CMakeLists.txt
@@ -7,7 +7,10 @@ list(APPEND SOURCE
imcc.c
ImmGetImeInfoEx.c
ImmIsUIMessage.c
- testlist.c)
+ JapanImeConvTestA.c
+ JapanImeConvTestW.c
+ testlist.c
+ resource.rc)
add_executable(imm32_apitest ${SOURCE})
target_link_libraries(imm32_apitest wine ${PSEH_LIB})
diff --git a/modules/rostests/apitests/imm32/JapanImeConvTest.h
b/modules/rostests/apitests/imm32/JapanImeConvTest.h
new file mode 100644
index 00000000000..8878553d1c1
--- /dev/null
+++ b/modules/rostests/apitests/imm32/JapanImeConvTest.h
@@ -0,0 +1,284 @@
+/*
+ * PROJECT: ReactOS api tests
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Test for Japanese IME conversion
+ * COPYRIGHT: Copyright 2022 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
+ */
+
+#include <windows.h>
+#include <windowsx.h>
+#include <imm.h>
+#include <wine/test.h>
+
+/*
+ * We emulate some keyboard typing on dialog box and watch the conversion of Japanese
IME.
+ * This program needs Japanese environment and Japanese IME.
+ * Tested on Japanese WinXP and Japanese Win10.
+ */
+
+#define INTERVAL 300
+#define WM_PRESS_KEY_COMPLETE (WM_USER + 100)
+
+/* The test entry structure */
+typedef struct tagTEST_ENTRY
+{
+ const UINT *pKeys;
+ UINT cKeys;
+ const void *pvResult;
+ INT cWM_IME_ENDCOMPOSITION;
+} TEST_ENTRY, *PTEST_ENTRY;
+
+// The Japanese word "テスト" conversion in Romaji
+static const UINT s_keys1[] =
+{
+ 'T', 'E', 'S', 'U', 'T', 'O',
VK_SPACE, VK_RETURN
+};
+// The Japanese word "調査員" conversion in Romaji
+static const UINT s_keys2[] =
+{
+ 'C', 'H', 'O', 'U', 'S', 'A',
'I', 'N', 'N', VK_SPACE, VK_RETURN
+};
+
+#ifdef UNICODE
+ #define AorW(a, w) w
+#else
+ #define AorW(a, w) a
+#endif
+
+/* The test entries */
+static const TEST_ENTRY s_entries[] =
+{
+ // "テスト"
+ { s_keys1, _countof(s_keys1), AorW("\x83\x65\x83\x58\x83\x67",
L"\x30C6\x30B9\x30C8"), 1 },
+ // "調査員"
+ { s_keys2, _countof(s_keys2), AorW("\x92\xB2\x8D\xB8\x88\xF5",
L"\x8ABF\x67FB\x54E1"), 1 },
+};
+
+static INT s_iEntry = 0;
+static INT s_cWM_IME_ENDCOMPOSITION = 0;
+static WNDPROC s_fnOldEditWndProc = NULL;
+
+#ifdef UNICODE
+static LPSTR WideToAnsi(INT nCodePage, LPCWSTR pszWide)
+{
+ static CHAR s_sz[512];
+ WideCharToMultiByte(nCodePage, 0, pszWide, -1, s_sz, _countof(s_sz), NULL, NULL);
+ return s_sz;
+}
+#endif
+
+/* The window procedure for textbox to watch the IME conversion */
+static LRESULT CALLBACK
+EditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_IME_ENDCOMPOSITION:
+ {
+ const TEST_ENTRY *entry = &s_entries[s_iEntry];
+ HIMC hIMC;
+ LONG cbResult, cbBuffer;
+ LPTSTR pszResult;
+
+ /* Check conversion results of composition string */
+ hIMC = ImmGetContext(hwnd);
+ cbResult = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0);
+ trace("cbResult: %ld\n", cbResult);
+ if (cbResult > 0) /* Ignore zero string */
+ {
+ ok(hIMC != NULL, "hIMC was NULL\n");
+ ++s_cWM_IME_ENDCOMPOSITION;
+
+ cbBuffer = cbResult + sizeof(WCHAR);
+ pszResult = (LPTSTR)calloc(cbBuffer, sizeof(BYTE)); /* Zero-fill */
+ ok(pszResult != NULL, "pszResult was NULL\n");
+ ImmGetCompositionString(hIMC, GCS_RESULTSTR, pszResult, cbBuffer);
+#ifdef UNICODE
+ trace("%s\n", WideToAnsi(CP_ACP, (LPTSTR)pszResult));
+#else
+ trace("%s\n", (LPTSTR)pszResult);
+#endif
+ ok(lstrcmp(pszResult, (LPTSTR)entry->pvResult) == 0, "pszResult
differs\n");
+ free(pszResult);
+ }
+
+ ImmReleaseContext(hwnd, hIMC);
+ }
+ break;
+ }
+
+ return CallWindowProc(s_fnOldEditWndProc, hwnd, uMsg, wParam, lParam);
+}
+
+/* Timer IDs */
+#define STAGE_1 10001
+#define STAGE_2 10002
+#define STAGE_3 10003
+#define STAGE_4 10004
+#define STAGE_5 10005
+
+/* WM_INITDIALOG */
+static BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
+{
+ /* Subclass the textbox to watch the IME conversion */
+ HWND hEdt1 = GetDlgItem(hwnd, edt1);
+ s_fnOldEditWndProc = (WNDPROC)SetWindowLongPtr(hEdt1, GWLP_WNDPROC,
(LONG_PTR)EditWindowProc);
+
+ /* Go to first stage */
+ SetTimer(hwnd, STAGE_1, INTERVAL, 0);
+ return TRUE;
+}
+
+/* WM_COMMAND */
+static void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
+{
+ switch (id)
+ {
+ case IDOK:
+ case IDCANCEL:
+ EndDialog(hwnd, id);
+ break;
+ }
+}
+
+/* Emulate keyboard typing */
+static VOID PressKey(UINT vk)
+{
+ INPUT inputs[2];
+ ZeroMemory(inputs, sizeof(inputs));
+ inputs[0].type = INPUT_KEYBOARD;
+ inputs[0].ki.wVk = vk;
+ inputs[1].type = INPUT_KEYBOARD;
+ inputs[1].ki.wVk = vk;
+ inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
+ SendInput(_countof(inputs), inputs, sizeof(INPUT));
+}
+
+/* WM_TIMER */
+static void OnTimer(HWND hwnd, UINT id)
+{
+ HIMC hIMC;
+ INT i;
+ const TEST_ENTRY *entry = &s_entries[s_iEntry];
+ static DWORD dwOldConversion, dwOldSentence;
+
+ KillTimer(hwnd, id);
+
+ switch (id)
+ {
+ case STAGE_1:
+ /* Check focus. See WM_INITDIALOG return code. */
+ ok(GetFocus() == GetDlgItem(hwnd, edt1), "GetFocus() was %p\n",
GetFocus());
+
+ hIMC = ImmGetContext(hwnd);
+ ok(hIMC != NULL, "hIMC was NULL");
+ if (hIMC)
+ {
+ /* Open the IME */
+ ImmSetOpenStatus(hIMC, TRUE);
+ /* Save the IME conversion status */
+ ImmGetConversionStatus(hIMC, &dwOldConversion, &dwOldSentence);
+ /* Modify the IME conversion status */
+ ImmSetConversionStatus(hIMC,
+ IME_CMODE_FULLSHAPE | IME_CMODE_ROMAN |
IME_CMODE_NATIVE,
+ IME_SMODE_SINGLECONVERT);
+
+ ImmReleaseContext(hwnd, hIMC);
+ }
+ /* Initialize the counter */
+ s_cWM_IME_ENDCOMPOSITION = 0;
+ /* Go to next stage */
+ SetTimer(hwnd, STAGE_2, INTERVAL, NULL);
+ break;
+
+ case STAGE_2:
+ /* Emulate keyboard typing */
+ for (i = 0; i < entry->cKeys; ++i)
+ {
+ PressKey(entry->pKeys[i]);
+ }
+ /* Wait for message queue processed */
+ PostMessage(hwnd, WM_PRESS_KEY_COMPLETE, 0, 0);
+ break;
+
+ case STAGE_3:
+ /* Revert the IME conversion status */
+ hIMC = ImmGetContext(hwnd);
+ ok(hIMC != NULL, "hIMC was NULL");
+ if (hIMC)
+ {
+ ImmSetConversionStatus(hIMC, dwOldConversion, dwOldSentence);
+ ImmReleaseContext(hwnd, hIMC);
+ }
+ /* Go to next stage */
+ SetTimer(hwnd, STAGE_4, INTERVAL, NULL);
+ break;
+
+ case STAGE_4:
+ /* Check the counter */
+ ok_int(s_cWM_IME_ENDCOMPOSITION, entry->cWM_IME_ENDCOMPOSITION);
+ if (s_cWM_IME_ENDCOMPOSITION < entry->cWM_IME_ENDCOMPOSITION)
+ {
+ skip("Some tests were skipped.\n");
+ }
+
+ /* Go to next test entry */
+ ++s_iEntry;
+ if (s_iEntry == _countof(s_entries))
+ PostMessage(hwnd, WM_CLOSE, 0, 0); /* No more entry */
+ else
+ SetTimer(hwnd, STAGE_1, INTERVAL, NULL);
+ break;
+ }
+}
+
+/* Dialog procedure */
+static INT_PTR CALLBACK
+DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ HANDLE_MSG(hwnd, WM_INITDIALOG, OnInitDialog);
+ HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
+ HANDLE_MSG(hwnd, WM_TIMER, OnTimer);
+
+ case WM_PRESS_KEY_COMPLETE:
+ /* Message queue is processed. Go to next stage. */
+ SetTimer(hwnd, STAGE_3, INTERVAL, NULL);
+ break;
+ }
+ return 0;
+}
+
+#ifdef UNICODE
+START_TEST(JapanImeConvTestW)
+#else
+START_TEST(JapanImeConvTestA)
+#endif
+{
+ /* Is the system Japanese? */
+ if (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_JAPANESE)
+ {
+ skip("This testcase is for Japanese only.\n");
+ return;
+ }
+
+ /* Is IMM enabled? */
+ if (!GetSystemMetrics(SM_IMMENABLED))
+ {
+ skip("SM_IMMENABLED is OFF.\n");
+ return;
+ }
+
+ /* Check the current keyboard layout is IME */
+ if (!ImmIsIME(GetKeyboardLayout(0)))
+ {
+ skip("The IME keyboard layout was not default\n");
+ return;
+ }
+
+ DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(1), NULL, DialogProc);
+
+ if (s_iEntry < _countof(s_entries))
+ skip("Some tests were skipped.\n");
+}
diff --git a/modules/rostests/apitests/imm32/JapanImeConvTestA.c
b/modules/rostests/apitests/imm32/JapanImeConvTestA.c
new file mode 100644
index 00000000000..72d2e83581f
--- /dev/null
+++ b/modules/rostests/apitests/imm32/JapanImeConvTestA.c
@@ -0,0 +1,9 @@
+/*
+ * PROJECT: ReactOS api tests
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Test for Japanese IME conversion
+ * COPYRIGHT: Copyright 2022 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
+ */
+
+#undef UNICODE /* ANSI */
+#include "JapanImeConvTest.h"
diff --git a/modules/rostests/apitests/imm32/JapanImeConvTestW.c
b/modules/rostests/apitests/imm32/JapanImeConvTestW.c
new file mode 100644
index 00000000000..9499b861931
--- /dev/null
+++ b/modules/rostests/apitests/imm32/JapanImeConvTestW.c
@@ -0,0 +1,9 @@
+/*
+ * PROJECT: ReactOS api tests
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Test for Japanese IME conversion
+ * COPYRIGHT: Copyright 2022 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
+ */
+
+#define UNICODE /* Unicode */
+#include "JapanImeConvTest.h"
diff --git a/modules/rostests/apitests/imm32/resource.rc
b/modules/rostests/apitests/imm32/resource.rc
new file mode 100644
index 00000000000..c01bc75b2da
--- /dev/null
+++ b/modules/rostests/apitests/imm32/resource.rc
@@ -0,0 +1,16 @@
+#include <windows.h>
+#include <commctrl.h>
+#pragma code_page(65001) /* UTF-8 */
+
+LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
+
+1 DIALOG 0, 0, 215, 135
+CAPTION "JapanImeConvTest"
+STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION
+FONT 9, "MS UI Gothic"
+{
+ EDITTEXT edt1, 8, 7, 147, 14
+ LISTBOX lst1, 7, 30, 202, 82, LBS_NOINTEGRALHEIGHT | LBS_HASSTRINGS | WS_VSCROLL |
WS_TABSTOP
+ DEFPUSHBUTTON "OK", IDOK, 35, 115, 60, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 115, 115, 60, 14
+}
diff --git a/modules/rostests/apitests/imm32/testlist.c
b/modules/rostests/apitests/imm32/testlist.c
index d73e9878113..b9c16be52cf 100644
--- a/modules/rostests/apitests/imm32/testlist.c
+++ b/modules/rostests/apitests/imm32/testlist.c
@@ -7,6 +7,8 @@ extern void func_himc(void);
extern void func_imcc(void);
extern void func_ImmGetImeInfoEx(void);
extern void func_ImmIsUIMessage(void);
+extern void func_JapanImeConvTestA(void);
+extern void func_JapanImeConvTestW(void);
const struct test winetest_testlist[] =
{
@@ -15,5 +17,7 @@ const struct test winetest_testlist[] =
{ "imcc", func_imcc },
{ "ImmGetImeInfoEx", func_ImmGetImeInfoEx },
{ "ImmIsUIMessage", func_ImmIsUIMessage },
+ { "JapanImeConvTestA", func_JapanImeConvTestA },
+ { "JapanImeConvTestW", func_JapanImeConvTestW },
{ 0, 0 }
};