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