[IMM32_APITEST] Add KLID testcase (#6590)

Confirming keyboard layout
implementation by checking
HKL, KLID, and registry.
JIRA issue: CORE-19268
- Add KLID testcase.
- Check HKLs, KLIDs (Keyboard
  Layout IDs), and related
 registry, with using
  user32!GetKeyboardLayoutList
  function.
This commit is contained in:
Katayama Hirofumi MZ 2024-03-10 22:36:40 +09:00 committed by GitHub
parent 0c65ceca3c
commit e6c0081c28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 203 additions and 1 deletions

View file

@ -10,11 +10,12 @@ list(APPEND SOURCE
ImmIsUIMessage.c
JapanImeConvTestA.c
JapanImeConvTestW.c
KLID.c
testlist.c
resource.rc)
add_executable(imm32_apitest ${SOURCE})
target_link_libraries(imm32_apitest wine ${PSEH_LIB})
set_module_type(imm32_apitest win32cui)
add_importlibs(imm32_apitest imm32 msvcrt user32 kernel32 ntdll)
add_importlibs(imm32_apitest advapi32 imm32 msvcrt user32 kernel32 ntdll)
add_rostests_file(TARGET imm32_apitest)

View file

@ -0,0 +1,199 @@
/*
* PROJECT: ReactOS api tests
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Test for Keyboard Layout ID (KLID), HKL, and registry
* COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#include "precomp.h"
#include <stdlib.h>
#include <imm32_undoc.h>
#include <strsafe.h>
typedef enum tagHKL_TYPE
{
HKL_TYPE_PURE = 0,
HKL_TYPE_SPECIAL = 1,
HKL_TYPE_IME = 2,
HKL_TYPE_CHIMERA = 3,
} HKL_TYPE;
static HKL_TYPE GetHKLType(HKL hKL)
{
/* 0xEXXXYYYY: An IME HKL. EXXX is an IME keyboard. YYYY is a language */
if (IS_IME_HKL(hKL))
return HKL_TYPE_IME;
/* 0xFXXXYYYY: A special HKL. XXX is a special ID. YYYY is a language */
if (IS_SPECIAL_HKL(hKL))
return HKL_TYPE_SPECIAL;
/* 0xXXXXXXXX: The keyboard layout and language is the same value */
if (LOWORD(hKL) == HIWORD(hKL))
return HKL_TYPE_PURE;
/* 0xXXXXYYYY: XXXX is a keyboard. YYYY is a language */
return HKL_TYPE_CHIMERA;
}
static HKEY OpenKeyboardLayouts(void)
{
HKEY hKey = NULL;
RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts",
0, KEY_READ, &hKey);
return hKey;
}
static DWORD KLIDFromSpecialHKL(HKL hKL)
{
WCHAR szName[16], szLayoutId[16];
HKEY hkeyLayouts, hkeyKLID;
LSTATUS error;
DWORD dwSpecialId, dwLayoutId, cbValue, dwKLID = 0;
hkeyLayouts = OpenKeyboardLayouts();
ok(hkeyLayouts != NULL, "hkeyLayouts was NULL\n");
dwSpecialId = SPECIALIDFROMHKL(hKL);
/* Search from "Keyboard Layouts" registry key */
for (DWORD dwIndex = 0; dwIndex < 1000; ++dwIndex)
{
error = RegEnumKeyW(hkeyLayouts, dwIndex, szName, _countof(szName));
szName[_countof(szName) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
if (error != ERROR_SUCCESS)
break;
error = RegOpenKeyExW(hkeyLayouts, szName, 0, KEY_READ, &hkeyKLID);
if (error != ERROR_SUCCESS)
break;
cbValue = sizeof(szLayoutId);
error = RegQueryValueExW(hkeyKLID, L"Layout Id", NULL, NULL, (LPBYTE)szLayoutId, &cbValue);
szLayoutId[_countof(szLayoutId) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
if (error != ERROR_SUCCESS)
{
RegCloseKey(hkeyKLID);
continue;
}
dwLayoutId = wcstoul(szLayoutId, NULL, 16);
RegCloseKey(hkeyKLID);
if (dwLayoutId == dwSpecialId) /* Found */
{
dwKLID = wcstoul(szName, NULL, 16);
break;
}
}
RegCloseKey(hkeyLayouts);
return dwKLID;
}
static DWORD KLIDFromHKL(HKL hKL)
{
HKL_TYPE type = GetHKLType(hKL);
trace("type: %d\n", type);
switch (type)
{
case HKL_TYPE_PURE:
case HKL_TYPE_CHIMERA:
return HIWORD(hKL);
case HKL_TYPE_SPECIAL:
return KLIDFromSpecialHKL(hKL);
case HKL_TYPE_IME:
return HandleToUlong(hKL);
}
return 0;
}
static void Test_KLID(DWORD dwKLID, HKL hKL)
{
WCHAR szKLID[16], szValue[MAX_PATH];
LSTATUS error;
DWORD dwValue, cbValue;
HKEY hkeyKLID, hkeyLayouts;
HKL_TYPE type;
hkeyLayouts = OpenKeyboardLayouts();
ok(hkeyLayouts != NULL, "hkeyLayouts was NULL\n");
StringCchPrintfW(szKLID, _countof(szKLID), L"%08lX", dwKLID);
RegOpenKeyExW(hkeyLayouts, szKLID, 0, KEY_READ, &hkeyKLID);
ok(hkeyKLID != NULL, "hkeyKLID was NULL\n");
error = RegQueryValueExW(hkeyKLID, L"Layout File", NULL, NULL, NULL, NULL);
ok_long(error, ERROR_SUCCESS);
type = GetHKLType(hKL);
if (type == HKL_TYPE_IME)
{
ok_long(dwKLID, HandleToUlong(hKL));
error = RegQueryValueExW(hkeyKLID, L"IME File", NULL, NULL, NULL, NULL);
ok_long(error, ERROR_SUCCESS);
}
if (type == HKL_TYPE_SPECIAL)
{
cbValue = sizeof(szValue);
error = RegQueryValueExW(hkeyKLID, L"Layout Id", NULL, NULL, (LPBYTE)&szValue, &cbValue);
ok_long(error, ERROR_SUCCESS);
dwValue = wcstoul(szValue, NULL, 16);
ok_long(dwValue, SPECIALIDFROMHKL(hKL));
}
RegCloseKey(hkeyKLID);
RegCloseKey(hkeyLayouts);
}
static void Test_HKL(HKL hKL)
{
DWORD dwKLID;
ok(hKL != NULL, "hKL was NULL\n");
dwKLID = KLIDFromHKL(hKL);
trace("dwKLID 0x%08lX, hKL %p\n", dwKLID, hKL);
Test_KLID(dwKLID, hKL);
}
START_TEST(KLID)
{
HKL *phKLs;
INT iKL, cKLs;
cKLs = GetKeyboardLayoutList(0, NULL);
trace("cKLs: %d\n", cKLs);
if (!cKLs)
{
skip("cKLs was zero\n");
return;
}
phKLs = calloc(cKLs, sizeof(HKL));
if (!phKLs)
{
skip("!phKLs\n");
return;
}
ok_int(GetKeyboardLayoutList(cKLs, phKLs), cKLs);
for (iKL = 0; iKL < cKLs; ++iKL)
{
trace("---\n");
trace("phKLs[%d]: %p\n", iKL, phKLs[iKL]);
Test_HKL(phKLs[iKL]);
}
free(phKLs);
}

View file

@ -8,6 +8,7 @@ extern void func_imcc(void);
extern void func_ImmEnumInputContext(void);
extern void func_ImmGetImeInfoEx(void);
extern void func_ImmIsUIMessage(void);
extern void func_KLID(void);
extern void func_JapanImeConvTestA(void);
extern void func_JapanImeConvTestW(void);
@ -19,6 +20,7 @@ const struct test winetest_testlist[] =
{ "ImmEnumInputContext", func_ImmEnumInputContext },
{ "ImmGetImeInfoEx", func_ImmGetImeInfoEx },
{ "ImmIsUIMessage", func_ImmIsUIMessage },
{ "KLID", func_KLID },
{ "JapanImeConvTestA", func_JapanImeConvTestA },
{ "JapanImeConvTestW", func_JapanImeConvTestW },
{ 0, 0 }