1 /* DirectInput Keyboard device
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2005 Raphael Junqueira
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.
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.
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
24 #include "wine/port.h"
34 #include "dinput_private.h"
35 #include "device_private.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(dinput
);
41 #define WINE_DINPUT_KEYBOARD_MAX_KEYS 256
43 static const IDirectInputDevice8WVtbl SysKeyboardWvt
;
45 typedef struct SysKeyboardImpl SysKeyboardImpl
;
46 struct SysKeyboardImpl
48 struct IDirectInputDeviceImpl base
;
49 BYTE DInputKeyState
[WINE_DINPUT_KEYBOARD_MAX_KEYS
];
53 static inline SysKeyboardImpl
*impl_from_IDirectInputDevice8W(IDirectInputDevice8W
*iface
)
55 return CONTAINING_RECORD(CONTAINING_RECORD(iface
, IDirectInputDeviceImpl
, IDirectInputDevice8W_iface
), SysKeyboardImpl
, base
);
58 static BYTE
map_dik_code(DWORD scanCode
, DWORD vkCode
, DWORD subType
, DWORD version
)
60 if (!scanCode
&& version
< 0x0800)
61 scanCode
= MapVirtualKeyW(vkCode
, MAPVK_VK_TO_VSC
);
63 if (subType
== DIDEVTYPEKEYBOARD_JAPAN106
)
68 scanCode
= DIK_CIRCUMFLEX
;
74 scanCode
= DIK_LBRACKET
;
79 case 0x29: /* Hankaku/Zenkaku */
83 scanCode
= DIK_RBRACKET
;
86 scanCode
= DIK_BACKSLASH
;
93 int dinput_keyboard_hook( IDirectInputDevice8W
*iface
, WPARAM wparam
, LPARAM lparam
)
95 SysKeyboardImpl
*This
= impl_from_IDirectInputDevice8W( iface
);
96 int dik_code
, ret
= This
->base
.dwCoopLevel
& DISCL_EXCLUSIVE
;
97 KBDLLHOOKSTRUCT
*hook
= (KBDLLHOOKSTRUCT
*)lparam
;
100 if (wparam
!= WM_KEYDOWN
&& wparam
!= WM_KEYUP
&&
101 wparam
!= WM_SYSKEYDOWN
&& wparam
!= WM_SYSKEYUP
)
104 TRACE("(%p) wp %08lx, lp %08lx, vk %02x, scan %02x\n",
105 iface
, wparam
, lparam
, hook
->vkCode
, hook
->scanCode
);
107 switch (hook
->vkCode
)
109 /* R-Shift is special - it is an extended key with separate scan code */
110 case VK_RSHIFT
: dik_code
= DIK_RSHIFT
; break;
111 case VK_PAUSE
: dik_code
= DIK_PAUSE
; break;
112 case VK_NUMLOCK
: dik_code
= DIK_NUMLOCK
; break;
113 case VK_SUBTRACT
: dik_code
= DIK_SUBTRACT
; break;
115 dik_code
= map_dik_code(hook
->scanCode
& 0xff, hook
->vkCode
, This
->subtype
, This
->base
.dinput
->dwVersion
);
116 if (hook
->flags
& LLKHF_EXTENDED
) dik_code
|= 0x80;
118 new_diks
= hook
->flags
& LLKHF_UP
? 0 : 0x80;
120 /* returns now if key event already known */
121 if (new_diks
== This
->DInputKeyState
[dik_code
])
124 This
->DInputKeyState
[dik_code
] = new_diks
;
125 TRACE(" setting %02X to %02X\n", dik_code
, This
->DInputKeyState
[dik_code
]);
127 EnterCriticalSection(&This
->base
.crit
);
128 queue_event(iface
, DIDFT_MAKEINSTANCE(dik_code
) | DIDFT_PSHBUTTON
,
129 new_diks
, GetCurrentTime(), This
->base
.dinput
->evsequence
++);
130 LeaveCriticalSection(&This
->base
.crit
);
135 static DWORD
get_keyboard_subtype(void)
137 DWORD kbd_type
, kbd_subtype
, dev_subtype
;
138 kbd_type
= GetKeyboardType(0);
139 kbd_subtype
= GetKeyboardType(1);
141 if (kbd_type
== 4 || (kbd_type
== 7 && kbd_subtype
== 0))
142 dev_subtype
= DIDEVTYPEKEYBOARD_PCENH
;
143 else if (kbd_type
== 7 && kbd_subtype
== 2)
144 dev_subtype
= DIDEVTYPEKEYBOARD_JAPAN106
;
146 FIXME("Unknown keyboard type=%u, subtype=%u\n", kbd_type
, kbd_subtype
);
147 dev_subtype
= DIDEVTYPEKEYBOARD_PCENH
;
152 static void fill_keyboard_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi
, DWORD version
, DWORD subtype
) {
154 DIDEVICEINSTANCEW ddi
;
156 dwSize
= lpddi
->dwSize
;
158 TRACE("%d %p\n", dwSize
, lpddi
);
160 memset(lpddi
, 0, dwSize
);
161 memset(&ddi
, 0, sizeof(ddi
));
164 ddi
.guidInstance
= GUID_SysKeyboard
;/* DInput's GUID */
165 ddi
.guidProduct
= GUID_SysKeyboard
;
166 if (version
>= 0x0800)
167 ddi
.dwDevType
= DI8DEVTYPE_KEYBOARD
| (subtype
<< 8);
169 ddi
.dwDevType
= DIDEVTYPE_KEYBOARD
| (subtype
<< 8);
170 MultiByteToWideChar(CP_ACP
, 0, "Keyboard", -1, ddi
.tszInstanceName
, MAX_PATH
);
171 MultiByteToWideChar(CP_ACP
, 0, "Wine Keyboard", -1, ddi
.tszProductName
, MAX_PATH
);
173 memcpy(lpddi
, &ddi
, (dwSize
< sizeof(ddi
) ? dwSize
: sizeof(ddi
)));
176 static HRESULT
keyboarddev_enum_device(DWORD dwDevType
, DWORD dwFlags
, LPDIDEVICEINSTANCEW lpddi
, DWORD version
, int id
)
181 if (dwFlags
& DIEDFL_FORCEFEEDBACK
)
184 if ((dwDevType
== 0) ||
185 ((dwDevType
== DIDEVTYPE_KEYBOARD
) && (version
< 0x0800)) ||
186 (((dwDevType
== DI8DEVCLASS_KEYBOARD
) || (dwDevType
== DI8DEVTYPE_KEYBOARD
)) && (version
>= 0x0800))) {
187 TRACE("Enumerating the Keyboard device\n");
189 fill_keyboard_dideviceinstanceW(lpddi
, version
, get_keyboard_subtype());
197 static HRESULT
alloc_device( REFGUID rguid
, IDirectInputImpl
*dinput
, SysKeyboardImpl
**out
)
199 SysKeyboardImpl
* newDevice
;
200 LPDIDATAFORMAT df
= NULL
;
204 if (FAILED(hr
= direct_input_device_alloc( sizeof(SysKeyboardImpl
), &SysKeyboardWvt
, rguid
, dinput
, (void **)&newDevice
)))
206 newDevice
->base
.crit
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": SysKeyboardImpl*->base.crit");
208 newDevice
->subtype
= get_keyboard_subtype();
210 /* Create copy of default data format */
211 if (!(df
= HeapAlloc(GetProcessHeap(), 0, c_dfDIKeyboard
.dwSize
))) goto failed
;
212 memcpy(df
, &c_dfDIKeyboard
, c_dfDIKeyboard
.dwSize
);
213 if (!(df
->rgodf
= HeapAlloc(GetProcessHeap(), 0, df
->dwNumObjs
* df
->dwObjSize
))) goto failed
;
215 for (i
= 0; i
< df
->dwNumObjs
; i
++)
220 if (!GetKeyNameTextA(((i
& 0x7f) << 16) | ((i
& 0x80) << 17), buf
, sizeof(buf
)))
223 dik_code
= map_dik_code(i
, 0, newDevice
->subtype
, dinput
->dwVersion
);
224 memcpy(&df
->rgodf
[idx
], &c_dfDIKeyboard
.rgodf
[dik_code
], df
->dwObjSize
);
225 df
->rgodf
[idx
++].dwType
= DIDFT_MAKEINSTANCE(dik_code
) | DIDFT_PSHBUTTON
;
229 newDevice
->base
.data_format
.wine_df
= df
;
235 if (df
) HeapFree(GetProcessHeap(), 0, df
->rgodf
);
236 HeapFree(GetProcessHeap(), 0, df
);
237 HeapFree(GetProcessHeap(), 0, newDevice
);
238 return DIERR_OUTOFMEMORY
;
241 static HRESULT
keyboarddev_create_device( IDirectInputImpl
*dinput
, REFGUID rguid
, IDirectInputDevice8W
**out
)
243 TRACE( "%p %s %p\n", dinput
, debugstr_guid( rguid
), out
);
246 if (IsEqualGUID(&GUID_SysKeyboard
, rguid
)) /* Wine Keyboard */
248 SysKeyboardImpl
*This
;
251 if (FAILED(hr
= alloc_device( rguid
, dinput
, &This
))) return hr
;
253 TRACE( "Created a Keyboard device (%p)\n", This
);
255 *out
= &This
->base
.IDirectInputDevice8W_iface
;
259 return DIERR_DEVICENOTREG
;
262 const struct dinput_device keyboard_device
= {
263 "Wine keyboard driver",
264 keyboarddev_enum_device
,
265 keyboarddev_create_device
268 static HRESULT WINAPI
SysKeyboardWImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface
, DWORD len
, LPVOID ptr
)
270 SysKeyboardImpl
*This
= impl_from_IDirectInputDevice8W(iface
);
271 TRACE("(%p)->(%d,%p)\n", This
, len
, ptr
);
273 if (!This
->base
.acquired
) return DIERR_NOTACQUIRED
;
275 if (len
!= This
->base
.data_format
.user_df
->dwDataSize
)
276 return DIERR_INVALIDPARAM
;
278 check_dinput_events();
280 EnterCriticalSection(&This
->base
.crit
);
282 if (TRACE_ON(dinput
)) {
284 for (i
= 0; i
< WINE_DINPUT_KEYBOARD_MAX_KEYS
; i
++) {
285 if (This
->DInputKeyState
[i
] != 0x00)
286 TRACE(" - %02X: %02x\n", i
, This
->DInputKeyState
[i
]);
290 fill_DataFormat(ptr
, len
, This
->DInputKeyState
, &This
->base
.data_format
);
291 LeaveCriticalSection(&This
->base
.crit
);
296 /******************************************************************************
297 * GetCapabilities : get the device capabilities
299 static HRESULT WINAPI
SysKeyboardWImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface
, LPDIDEVCAPS lpDIDevCaps
)
301 SysKeyboardImpl
*This
= impl_from_IDirectInputDevice8W(iface
);
304 TRACE("(this=%p,%p)\n",This
,lpDIDevCaps
);
306 if ((lpDIDevCaps
->dwSize
!= sizeof(DIDEVCAPS
)) && (lpDIDevCaps
->dwSize
!= sizeof(DIDEVCAPS_DX3
))) {
307 WARN("invalid parameter\n");
308 return DIERR_INVALIDPARAM
;
311 devcaps
.dwSize
= lpDIDevCaps
->dwSize
;
312 devcaps
.dwFlags
= DIDC_ATTACHED
| DIDC_EMULATED
;
313 if (This
->base
.dinput
->dwVersion
>= 0x0800)
314 devcaps
.dwDevType
= DI8DEVTYPE_KEYBOARD
| (This
->subtype
<< 8);
316 devcaps
.dwDevType
= DIDEVTYPE_KEYBOARD
| (This
->subtype
<< 8);
318 devcaps
.dwButtons
= This
->base
.data_format
.wine_df
->dwNumObjs
;
320 devcaps
.dwFFSamplePeriod
= 0;
321 devcaps
.dwFFMinTimeResolution
= 0;
322 devcaps
.dwFirmwareRevision
= 100;
323 devcaps
.dwHardwareRevision
= 100;
324 devcaps
.dwFFDriverVersion
= 0;
326 memcpy(lpDIDevCaps
, &devcaps
, lpDIDevCaps
->dwSize
);
331 static DWORD
map_dik_to_scan(DWORD dik_code
, DWORD subtype
)
333 if (dik_code
== DIK_PAUSE
|| dik_code
== DIK_NUMLOCK
) dik_code
^= 0x80;
334 if (subtype
== DIDEVTYPEKEYBOARD_JAPAN106
)
365 /******************************************************************************
366 * GetObjectInfo : get information about a device object such as a button
369 static HRESULT WINAPI
SysKeyboardWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface
,
370 LPDIDEVICEOBJECTINSTANCEW pdidoi
,
374 SysKeyboardImpl
*This
= impl_from_IDirectInputDevice8W(iface
);
378 res
= IDirectInputDevice2WImpl_GetObjectInfo(iface
, pdidoi
, dwObj
, dwHow
);
379 if (res
!= DI_OK
) return res
;
381 scan
= map_dik_to_scan(DIDFT_GETINSTANCE(pdidoi
->dwType
), This
->subtype
);
382 if (!GetKeyNameTextW((scan
& 0x80) << 17 | (scan
& 0x7f) << 16,
383 pdidoi
->tszName
, ARRAY_SIZE(pdidoi
->tszName
)))
384 return DIERR_OBJECTNOTFOUND
;
386 _dump_OBJECTINSTANCEW(pdidoi
);
390 /******************************************************************************
391 * GetDeviceInfo : get information about a device's identity
393 static HRESULT WINAPI
SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface
, LPDIDEVICEINSTANCEW pdidi
)
395 SysKeyboardImpl
*This
= impl_from_IDirectInputDevice8W(iface
);
396 TRACE("(this=%p,%p)\n", This
, pdidi
);
398 if (pdidi
->dwSize
!= sizeof(DIDEVICEINSTANCEW
)) {
399 WARN(" dinput3 not supported yet...\n");
403 fill_keyboard_dideviceinstanceW(pdidi
, This
->base
.dinput
->dwVersion
, This
->subtype
);
408 /******************************************************************************
409 * GetProperty : Retrieves information about the input device.
411 static HRESULT WINAPI
SysKeyboardWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface
,
412 REFGUID rguid
, LPDIPROPHEADER pdiph
)
414 SysKeyboardImpl
*This
= impl_from_IDirectInputDevice8W(iface
);
416 TRACE("(%p)->(%s,%p)\n", This
, debugstr_guid(rguid
), pdiph
);
417 _dump_DIPROPHEADER(pdiph
);
419 if (!IS_DIPROP(rguid
)) return DI_OK
;
421 switch (LOWORD(rguid
))
423 case (DWORD_PTR
)DIPROP_KEYNAME
:
426 LPDIPROPSTRING ps
= (LPDIPROPSTRING
)pdiph
;
427 DIDEVICEOBJECTINSTANCEW didoi
;
429 if (pdiph
->dwSize
!= sizeof(DIPROPSTRING
))
430 return DIERR_INVALIDPARAM
;
432 didoi
.dwSize
= sizeof(DIDEVICEOBJECTINSTANCEW
);
434 hr
= SysKeyboardWImpl_GetObjectInfo(iface
, &didoi
, ps
->diph
.dwObj
, ps
->diph
.dwHow
);
436 memcpy(ps
->wsz
, didoi
.tszName
, sizeof(ps
->wsz
));
439 case (DWORD_PTR
) DIPROP_VIDPID
:
440 case (DWORD_PTR
) DIPROP_RANGE
:
441 return DIERR_UNSUPPORTED
;
443 return IDirectInputDevice2WImpl_GetProperty( iface
, rguid
, pdiph
);
448 static HRESULT WINAPI
SysKeyboardWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface
)
450 SysKeyboardImpl
*This
= impl_from_IDirectInputDevice8W(iface
);
453 TRACE("(%p)\n", This
);
455 res
= IDirectInputDevice2WImpl_Acquire(iface
);
458 TRACE("clearing keystate\n");
459 memset(This
->DInputKeyState
, 0, sizeof(This
->DInputKeyState
));
465 static HRESULT WINAPI
SysKeyboardWImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface
,
466 LPDIACTIONFORMATW lpdiaf
,
467 LPCWSTR lpszUserName
,
470 SysKeyboardImpl
*This
= impl_from_IDirectInputDevice8W(iface
);
471 FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This
, lpdiaf
, debugstr_w(lpszUserName
), dwFlags
);
473 return _build_action_map(iface
, lpdiaf
, lpszUserName
, dwFlags
, DIKEYBOARD_MASK
, &c_dfDIKeyboard
);
476 static HRESULT WINAPI
SysKeyboardWImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface
,
477 LPDIACTIONFORMATW lpdiaf
,
478 LPCWSTR lpszUserName
,
481 SysKeyboardImpl
*This
= impl_from_IDirectInputDevice8W(iface
);
482 FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This
, lpdiaf
, debugstr_w(lpszUserName
), dwFlags
);
484 return _set_action_map(iface
, lpdiaf
, lpszUserName
, dwFlags
, &c_dfDIKeyboard
);
487 static const IDirectInputDevice8WVtbl SysKeyboardWvt
=
489 IDirectInputDevice2WImpl_QueryInterface
,
490 IDirectInputDevice2WImpl_AddRef
,
491 IDirectInputDevice2WImpl_Release
,
492 SysKeyboardWImpl_GetCapabilities
,
493 IDirectInputDevice2WImpl_EnumObjects
,
494 SysKeyboardWImpl_GetProperty
,
495 IDirectInputDevice2WImpl_SetProperty
,
496 SysKeyboardWImpl_Acquire
,
497 IDirectInputDevice2WImpl_Unacquire
,
498 SysKeyboardWImpl_GetDeviceState
,
499 IDirectInputDevice2WImpl_GetDeviceData
,
500 IDirectInputDevice2WImpl_SetDataFormat
,
501 IDirectInputDevice2WImpl_SetEventNotification
,
502 IDirectInputDevice2WImpl_SetCooperativeLevel
,
503 SysKeyboardWImpl_GetObjectInfo
,
504 SysKeyboardWImpl_GetDeviceInfo
,
505 IDirectInputDevice2WImpl_RunControlPanel
,
506 IDirectInputDevice2WImpl_Initialize
,
507 IDirectInputDevice2WImpl_CreateEffect
,
508 IDirectInputDevice2WImpl_EnumEffects
,
509 IDirectInputDevice2WImpl_GetEffectInfo
,
510 IDirectInputDevice2WImpl_GetForceFeedbackState
,
511 IDirectInputDevice2WImpl_SendForceFeedbackCommand
,
512 IDirectInputDevice2WImpl_EnumCreatedEffectObjects
,
513 IDirectInputDevice2WImpl_Escape
,
514 IDirectInputDevice2WImpl_Poll
,
515 IDirectInputDevice2WImpl_SendDeviceData
,
516 IDirectInputDevice7WImpl_EnumEffectsInFile
,
517 IDirectInputDevice7WImpl_WriteEffectToFile
,
518 SysKeyboardWImpl_BuildActionMap
,
519 SysKeyboardWImpl_SetActionMap
,
520 IDirectInputDevice8WImpl_GetImageInfo