xref: /reactos/dll/directx/wine/dinput/keyboard.c (revision f986527d)
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 static DWORD get_keyboard_subtype(void)
149 {
150     DWORD kbd_type, kbd_subtype, dev_subtype;
151     kbd_type = GetKeyboardType(0);
152     kbd_subtype = GetKeyboardType(1);
153 
154     if (kbd_type == 4 || (kbd_type == 7 && kbd_subtype == 0))
155         dev_subtype = DIDEVTYPEKEYBOARD_PCENH;
156     else if (kbd_type == 7 && kbd_subtype == 2)
157         dev_subtype = DIDEVTYPEKEYBOARD_JAPAN106;
158     else {
159         FIXME("Unknown keyboard type=%u, subtype=%u\n", kbd_type, kbd_subtype);
160         dev_subtype = DIDEVTYPEKEYBOARD_PCENH;
161     }
162     return dev_subtype;
163 }
164 
165 static void fill_keyboard_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, DWORD subtype) {
166     DWORD dwSize;
167     DIDEVICEINSTANCEA ddi;
168 
169     dwSize = lpddi->dwSize;
170 
171     TRACE("%d %p\n", dwSize, lpddi);
172 
173     memset(lpddi, 0, dwSize);
174     memset(&ddi, 0, sizeof(ddi));
175 
176     ddi.dwSize = dwSize;
177     ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */
178     ddi.guidProduct = GUID_SysKeyboard;
179     if (version >= 0x0800)
180         ddi.dwDevType = DI8DEVTYPE_KEYBOARD | (subtype << 8);
181     else
182         ddi.dwDevType = DIDEVTYPE_KEYBOARD | (subtype << 8);
183     strcpy(ddi.tszInstanceName, "Keyboard");
184     strcpy(ddi.tszProductName, "Wine Keyboard");
185 
186     memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
187 }
188 
189 static void fill_keyboard_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, DWORD subtype) {
190     DWORD dwSize;
191     DIDEVICEINSTANCEW ddi;
192 
193     dwSize = lpddi->dwSize;
194 
195     TRACE("%d %p\n", dwSize, lpddi);
196 
197     memset(lpddi, 0, dwSize);
198     memset(&ddi, 0, sizeof(ddi));
199 
200     ddi.dwSize = dwSize;
201     ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */
202     ddi.guidProduct = GUID_SysKeyboard;
203     if (version >= 0x0800)
204         ddi.dwDevType = DI8DEVTYPE_KEYBOARD | (subtype << 8);
205     else
206         ddi.dwDevType = DIDEVTYPE_KEYBOARD | (subtype << 8);
207     MultiByteToWideChar(CP_ACP, 0, "Keyboard", -1, ddi.tszInstanceName, MAX_PATH);
208     MultiByteToWideChar(CP_ACP, 0, "Wine Keyboard", -1, ddi.tszProductName, MAX_PATH);
209 
210     memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
211 }
212 
213 static HRESULT keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
214 {
215   if (id != 0)
216     return E_FAIL;
217 
218   if (dwFlags & DIEDFL_FORCEFEEDBACK)
219     return S_FALSE;
220 
221   if ((dwDevType == 0) ||
222       ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) ||
223       (((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD)) && (version >= 0x0800))) {
224     TRACE("Enumerating the Keyboard device\n");
225 
226     fill_keyboard_dideviceinstanceA(lpddi, version, get_keyboard_subtype());
227 
228     return S_OK;
229   }
230 
231   return S_FALSE;
232 }
233 
234 static HRESULT keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
235 {
236   if (id != 0)
237     return E_FAIL;
238 
239   if (dwFlags & DIEDFL_FORCEFEEDBACK)
240     return S_FALSE;
241 
242   if ((dwDevType == 0) ||
243       ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) ||
244       (((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD)) && (version >= 0x0800))) {
245     TRACE("Enumerating the Keyboard device\n");
246 
247     fill_keyboard_dideviceinstanceW(lpddi, version, get_keyboard_subtype());
248 
249     return S_OK;
250   }
251 
252   return S_FALSE;
253 }
254 
255 static SysKeyboardImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput)
256 {
257     SysKeyboardImpl* newDevice;
258     LPDIDATAFORMAT df = NULL;
259     int i, idx = 0;
260 
261     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardImpl));
262     newDevice->base.IDirectInputDevice8A_iface.lpVtbl = &SysKeyboardAvt;
263     newDevice->base.IDirectInputDevice8W_iface.lpVtbl = &SysKeyboardWvt;
264     newDevice->base.ref = 1;
265     memcpy(&newDevice->base.guid, rguid, sizeof(*rguid));
266     newDevice->base.dinput = dinput;
267     newDevice->base.event_proc = KeyboardCallback;
268     InitializeCriticalSection(&newDevice->base.crit);
269     newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysKeyboardImpl*->base.crit");
270     newDevice->subtype = get_keyboard_subtype();
271 
272     /* Create copy of default data format */
273     if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIKeyboard.dwSize))) goto failed;
274     memcpy(df, &c_dfDIKeyboard, c_dfDIKeyboard.dwSize);
275     if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed;
276 
277     for (i = 0; i < df->dwNumObjs; i++)
278     {
279         char buf[MAX_PATH];
280         BYTE dik_code;
281 
282         if (!GetKeyNameTextA(((i & 0x7f) << 16) | ((i & 0x80) << 17), buf, sizeof(buf)))
283             continue;
284 
285         dik_code = map_dik_code(i, 0, newDevice->subtype);
286         memcpy(&df->rgodf[idx], &c_dfDIKeyboard.rgodf[dik_code], df->dwObjSize);
287         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(dik_code) | DIDFT_PSHBUTTON;
288     }
289     df->dwNumObjs = idx;
290 
291     newDevice->base.data_format.wine_df = df;
292     IDirectInput_AddRef(&newDevice->base.dinput->IDirectInput7A_iface);
293 
294     EnterCriticalSection(&dinput->crit);
295     list_add_tail(&dinput->devices_list, &newDevice->base.entry);
296     LeaveCriticalSection(&dinput->crit);
297 
298     return newDevice;
299 
300 failed:
301     if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
302     HeapFree(GetProcessHeap(), 0, df);
303     HeapFree(GetProcessHeap(), 0, newDevice);
304     return NULL;
305 }
306 
307 
308 static HRESULT keyboarddev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
309 {
310     TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
311     *pdev = NULL;
312 
313     if (IsEqualGUID(&GUID_SysKeyboard, rguid)) /* Wine Keyboard */
314     {
315         SysKeyboardImpl *This;
316 
317         if (riid == NULL)
318             ;/* nothing */
319         else if (IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
320                  IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
321                  IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
322                  IsEqualGUID(&IID_IDirectInputDevice8A, riid))
323         {
324             unicode = 0;
325         }
326         else if (IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
327                  IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
328                  IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
329                  IsEqualGUID(&IID_IDirectInputDevice8W, riid))
330         {
331             unicode = 1;
332         }
333         else
334         {
335             WARN("no interface\n");
336             return DIERR_NOINTERFACE;
337         }
338 
339         This = alloc_device(rguid, dinput);
340         TRACE("Created a Keyboard device (%p)\n", This);
341 
342         if (!This) return DIERR_OUTOFMEMORY;
343 
344         if (unicode)
345             *pdev = &This->base.IDirectInputDevice8W_iface;
346         else
347             *pdev = &This->base.IDirectInputDevice8A_iface;
348 
349         return DI_OK;
350     }
351 
352     return DIERR_DEVICENOTREG;
353 }
354 
355 const struct dinput_device keyboard_device = {
356   "Wine keyboard driver",
357   keyboarddev_enum_deviceA,
358   keyboarddev_enum_deviceW,
359   keyboarddev_create_device
360 };
361 
362 static HRESULT WINAPI SysKeyboardWImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface, DWORD len, LPVOID ptr)
363 {
364     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
365     TRACE("(%p)->(%d,%p)\n", This, len, ptr);
366 
367     if (!This->base.acquired) return DIERR_NOTACQUIRED;
368 
369     if (len != This->base.data_format.user_df->dwDataSize )
370         return DIERR_INVALIDPARAM;
371 
372     check_dinput_events();
373 
374     EnterCriticalSection(&This->base.crit);
375 
376     if (TRACE_ON(dinput)) {
377 	int i;
378 	for (i = 0; i < WINE_DINPUT_KEYBOARD_MAX_KEYS; i++) {
379 	    if (This->DInputKeyState[i] != 0x00)
380 		TRACE(" - %02X: %02x\n", i, This->DInputKeyState[i]);
381 	}
382     }
383 
384     fill_DataFormat(ptr, len, This->DInputKeyState, &This->base.data_format);
385     LeaveCriticalSection(&This->base.crit);
386 
387     return DI_OK;
388 }
389 
390 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState(LPDIRECTINPUTDEVICE8A iface, DWORD len, LPVOID ptr)
391 {
392     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
393     return SysKeyboardWImpl_GetDeviceState(IDirectInputDevice8W_from_impl(This), len, ptr);
394 }
395 
396 /******************************************************************************
397   *     GetCapabilities : get the device capabilities
398   */
399 static HRESULT WINAPI SysKeyboardWImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface, LPDIDEVCAPS lpDIDevCaps)
400 {
401     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
402     DIDEVCAPS devcaps;
403 
404     TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
405 
406     if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) {
407         WARN("invalid parameter\n");
408         return DIERR_INVALIDPARAM;
409     }
410 
411     devcaps.dwSize = lpDIDevCaps->dwSize;
412     devcaps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED;
413     if (This->base.dinput->dwVersion >= 0x0800)
414         devcaps.dwDevType = DI8DEVTYPE_KEYBOARD | (This->subtype << 8);
415     else
416         devcaps.dwDevType = DIDEVTYPE_KEYBOARD | (This->subtype << 8);
417     devcaps.dwAxes = 0;
418     devcaps.dwButtons = This->base.data_format.wine_df->dwNumObjs;
419     devcaps.dwPOVs = 0;
420     devcaps.dwFFSamplePeriod = 0;
421     devcaps.dwFFMinTimeResolution = 0;
422     devcaps.dwFirmwareRevision = 100;
423     devcaps.dwHardwareRevision = 100;
424     devcaps.dwFFDriverVersion = 0;
425 
426     memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize);
427 
428     return DI_OK;
429 }
430 
431 static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities(LPDIRECTINPUTDEVICE8A iface, LPDIDEVCAPS lpDIDevCaps)
432 {
433     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
434     return SysKeyboardWImpl_GetCapabilities(IDirectInputDevice8W_from_impl(This), lpDIDevCaps);
435 }
436 
437 static DWORD map_dik_to_scan(DWORD dik_code, DWORD subtype)
438 {
439     if (dik_code == DIK_PAUSE || dik_code == DIK_NUMLOCK) dik_code ^= 0x80;
440     if (subtype == DIDEVTYPEKEYBOARD_JAPAN106)
441     {
442         switch (dik_code)
443         {
444         case DIK_CIRCUMFLEX:
445             dik_code = 0x0d;
446             break;
447         case DIK_AT:
448             dik_code = 0x1a;
449             break;
450         case DIK_LBRACKET:
451             dik_code = 0x1b;
452             break;
453         case DIK_COLON:
454             dik_code = 0x28;
455             break;
456         case DIK_KANJI:
457             dik_code = 0x29;
458             break;
459         case DIK_RBRACKET:
460             dik_code = 0x2b;
461             break;
462         case DIK_BACKSLASH:
463             dik_code = 0x73;
464             break;
465         }
466     }
467 
468     return dik_code;
469 }
470 
471 /******************************************************************************
472   *     GetObjectInfo : get information about a device object such as a button
473   *                     or axis
474   */
475 static HRESULT WINAPI
476 SysKeyboardAImpl_GetObjectInfo(
477 	LPDIRECTINPUTDEVICE8A iface,
478 	LPDIDEVICEOBJECTINSTANCEA pdidoi,
479 	DWORD dwObj,
480 	DWORD dwHow)
481 {
482     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
483     HRESULT res;
484     LONG scan;
485 
486     res = IDirectInputDevice2AImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow);
487     if (res != DI_OK) return res;
488 
489     scan = map_dik_to_scan(DIDFT_GETINSTANCE(pdidoi->dwType), This->subtype);
490     if (!GetKeyNameTextA((scan & 0x80) << 17 | (scan & 0x7f) << 16,
491                          pdidoi->tszName, sizeof(pdidoi->tszName)))
492         return DIERR_OBJECTNOTFOUND;
493 
494     _dump_OBJECTINSTANCEA(pdidoi);
495     return res;
496 }
497 
498 static HRESULT WINAPI SysKeyboardWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
499 						     LPDIDEVICEOBJECTINSTANCEW pdidoi,
500 						     DWORD dwObj,
501 						     DWORD dwHow)
502 {
503     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
504     HRESULT res;
505     LONG scan;
506 
507     res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow);
508     if (res != DI_OK) return res;
509 
510     scan = map_dik_to_scan(DIDFT_GETINSTANCE(pdidoi->dwType), This->subtype);
511     if (!GetKeyNameTextW((scan & 0x80) << 17 | (scan & 0x7f) << 16,
512                          pdidoi->tszName, ARRAY_SIZE(pdidoi->tszName)))
513         return DIERR_OBJECTNOTFOUND;
514 
515     _dump_OBJECTINSTANCEW(pdidoi);
516     return res;
517 }
518 
519 /******************************************************************************
520   *     GetDeviceInfo : get information about a device's identity
521   */
522 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceInfo(
523 	LPDIRECTINPUTDEVICE8A iface,
524 	LPDIDEVICEINSTANCEA pdidi)
525 {
526     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
527     TRACE("(this=%p,%p)\n", This, pdidi);
528 
529     fill_keyboard_dideviceinstanceA(pdidi, This->base.dinput->dwVersion, This->subtype);
530 
531     return DI_OK;
532 }
533 
534 static HRESULT WINAPI SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi)
535 {
536     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
537     TRACE("(this=%p,%p)\n", This, pdidi);
538 
539     if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) {
540         WARN(" dinput3 not supported yet...\n");
541 	return DI_OK;
542     }
543 
544     fill_keyboard_dideviceinstanceW(pdidi, This->base.dinput->dwVersion, This->subtype);
545 
546     return DI_OK;
547 }
548 
549 /******************************************************************************
550  *      GetProperty : Retrieves information about the input device.
551  */
552 static HRESULT WINAPI SysKeyboardWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface,
553                                                    REFGUID rguid, LPDIPROPHEADER pdiph)
554 {
555     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
556 
557     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(rguid), pdiph);
558     _dump_DIPROPHEADER(pdiph);
559 
560     if (!IS_DIPROP(rguid)) return DI_OK;
561 
562     switch (LOWORD(rguid))
563     {
564         case (DWORD_PTR)DIPROP_KEYNAME:
565         {
566             HRESULT hr;
567             LPDIPROPSTRING ps = (LPDIPROPSTRING)pdiph;
568             DIDEVICEOBJECTINSTANCEW didoi;
569 
570             if (pdiph->dwSize != sizeof(DIPROPSTRING))
571                 return DIERR_INVALIDPARAM;
572 
573             didoi.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW);
574 
575             hr = SysKeyboardWImpl_GetObjectInfo(iface, &didoi, ps->diph.dwObj, ps->diph.dwHow);
576             if (hr == DI_OK)
577                 memcpy(ps->wsz, didoi.tszName, sizeof(ps->wsz));
578             return hr;
579         }
580         case (DWORD_PTR) DIPROP_RANGE:
581             return DIERR_UNSUPPORTED;
582         default:
583             return IDirectInputDevice2AImpl_GetProperty( IDirectInputDevice8A_from_impl(This), rguid, pdiph );
584     }
585     return DI_OK;
586 }
587 
588 static HRESULT WINAPI SysKeyboardAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
589                                                    REFGUID rguid, LPDIPROPHEADER pdiph)
590 {
591     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
592     return SysKeyboardWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
593 }
594 
595 static HRESULT WINAPI SysKeyboardWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
596 {
597     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
598     HRESULT res;
599 
600     TRACE("(%p)\n", This);
601 
602     res = IDirectInputDevice2WImpl_Acquire(iface);
603     if (res == DI_OK)
604     {
605         TRACE("clearing keystate\n");
606         memset(This->DInputKeyState, 0, sizeof(This->DInputKeyState));
607     }
608 
609     return res;
610 }
611 
612 static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
613 {
614     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
615     return SysKeyboardWImpl_Acquire(IDirectInputDevice8W_from_impl(This));
616 }
617 
618 static HRESULT WINAPI SysKeyboardWImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
619                                                       LPDIACTIONFORMATW lpdiaf,
620                                                       LPCWSTR lpszUserName,
621                                                       DWORD dwFlags)
622 {
623     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
624     FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This, lpdiaf, debugstr_w(lpszUserName), dwFlags);
625 
626     return  _build_action_map(iface, lpdiaf, lpszUserName, dwFlags, DIKEYBOARD_MASK, &c_dfDIKeyboard);
627 }
628 
629 static HRESULT WINAPI SysKeyboardAImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface,
630                                                       LPDIACTIONFORMATA lpdiaf,
631                                                       LPCSTR lpszUserName,
632                                                       DWORD dwFlags)
633 {
634     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
635     DIACTIONFORMATW diafW;
636     HRESULT hr;
637     WCHAR *lpszUserNameW = NULL;
638     int username_size;
639 
640     diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions);
641     _copy_diactionformatAtoW(&diafW, lpdiaf);
642 
643     if (lpszUserName != NULL)
644     {
645         username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
646         lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size);
647         MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size);
648     }
649 
650     hr = SysKeyboardWImpl_BuildActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
651 
652     _copy_diactionformatWtoA(lpdiaf, &diafW);
653     HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
654     HeapFree(GetProcessHeap(), 0, lpszUserNameW);
655 
656     return hr;
657 }
658 
659 static HRESULT WINAPI SysKeyboardWImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
660                                                     LPDIACTIONFORMATW lpdiaf,
661                                                     LPCWSTR lpszUserName,
662                                                     DWORD dwFlags)
663 {
664     SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
665     FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This, lpdiaf, debugstr_w(lpszUserName), dwFlags);
666 
667     return _set_action_map(iface, lpdiaf, lpszUserName, dwFlags, &c_dfDIKeyboard);
668 }
669 
670 static HRESULT WINAPI SysKeyboardAImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface,
671                                                     LPDIACTIONFORMATA lpdiaf,
672                                                     LPCSTR lpszUserName,
673                                                     DWORD dwFlags)
674 {
675     SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
676     DIACTIONFORMATW diafW;
677     HRESULT hr;
678     WCHAR *lpszUserNameW = NULL;
679     int username_size;
680 
681     diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions);
682     _copy_diactionformatAtoW(&diafW, lpdiaf);
683 
684     if (lpszUserName != NULL)
685     {
686         username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
687         lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size);
688         MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size);
689     }
690 
691     hr = SysKeyboardWImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
692 
693     lpdiaf->dwCRC = diafW.dwCRC;
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