Better implementation of GetCalendarInfo{A,W}, not perfect.
[wine] / dlls / dinput / keyboard / main.c
1 /*              DirectInput Keyboard device
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include <string.h>
23 #ifdef HAVE_SYS_ERRNO_H
24 # include <sys/errno.h>
25 #endif
26
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "dinput.h"
31
32 #include "dinput_private.h"
33 #include "device_private.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
37
38 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt;
39 static ICOM_VTABLE(IDirectInputDevice7A) SysKeyboard7Avt;
40
41 typedef struct SysKeyboardAImpl SysKeyboardAImpl;
42 struct SysKeyboardAImpl
43 {
44         /* IDirectInputDevice2AImpl */
45         ICOM_VFIELD(IDirectInputDevice2A);
46         DWORD                           ref;
47         GUID                            guid;
48
49         IDirectInputAImpl *dinput;
50         
51         HANDLE  hEvent; 
52         HHOOK hook;
53         /* SysKeyboardAImpl */
54         BYTE                            keystate[256];
55         int                             acquired;
56 };
57
58 static SysKeyboardAImpl* current_lock = NULL;
59
60 static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
61   0x0ab8648a,
62   0x7735,
63   0x11d2,
64   {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41}
65 };
66
67 static BOOL keyboarddev_enum_device(DWORD dwDevType, DWORD dwFlags, LPCDIDEVICEINSTANCEA lpddi)
68 {
69   if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) {
70     TRACE("Enumerating the Keyboard device\n");
71     
72     lpddi->guidInstance = GUID_SysKeyboard;/* DInput's GUID */
73     lpddi->guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */
74     lpddi->dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8);
75     strcpy(lpddi->tszInstanceName, "Keyboard");
76     strcpy(lpddi->tszProductName, "Wine Keyboard");
77     
78     return TRUE;
79   }
80
81   return FALSE;
82 }
83
84 static SysKeyboardAImpl *alloc_device(REFGUID rguid, ICOM_VTABLE(IDirectInputDevice2A) *kvt, IDirectInputAImpl *dinput)
85 {
86     SysKeyboardAImpl* newDevice;
87     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardAImpl));
88     newDevice->ref = 1;
89     ICOM_VTBL(newDevice) = kvt;
90     memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
91     memset(newDevice->keystate,0,256);
92     newDevice->dinput = dinput;
93
94     return newDevice;
95 }
96
97
98 static HRESULT keyboarddev_create_device(IDirectInputAImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
99 {
100   if ((IsEqualGUID(&GUID_SysKeyboard,rguid)) ||          /* Generic Keyboard */
101       (IsEqualGUID(&DInput_Wine_Keyboard_GUID,rguid))) { /* Wine Keyboard */
102     if ((riid == NULL) || (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) || (IsEqualGUID(&IID_IDirectInputDevice2A,riid))) {
103       *pdev=(IDirectInputDeviceA*) alloc_device(rguid, &SysKeyboardAvt, dinput);
104     
105       TRACE("Creating a Keyboard device (%p)\n", *pdev);
106       return DI_OK;
107     } else if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) {
108       *pdev=(IDirectInputDeviceA*) alloc_device(rguid, (ICOM_VTABLE(IDirectInputDevice2A) *) &SysKeyboard7Avt, dinput);
109     
110       TRACE("Creating a Keyboard DInput7A device (%p)\n", *pdev);
111       return DI_OK;
112     } else
113       return DIERR_NOINTERFACE;
114   }
115
116   return DIERR_DEVICENOTREG;
117 }
118
119 static dinput_device keyboarddev = {
120   100,
121   keyboarddev_enum_device,
122   keyboarddev_create_device
123 };
124
125 DECL_GLOBAL_CONSTRUCTOR(keyboarddev_register) { dinput_register_device(&keyboarddev); }
126
127 static HRESULT WINAPI SysKeyboardAImpl_SetProperty(
128         LPDIRECTINPUTDEVICE2A iface,REFGUID rguid,LPCDIPROPHEADER ph
129 )
130 {
131         ICOM_THIS(SysKeyboardAImpl,iface);
132
133         TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
134         TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n",
135             ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow);
136         if (!HIWORD(rguid)) {
137                 switch ((DWORD)rguid) {
138                 case (DWORD) DIPROP_BUFFERSIZE: {
139                         LPCDIPROPDWORD  pd = (LPCDIPROPDWORD)ph;
140
141                         TRACE("(buffersize=%ld)\n",pd->dwData);
142                         break;
143                 }
144                 default:
145                         WARN("Unknown type %ld\n",(DWORD)rguid);
146                         break;
147                 }
148         }
149         return 0;
150 }
151
152 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState(
153         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
154 )
155 {
156     DWORD i;
157
158     memset( ptr, 0, len );
159     if (len != 256)
160     {
161         WARN("whoops, got len %ld?\n", len);
162         return DI_OK;
163     }
164     for (i = 0; i < 0x80; i++)
165     {
166         WORD vkey = MapVirtualKeyA( i, 1 );
167         if (vkey && (GetAsyncKeyState( vkey ) & 0x8000))
168         {
169             ((LPBYTE)ptr)[i] = 0x80;
170             ((LPBYTE)ptr)[i | 0x80] = 0x80;
171         }
172     }
173     return DI_OK;
174 }
175
176 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData(
177         LPDIRECTINPUTDEVICE2A iface,DWORD dodsize,LPDIDEVICEOBJECTDATA dod,
178         LPDWORD entries,DWORD flags
179 )
180 {
181         ICOM_THIS(SysKeyboardAImpl,iface);
182         int i, n;
183
184         TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
185               This,dodsize,dod,entries,entries?*entries:0,flags);
186
187
188         for (i = n = 0; (i < 0x80) && (n < *entries); i++)
189         {
190             WORD state, vkey = MapVirtualKeyA( i, 1 );
191             if (!vkey) continue;
192             state = (GetAsyncKeyState( vkey ) >> 8) & 0x80;
193             if (state != This->keystate[vkey])
194             {
195                 if (dod)
196                 {
197                     /* add an entry */
198                     dod[n].dwOfs       = i; /* scancode */
199                     dod[n].dwData      = state;
200                     dod[n].dwTimeStamp = GetCurrentTime(); /* umm */
201                     dod[n].dwSequence  = This->dinput->evsequence++;
202                     n++;
203                 }
204                 if (!(flags & DIGDD_PEEK)) This->keystate[vkey] = state;
205             }
206         }
207         if (n) TRACE_(dinput)("%d entries\n",n);
208         *entries = n;
209         return DI_OK;
210 }
211
212 static LRESULT CALLBACK dinput_keyboard_hook(int code, WPARAM wparam, LPARAM lparam)
213 {
214         SysKeyboardAImpl *This = current_lock;
215         if (This && This->hEvent)
216                 SetEvent(This->hEvent);
217         return 1;
218 }
219
220 static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
221 {
222         ICOM_THIS(SysKeyboardAImpl,iface);
223         
224         TRACE("(this=%p)\n",This);
225         
226         if (This->acquired == 0) {
227           This->acquired = 1;
228         }
229         
230         This->hook = SetWindowsHookExW(WH_KEYBOARD, dinput_keyboard_hook, 0, 0);
231         return DI_OK;
232 }
233
234 static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
235 {
236         ICOM_THIS(SysKeyboardAImpl,iface);
237         TRACE("(this=%p)\n",This);
238
239         if (This->acquired == 1) {
240           This->acquired = 0;
241           UnhookWindowsHookEx( This->hook );
242         } else {
243           ERR("Unacquiring a not-acquired device !!!\n");
244         }
245
246         return DI_OK;
247 }
248
249 /******************************************************************************
250   *     GetCapabilities : get the device capablitites
251   */
252 static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
253                                                          HANDLE hnd) {
254   ICOM_THIS(SysKeyboardAImpl,iface);
255
256   TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
257
258   This->hEvent = hnd;
259   current_lock = This;
260   return DI_OK;
261 }
262
263 static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities(
264         LPDIRECTINPUTDEVICE2A iface,
265         LPDIDEVCAPS lpDIDevCaps)
266 {
267   ICOM_THIS(SysKeyboardAImpl,iface);
268
269   TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
270
271   if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
272     lpDIDevCaps->dwFlags = DIDC_ATTACHED;
273     lpDIDevCaps->dwDevType = DIDEVTYPE_KEYBOARD;
274     lpDIDevCaps->dwAxes = 0;
275     lpDIDevCaps->dwButtons = 0;
276     lpDIDevCaps->dwPOVs = 0;
277     lpDIDevCaps->dwFFSamplePeriod = 0;
278     lpDIDevCaps->dwFFMinTimeResolution = 0;
279     lpDIDevCaps->dwFirmwareRevision = 100;
280     lpDIDevCaps->dwHardwareRevision = 100;
281     lpDIDevCaps->dwFFDriverVersion = 0;
282   } else {
283     /* DirectX 3.0 */
284     FIXME("DirectX 3.0 not supported....\n");
285   }
286   
287   return DI_OK;
288 }
289
290 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt = 
291 {
292         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
293         IDirectInputDevice2AImpl_QueryInterface,
294         IDirectInputDevice2AImpl_AddRef,
295         IDirectInputDevice2AImpl_Release,
296         SysKeyboardAImpl_GetCapabilities,
297         IDirectInputDevice2AImpl_EnumObjects,
298         IDirectInputDevice2AImpl_GetProperty,
299         SysKeyboardAImpl_SetProperty,
300         SysKeyboardAImpl_Acquire,
301         SysKeyboardAImpl_Unacquire,
302         SysKeyboardAImpl_GetDeviceState,
303         SysKeyboardAImpl_GetDeviceData,
304         IDirectInputDevice2AImpl_SetDataFormat,
305         SysKeyboardAImpl_SetEventNotification,
306         IDirectInputDevice2AImpl_SetCooperativeLevel,
307         IDirectInputDevice2AImpl_GetObjectInfo,
308         IDirectInputDevice2AImpl_GetDeviceInfo,
309         IDirectInputDevice2AImpl_RunControlPanel,
310         IDirectInputDevice2AImpl_Initialize,
311         IDirectInputDevice2AImpl_CreateEffect,
312         IDirectInputDevice2AImpl_EnumEffects,
313         IDirectInputDevice2AImpl_GetEffectInfo,
314         IDirectInputDevice2AImpl_GetForceFeedbackState,
315         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
316         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
317         IDirectInputDevice2AImpl_Escape,
318         IDirectInputDevice2AImpl_Poll,
319         IDirectInputDevice2AImpl_SendDeviceData
320 };
321
322 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
323 # define XCAST(fun)     (typeof(SysKeyboard7Avt.fun))
324 #else
325 # define XCAST(fun)     (void*)
326 #endif
327
328 static ICOM_VTABLE(IDirectInputDevice7A) SysKeyboard7Avt = 
329 {
330         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
331         XCAST(QueryInterface)IDirectInputDevice2AImpl_QueryInterface,
332         XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
333         XCAST(Release)IDirectInputDevice2AImpl_Release,
334         XCAST(GetCapabilities)SysKeyboardAImpl_GetCapabilities,
335         XCAST(EnumObjects)IDirectInputDevice2AImpl_EnumObjects,
336         XCAST(GetProperty)IDirectInputDevice2AImpl_GetProperty,
337         XCAST(SetProperty)SysKeyboardAImpl_SetProperty,
338         XCAST(Acquire)SysKeyboardAImpl_Acquire,
339         XCAST(Unacquire)SysKeyboardAImpl_Unacquire,
340         XCAST(GetDeviceState)SysKeyboardAImpl_GetDeviceState,
341         XCAST(GetDeviceData)SysKeyboardAImpl_GetDeviceData,
342         XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat,
343         XCAST(SetEventNotification)SysKeyboardAImpl_SetEventNotification,
344         XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
345         XCAST(GetObjectInfo)IDirectInputDevice2AImpl_GetObjectInfo,
346         XCAST(GetDeviceInfo)IDirectInputDevice2AImpl_GetDeviceInfo,
347         XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
348         XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
349         XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
350         XCAST(EnumEffects)IDirectInputDevice2AImpl_EnumEffects,
351         XCAST(GetEffectInfo)IDirectInputDevice2AImpl_GetEffectInfo,
352         XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
353         XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
354         XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
355         XCAST(Escape)IDirectInputDevice2AImpl_Escape,
356         XCAST(Poll)IDirectInputDevice2AImpl_Poll,
357         XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
358         IDirectInputDevice7AImpl_EnumEffectsInFile,
359         IDirectInputDevice7AImpl_WriteEffectToFile
360 };
361
362 #undef XCAST