[PATCH 2/2] dinput/tests: Add some tests for DIK_ codes using different keyboard layouts.

Dmitry Timoshkov dmitry at baikal.ru
Mon Apr 16 07:30:10 CDT 2018


Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/dinput/keyboard.c       |   3 +-
 dlls/dinput/tests/keyboard.c | 178 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 178 insertions(+), 3 deletions(-)

diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c
index e1ba15edd1..8a59ce01bc 100644
--- a/dlls/dinput/keyboard.c
+++ b/dlls/dinput/keyboard.c
@@ -86,7 +86,8 @@ static int KeyboardCallback( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM
         wparam != WM_SYSKEYDOWN && wparam != WM_SYSKEYUP)
         return 0;
 
-    TRACE("(%p) %ld,%ld\n", iface, wparam, lparam);
+    TRACE("(%p) wp %08lx, lp %08lx, vk %02x, scan %02x\n",
+          iface, wparam, lparam, hook->vkCode, hook->scanCode);
 
     switch (hook->vkCode)
     {
diff --git a/dlls/dinput/tests/keyboard.c b/dlls/dinput/tests/keyboard.c
index e51e332535..c5d890ab52 100644
--- a/dlls/dinput/tests/keyboard.c
+++ b/dlls/dinput/tests/keyboard.c
@@ -30,6 +30,53 @@
 #include "wingdi.h"
 #include "dinput.h"
 
+/* to make things easier with PSDK without a dinput.lib */
+static HRESULT (WINAPI *pDirectInputCreateA)(HINSTANCE,DWORD,IDirectInputA **,IUnknown *);
+
+static void pump_messages(void)
+{
+    MSG msg;
+
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
+    {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+}
+
+static HKL activate_keyboard_layout(LANGID langid, HKL *hkl_orig)
+{
+    HKL hkl, hkl_current;
+    char hkl_name[64];
+
+    sprintf(hkl_name, "%08x", langid);
+    trace("Loading keyboard layout %s\n", hkl_name);
+    hkl = LoadKeyboardLayoutA(hkl_name, 0);
+    if (!hkl)
+    {
+        win_skip("Unable to load keyboard layout %s\n", hkl_name);
+        return 0;
+    }
+    *hkl_orig = ActivateKeyboardLayout(hkl, 0);
+    ok(*hkl_orig != 0, "Unable to activate keyboard layout %s\n", hkl_name);
+    if (!*hkl_orig) return 0;
+
+    hkl_current = GetKeyboardLayout(0);
+    if (LOWORD(hkl_current) != langid)
+    {
+        /* FIXME: Wine can't activate different keyboard layouts.
+         * for testing purposes use this workaround:
+         * setxkbmap us && LANG=en_US.UTF-8 make test
+         * setxkbmap fr && LANG=fr_FR.UTF-8 make test
+         * setxkbmap de && LANG=de_DE.UTF-8 make test
+         */
+        skip("current %08x != langid %08x\n", LOWORD(hkl_current), langid);
+        return 0;
+    }
+
+    return hkl;
+}
+
 static void acquire_tests(IDirectInputA *pDI, HWND hwnd)
 {
     HRESULT hr;
@@ -44,8 +91,12 @@ static void acquire_tests(IDirectInputA *pDI, HWND hwnd)
             { &GUID_Key, sizeof(LONG) * 2, DIDFT_MAKEINSTANCE(DIK_E)|DIDFT_BUTTON, 0 },
             { &GUID_Key, sizeof(LONG) * 4, DIDFT_MAKEINSTANCE(DIK_R)|DIDFT_BUTTON, 0 },
         };
-
     DIDATAFORMAT df;
+    HKL hkl, hkl_orig;
+
+    hkl = activate_keyboard_layout(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), &hkl_orig);
+    if (!hkl) return;
+
     df.dwSize = sizeof( df );
     df.dwObjSize = sizeof( DIOBJECTDATAFORMAT );
     df.dwFlags = DIDF_RELAXIS;
@@ -93,6 +144,8 @@ static void acquire_tests(IDirectInputA *pDI, HWND hwnd)
 
     /* simulate some keyboard input */
     SetFocus(hwnd);
+    pump_messages();
+
     keybd_event('Q', 0, 0, 0);
     hr = IDirectInputDevice_GetDeviceState(pKeyboard, sizeof(custom_state), custom_state);
     ok(SUCCEEDED(hr), "IDirectInputDevice_GetDeviceState() failed: %08x\n", hr);
@@ -113,6 +166,9 @@ static void acquire_tests(IDirectInputA *pDI, HWND hwnd)
     keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
 
     if (pKeyboard) IUnknown_Release(pKeyboard);
+
+    ActivateKeyboardLayout(hkl_orig, 0);
+    UnloadKeyboardLayout(hkl);
 }
 
 static const HRESULT SetCoop_null_window[16] =  {
@@ -225,6 +281,115 @@ static void test_capabilities(IDirectInputA *pDI, HWND hwnd)
     IUnknown_Release(pKeyboard);
 }
 
+static void test_dik_codes(IDirectInputA *dI, HWND hwnd, LANGID langid)
+{
+    static const struct key2dik
+    {
+        BYTE key, dik;
+    } key2dik_en[] =
+    {
+        {'Q',DIK_Q}, {'W',DIK_W}, {'E',DIK_E}, {'R', DIK_R}, {'T', DIK_T}, {'Y', DIK_Y}
+    },
+    key2dik_fr[] =
+    {
+        {'A',DIK_Q}, {'Z',DIK_W}, {'E',DIK_E}, {'R', DIK_R}, {'T', DIK_T}, {'Y', DIK_Y}
+    },
+    key2dik_de[] =
+    {
+        {'Q',DIK_Q}, {'W',DIK_W}, {'E',DIK_E}, {'R', DIK_R}, {'T', DIK_T}, {'Z', DIK_Y}
+    };
+    static const struct
+    {
+        LANGID langid;
+        const struct key2dik *map;
+    } expected[] =
+    {
+        { MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), key2dik_en },
+        { MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH), key2dik_fr },
+        { MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), key2dik_de },
+        { MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), key2dik_en }
+    };
+    const struct key2dik *map = NULL;
+    UINT i;
+    HRESULT hr;
+    IDirectInputDeviceA *device;
+    HKL hkl, hkl_orig;
+    MSG msg;
+
+    for (i = 0; i < sizeof(expected)/sizeof(expected[0]); i++)
+    {
+        if (expected[i].langid == langid)
+        {
+            map = expected[i].map;
+            break;
+        }
+    }
+    ok(map != NULL, "can't find mapping for langid %04x\n", langid);
+    if (!map) return;
+
+    hr = IDirectInput_CreateDevice(dI, &GUID_SysKeyboard, &device, NULL);
+    ok(hr == S_OK, "CreateDevice() failed: %08x\n", hr);
+    hr = IDirectInputDevice_SetDataFormat(device, &c_dfDIKeyboard);
+    ok(hr == S_OK, "SetDataFormat() failed: %08x\n", hr);
+    hr = IDirectInputDevice_Acquire(device);
+    ok(hr == S_OK, "Acquire() failed: %08x\n", hr);
+
+    hkl = activate_keyboard_layout(langid, &hkl_orig);
+    if (!hkl) goto fail;
+
+    SetFocus(hwnd);
+    pump_messages();
+
+    for (i = 0; i < sizeof(key2dik_en)/sizeof(key2dik_en[0]); i++)
+    {
+        BYTE kbd_state[256];
+        UINT n;
+        INPUT in;
+
+        n = MapVirtualKeyA(map[i].key, MAPVK_VK_TO_CHAR);
+        ok(n == map[i].key, "%u: expected %c, got %c\n", i, map[i].key, n);
+        n = MapVirtualKeyA(map[i].key, MAPVK_VK_TO_VSC);
+        ok(n == map[i].dik, "%u: expected %02x, got %02x\n", i, map[i].dik, n);
+
+        in.type = INPUT_KEYBOARD;
+        U(in).ki.wVk = map[i].key;
+        U(in).ki.wScan = map[i].dik; /* scan codes match the DIK_ codes */
+        U(in).ki.dwFlags = 0;
+        U(in).ki.dwExtraInfo = 0;
+        U(in).ki.time = 0;
+        n = SendInput(1, &in, sizeof(in));
+        ok(n == 1, "got %u\n", n);
+
+        if (!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
+        {
+            win_skip("failed to queue keyboard event\n");
+            break;
+        }
+        ok(msg.message == WM_KEYDOWN, "expected WM_KEYDOWN, got %04x\n", msg.message);
+        DispatchMessageA(&msg);
+
+        trace("keydown wParam: %#lx (%c) lParam: %#lx, MapVirtualKey(MAPVK_VK_TO_CHAR) = %c\n",
+              msg.wParam, LOWORD(msg.wParam), msg.lParam, MapVirtualKeyA(msg.wParam, MAPVK_VK_TO_CHAR));
+
+        hr = IDirectInputDevice_GetDeviceState(device, sizeof(kbd_state), kbd_state);
+        ok(hr == S_OK, "GetDeviceState() failed: %08x\n", hr);
+
+        ok(kbd_state[map[i].dik] == 0x80, "DI key %#x has state %#x\n", map[i].dik, kbd_state[map[i].dik]);
+
+        U(in).ki.dwFlags = KEYEVENTF_KEYUP;
+        n = SendInput(1, &in, sizeof(in));
+        ok(n == 1, "got %u\n", n);
+
+        pump_messages();
+    }
+
+    ActivateKeyboardLayout(hkl_orig, 0);
+    UnloadKeyboardLayout(hkl);
+fail:
+    IDirectInputDevice_Unacquire(device);
+    IUnknown_Release(device);
+}
+
 static void keyboard_tests(DWORD version)
 {
     HRESULT hr;
@@ -233,7 +398,7 @@ static void keyboard_tests(DWORD version)
     HWND hwnd;
     ULONG ref = 0;
 
-    hr = DirectInputCreateA(hInstance, version, &pDI, NULL);
+    hr = pDirectInputCreateA(hInstance, version, &pDI, NULL);
     if (hr == DIERR_OLDDIRECTINPUTVERSION)
     {
         skip("Tests require a newer dinput version\n");
@@ -248,10 +413,17 @@ static void keyboard_tests(DWORD version)
 
     if (hwnd)
     {
+        pump_messages();
+
         acquire_tests(pDI, hwnd);
         test_set_coop(pDI, hwnd);
         test_get_prop(pDI, hwnd);
         test_capabilities(pDI, hwnd);
+
+        test_dik_codes(pDI, hwnd, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT));
+        test_dik_codes(pDI, hwnd, MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH));
+        test_dik_codes(pDI, hwnd, MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN));
+        test_dik_codes(pDI, hwnd, MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN));
     }
 
     DestroyWindow(hwnd);
@@ -261,6 +433,8 @@ static void keyboard_tests(DWORD version)
 
 START_TEST(keyboard)
 {
+    pDirectInputCreateA = (void *)GetProcAddress(LoadLibraryA("dinput.dll"), "DirectInputCreateA");
+
     CoInitialize(NULL);
 
     keyboard_tests(0x0700);
-- 
2.16.3




More information about the wine-devel mailing list