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
31 #include "dinput_private.h"
32 #include "device_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(dinput
);
37 static const struct dinput_device_vtbl keyboard_vtbl
;
41 struct dinput_device base
;
44 static inline struct keyboard
*impl_from_IDirectInputDevice8W( IDirectInputDevice8W
*iface
)
46 return CONTAINING_RECORD( CONTAINING_RECORD( iface
, struct dinput_device
, IDirectInputDevice8W_iface
),
47 struct keyboard
, base
);
50 static BYTE
map_dik_code(DWORD scanCode
, DWORD vkCode
, DWORD subType
, DWORD version
)
52 if (!scanCode
&& version
< 0x0800)
53 scanCode
= MapVirtualKeyW(vkCode
, MAPVK_VK_TO_VSC
);
55 if (subType
== DIDEVTYPEKEYBOARD_JAPAN106
)
60 scanCode
= DIK_CIRCUMFLEX
;
66 scanCode
= DIK_LBRACKET
;
71 case 0x29: /* Hankaku/Zenkaku */
75 scanCode
= DIK_RBRACKET
;
78 scanCode
= DIK_BACKSLASH
;
82 if (scanCode
& 0x100) scanCode
|= 0x80;
83 return (BYTE
)scanCode
;
86 int dinput_keyboard_hook( IDirectInputDevice8W
*iface
, WPARAM wparam
, LPARAM lparam
)
88 struct keyboard
*impl
= impl_from_IDirectInputDevice8W( iface
);
89 BYTE new_diks
, subtype
= GET_DIDEVICE_SUBTYPE( impl
->base
.instance
.dwDevType
);
90 int dik_code
, ret
= impl
->base
.dwCoopLevel
& DISCL_EXCLUSIVE
;
91 KBDLLHOOKSTRUCT
*hook
= (KBDLLHOOKSTRUCT
*)lparam
;
94 if (wparam
!= WM_KEYDOWN
&& wparam
!= WM_KEYUP
&&
95 wparam
!= WM_SYSKEYDOWN
&& wparam
!= WM_SYSKEYUP
)
98 TRACE("(%p) wp %08lx, lp %08lx, vk %02x, scan %02x\n",
99 iface
, wparam
, lparam
, hook
->vkCode
, hook
->scanCode
);
101 switch (hook
->vkCode
)
103 /* R-Shift is special - it is an extended key with separate scan code */
104 case VK_RSHIFT
: dik_code
= DIK_RSHIFT
; break;
105 case VK_PAUSE
: dik_code
= DIK_PAUSE
; break;
106 case VK_NUMLOCK
: dik_code
= DIK_NUMLOCK
; break;
107 case VK_SUBTRACT
: dik_code
= DIK_SUBTRACT
; break;
109 scan_code
= hook
->scanCode
& 0xff;
110 if (hook
->flags
& LLKHF_EXTENDED
) scan_code
|= 0x100;
111 dik_code
= map_dik_code( scan_code
, hook
->vkCode
, subtype
, impl
->base
.dinput
->dwVersion
);
113 new_diks
= hook
->flags
& LLKHF_UP
? 0 : 0x80;
115 /* returns now if key event already known */
116 if (new_diks
== impl
->base
.device_state
[dik_code
]) return ret
;
118 impl
->base
.device_state
[dik_code
] = new_diks
;
119 TRACE( " setting key %02x to %02x\n", dik_code
, impl
->base
.device_state
[dik_code
] );
121 EnterCriticalSection( &impl
->base
.crit
);
122 queue_event( iface
, DIDFT_MAKEINSTANCE( dik_code
) | DIDFT_PSHBUTTON
, new_diks
,
123 GetCurrentTime(), impl
->base
.dinput
->evsequence
++ );
124 if (impl
->base
.hEvent
) SetEvent( impl
->base
.hEvent
);
125 LeaveCriticalSection( &impl
->base
.crit
);
130 static DWORD
get_keyboard_subtype(void)
132 DWORD kbd_type
, kbd_subtype
, dev_subtype
;
133 kbd_type
= GetKeyboardType(0);
134 kbd_subtype
= GetKeyboardType(1);
136 if (kbd_type
== 4 || (kbd_type
== 7 && kbd_subtype
== 0))
137 dev_subtype
= DIDEVTYPEKEYBOARD_PCENH
;
138 else if (kbd_type
== 7 && kbd_subtype
== 2)
139 dev_subtype
= DIDEVTYPEKEYBOARD_JAPAN106
;
141 FIXME("Unknown keyboard type=%u, subtype=%u\n", kbd_type
, kbd_subtype
);
142 dev_subtype
= DIDEVTYPEKEYBOARD_PCENH
;
147 HRESULT
keyboard_enum_device( DWORD type
, DWORD flags
, DIDEVICEINSTANCEW
*instance
, DWORD version
)
149 BYTE subtype
= get_keyboard_subtype();
152 TRACE( "type %#x, flags %#x, instance %p, version %#04x\n", type
, flags
, instance
, version
);
154 size
= instance
->dwSize
;
155 memset( instance
, 0, size
);
156 instance
->dwSize
= size
;
157 instance
->guidInstance
= GUID_SysKeyboard
;
158 instance
->guidProduct
= GUID_SysKeyboard
;
159 if (version
>= 0x0800) instance
->dwDevType
= DI8DEVTYPE_KEYBOARD
| (subtype
<< 8);
160 else instance
->dwDevType
= DIDEVTYPE_KEYBOARD
| (subtype
<< 8);
161 MultiByteToWideChar( CP_ACP
, 0, "Keyboard", -1, instance
->tszInstanceName
, MAX_PATH
);
162 MultiByteToWideChar( CP_ACP
, 0, "Wine Keyboard", -1, instance
->tszProductName
, MAX_PATH
);
167 HRESULT
keyboard_create_device( IDirectInputImpl
*dinput
, const GUID
*guid
, IDirectInputDevice8W
**out
)
169 struct keyboard
*impl
;
172 TRACE( "dinput %p, guid %s, out %p\n", dinput
, debugstr_guid( guid
), out
);
175 if (!IsEqualGUID( &GUID_SysKeyboard
, guid
)) return DIERR_DEVICENOTREG
;
177 if (FAILED(hr
= dinput_device_alloc( sizeof(struct keyboard
), &keyboard_vtbl
, guid
, dinput
, (void **)&impl
)))
179 impl
->base
.crit
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": struct keyboard*->base.crit");
181 keyboard_enum_device( 0, 0, &impl
->base
.instance
, dinput
->dwVersion
);
182 impl
->base
.caps
.dwDevType
= impl
->base
.instance
.dwDevType
;
183 impl
->base
.caps
.dwFirmwareRevision
= 100;
184 impl
->base
.caps
.dwHardwareRevision
= 100;
186 if (FAILED(hr
= dinput_device_init( &impl
->base
.IDirectInputDevice8W_iface
)))
188 IDirectInputDevice_Release( &impl
->base
.IDirectInputDevice8W_iface
);
192 *out
= &impl
->base
.IDirectInputDevice8W_iface
;
196 static HRESULT
keyboard_poll( IDirectInputDevice8W
*iface
)
198 check_dinput_events();
202 static HRESULT
keyboard_acquire( IDirectInputDevice8W
*iface
)
207 static HRESULT
keyboard_unacquire( IDirectInputDevice8W
*iface
)
209 struct keyboard
*impl
= impl_from_IDirectInputDevice8W( iface
);
210 memset( impl
->base
.device_state
, 0, sizeof(impl
->base
.device_state
) );
214 static BOOL
try_enum_object( const DIPROPHEADER
*filter
, DWORD flags
, LPDIENUMDEVICEOBJECTSCALLBACKW callback
,
215 DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
217 if (flags
!= DIDFT_ALL
&& !(flags
& DIDFT_GETTYPE( instance
->dwType
))) return DIENUM_CONTINUE
;
219 switch (filter
->dwHow
)
222 return callback( instance
, data
);
224 if (filter
->dwObj
!= instance
->dwOfs
) return DIENUM_CONTINUE
;
225 return callback( instance
, data
);
227 if ((filter
->dwObj
& 0x00ffffff) != (instance
->dwType
& 0x00ffffff)) return DIENUM_CONTINUE
;
228 return callback( instance
, data
);
231 return DIENUM_CONTINUE
;
234 static HRESULT
keyboard_enum_objects( IDirectInputDevice8W
*iface
, const DIPROPHEADER
*filter
,
235 DWORD flags
, LPDIENUMDEVICEOBJECTSCALLBACKW callback
, void *context
)
237 struct keyboard
*impl
= impl_from_IDirectInputDevice8W( iface
);
238 BYTE subtype
= GET_DIDEVICE_SUBTYPE( impl
->base
.instance
.dwDevType
);
239 DIDEVICEOBJECTINSTANCEW instance
=
241 .dwSize
= sizeof(DIDEVICEOBJECTINSTANCEW
),
242 .guidType
= GUID_Key
,
244 .dwType
= DIDFT_PSHBUTTON
| DIDFT_MAKEINSTANCE( DIK_ESCAPE
),
249 for (i
= 0; i
< 512; ++i
)
251 if (!GetKeyNameTextW( i
<< 16, instance
.tszName
, ARRAY_SIZE(instance
.tszName
) )) continue;
252 if (!(dik
= map_dik_code( i
, 0, subtype
, impl
->base
.dinput
->dwVersion
))) continue;
253 instance
.dwOfs
= dik
;
254 instance
.dwType
= DIDFT_PSHBUTTON
| DIDFT_MAKEINSTANCE( dik
);
255 ret
= try_enum_object( filter
, flags
, callback
, &instance
, context
);
256 if (ret
!= DIENUM_CONTINUE
) return DIENUM_STOP
;
259 return DIENUM_CONTINUE
;
262 static HRESULT
keyboard_get_property( IDirectInputDevice8W
*iface
, DWORD property
,
263 DIPROPHEADER
*header
, const DIDEVICEOBJECTINSTANCEW
*instance
)
267 case (DWORD_PTR
)DIPROP_KEYNAME
:
269 DIPROPSTRING
*value
= (DIPROPSTRING
*)header
;
270 lstrcpynW( value
->wsz
, instance
->tszName
, ARRAY_SIZE(value
->wsz
) );
274 return DIERR_UNSUPPORTED
;
277 static const struct dinput_device_vtbl keyboard_vtbl
=
284 keyboard_enum_objects
,
285 keyboard_get_property
,