xref: /reactos/dll/directx/wine/dinput/keyboard.c (revision 321bcc05)
1 /*		DirectInput Keyboard device
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  * Copyright 2005 Raphael Junqueira
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include "dinput_private.h"
24 
25 #define WINE_DINPUT_KEYBOARD_MAX_KEYS 256
26 
27 static const IDirectInputDevice8AVtbl SysKeyboardAvt;
28 static const IDirectInputDevice8WVtbl SysKeyboardWvt;
29 
30 typedef struct SysKeyboardImpl SysKeyboardImpl;
31 struct SysKeyboardImpl
32 {
33     struct IDirectInputDeviceImpl base;
34     BYTE DInputKeyState[WINE_DINPUT_KEYBOARD_MAX_KEYS];
35 };
36 
37 static inline SysKeyboardImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
38 {
39     return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface), SysKeyboardImpl, base);
40 }
41 static inline SysKeyboardImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
42 {
43     return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface), SysKeyboardImpl, base);
44 }
45 static inline IDirectInputDevice8A *IDirectInputDevice8A_from_impl(SysKeyboardImpl *This)
46 {
47     return &This->base.IDirectInputDevice8A_iface;
48 }
49 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(SysKeyboardImpl *This)
50 {
51     return &This->base.IDirectInputDevice8W_iface;
52 }
53 
54 static BYTE map_dik_code(DWORD scanCode, DWORD vkCode)
55 {
56     static const BYTE asciiCodes[] =
57      {/*32*/  DIK_SPACE,0,0,0,0,0,0,DIK_APOSTROPHE,
58       /*40*/  0,0,0,0,DIK_COMMA,DIK_MINUS,DIK_PERIOD,DIK_SLASH,
59       /*48*/  DIK_0,DIK_1,DIK_2,DIK_3,DIK_4,DIK_5,DIK_6,DIK_7,
60       /*56*/  DIK_8,DIK_9,DIK_COLON,DIK_SEMICOLON,0,DIK_EQUALS,0,0,
61       /*64*/  DIK_AT,DIK_A,DIK_B,DIK_C,DIK_D,DIK_E,DIK_F,DIK_G,
62       /*72*/  DIK_H,DIK_I,DIK_J,DIK_K,DIK_L,DIK_M,DIK_N,DIK_O,
63       /*80*/  DIK_P,DIK_Q,DIK_R,DIK_S,DIK_T,DIK_U,DIK_V,DIK_W,
64       /*88*/  DIK_X,DIK_Y,DIK_Z,DIK_LBRACKET,0,DIK_RBRACKET,DIK_CIRCUMFLEX,DIK_UNDERLINE}      /*95*/ ;
65 
66     BYTE out_code = 0;
67     WCHAR c = MapVirtualKeyW(vkCode,MAPVK_VK_TO_CHAR);
68 
69     if (c > 31 && c < 96)
70         out_code = asciiCodes[c - 32];
71 
72     if (out_code == 0)
73         out_code = scanCode;
74 
75     return out_code;
76 }
77 
78 static int KeyboardCallback( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam )
79 {
80     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
81     int dik_code, ret = This->base.dwCoopLevel & DISCL_EXCLUSIVE;
82     KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam;
83     BYTE new_diks;
84 
85     if (wparam != WM_KEYDOWN && wparam != WM_KEYUP &&
86         wparam != WM_SYSKEYDOWN && wparam != WM_SYSKEYUP)
87         return 0;
88 
89     TRACE("(%p) %ld,%ld\n", iface, wparam, lparam);
90 
91     switch (hook->vkCode)
92     {
93         /* R-Shift is special - it is an extended key with separate scan code */
94         case VK_RSHIFT  : dik_code = DIK_RSHIFT; break;
95         case VK_PAUSE   : dik_code = DIK_PAUSE; break;
96         case VK_NUMLOCK : dik_code = DIK_NUMLOCK; break;
97         case VK_SUBTRACT: dik_code = DIK_SUBTRACT; break;
98         default:
99             dik_code = map_dik_code(hook->scanCode & 0xff, hook->vkCode);
100             if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80;
101     }
102     new_diks = hook->flags & LLKHF_UP ? 0 : 0x80;
103 
104     /* returns now if key event already known */
105     if (new_diks == This->DInputKeyState[dik_code])
106         return ret;
107 
108     This->DInputKeyState[dik_code] = new_diks;
109     TRACE(" setting %02X to %02X\n", dik_code, This->DInputKeyState[dik_code]);
110 
111     EnterCriticalSection(&This->base.crit);
112     queue_event(iface, DIDFT_MAKEINSTANCE(dik_code) | DIDFT_PSHBUTTON,
113                 new_diks, GetCurrentTime(), This->base.dinput->evsequence++);
114     LeaveCriticalSection(&This->base.crit);
115 
116     return ret;
117 }
118 
119 const GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
120     0x0ab8648a, 0x7735, 0x11d2, {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41}
121 };
122 
123 static void fill_keyboard_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version) {
124     DWORD dwSize;
125     DIDEVICEINSTANCEA ddi;
126 
127     dwSize = lpddi->dwSize;
128 
129     TRACE("%d %p\n", dwSize, lpddi);
130 
131     memset(lpddi, 0, dwSize);
132     memset(&ddi, 0, sizeof(ddi));
133 
134     ddi.dwSize = dwSize;
135     ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */
136     ddi.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */
137     if (version >= 0x0800)
138         ddi.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8);
139     else
140         ddi.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8);
141     strcpy(ddi.tszInstanceName, "Keyboard");
142     strcpy(ddi.tszProductName, "Wine Keyboard");
143 
144     memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
145 }
146 
147 static void fill_keyboard_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version) {
148     DWORD dwSize;
149     DIDEVICEINSTANCEW ddi;
150 
151     dwSize = lpddi->dwSize;
152 
153     TRACE("%d %p\n", dwSize, lpddi);
154 
155     memset(lpddi, 0, dwSize);
156     memset(&ddi, 0, sizeof(ddi));
157 
158     ddi.dwSize = dwSize;
159     ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */
160     ddi.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */
161     if (version >= 0x0800)
162         ddi.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8);
163     else
164         ddi.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8);
165     MultiByteToWideChar(CP_ACP, 0, "Keyboard", -1, ddi.tszInstanceName, MAX_PATH);
166     MultiByteToWideChar(CP_ACP, 0, "Wine Keyboard", -1, ddi.tszProductName, MAX_PATH);
167 
168     memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
169 }
170 
171 static HRESULT keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
172 {
173   if (id != 0)
174     return E_FAIL;
175 
176   if ((dwDevType == 0) ||
177       ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) ||
178       (((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD)) && (version >= 0x0800))) {
179     TRACE("Enumerating the Keyboard device\n");
180 
181     fill_keyboard_dideviceinstanceA(lpddi, version);
182 
183     return S_OK;
184   }
185 
186   return S_FALSE;
187 }
188 
189 static HRESULT keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
190 {
191   if (id != 0)
192     return E_FAIL;
193 
194   if ((dwDevType == 0) ||
195       ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) ||
196       (((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD)) && (version >= 0x0800))) {
197     TRACE("Enumerating the Keyboard device\n");
198 
199     fill_keyboard_dideviceinstanceW(lpddi, version);
200 
201     return S_OK;
202   }
203 
204   return S_FALSE;
205 }
206 
207 static SysKeyboardImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput)
208 {
209     SysKeyboardImpl* newDevice;
210     LPDIDATAFORMAT df = NULL;
211     int i, idx = 0;
212 
213     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardImpl));
214     newDevice->base.IDirectInputDevice8A_iface.lpVtbl = &SysKeyboardAvt;
215     newDevice->base.IDirectInputDevice8W_iface.lpVtbl = &SysKeyboardWvt;
216     newDevice->base.ref = 1;
217     memcpy(&newDevice->base.guid, rguid, sizeof(*rguid));
218     newDevice->base.dinput = dinput;
219     newDevice->base.event_proc = KeyboardCallback;
220     InitializeCriticalSection(&newDevice->base.crit);
221     newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysKeyboardImpl*->base.crit");
222 
223     /* Create copy of default data format */
224     if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIKeyboard.dwSize))) goto failed;
225     memcpy(df, &c_dfDIKeyboard, c_dfDIKeyboard.dwSize);
226     if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed;
227 
228     for (i = 0; i < df->dwNumObjs; i++)
229     {
230         char buf[MAX_PATH];
231 
232         if (!GetKeyNameTextA(((i & 0x7f) << 16) | ((i & 0x80) << 17), buf, sizeof(buf)))
233             continue;
234 
235         memcpy(&df->rgodf[idx], &c_dfDIKeyboard.rgodf[i], df->dwObjSize);
236         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
237     }
238     df->dwNumObjs = idx;
239 
240     newDevice->base.data_format.wine_df = df;
241     IDirectInput_AddRef(&newDevice->base.dinput->IDirectInput7A_iface);
242 
243     EnterCriticalSection(&dinput->crit);
244     list_add_tail(&dinput->devices_list, &newDevice->base.entry);
245     LeaveCriticalSection(&dinput->crit);
246 
247     return newDevice;
248 
249 failed:
250     if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
251     HeapFree(GetProcessHeap(), 0, df);
252     HeapFree(GetProcessHeap(), 0, newDevice);
253     return NULL;
254 }
255 
256 
257 static HRESULT keyboarddev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
258 {
259     TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
260     *pdev = NULL;
261 
262     if (IsEqualGUID(&GUID_SysKeyboard, rguid) ||        /* Generic Keyboard */
263         IsEqualGUID(&DInput_Wine_Keyboard_GUID, rguid)) /* Wine Keyboard */
264     {
265         SysKeyboardImpl *This;
266 
267         if (riid == NULL)
268             ;/* nothing */
269         else if (IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
270                  IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
271                  IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
272                  IsEqualGUID(&IID_IDirectInputDevice8A, riid))
273         {
274             unicode = 0;
275         }
276         else if (IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
277                  IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
278                  IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
279                  IsEqualGUID(&IID_IDirectInputDevice8W, riid))
280         {
281             unicode = 1;
282         }
283         else
284         {
285             WARN("no interface\n");
286             return DIERR_NOINTERFACE;
287         }
288 
289         This = alloc_device(rguid, dinput);
290         TRACE("Created a Keyboard device (%p)\n", This);
291 
292         if (!This) return DIERR_OUTOFMEMORY;
293 
294         if (unicode)
295             *pdev = &This->base.IDirectInputDevice8W_iface;
296         else
297             *pdev = &This->base.IDirectInputDevice8A_iface;
298 
299         return DI_OK;
300     }
301 
302     return DIERR_DEVICENOTREG;
303 }
304 
305 const struct dinput_device keyboard_device = {
306   "Wine keyboard driver",
307   keyboarddev_enum_deviceA,
308   keyboarddev_enum_deviceW,
309   keyboarddev_create_device
310 };
311 
312 static HRESULT WINAPI SysKeyboardWImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface, DWORD len, LPVOID ptr)
313 {
314     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
315     TRACE("(%p)->(%d,%p)\n", This, len, ptr);
316 
317     if (!This->base.acquired) return DIERR_NOTACQUIRED;
318 
319     if (len != This->base.data_format.user_df->dwDataSize )
320         return DIERR_INVALIDPARAM;
321 
322     check_dinput_events();
323 
324     EnterCriticalSection(&This->base.crit);
325 
326     if (TRACE_ON(dinput)) {
327 	int i;
328 	for (i = 0; i < WINE_DINPUT_KEYBOARD_MAX_KEYS; i++) {
329 	    if (This->DInputKeyState[i] != 0x00)
330 		TRACE(" - %02X: %02x\n", i, This->DInputKeyState[i]);
331 	}
332     }
333 
334     fill_DataFormat(ptr, len, This->DInputKeyState, &This->base.data_format);
335     LeaveCriticalSection(&This->base.crit);
336 
337     return DI_OK;
338 }
339 
340 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState(LPDIRECTINPUTDEVICE8A iface, DWORD len, LPVOID ptr)
341 {
342     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
343     return SysKeyboardWImpl_GetDeviceState(IDirectInputDevice8W_from_impl(This), len, ptr);
344 }
345 
346 /******************************************************************************
347   *     GetCapabilities : get the device capabilities
348   */
349 static HRESULT WINAPI SysKeyboardWImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface, LPDIDEVCAPS lpDIDevCaps)
350 {
351     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
352     DIDEVCAPS devcaps;
353 
354     TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
355 
356     if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) {
357         WARN("invalid parameter\n");
358         return DIERR_INVALIDPARAM;
359     }
360 
361     devcaps.dwSize = lpDIDevCaps->dwSize;
362     devcaps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED;
363     if (This->base.dinput->dwVersion >= 0x0800)
364         devcaps.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_PCENH << 8);
365     else
366         devcaps.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_PCENH << 8);
367     devcaps.dwAxes = 0;
368     devcaps.dwButtons = This->base.data_format.wine_df->dwNumObjs;
369     devcaps.dwPOVs = 0;
370     devcaps.dwFFSamplePeriod = 0;
371     devcaps.dwFFMinTimeResolution = 0;
372     devcaps.dwFirmwareRevision = 100;
373     devcaps.dwHardwareRevision = 100;
374     devcaps.dwFFDriverVersion = 0;
375 
376     memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize);
377 
378     return DI_OK;
379 }
380 
381 static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities(LPDIRECTINPUTDEVICE8A iface, LPDIDEVCAPS lpDIDevCaps)
382 {
383     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
384     return SysKeyboardWImpl_GetCapabilities(IDirectInputDevice8W_from_impl(This), lpDIDevCaps);
385 }
386 
387 /******************************************************************************
388   *     GetObjectInfo : get information about a device object such as a button
389   *                     or axis
390   */
391 static HRESULT WINAPI
392 SysKeyboardAImpl_GetObjectInfo(
393 	LPDIRECTINPUTDEVICE8A iface,
394 	LPDIDEVICEOBJECTINSTANCEA pdidoi,
395 	DWORD dwObj,
396 	DWORD dwHow)
397 {
398     HRESULT res;
399     LONG scan;
400 
401     res = IDirectInputDevice2AImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow);
402     if (res != DI_OK) return res;
403 
404     scan = DIDFT_GETINSTANCE(pdidoi->dwType);
405     if (scan == DIK_PAUSE || scan == DIK_NUMLOCK) scan ^= 0x80;
406     if (!GetKeyNameTextA((scan & 0x80) << 17 | (scan & 0x7f) << 16,
407                          pdidoi->tszName, sizeof(pdidoi->tszName)))
408         return DIERR_OBJECTNOTFOUND;
409 
410     _dump_OBJECTINSTANCEA(pdidoi);
411     return res;
412 }
413 
414 static HRESULT WINAPI SysKeyboardWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
415 						     LPDIDEVICEOBJECTINSTANCEW pdidoi,
416 						     DWORD dwObj,
417 						     DWORD dwHow)
418 {
419     HRESULT res;
420     LONG scan;
421 
422     res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow);
423     if (res != DI_OK) return res;
424 
425     scan = DIDFT_GETINSTANCE(pdidoi->dwType);
426     if (scan == DIK_PAUSE || scan == DIK_NUMLOCK) scan ^= 0x80;
427     if (!GetKeyNameTextW((scan & 0x80) << 17 | (scan & 0x7f) << 16,
428                          pdidoi->tszName, sizeof(pdidoi->tszName)/sizeof(pdidoi->tszName[0])))
429         return DIERR_OBJECTNOTFOUND;
430 
431     _dump_OBJECTINSTANCEW(pdidoi);
432     return res;
433 }
434 
435 /******************************************************************************
436   *     GetDeviceInfo : get information about a device's identity
437   */
438 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceInfo(
439 	LPDIRECTINPUTDEVICE8A iface,
440 	LPDIDEVICEINSTANCEA pdidi)
441 {
442     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
443     TRACE("(this=%p,%p)\n", This, pdidi);
444 
445     if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) {
446         WARN(" dinput3 not supported yet...\n");
447 	return DI_OK;
448     }
449 
450     fill_keyboard_dideviceinstanceA(pdidi, This->base.dinput->dwVersion);
451 
452     return DI_OK;
453 }
454 
455 static HRESULT WINAPI SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi)
456 {
457     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
458     TRACE("(this=%p,%p)\n", This, pdidi);
459 
460     if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) {
461         WARN(" dinput3 not supported yet...\n");
462 	return DI_OK;
463     }
464 
465     fill_keyboard_dideviceinstanceW(pdidi, This->base.dinput->dwVersion);
466 
467     return DI_OK;
468 }
469 
470 /******************************************************************************
471  *      GetProperty : Retrieves information about the input device.
472  */
473 static HRESULT WINAPI SysKeyboardWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface,
474                                                    REFGUID rguid, LPDIPROPHEADER pdiph)
475 {
476     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
477 
478     TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
479     _dump_DIPROPHEADER(pdiph);
480 
481     if (!IS_DIPROP(rguid)) return DI_OK;
482 
483     switch (LOWORD(rguid))
484     {
485         case (DWORD_PTR)DIPROP_KEYNAME:
486         {
487             HRESULT hr;
488             LPDIPROPSTRING ps = (LPDIPROPSTRING)pdiph;
489             DIDEVICEOBJECTINSTANCEW didoi;
490 
491             if (pdiph->dwSize != sizeof(DIPROPSTRING))
492                 return DIERR_INVALIDPARAM;
493 
494             didoi.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW);
495 
496             hr = SysKeyboardWImpl_GetObjectInfo(iface, &didoi, ps->diph.dwObj, ps->diph.dwHow);
497             if (hr == DI_OK)
498                 memcpy(ps->wsz, didoi.tszName, sizeof(ps->wsz));
499             return hr;
500         }
501         case (DWORD_PTR) DIPROP_RANGE:
502             return DIERR_UNSUPPORTED;
503         default:
504             return IDirectInputDevice2AImpl_GetProperty( IDirectInputDevice8A_from_impl(This), rguid, pdiph );
505     }
506     return DI_OK;
507 }
508 
509 static HRESULT WINAPI SysKeyboardAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
510                                                    REFGUID rguid, LPDIPROPHEADER pdiph)
511 {
512     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
513     return SysKeyboardWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
514 }
515 
516 static HRESULT WINAPI SysKeyboardWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
517 {
518     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
519     HRESULT res;
520 
521     TRACE("(%p)\n", This);
522 
523     res = IDirectInputDevice2WImpl_Acquire(iface);
524     if (res == DI_OK)
525     {
526         TRACE("clearing keystate\n");
527         memset(This->DInputKeyState, 0, sizeof(This->DInputKeyState));
528     }
529 
530     return res;
531 }
532 
533 static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
534 {
535     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
536     return SysKeyboardWImpl_Acquire(IDirectInputDevice8W_from_impl(This));
537 }
538 
539 static HRESULT WINAPI SysKeyboardWImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
540                                                       LPDIACTIONFORMATW lpdiaf,
541                                                       LPCWSTR lpszUserName,
542                                                       DWORD dwFlags)
543 {
544     FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
545 
546     return  _build_action_map(iface, lpdiaf, lpszUserName, dwFlags, DIKEYBOARD_MASK, &c_dfDIKeyboard);
547 }
548 
549 static HRESULT WINAPI SysKeyboardAImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface,
550                                                       LPDIACTIONFORMATA lpdiaf,
551                                                       LPCSTR lpszUserName,
552                                                       DWORD dwFlags)
553 {
554     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
555     DIACTIONFORMATW diafW;
556     HRESULT hr;
557     WCHAR *lpszUserNameW = NULL;
558     int username_size;
559 
560     diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions);
561     _copy_diactionformatAtoW(&diafW, lpdiaf);
562 
563     if (lpszUserName != NULL)
564     {
565         username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
566         lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size);
567         MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size);
568     }
569 
570     hr = SysKeyboardWImpl_BuildActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
571 
572     _copy_diactionformatWtoA(lpdiaf, &diafW);
573     HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
574     HeapFree(GetProcessHeap(), 0, lpszUserNameW);
575 
576     return hr;
577 }
578 
579 static HRESULT WINAPI SysKeyboardWImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
580                                                     LPDIACTIONFORMATW lpdiaf,
581                                                     LPCWSTR lpszUserName,
582                                                     DWORD dwFlags)
583 {
584     FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
585 
586     return _set_action_map(iface, lpdiaf, lpszUserName, dwFlags, &c_dfDIKeyboard);
587 }
588 
589 static HRESULT WINAPI SysKeyboardAImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface,
590                                                     LPDIACTIONFORMATA lpdiaf,
591                                                     LPCSTR lpszUserName,
592                                                     DWORD dwFlags)
593 {
594     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
595     DIACTIONFORMATW diafW;
596     HRESULT hr;
597     WCHAR *lpszUserNameW = NULL;
598     int username_size;
599 
600     diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions);
601     _copy_diactionformatAtoW(&diafW, lpdiaf);
602 
603     if (lpszUserName != NULL)
604     {
605         username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
606         lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size);
607         MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size);
608     }
609 
610     hr = SysKeyboardWImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
611 
612     HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
613     HeapFree(GetProcessHeap(), 0, lpszUserNameW);
614 
615     return hr;
616 }
617 
618 static const IDirectInputDevice8AVtbl SysKeyboardAvt =
619 {
620     IDirectInputDevice2AImpl_QueryInterface,
621     IDirectInputDevice2AImpl_AddRef,
622     IDirectInputDevice2AImpl_Release,
623     SysKeyboardAImpl_GetCapabilities,
624     IDirectInputDevice2AImpl_EnumObjects,
625     SysKeyboardAImpl_GetProperty,
626     IDirectInputDevice2AImpl_SetProperty,
627     SysKeyboardAImpl_Acquire,
628     IDirectInputDevice2AImpl_Unacquire,
629     SysKeyboardAImpl_GetDeviceState,
630     IDirectInputDevice2AImpl_GetDeviceData,
631     IDirectInputDevice2AImpl_SetDataFormat,
632     IDirectInputDevice2AImpl_SetEventNotification,
633     IDirectInputDevice2AImpl_SetCooperativeLevel,
634     SysKeyboardAImpl_GetObjectInfo,
635     SysKeyboardAImpl_GetDeviceInfo,
636     IDirectInputDevice2AImpl_RunControlPanel,
637     IDirectInputDevice2AImpl_Initialize,
638     IDirectInputDevice2AImpl_CreateEffect,
639     IDirectInputDevice2AImpl_EnumEffects,
640     IDirectInputDevice2AImpl_GetEffectInfo,
641     IDirectInputDevice2AImpl_GetForceFeedbackState,
642     IDirectInputDevice2AImpl_SendForceFeedbackCommand,
643     IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
644     IDirectInputDevice2AImpl_Escape,
645     IDirectInputDevice2AImpl_Poll,
646     IDirectInputDevice2AImpl_SendDeviceData,
647     IDirectInputDevice7AImpl_EnumEffectsInFile,
648     IDirectInputDevice7AImpl_WriteEffectToFile,
649     SysKeyboardAImpl_BuildActionMap,
650     SysKeyboardAImpl_SetActionMap,
651     IDirectInputDevice8AImpl_GetImageInfo
652 };
653 
654 static const IDirectInputDevice8WVtbl SysKeyboardWvt =
655 {
656     IDirectInputDevice2WImpl_QueryInterface,
657     IDirectInputDevice2WImpl_AddRef,
658     IDirectInputDevice2WImpl_Release,
659     SysKeyboardWImpl_GetCapabilities,
660     IDirectInputDevice2WImpl_EnumObjects,
661     SysKeyboardWImpl_GetProperty,
662     IDirectInputDevice2WImpl_SetProperty,
663     SysKeyboardWImpl_Acquire,
664     IDirectInputDevice2WImpl_Unacquire,
665     SysKeyboardWImpl_GetDeviceState,
666     IDirectInputDevice2WImpl_GetDeviceData,
667     IDirectInputDevice2WImpl_SetDataFormat,
668     IDirectInputDevice2WImpl_SetEventNotification,
669     IDirectInputDevice2WImpl_SetCooperativeLevel,
670     SysKeyboardWImpl_GetObjectInfo,
671     SysKeyboardWImpl_GetDeviceInfo,
672     IDirectInputDevice2WImpl_RunControlPanel,
673     IDirectInputDevice2WImpl_Initialize,
674     IDirectInputDevice2WImpl_CreateEffect,
675     IDirectInputDevice2WImpl_EnumEffects,
676     IDirectInputDevice2WImpl_GetEffectInfo,
677     IDirectInputDevice2WImpl_GetForceFeedbackState,
678     IDirectInputDevice2WImpl_SendForceFeedbackCommand,
679     IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
680     IDirectInputDevice2WImpl_Escape,
681     IDirectInputDevice2WImpl_Poll,
682     IDirectInputDevice2WImpl_SendDeviceData,
683     IDirectInputDevice7WImpl_EnumEffectsInFile,
684     IDirectInputDevice7WImpl_WriteEffectToFile,
685     SysKeyboardWImpl_BuildActionMap,
686     SysKeyboardWImpl_SetActionMap,
687     IDirectInputDevice8WImpl_GetImageInfo
688 };
689