From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/Makefile.in | 3 +- dlls/dinput/tests/device8.c | 298 ++++++++++++++++++++++ dlls/dinput/tests/keyboard.c | 458 ---------------------------------- 3 files changed, 299 insertions(+), 460 deletions(-) delete mode 100644 dlls/dinput/tests/keyboard.c
diff --git a/dlls/dinput/tests/Makefile.in b/dlls/dinput/tests/Makefile.in index 6ef155e5160..87522c12abf 100644 --- a/dlls/dinput/tests/Makefile.in +++ b/dlls/dinput/tests/Makefile.in @@ -21,5 +21,4 @@ SOURCES = \ hid.c \ hotplug.c \ joystick.c \ - joystick8.c \ - keyboard.c + joystick8.c diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 7ad3f98af24..927bf18949a 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -122,6 +122,29 @@ static HRESULT create_dinput_device( DWORD version, const GUID *guid, IDirectInp return DI_OK; }
+static HKL activate_keyboard_layout( LANGID langid, HKL *old_hkl ) +{ + WCHAR hkl_name[64]; + HKL hkl; + + swprintf( hkl_name, ARRAY_SIZE(hkl_name), L"%08x", langid ); + hkl = LoadKeyboardLayoutW( hkl_name, 0 ); + if (!hkl) + { + win_skip( "Unable to load keyboard layout %#x\n", langid ); + *old_hkl = GetKeyboardLayout( 0 ); + return 0; + } + + *old_hkl = ActivateKeyboardLayout( hkl, 0 ); + ok( !!*old_hkl, "ActivateKeyboardLayout failed, error %lu\n", GetLastError() ); + + hkl = GetKeyboardLayout( 0 ); + todo_wine_if( LOWORD(*old_hkl) != langid ) + ok( LOWORD(hkl) == langid, "GetKeyboardLayout returned %p\n", hkl ); + return hkl; +} + static HRESULT direct_input_create( DWORD version, IDirectInputA **out ) { HRESULT hr; @@ -2047,6 +2070,126 @@ static void test_sys_mouse( DWORD version ) localized = old_localized; }
+static void test_dik_codes( IDirectInputDevice8W *device, HANDLE event, HWND hwnd ) +{ + static const struct key2dik + { + BYTE key, dik, todo; + } + key2dik_en[] = + { + {'Q',DIK_Q}, {'W',DIK_W}, {'E',DIK_E}, {'R',DIK_R}, {'T',DIK_T}, {'Y',DIK_Y}, + {'[',DIK_LBRACKET}, {']',DIK_RBRACKET}, {'.',DIK_PERIOD} + }, + key2dik_fr[] = + { + {'A',DIK_Q}, {'Z',DIK_W}, {'E',DIK_E}, {'R',DIK_R}, {'T',DIK_T}, {'Y',DIK_Y}, + {'^',DIK_LBRACKET}, {'$',DIK_RBRACKET}, {':',DIK_PERIOD} + }, + key2dik_de[] = + { + {'Q',DIK_Q}, {'W',DIK_W}, {'E',DIK_E}, {'R',DIK_R}, {'T',DIK_T}, {'Z',DIK_Y}, + {'\xfc',DIK_LBRACKET,1}, {'+',DIK_RBRACKET}, {'.',DIK_PERIOD} + }, + key2dik_ja[] = + { + {'Q',DIK_Q}, {'W',DIK_W}, {'E',DIK_E}, {'R',DIK_R}, {'T',DIK_T}, {'Y',DIK_Y}, + {'@',DIK_AT}, {']',DIK_RBRACKET}, {'.',DIK_PERIOD} + }; + static const struct + { + LANGID langid; + const struct key2dik *map; + DWORD type; + } tests[] = + { + { MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), key2dik_en, DIDEVTYPEKEYBOARD_PCENH }, + { MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH), key2dik_fr, DIDEVTYPEKEYBOARD_PCENH }, + { MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), key2dik_de, DIDEVTYPEKEYBOARD_PCENH }, + { MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), key2dik_ja, DIDEVTYPEKEYBOARD_JAPAN106 } + }; + DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; + const struct key2dik *map; + BYTE key_state[256]; + HKL hkl, old_hkl; + WORD vkey, scan; + HRESULT hr; + ULONG res; + UINT i, j; + + hr = IDirectInputDevice_SetDataFormat( device, &c_dfDIKeyboard ); + ok( hr == DI_OK, "SetDataFormat returned %#lx\n", hr ); + hr = IDirectInputDevice_Acquire( device ); + ok( hr == DI_OK, "Acquire returned %#lx\n", hr ); + hr = IDirectInputDevice_GetCapabilities( device, &caps ); + ok( hr == DI_OK, "GetDeviceInstance returned %#lx\n", hr ); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + if (tests[i].type != GET_DIDEVICE_SUBTYPE( caps.dwDevType )) + { + skip( "keyboard type %#x doesn't match for lang %#x\n", + GET_DIDEVICE_SUBTYPE( caps.dwDevType ), tests[i].langid ); + continue; + } + + winetest_push_context( "lang %#x", tests[i].langid ); + + hkl = activate_keyboard_layout( tests[i].langid, &old_hkl ); + if (LOWORD(old_hkl) != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) || + LOWORD(hkl) != tests[i].langid) goto skip_key_tests; + + map = tests[i].map; + for (j = 0; j < ARRAY_SIZE(key2dik_en); j++) + { + winetest_push_context( "key %#x, dik %#x", map[j].key, map[j].dik ); + + vkey = VkKeyScanExW( map[j].key, hkl ); + todo_wine_if( map[j].todo ) + ok( vkey != 0xffff, "VkKeyScanExW failed\n" ); + + vkey = LOBYTE(vkey); + res = MapVirtualKeyExA( vkey, MAPVK_VK_TO_CHAR, hkl ) & 0xff; + todo_wine_if( map[j].todo ) + ok( res == map[j].key, "MapVirtualKeyExA failed\n" ); + + scan = MapVirtualKeyExA( vkey, MAPVK_VK_TO_VSC, hkl ); + todo_wine_if( map[j].todo ) + ok( scan, "MapVirtualKeyExA failed\n" ); + + keybd_event( vkey, scan, 0, 0 ); + res = WaitForSingleObject( event, 100 ); + if (i == 0 && j == 0 && res == WAIT_TIMEOUT) /* Acquire is asynchronous */ + { + keybd_event( vkey, scan, 0, 0 ); + res = WaitForSingleObject( event, 100 ); + } + ok( !res, "WaitForSingleObject returned %#lx\n", res ); + + hr = IDirectInputDevice_GetDeviceState( device, sizeof(key_state), key_state ); + ok( hr == DI_OK, "GetDeviceState returned %#lx\n", hr ); + + todo_wine_if( map[j].todo ) + ok( key_state[map[j].dik] == 0x80, "got state %#x\n", key_state[map[j].dik] ); + + keybd_event( vkey, scan, KEYEVENTF_KEYUP, 0 ); + res = WaitForSingleObject( event, 100 ); + ok( !res, "WaitForSingleObject returned %#lx\n", res ); + + winetest_pop_context(); + } + + skip_key_tests: + ActivateKeyboardLayout( old_hkl, 0 ); + UnloadKeyboardLayout( hkl ); + + winetest_pop_context(); + } + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned %#lx\n", hr ); +} + static void test_sys_keyboard( DWORD version ) { const DIDEVCAPS expect_caps = @@ -2151,12 +2294,31 @@ static void test_sys_keyboard( DWORD version ) .dwHow = DIPH_DEVICE, }, }; + + LONG key_state[6], zero_state[6] = {0}; + DIOBJECTDATAFORMAT obj_data_format[] = + { + {&GUID_Key, sizeof(LONG) * 0, DIDFT_MAKEINSTANCE( DIK_Q ) | DIDFT_BUTTON, 0}, + {&GUID_Key, sizeof(LONG) * 1, DIDFT_MAKEINSTANCE( DIK_W ) | DIDFT_BUTTON, 0}, + {&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 data_format = + { + sizeof(DIDATAFORMAT), sizeof(DIOBJECTDATAFORMAT), DIDF_RELAXIS, + sizeof(key_state), ARRAY_SIZE(obj_data_format), obj_data_format, + }; + DIDEVICEOBJECTINSTANCEW objinst = {0}; DIDEVICEINSTANCEW devinst = {0}; BOOL old_localized = localized; IDirectInputDevice8W *device; DIDEVCAPS caps = {0}; + BYTE full_state[256]; + HKL hkl, old_hkl; + HWND hwnd, child; ULONG res, ref; + HANDLE event; HRESULT hr; GUID guid;
@@ -2388,6 +2550,142 @@ static void test_sys_keyboard( DWORD version ) check_member( objinst, expect_objects[2], "%#04x", wExponent ); check_member( objinst, expect_objects[2], "%u", wReportId );
+ + hwnd = CreateWindowW( L"static", L"static", WS_POPUP | WS_VISIBLE, + 50, 50, 200, 200, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + flush_events(); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_FOREGROUND ); + ok( hr == DIERR_INVALIDPARAM, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_FOREGROUND|DISCL_EXCLUSIVE ); + ok( hr == E_HANDLE, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE ); + ok( hr == E_HANDLE, "SetCooperativeLevel returned %#lx\n", hr ); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND ); + ok( hr == DIERR_INVALIDPARAM, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND|DISCL_EXCLUSIVE ); + ok( hr == E_HANDLE, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND|DISCL_NONEXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned %#lx\n", hr ); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_FOREGROUND ); + ok( hr == DIERR_INVALIDPARAM, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_FOREGROUND|DISCL_EXCLUSIVE ); + todo_wine_if( version == 0x500 ) + ok( hr == (version == 0x500 ? DIERR_INVALIDPARAM : DI_OK), "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned %#lx\n", hr ); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND ); + ok( hr == DIERR_INVALIDPARAM, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND|DISCL_EXCLUSIVE ); + todo_wine_if( version == 0x500 ) + ok( hr == (version == 0x500 ? DIERR_INVALIDPARAM : DIERR_UNSUPPORTED), "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND|DISCL_NONEXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned %#lx\n", hr ); + + child = CreateWindowW( L"static", L"static", WS_CHILD | WS_VISIBLE, + 10, 10, 50, 50, hwnd, NULL, NULL, NULL ); + ok( !!child, "CreateWindowW failed, error %lu\n", GetLastError() ); + flush_events(); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, child, DISCL_FOREGROUND ); + ok( hr == DIERR_INVALIDPARAM, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, child, DISCL_FOREGROUND|DISCL_EXCLUSIVE ); + ok( hr == E_HANDLE, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, child, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE ); + ok( hr == E_HANDLE, "SetCooperativeLevel returned %#lx\n", hr ); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, child, DISCL_BACKGROUND ); + ok( hr == DIERR_INVALIDPARAM, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, child, DISCL_BACKGROUND|DISCL_EXCLUSIVE ); + ok( hr == E_HANDLE, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, child, DISCL_BACKGROUND|DISCL_NONEXCLUSIVE ); + ok( hr == E_HANDLE, "SetCooperativeLevel returned %#lx\n", hr ); + + DestroyWindow( child ); + + event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!event, "CreateEventW failed, error %lu\n", GetLastError() ); + + hkl = activate_keyboard_layout( MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), &old_hkl ); + if (LOWORD(hkl) != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) goto skip_key_tests; + + hr = IDirectInputDevice8_SetEventNotification( device, event ); + ok( hr == DI_OK, "SetEventNotification returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIKeyboard ); + ok( hr == DI_OK, "SetDataFormat returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND ); + ok( hr == DI_OK, "SetCooperativeLevel returned %#lx\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, 10, full_state ); + ok( hr == DIERR_NOTACQUIRED, "GetDeviceState returned %#lx\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(full_state), full_state ); + ok( hr == DIERR_NOTACQUIRED, "GetDeviceState returned %#lx\n", hr ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_NOEFFECT, "Unacquire returned %#lx\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned %#lx\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_NOEFFECT, "Acquire returned %#lx\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, 10, full_state ); + ok( hr == DIERR_INVALIDPARAM, "GetDeviceState returned %#lx\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(full_state), full_state ); + ok( hr == DI_OK, "GetDeviceState returned %#lx\n", hr ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Uncquire returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetDataFormat( device, &data_format ); + ok( hr == DI_OK, "SetDataFormat returned %#lx\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned %#lx\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(key_state), key_state ); + ok( hr == DI_OK, "GetDeviceState returned %#lx\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(full_state), full_state ); + ok( hr == DIERR_INVALIDPARAM, "GetDeviceState returned %#lx\n", hr ); + + memset( key_state, 0x56, sizeof(key_state) ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(key_state), key_state ); + ok( hr == DI_OK, "GetDeviceState returned %#lx\n", hr ); + ok( !memcmp( key_state, zero_state, sizeof(key_state) ), "got non zero state\n" ); + + keybd_event( 'Q', 0, 0, 0 ); + res = WaitForSingleObject( event, 100 ); + if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ + { + keybd_event( 'Q', 0, 0, 0 ); + res = WaitForSingleObject( event, 100 ); + } + ok( !res, "WaitForSingleObject returned %#lx\n", res ); + + memset( key_state, 0xcd, sizeof(key_state) ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(key_state), key_state ); + ok( hr == DI_OK, "GetDeviceState returned %#lx\n", hr ); + ok( key_state[0] == (version < 0x800 ? 0x80 : 0), "got key_state[0] %lu\n", key_state[0] ); + + /* unacquiring should reset the device state */ + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned %#lx\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned %#lx\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(key_state), key_state ); + ok( hr == DI_OK, "GetDeviceState returned %#lx\n", hr ); + ok( !memcmp( key_state, zero_state, sizeof(key_state) ), "got non zero state\n" ); + + keybd_event( 'Q', 0, KEYEVENTF_KEYUP, 0 ); + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned %#lx\n", hr ); + +skip_key_tests: + ActivateKeyboardLayout( old_hkl, 0 ); + UnloadKeyboardLayout( hkl ); + + test_dik_codes( device, event, hwnd ); + + CloseHandle( event ); + DestroyWindow( hwnd ); + ref = IDirectInputDevice8_Release( device ); ok( ref == 0, "Release returned %ld\n", ref );
diff --git a/dlls/dinput/tests/keyboard.c b/dlls/dinput/tests/keyboard.c deleted file mode 100644 index 2aa4fa86f98..00000000000 --- a/dlls/dinput/tests/keyboard.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright (c) 2005 Robert Reif - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define DIRECTINPUT_VERSION 0x0700 - -#include <stdarg.h> -#include <stddef.h> - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" - -#define COBJMACROS -#include "dinput.h" - -#include "dinput_test.h" - -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, "%#x", 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 %#x != langid %#x\n", LOWORD(hkl_current), langid); - return 0; - } - - return hkl; -} - -static void acquire_tests(IDirectInputA *pDI, HWND hwnd) -{ - HRESULT hr; - IDirectInputDeviceA *pKeyboard; - BYTE kbd_state[256]; - LONG custom_state[6]; - int i; - DIOBJECTDATAFORMAT dodf[] = - { - { &GUID_Key, sizeof(LONG) * 0, DIDFT_MAKEINSTANCE(DIK_Q)|DIDFT_BUTTON, 0 }, - { &GUID_Key, sizeof(LONG) * 1, DIDFT_MAKEINSTANCE(DIK_W)|DIDFT_BUTTON, 0 }, - { &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; - UINT prev_raw_devices_count, raw_devices_count; - - 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; - df.dwDataSize = sizeof( custom_state ); - df.dwNumObjs = ARRAY_SIZE(dodf); - df.rgodf = dodf; - - hr = IDirectInput_CreateDevice(pDI, &GUID_SysKeyboard, &pKeyboard, NULL); - ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %#lx\n", hr); - if (FAILED(hr)) return; - - hr = IDirectInputDevice_SetDataFormat(pKeyboard, &c_dfDIKeyboard); - ok(SUCCEEDED(hr), "IDirectInputDevice_SetDataFormat() failed: %#lx\n", hr); - hr = IDirectInputDevice_SetCooperativeLevel(pKeyboard, NULL, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); - ok(SUCCEEDED(hr), "IDirectInputDevice_SetCooperativeLevel() failed: %#lx\n", hr); - hr = IDirectInputDevice_GetDeviceState(pKeyboard, 10, kbd_state); - ok(hr == DIERR_NOTACQUIRED, "IDirectInputDevice_GetDeviceState(10,) should have failed: %#lx\n", hr); - hr = IDirectInputDevice_GetDeviceState(pKeyboard, sizeof(kbd_state), kbd_state); - ok(hr == DIERR_NOTACQUIRED, "IDirectInputDevice_GetDeviceState() should have failed: %#lx\n", hr); - hr = IDirectInputDevice_Unacquire(pKeyboard); - ok(hr == S_FALSE, "IDirectInputDevice_Unacquire() should have failed: %#lx\n", hr); - hr = IDirectInputDevice_Acquire(pKeyboard); - ok(SUCCEEDED(hr), "IDirectInputDevice_Acquire() failed: %#lx\n", hr); - hr = IDirectInputDevice_Acquire(pKeyboard); - ok(hr == S_FALSE, "IDirectInputDevice_Acquire() should have failed: %#lx\n", hr); - hr = IDirectInputDevice_GetDeviceState(pKeyboard, 10, kbd_state); - ok(hr == DIERR_INVALIDPARAM, "IDirectInputDevice_GetDeviceState(10,) should have failed: %#lx\n", hr); - hr = IDirectInputDevice_GetDeviceState(pKeyboard, sizeof(kbd_state), kbd_state); - ok(SUCCEEDED(hr), "IDirectInputDevice_GetDeviceState() failed: %#lx\n", hr); - hr = IDirectInputDevice_Unacquire(pKeyboard); - ok(SUCCEEDED(hr), "IDirectInputDevice_Uncquire() failed: %#lx\n", hr); - hr = IDirectInputDevice_SetDataFormat( pKeyboard , &df ); - ok(SUCCEEDED(hr), "IDirectInputDevice_SetDataFormat() failed: %#lx\n", hr); - hr = IDirectInputDevice_Acquire(pKeyboard); - ok(SUCCEEDED(hr), "IDirectInputDevice_Acquire() failed: %#lx\n", hr); - hr = IDirectInputDevice_GetDeviceState(pKeyboard, sizeof(custom_state), custom_state); - ok(SUCCEEDED(hr), "IDirectInputDevice_GetDeviceState(4,) failed: %#lx\n", hr); - hr = IDirectInputDevice_GetDeviceState(pKeyboard, sizeof(kbd_state), kbd_state); - ok(hr == DIERR_INVALIDPARAM, "IDirectInputDevice_GetDeviceState(256,) should have failed: %#lx\n", hr); - - memset(custom_state, 0x56, sizeof(custom_state)); - IDirectInputDevice_GetDeviceState(pKeyboard, sizeof(custom_state), custom_state); - for (i = 0; i < ARRAY_SIZE(custom_state); i++) - ok(custom_state[i] == 0, "Should be zeroed, got 0x%#lx\n", custom_state[i]); - - /* 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: %#lx\n", hr); - if (!custom_state[0]) - win_skip("Keyboard event not processed, skipping test\n"); - else - { - /* unacquiring should reset the device state */ - hr = IDirectInputDevice_Unacquire(pKeyboard); - ok(SUCCEEDED(hr), "IDirectInputDevice_Unacquire() failed: %#lx\n", hr); - hr = IDirectInputDevice_Acquire(pKeyboard); - ok(SUCCEEDED(hr), "IDirectInputDevice_Acquire() failed: %#lx\n", hr); - hr = IDirectInputDevice_GetDeviceState(pKeyboard, sizeof(custom_state), custom_state); - ok(SUCCEEDED(hr), "IDirectInputDevice_GetDeviceState failed: %#lx\n", hr); - for (i = 0; i < ARRAY_SIZE(custom_state); i++) - ok(custom_state[i] == 0, "Should be zeroed, got 0x%#lx\n", custom_state[i]); - } - keybd_event('Q', 0, KEYEVENTF_KEYUP, 0); - - prev_raw_devices_count = 0; - GetRegisteredRawInputDevices(NULL, &prev_raw_devices_count, sizeof(RAWINPUTDEVICE)); - ok(prev_raw_devices_count == 0 || broken(prev_raw_devices_count == 1) /* wxppro, w2003std */, - "Unexpected raw devices registered: %d\n", prev_raw_devices_count); - - hr = IDirectInputDevice_Acquire(pKeyboard); - ok(SUCCEEDED(hr), "IDirectInputDevice_Acquire() failed: %#lx\n", hr); - - raw_devices_count = 0; - GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - ok(raw_devices_count == prev_raw_devices_count, - "Unexpected raw devices registered: %d\n", raw_devices_count); - - hr = IDirectInputDevice_Unacquire(pKeyboard); - ok(SUCCEEDED(hr), "IDirectInputDevice_Unacquire() failed: %#lx\n", hr); - - IUnknown_Release(pKeyboard); - - ActivateKeyboardLayout(hkl_orig, 0); - UnloadKeyboardLayout(hkl); -} - -static const HRESULT SetCoop_null_window[16] = { - E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, - E_INVALIDARG, E_HANDLE, E_HANDLE, E_INVALIDARG, - E_INVALIDARG, E_HANDLE, S_OK, E_INVALIDARG, - E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG}; - -static const HRESULT SetCoop_invalid_window[16] = { - E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, - E_INVALIDARG, E_HANDLE, E_HANDLE, E_INVALIDARG, - E_INVALIDARG, E_HANDLE, E_HANDLE, E_INVALIDARG, - E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG}; - -static const HRESULT SetCoop_real_window[16] = { - E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, - E_INVALIDARG, S_OK, S_OK, E_INVALIDARG, - E_INVALIDARG, E_NOTIMPL, S_OK, E_INVALIDARG, - E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG}; - -static const HRESULT SetCoop_child_window[16] = { - E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, - E_INVALIDARG, E_HANDLE, E_HANDLE, E_INVALIDARG, - E_INVALIDARG, E_HANDLE, E_HANDLE, E_INVALIDARG, - E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG}; - -static void test_set_coop(IDirectInputA *pDI, HWND hwnd) -{ - HRESULT hr; - IDirectInputDeviceA *pKeyboard = NULL; - int i; - HWND child; - - hr = IDirectInput_CreateDevice(pDI, &GUID_SysKeyboard, &pKeyboard, NULL); - ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %#lx\n", hr); - if (FAILED(hr)) return; - - for (i=0; i<16; i++) - { - hr = IDirectInputDevice_SetCooperativeLevel(pKeyboard, NULL, i); - ok(hr == SetCoop_null_window[i], "SetCooperativeLevel(NULL, %d): %#lx\n", i, hr); - } - for (i=0; i<16; i++) - { - hr = IDirectInputDevice_SetCooperativeLevel(pKeyboard, (HWND)0x400000, i); - ok(hr == SetCoop_invalid_window[i], "SetCooperativeLevel(invalid, %d): %#lx\n", i, hr); - } - for (i=0; i<16; i++) - { - hr = IDirectInputDevice_SetCooperativeLevel(pKeyboard, hwnd, i); - ok(hr == SetCoop_real_window[i], "SetCooperativeLevel(hwnd, %d): %#lx\n", i, hr); - } - - child = CreateWindowA("static", "Title", WS_CHILD | WS_VISIBLE, 10, 10, 50, 50, hwnd, NULL, - NULL, NULL); - ok(child != NULL, "err: %lu\n", GetLastError()); - - for (i=0; i<16; i++) - { - hr = IDirectInputDevice_SetCooperativeLevel(pKeyboard, child, i); - ok(hr == SetCoop_child_window[i], "SetCooperativeLevel(child, %d): %#lx\n", i, hr); - } - - DestroyWindow(child); - if (pKeyboard) IUnknown_Release(pKeyboard); -} - -static void test_dik_codes(IDirectInputA *dI, HWND hwnd, LANGID langid) -{ - static const struct key2dik - { - BYTE key, dik, todo; - } key2dik_en[] = - { - {'Q',DIK_Q}, {'W',DIK_W}, {'E',DIK_E}, {'R',DIK_R}, {'T',DIK_T}, {'Y',DIK_Y}, - {'[',DIK_LBRACKET}, {']',DIK_RBRACKET}, {'.',DIK_PERIOD} - }, - key2dik_fr[] = - { - {'A',DIK_Q}, {'Z',DIK_W}, {'E',DIK_E}, {'R',DIK_R}, {'T',DIK_T}, {'Y',DIK_Y}, - {'^',DIK_LBRACKET}, {'$',DIK_RBRACKET}, {':',DIK_PERIOD} - }, - key2dik_de[] = - { - {'Q',DIK_Q}, {'W',DIK_W}, {'E',DIK_E}, {'R',DIK_R}, {'T',DIK_T}, {'Z',DIK_Y}, - {'\xfc',DIK_LBRACKET,1}, {'+',DIK_RBRACKET}, {'.',DIK_PERIOD} - }, - key2dik_ja[] = - { - {'Q',DIK_Q}, {'W',DIK_W}, {'E',DIK_E}, {'R',DIK_R}, {'T',DIK_T}, {'Y',DIK_Y}, - {'@',DIK_AT}, {']',DIK_RBRACKET}, {'.',DIK_PERIOD} - }; - static const struct - { - LANGID langid; - const struct key2dik *map; - DWORD type; - } expected[] = - { - { MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), - key2dik_en, DIDEVTYPEKEYBOARD_PCENH }, - { MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH), - key2dik_fr, DIDEVTYPEKEYBOARD_PCENH }, - { MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), - key2dik_de, DIDEVTYPEKEYBOARD_PCENH }, - { MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), - key2dik_ja, DIDEVTYPEKEYBOARD_JAPAN106 } - }; - const struct key2dik *map = NULL; - UINT i; - HRESULT hr; - IDirectInputDeviceA *device; - DIDEVCAPS caps; - HKL hkl, hkl_orig; - MSG msg; - - for (i = 0; i < ARRAY_SIZE(expected); 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: %#lx\n", hr); - hr = IDirectInputDevice_SetDataFormat(device, &c_dfDIKeyboard); - ok(hr == S_OK, "SetDataFormat() failed: %#lx\n", hr); - hr = IDirectInputDevice_Acquire(device); - ok(hr == S_OK, "Acquire() failed: %#lx\n", hr); - caps.dwSize = sizeof( caps ); - hr = IDirectInputDevice_GetCapabilities(device, &caps); - ok(hr == S_OK, "GetDeviceInstance() failed: %#lx\n", hr); - if (expected[i].type != GET_DIDEVICE_SUBTYPE(caps.dwDevType)) { - skip("Keyboard type(%u) doesn't match for lang %04x\n", - GET_DIDEVICE_SUBTYPE(caps.dwDevType), langid); - goto fail; - } - - hkl = activate_keyboard_layout(langid, &hkl_orig); - if (!hkl) goto fail; - - SetFocus(hwnd); - pump_messages(); - - for (i = 0; i < ARRAY_SIZE(key2dik_en); i++) - { - BYTE kbd_state[256]; - UINT n; - WORD vkey, scan; - INPUT in; - - n = VkKeyScanExW(map[i].key, hkl); - todo_wine_if(map[i].todo & 1) - ok(n != 0xffff, "%u: failed to get virtual key value for %c(%02x)\n", i, map[i].key, map[i].key); - vkey = LOBYTE(n); - n = MapVirtualKeyExA(vkey, MAPVK_VK_TO_CHAR, hkl) & 0xff; - todo_wine_if(map[i].todo & 1) - ok(n == map[i].key, "%u: expected %c(%02x), got %c(%02x)\n", i, map[i].key, map[i].key, n, n); - scan = MapVirtualKeyExA(vkey, MAPVK_VK_TO_VSC, hkl); - /* scan codes match the DIK_ codes on US keyboard. - however, it isn't true for symbols and punctuations in other layouts. */ - if (isalpha(map[i].key) || langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) - ok(scan == map[i].dik, "%u: expected %02x, got %02x\n", i, map[i].dik, n); - else - todo_wine_if(map[i].todo & 1) - ok(scan, "%u: fail to get scan code value, expected %02x (vkey=%02x)\n", - i, map[i].dik, vkey); - - in.type = INPUT_KEYBOARD; - U(in).ki.wVk = vkey; - U(in).ki.wScan = scan; - 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, hwnd, 0, 0, PM_REMOVE)) - { - U(in).ki.dwFlags = KEYEVENTF_KEYUP; - SendInput(1, &in, sizeof(in)); - win_skip("failed to queue keyboard event\n"); - break; - } - ok(msg.message == WM_KEYDOWN, "expected WM_KEYDOWN, got %04x\n", msg.message); - DispatchMessageA(&msg); - - n = MapVirtualKeyExA(msg.wParam, MAPVK_VK_TO_CHAR, hkl); - trace("keydown wParam: %#Ix (%c) lParam: %#Ix, MapVirtualKey(MAPVK_VK_TO_CHAR) = %c\n", - msg.wParam, isprint(LOWORD(msg.wParam)) ? LOWORD(msg.wParam) : '?', - msg.lParam, isprint(n) ? n : '?'); - - pump_messages(); - - hr = IDirectInputDevice_GetDeviceState(device, sizeof(kbd_state), kbd_state); - ok(hr == S_OK, "GetDeviceState() failed: %#lx\n", hr); - - /* this never happens on real hardware but tesbot VMs seem to have timing issues */ - if (i == 0 && kbd_state[map[0].dik] != 0x80) - { - win_skip("dinput failed to handle keyboard event\n"); - break; - } - - todo_wine_if(map[i].todo) - 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; - IDirectInputA *pDI = NULL; - HWND hwnd; - ULONG ref = 0; - - hr = DirectInputCreateA(instance, version, &pDI, NULL); - if (hr == DIERR_OLDDIRECTINPUTVERSION) - { - skip("Tests require a newer dinput version\n"); - return; - } - ok(SUCCEEDED(hr), "DirectInputCreateA() failed: %#lx\n", hr); - if (FAILED(hr)) return; - - hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 10, 10, 200, 200, - NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "err: %lu\n", GetLastError()); - SetForegroundWindow( hwnd ); - - if (hwnd) - { - pump_messages(); - - acquire_tests(pDI, hwnd); - test_set_coop(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); - if (pDI) ref = IUnknown_Release(pDI); - ok(!ref, "IDirectInput_Release() reference count = %ld\n", ref); -} - -START_TEST(keyboard) -{ - dinput_test_init(); - - keyboard_tests(0x0700); - - dinput_test_exit(); -}