- Made sure const LP were actually const in dinput.h.
[wine/wine64.git] / dlls / dinput / keyboard / main.c
blobc2f56eee16da48e73697bb8c69855d04be64ad8e
1 /* DirectInput Keyboard device
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include <string.h>
23 #ifdef HAVE_SYS_ERRNO_H
24 # include <sys/errno.h>
25 #endif
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "dinput.h"
32 #include "dinput_private.h"
33 #include "device_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
38 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt;
39 static ICOM_VTABLE(IDirectInputDevice7A) SysKeyboard7Avt;
41 typedef struct SysKeyboardAImpl SysKeyboardAImpl;
42 struct SysKeyboardAImpl
44 /* IDirectInputDevice2AImpl */
45 ICOM_VFIELD(IDirectInputDevice2A);
46 DWORD ref;
47 GUID guid;
49 IDirectInputAImpl *dinput;
51 HANDLE hEvent;
52 /* SysKeyboardAImpl */
53 int acquired;
54 int buffersize; /* set in 'SetProperty' */
55 LPDIDEVICEOBJECTDATA buffer; /* buffer for 'GetDeviceData'.
56 Alloc at 'Acquire', Free at
57 'Unacquire' */
58 int count; /* number of objects in use in
59 'buffer' */
60 int start; /* 'buffer' rotates. This is the
61 first in use (if count > 0) */
62 BOOL overflow; /* return DI_BUFFEROVERFLOW in
63 'GetDeviceData' */
64 CRITICAL_SECTION crit;
67 SysKeyboardAImpl *current; /* Today's acquired device
68 FIXME: currently this can be only one.
69 Maybe this should be a linked list or st.
70 I don't know what the rules are for multiple acquired keyboards,
71 but 'DI_LOSTFOCUS' and 'DI_UNACQUIRED' exist for a reason.
74 static BYTE DInputKeyState[256]; /* array for 'GetDeviceState' */
76 HHOOK keyboard_hook;
78 LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam )
80 if (code == HC_ACTION)
82 BYTE dik_code;
83 BOOL down;
84 DWORD timestamp;
87 KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam;
88 dik_code = hook->scanCode;
89 if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80;
90 down = !(hook->flags & LLKHF_UP);
91 timestamp = hook->time;
94 DInputKeyState[dik_code] = (down ? 0x80 : 0);
96 if (current != NULL)
98 if (current->hEvent)
99 SetEvent(current->hEvent);
101 if (current->buffer != NULL)
103 int n;
105 EnterCriticalSection(&(current->crit));
107 n = (current->start + current->count) % current->buffersize;
109 current->buffer[n].dwOfs = dik_code;
110 current->buffer[n].dwData = down ? 0x80 : 0;
111 current->buffer[n].dwTimeStamp = timestamp;
112 current->buffer[n].dwSequence = current->dinput->evsequence++;
114 if (current->count == current->buffersize)
116 current->start++;
117 current->overflow = TRUE;
119 else
120 current->count++;
122 LeaveCriticalSection(&(current->crit));
127 return CallNextHookEx(keyboard_hook, code, wparam, lparam);
130 static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
131 0x0ab8648a,
132 0x7735,
133 0x11d2,
134 {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41}
137 static BOOL keyboarddev_enum_device(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi)
139 if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) {
140 TRACE("Enumerating the Keyboard device\n");
142 lpddi->guidInstance = GUID_SysKeyboard;/* DInput's GUID */
143 lpddi->guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */
144 lpddi->dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8);
145 strcpy(lpddi->tszInstanceName, "Keyboard");
146 strcpy(lpddi->tszProductName, "Wine Keyboard");
148 return TRUE;
151 return FALSE;
154 static SysKeyboardAImpl *alloc_device(REFGUID rguid, ICOM_VTABLE(IDirectInputDevice2A) *kvt, IDirectInputAImpl *dinput)
156 SysKeyboardAImpl* newDevice;
157 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardAImpl));
158 newDevice->ref = 1;
159 ICOM_VTBL(newDevice) = kvt;
160 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
161 newDevice->dinput = dinput;
163 return newDevice;
167 static HRESULT keyboarddev_create_device(IDirectInputAImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
169 if ((IsEqualGUID(&GUID_SysKeyboard,rguid)) || /* Generic Keyboard */
170 (IsEqualGUID(&DInput_Wine_Keyboard_GUID,rguid))) { /* Wine Keyboard */
171 if ((riid == NULL) || (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) || (IsEqualGUID(&IID_IDirectInputDevice2A,riid))) {
172 *pdev=(IDirectInputDeviceA*) alloc_device(rguid, &SysKeyboardAvt, dinput);
174 TRACE("Creating a Keyboard device (%p)\n", *pdev);
175 return DI_OK;
176 } else if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) {
177 *pdev=(IDirectInputDeviceA*) alloc_device(rguid, (ICOM_VTABLE(IDirectInputDevice2A) *) &SysKeyboard7Avt, dinput);
179 TRACE("Creating a Keyboard DInput7A device (%p)\n", *pdev);
180 return DI_OK;
181 } else
182 return DIERR_NOINTERFACE;
185 return DIERR_DEVICENOTREG;
188 static dinput_device keyboarddev = {
189 100,
190 keyboarddev_enum_device,
191 keyboarddev_create_device
194 DECL_GLOBAL_CONSTRUCTOR(keyboarddev_register) { dinput_register_device(&keyboarddev); }
196 static HRESULT WINAPI SysKeyboardAImpl_SetProperty(
197 LPDIRECTINPUTDEVICE2A iface,REFGUID rguid,LPCDIPROPHEADER ph
200 ICOM_THIS(SysKeyboardAImpl,iface);
202 TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
203 TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n",
204 ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow);
205 if (!HIWORD(rguid)) {
206 switch ((DWORD)rguid) {
207 case (DWORD) DIPROP_BUFFERSIZE: {
208 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
210 TRACE("(buffersize=%ld)\n",pd->dwData);
212 if (This->acquired)
213 return DIERR_INVALIDPARAM;
215 This->buffersize = pd->dwData;
217 break;
219 default:
220 WARN("Unknown type %ld\n",(DWORD)rguid);
221 break;
224 return 0;
227 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState(
228 LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
231 /* Note: device does not need to be acquired */
232 if (len != 256)
233 return DIERR_INVALIDPARAM;
235 memcpy(ptr, DInputKeyState, 256);
236 return DI_OK;
239 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData(
240 LPDIRECTINPUTDEVICE2A iface,DWORD dodsize,LPDIDEVICEOBJECTDATA dod,
241 LPDWORD entries,DWORD flags
244 ICOM_THIS(SysKeyboardAImpl,iface);
245 int ret = DI_OK, i = 0;
247 TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
248 This,dodsize,dod,entries,entries?*entries:0,flags);
250 if (This->buffer == NULL)
251 return DIERR_NOTBUFFERED;
253 if (dodsize < sizeof(*dod))
254 return DIERR_INVALIDPARAM;
256 EnterCriticalSection(&(This->crit));
258 /* Copy item at a time for the case dodsize > sizeof(buffer[n]) */
259 while ((i < *entries || *entries == INFINITE) && i < This->count)
261 if (dod != NULL)
263 int n = (This->start + i) % This->buffersize;
264 LPDIDEVICEOBJECTDATA pd
265 = (LPDIDEVICEOBJECTDATA)((BYTE *)dod + dodsize * i);
266 pd->dwOfs = This->buffer[n].dwOfs;
267 pd->dwData = This->buffer[n].dwData;
268 pd->dwTimeStamp = This->buffer[n].dwTimeStamp;
269 pd->dwSequence = This->buffer[n].dwSequence;
271 i++;
274 *entries = i;
276 if (This->overflow)
277 ret = DI_BUFFEROVERFLOW;
279 if (!(flags & DIGDD_PEEK))
281 /* Empty buffer */
282 This->count -= i;
283 This->start = (This->start + i) % This->buffersize;
284 This->overflow = FALSE;
287 LeaveCriticalSection(&(This->crit));
289 return ret;
292 static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface);
294 static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
296 ICOM_THIS(SysKeyboardAImpl,iface);
298 TRACE("(this=%p)\n",This);
300 if (This->acquired)
301 return S_FALSE;
303 This->acquired = 1;
305 if (current != NULL)
307 FIXME("Not more than one keyboard can be acquired at the same time.\n");
308 SysKeyboardAImpl_Unacquire(iface);
311 current = This;
313 if (This->buffersize > 0)
315 This->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
316 This->buffersize * sizeof(*(This->buffer)));
317 This->start = 0;
318 This->count = 0;
319 This->overflow = FALSE;
320 InitializeCriticalSection(&(This->crit));
322 else
323 This->buffer = NULL;
325 return DI_OK;
328 static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
330 ICOM_THIS(SysKeyboardAImpl,iface);
331 TRACE("(this=%p)\n",This);
333 if (This->acquired == 0)
334 return DI_NOEFFECT;
336 if (current == This)
337 current = NULL;
338 else
339 ERR("this != current\n");
341 This->acquired = 0;
343 if (This->buffersize >= 0)
345 HeapFree(GetProcessHeap(), 0, This->buffer);
346 This->buffer = NULL;
347 DeleteCriticalSection(&(This->crit));
350 return DI_OK;
353 static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
354 HANDLE hnd) {
355 ICOM_THIS(SysKeyboardAImpl,iface);
357 TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
359 This->hEvent = hnd;
360 return DI_OK;
363 /******************************************************************************
364 * GetCapabilities : get the device capablitites
366 static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities(
367 LPDIRECTINPUTDEVICE2A iface,
368 LPDIDEVCAPS lpDIDevCaps)
370 ICOM_THIS(SysKeyboardAImpl,iface);
372 TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
374 if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
375 lpDIDevCaps->dwFlags = DIDC_ATTACHED;
376 lpDIDevCaps->dwDevType = DIDEVTYPE_KEYBOARD;
377 lpDIDevCaps->dwAxes = 0;
378 lpDIDevCaps->dwButtons = 0;
379 lpDIDevCaps->dwPOVs = 0;
380 lpDIDevCaps->dwFFSamplePeriod = 0;
381 lpDIDevCaps->dwFFMinTimeResolution = 0;
382 lpDIDevCaps->dwFirmwareRevision = 100;
383 lpDIDevCaps->dwHardwareRevision = 100;
384 lpDIDevCaps->dwFFDriverVersion = 0;
385 } else {
386 /* DirectX 3.0 */
387 FIXME("DirectX 3.0 not supported....\n");
390 return DI_OK;
393 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt =
395 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
396 IDirectInputDevice2AImpl_QueryInterface,
397 IDirectInputDevice2AImpl_AddRef,
398 IDirectInputDevice2AImpl_Release,
399 SysKeyboardAImpl_GetCapabilities,
400 IDirectInputDevice2AImpl_EnumObjects,
401 IDirectInputDevice2AImpl_GetProperty,
402 SysKeyboardAImpl_SetProperty,
403 SysKeyboardAImpl_Acquire,
404 SysKeyboardAImpl_Unacquire,
405 SysKeyboardAImpl_GetDeviceState,
406 SysKeyboardAImpl_GetDeviceData,
407 IDirectInputDevice2AImpl_SetDataFormat,
408 SysKeyboardAImpl_SetEventNotification,
409 IDirectInputDevice2AImpl_SetCooperativeLevel,
410 IDirectInputDevice2AImpl_GetObjectInfo,
411 IDirectInputDevice2AImpl_GetDeviceInfo,
412 IDirectInputDevice2AImpl_RunControlPanel,
413 IDirectInputDevice2AImpl_Initialize,
414 IDirectInputDevice2AImpl_CreateEffect,
415 IDirectInputDevice2AImpl_EnumEffects,
416 IDirectInputDevice2AImpl_GetEffectInfo,
417 IDirectInputDevice2AImpl_GetForceFeedbackState,
418 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
419 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
420 IDirectInputDevice2AImpl_Escape,
421 IDirectInputDevice2AImpl_Poll,
422 IDirectInputDevice2AImpl_SendDeviceData
425 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
426 # define XCAST(fun) (typeof(SysKeyboard7Avt.fun))
427 #else
428 # define XCAST(fun) (void*)
429 #endif
431 static ICOM_VTABLE(IDirectInputDevice7A) SysKeyboard7Avt =
433 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
434 XCAST(QueryInterface)IDirectInputDevice2AImpl_QueryInterface,
435 XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
436 XCAST(Release)IDirectInputDevice2AImpl_Release,
437 XCAST(GetCapabilities)SysKeyboardAImpl_GetCapabilities,
438 XCAST(EnumObjects)IDirectInputDevice2AImpl_EnumObjects,
439 XCAST(GetProperty)IDirectInputDevice2AImpl_GetProperty,
440 XCAST(SetProperty)SysKeyboardAImpl_SetProperty,
441 XCAST(Acquire)SysKeyboardAImpl_Acquire,
442 XCAST(Unacquire)SysKeyboardAImpl_Unacquire,
443 XCAST(GetDeviceState)SysKeyboardAImpl_GetDeviceState,
444 XCAST(GetDeviceData)SysKeyboardAImpl_GetDeviceData,
445 XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat,
446 XCAST(SetEventNotification)SysKeyboardAImpl_SetEventNotification,
447 XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
448 XCAST(GetObjectInfo)IDirectInputDevice2AImpl_GetObjectInfo,
449 XCAST(GetDeviceInfo)IDirectInputDevice2AImpl_GetDeviceInfo,
450 XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
451 XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
452 XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
453 XCAST(EnumEffects)IDirectInputDevice2AImpl_EnumEffects,
454 XCAST(GetEffectInfo)IDirectInputDevice2AImpl_GetEffectInfo,
455 XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
456 XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
457 XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
458 XCAST(Escape)IDirectInputDevice2AImpl_Escape,
459 XCAST(Poll)IDirectInputDevice2AImpl_Poll,
460 XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
461 IDirectInputDevice7AImpl_EnumEffectsInFile,
462 IDirectInputDevice7AImpl_WriteEffectToFile
465 #undef XCAST