[PATCH v4 2/2] dinput: Fix DInput8 keyboard behavior for injected events with scancode=0.

Zebediah Figura z.figura12 at gmail.com
Fri Apr 17 13:45:42 CDT 2020


On 4/17/20 1:47 PM, Rémi Bernon wrote:
> On 4/17/20 8:35 PM, Brendan Shanks wrote:
>> Grand Theft Auto IV injects VK_F8 and scancode=0, and expects 
>> DirectInput not
>> to report that F8 is pressed.
>>
>> Signed-off-by: Brendan Shanks <bshanks at codeweavers.com>
>> ---
>> v4: Only make this behavior change for DirectInput 8.
>> It's difficult to show because of the separation of 8 and pre-8 tests,
>> but really does seem to depend only on the DI version used.
>>
>>   dlls/dinput/keyboard.c      | 8 ++++----
>>   dlls/dinput8/tests/device.c | 2 --
>>   2 files changed, 4 insertions(+), 6 deletions(-)
>>
>> diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c
>> index 47f28cac52..f842f1ca42 100644
>> --- a/dlls/dinput/keyboard.c
>> +++ b/dlls/dinput/keyboard.c
>> @@ -68,9 +68,9 @@ static inline IDirectInputDevice8W 
>> *IDirectInputDevice8W_from_impl(SysKeyboardIm
>>       return &This->base.IDirectInputDevice8W_iface;
>>   }
>> -static BYTE map_dik_code(DWORD scanCode, DWORD vkCode, DWORD subType)
>> +static BYTE map_dik_code(DWORD scanCode, DWORD vkCode, DWORD subType, 
>> DWORD version)
>>   {
>> -    if (!scanCode)
>> +    if (!scanCode && version < 0x0800)
>>           scanCode = MapVirtualKeyW(vkCode, MAPVK_VK_TO_VSC);
>>       if (subType == DIDEVTYPEKEYBOARD_JAPAN106)
>> @@ -125,7 +125,7 @@ static int KeyboardCallback( LPDIRECTINPUTDEVICE8A 
>> iface, WPARAM wparam, LPARAM
>>           case VK_NUMLOCK : dik_code = DIK_NUMLOCK; break;
>>           case VK_SUBTRACT: dik_code = DIK_SUBTRACT; break;
>>           default:
>> -            dik_code = map_dik_code(hook->scanCode & 0xff, 
>> hook->vkCode, This->subtype);
>> +            dik_code = map_dik_code(hook->scanCode & 0xff, 
>> hook->vkCode, This->subtype, This->base.dinput->dwVersion);
>>               if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80;
>>       }
>>       new_diks = hook->flags & LLKHF_UP ? 0 : 0x80;
>> @@ -282,7 +282,7 @@ static SysKeyboardImpl *alloc_device(REFGUID 
>> rguid, IDirectInputImpl *dinput)
>>           if (!GetKeyNameTextA(((i & 0x7f) << 16) | ((i & 0x80) << 
>> 17), buf, sizeof(buf)))
>>               continue;
>> -        dik_code = map_dik_code(i, 0, newDevice->subtype);
>> +        dik_code = map_dik_code(i, 0, newDevice->subtype, 
>> dinput->dwVersion);
>>           memcpy(&df->rgodf[idx], &c_dfDIKeyboard.rgodf[dik_code], 
>> df->dwObjSize);
>>           df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(dik_code) | 
>> DIDFT_PSHBUTTON;
>>       }
>> diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c
>> index bb82855d40..39c635f2fb 100644
>> --- a/dlls/dinput8/tests/device.c
>> +++ b/dlls/dinput8/tests/device.c
>> @@ -820,7 +820,6 @@ static void test_keyboard_events(void)
>>       data_size = ARRAY_SIZE(obj_data);
>>       hr = IDirectInputDevice8_GetDeviceData(di_keyboard, 
>> sizeof(DIDEVICEOBJECTDATA), obj_data, &data_size, 0);
>>       ok(SUCCEEDED(hr), "Failed to get data hr=%08x\n", hr);
>> -    todo_wine
>>       ok(data_size == 0, "Expected 0 elements, received %d\n", 
>> data_size);
>>       hr = IDirectInputDevice8_GetDeviceState(di_keyboard, 
>> sizeof(kbdata), kbdata);
>> @@ -834,7 +833,6 @@ static void test_keyboard_events(void)
>>       data_size = ARRAY_SIZE(obj_data);
>>       hr = IDirectInputDevice8_GetDeviceData(di_keyboard, 
>> sizeof(DIDEVICEOBJECTDATA), obj_data, &data_size, 0);
>>       ok(SUCCEEDED(hr), "Failed to get data hr=%08x\n", hr);
>> -    todo_wine
>>       ok(data_size == 0, "Expected 0 elements, received %d\n", 
>> data_size);
>>       hr = IDirectInputDevice8_Unacquire(di_keyboard);
>>
> 
> Ha that's why it installs a LL keyboard hook, I was wondering why it was 
> doing that.
> 
> Long story short, DInput8 uses RawInput API to get input events, so I 
> believe it should not install any LL hook in that case.
> 
> In addition, in exclusive cooperative mode it should also set the 
> RIDEV_NOLEGACY flag which I believe prevents any input messages to be 
> sent -even to LL hooks.
> 
> The rawinput patches that are in Staging should implement that logic, 
> but I kept the hooks installed, specifically because of GTAV.
> 
> When no DInput hooks are there, wineserver sends the messages to GTAV 
> and they are neve handled for some reason, which causes a wait and 
> timeout on every keypress.
> 
> When the hooks are kept, and because the esync staging patch series also 
> includes a hook removal on timeout -as Win >=7 is supposed to do [*]-, 
> the first input makes GTAV hook time out, and it's then removed.
> 
> [*] I did some investigation and it looks like Windows >=7 removes hooks 
> that time out for 32bit applications, not 64bit apps for whatever reason.

For what it's worth, that patch could be removed; it was a workaround 
for an issue that I eventually had to fix another way. I figured it was 
correct anyway, but as this issue is showing, it may not be worth having...



More information about the wine-devel mailing list