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( "iface %p, wparam %#Ix, lparam %#Ix, vkCode %#lx, scanCode %#lx.\n", iface
, wparam
,
99 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 INT 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 %d, subtype %d\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 %#lx, flags %#lx, instance %p, version %#lx.\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( struct dinput
*dinput
, const GUID
*guid
, IDirectInputDevice8W
**out
)
169 struct keyboard
*impl
;
171 TRACE( "dinput %p, guid %s, out %p.\n", dinput
, debugstr_guid( guid
), out
);
174 if (!IsEqualGUID( &GUID_SysKeyboard
, guid
)) return DIERR_DEVICENOTREG
;
176 if (!(impl
= calloc( 1, sizeof(*impl
) ))) return E_OUTOFMEMORY
;
177 dinput_device_init( &impl
->base
, &keyboard_vtbl
, guid
, dinput
);
178 impl
->base
.crit
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": struct keyboard*->base.crit");
180 keyboard_enum_device( 0, 0, &impl
->base
.instance
, dinput
->dwVersion
);
181 impl
->base
.caps
.dwDevType
= impl
->base
.instance
.dwDevType
;
182 impl
->base
.caps
.dwFirmwareRevision
= 100;
183 impl
->base
.caps
.dwHardwareRevision
= 100;
185 *out
= &impl
->base
.IDirectInputDevice8W_iface
;
189 static HRESULT
keyboard_poll( IDirectInputDevice8W
*iface
)
191 check_dinput_events();
195 static HRESULT
keyboard_acquire( IDirectInputDevice8W
*iface
)
200 static HRESULT
keyboard_unacquire( IDirectInputDevice8W
*iface
)
202 struct keyboard
*impl
= impl_from_IDirectInputDevice8W( iface
);
203 memset( impl
->base
.device_state
, 0, sizeof(impl
->base
.device_state
) );
207 static BOOL
try_enum_object( const DIPROPHEADER
*filter
, DWORD flags
, LPDIENUMDEVICEOBJECTSCALLBACKW callback
,
208 DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
210 if (flags
!= DIDFT_ALL
&& !(flags
& DIDFT_GETTYPE( instance
->dwType
))) return DIENUM_CONTINUE
;
212 switch (filter
->dwHow
)
215 return callback( instance
, data
);
217 if (filter
->dwObj
!= instance
->dwOfs
) return DIENUM_CONTINUE
;
218 return callback( instance
, data
);
220 if ((filter
->dwObj
& 0x00ffffff) != (instance
->dwType
& 0x00ffffff)) return DIENUM_CONTINUE
;
221 return callback( instance
, data
);
224 return DIENUM_CONTINUE
;
227 static HRESULT
keyboard_enum_objects( IDirectInputDevice8W
*iface
, const DIPROPHEADER
*filter
,
228 DWORD flags
, LPDIENUMDEVICEOBJECTSCALLBACKW callback
, void *context
)
230 struct keyboard
*impl
= impl_from_IDirectInputDevice8W( iface
);
231 BYTE subtype
= GET_DIDEVICE_SUBTYPE( impl
->base
.instance
.dwDevType
);
232 DIDEVICEOBJECTINSTANCEW instance
=
234 .dwSize
= sizeof(DIDEVICEOBJECTINSTANCEW
),
235 .guidType
= GUID_Key
,
237 .dwType
= DIDFT_PSHBUTTON
| DIDFT_MAKEINSTANCE( DIK_ESCAPE
),
242 for (i
= 0; i
< 512; ++i
)
244 if (!GetKeyNameTextW( i
<< 16, instance
.tszName
, ARRAY_SIZE(instance
.tszName
) )) continue;
245 if (!(dik
= map_dik_code( i
, 0, subtype
, impl
->base
.dinput
->dwVersion
))) continue;
246 instance
.dwOfs
= dik
;
247 instance
.dwType
= DIDFT_PSHBUTTON
| DIDFT_MAKEINSTANCE( dik
);
248 ret
= try_enum_object( filter
, flags
, callback
, &instance
, context
);
249 if (ret
!= DIENUM_CONTINUE
) return DIENUM_STOP
;
252 return DIENUM_CONTINUE
;
255 static HRESULT
keyboard_get_property( IDirectInputDevice8W
*iface
, DWORD property
,
256 DIPROPHEADER
*header
, const DIDEVICEOBJECTINSTANCEW
*instance
)
260 case (DWORD_PTR
)DIPROP_KEYNAME
:
262 DIPROPSTRING
*value
= (DIPROPSTRING
*)header
;
263 lstrcpynW( value
->wsz
, instance
->tszName
, ARRAY_SIZE(value
->wsz
) );
267 return DIERR_UNSUPPORTED
;
270 static const struct dinput_device_vtbl keyboard_vtbl
=
277 keyboard_enum_objects
,
278 keyboard_get_property
,