1 /*
2  * PROJECT:     ReactOS API tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Tests for Keyboard Layouts DLL files
5  * COPYRIGHT:   Copyright 2022 Stanislav Motylkov <x86corez@gmail.com>
6  */
7 
8 #include "precomp.h"
9 #include <ndk/kbd.h>
10 #include <strsafe.h>
11 
12 typedef PVOID (*PFN_KBDLAYERDESCRIPTOR)(VOID);
13 
14 static void testLayout(
15     _In_ LPWSTR szFileName,
16     _In_ LPWSTR szFilePath)
17 {
18     HMODULE hModule;
19     PFN_KBDLAYERDESCRIPTOR pfnKbdLayerDescriptor;
20     PKBDTABLES pKbdTbl;
21     USHORT i, uTableSize;
22 
23     trace("Testing '%ls'...\n", szFileName);
24 
25     hModule = LoadLibraryW(szFilePath);
26     if (!hModule)
27     {
28         ok(FALSE, "LoadLibraryW failed with code %ld\n", GetLastError());
29         return;
30     }
31 
32     pfnKbdLayerDescriptor = (PFN_KBDLAYERDESCRIPTOR)GetProcAddress(hModule, "KbdLayerDescriptor");
33     if (!pfnKbdLayerDescriptor)
34     {
35         ok(FALSE, "KbdLayerDescriptor not found!\n");
36         goto Cleanup;
37     }
38 
39     pKbdTbl = pfnKbdLayerDescriptor();
40     if (!pKbdTbl)
41     {
42         ok(FALSE, "PKBDTABLES is NULL!\n");
43         goto Cleanup;
44     }
45 
46     if (!pKbdTbl->pusVSCtoVK)
47     {
48         ok(FALSE, "pusVSCtoVK table is NULL!\n");
49         goto Cleanup;
50     }
51 
52     if (wcscmp(szFileName, L"kbdnec.dll") == 0)
53         uTableSize = 128; /* Only NEC PC-9800 Japanese keyboard layout has 128 entries. */
54     else
55         uTableSize = 127;
56 
57     /* Validate number of entries in pusVSCtoVK array. */
58     ok(pKbdTbl->bMaxVSCtoVK == uTableSize, "pKbdTbl->bMaxVSCtoVK = %u\n", pKbdTbl->bMaxVSCtoVK);
59 
60     for (i = 0; i < pKbdTbl->bMaxVSCtoVK; ++i)
61     {
62         /* Make sure there are no Virtual Keys with zero value. */
63         if (pKbdTbl->pusVSCtoVK[i] == 0)
64             ok(FALSE, "Scan Code %u => Virtual Key %u\n", i, pKbdTbl->pusVSCtoVK[i]);
65     }
66 
67 Cleanup:
68     if (hModule)
69         FreeLibrary(hModule);
70 }
71 
72 static void testKeyboardLayouts(void)
73 {
74     DWORD dwRet;
75     WCHAR szSysPath[MAX_PATH],
76           szPattern[MAX_PATH],
77           szFilePath[MAX_PATH];
78     HANDLE hFindFile = INVALID_HANDLE_VALUE;
79     WIN32_FIND_DATAW wfd;
80     BOOL bFound = TRUE;
81 
82     dwRet = GetSystemDirectoryW(szSysPath, ARRAYSIZE(szSysPath));
83     if (!dwRet)
84     {
85         skip("GetSystemDirectoryW failed with code %ld\n", GetLastError());
86         return;
87     }
88 
89     StringCchCopyW(szPattern, ARRAYSIZE(szPattern), szSysPath);
90     StringCchCatW(szPattern, ARRAYSIZE(szPattern), L"\\kbd*.dll");
91 
92     for (hFindFile = FindFirstFileW(szPattern, &wfd);
93          bFound && (hFindFile != INVALID_HANDLE_VALUE);
94          bFound = FindNextFileW(hFindFile, &wfd))
95     {
96         if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
97             continue;
98 
99         StringCchCopyW(szFilePath, ARRAYSIZE(szFilePath), szSysPath);
100         StringCchCatW(szFilePath, ARRAYSIZE(szFilePath), L"\\");
101         StringCchCatW(szFilePath, ARRAYSIZE(szFilePath), wfd.cFileName);
102 
103         testLayout(wfd.cFileName, szFilePath);
104     }
105 
106     if (hFindFile != INVALID_HANDLE_VALUE)
107         FindClose(hFindFile);
108 }
109 
110 START_TEST(KbdLayout)
111 {
112     testKeyboardLayouts();
113 }
114