Properly #define sipx_node for FreeBSD.
[wine] / dlls / dinput / dinput_main.c
1 /*              DirectInput
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  * Copyright 2000-2002 TransGaming Technologies Inc.
6  *
7  *
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.
12  *
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.
17  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 /* Status:
23  *
24  * - Tomb Raider 2 Demo:
25  *   Playable using keyboard only.
26  * - WingCommander Prophecy Demo:
27  *   Doesn't get Input Focus.
28  *
29  * - Fallout : works great in X and DGA mode
30  */
31
32 #include "config.h"
33 #include <assert.h>
34 #include <string.h>
35
36 #include "wine/debug.h"
37 #include "winbase.h"
38 #include "winuser.h"
39 #include "winerror.h"
40 #include "windef.h"
41 #include "dinput_private.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
44
45 static ICOM_VTABLE(IDirectInput7A) ddi7avt;
46 static ICOM_VTABLE(IDirectInput8A) ddi8avt;
47
48 /* This array will be filled a dinput.so loading */
49 #define MAX_WINE_DINPUT_DEVICES 4
50 static dinput_device * dinput_devices[MAX_WINE_DINPUT_DEVICES];
51 static int nrof_dinput_devices = 0;
52
53 HINSTANCE DINPUT_instance = NULL;
54
55 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv)
56 {
57     switch(reason)
58     {
59       case DLL_PROCESS_ATTACH:
60         DINPUT_instance = inst;
61         keyboard_hook = SetWindowsHookExW( WH_KEYBOARD_LL, KeyboardCallback, inst, 0 );
62         break;
63       case DLL_PROCESS_DETACH:
64         UnhookWindowsHookEx(keyboard_hook);
65         break;
66     }
67     return TRUE;
68 }
69
70
71 /* register a direct draw driver. We better not use malloc for we are in
72  * the ELF startup initialisation at this point.
73  */
74 void dinput_register_device(dinput_device *device) {
75     int i;
76
77     /* insert according to priority */
78     for (i=0;i<nrof_dinput_devices;i++) {
79         if (dinput_devices[i]->pref <= device->pref) {
80             memcpy(dinput_devices+i+1,dinput_devices+i,sizeof(dinput_devices[0])*(nrof_dinput_devices-i));
81             dinput_devices[i] = device;
82             break;
83         }
84     }
85     if (i==nrof_dinput_devices) /* not found, or too low priority */
86         dinput_devices[nrof_dinput_devices] = device;
87
88     nrof_dinput_devices++;
89
90     /* increase MAX_DDRAW_DRIVERS if the line below triggers */
91     assert(nrof_dinput_devices <= MAX_WINE_DINPUT_DEVICES);
92 }
93
94 /******************************************************************************
95  *      DirectInputCreateEx (DINPUT.@)
96  */
97 HRESULT WINAPI DirectInputCreateEx(
98         HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI,
99         LPUNKNOWN punkOuter
100 ) {
101         IDirectInputAImpl* This;
102
103         TRACE("(0x%08lx,%04lx,%s,%p,%p)\n",
104                 (DWORD)hinst,dwVersion,debugstr_guid(riid),ppDI,punkOuter
105         );
106         if (IsEqualGUID(&IID_IDirectInputA,riid) ||
107             IsEqualGUID(&IID_IDirectInput2A,riid) ||
108             IsEqualGUID(&IID_IDirectInput7A,riid)) {
109           This = (IDirectInputAImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputAImpl));
110           This->lpVtbl = &ddi7avt;
111           This->ref = 1;
112           *ppDI = This;
113
114           return DI_OK;
115         }
116
117
118         if (IsEqualGUID(&IID_IDirectInput8A,riid)) {
119           This = (IDirectInputAImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputAImpl));
120           This->lpVtbl = &ddi8avt;
121           This->ref = 1;
122           *ppDI = This;
123
124           return DI_OK;
125         }
126
127         return DIERR_OLDDIRECTINPUTVERSION;
128 }
129
130 /******************************************************************************
131  *      DirectInputCreateA (DINPUT.@)
132  */
133 HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
134 {
135         IDirectInputAImpl* This;
136         TRACE("(0x%08lx,%04lx,%p,%p)\n",
137                 (DWORD)hinst,dwVersion,ppDI,punkOuter
138         );
139         This = (IDirectInputAImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputAImpl));
140         This->lpVtbl = &ddi7avt;
141         This->ref = 1;
142         *ppDI=(IDirectInputA*)This;
143         return 0;
144
145 }
146 /******************************************************************************
147  *      IDirectInputA_EnumDevices
148  */
149 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
150         LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
151         LPVOID pvRef, DWORD dwFlags
152 )
153 {
154         ICOM_THIS(IDirectInputAImpl,iface);
155         DIDEVICEINSTANCEA devInstance;
156         int i;
157
158         TRACE("(this=%p,0x%04lx,%p,%p,%04lx)\n", This, dwDevType, lpCallback, pvRef, dwFlags);
159
160         for (i = 0; i < nrof_dinput_devices; i++) {
161           if (dinput_devices[i]->enum_device(dwDevType, dwFlags, &devInstance)) {
162             devInstance.dwSize = sizeof(devInstance);
163             if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
164               return 0;
165           }
166         }
167
168         return 0;
169 }
170
171 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(
172         LPDIRECTINPUT7A iface,REFIID riid,LPVOID *ppobj
173 ) {
174         ICOM_THIS(IDirectInputAImpl,iface);
175
176         TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
177         if (IsEqualGUID(&IID_IUnknown,riid) ||
178             IsEqualGUID(&IID_IDirectInputA,riid) ||
179             IsEqualGUID(&IID_IDirectInput2A,riid) ||
180             IsEqualGUID(&IID_IDirectInput7A,riid)) {
181                 IDirectInputA_AddRef(iface);
182                 *ppobj = This;
183                 return 0;
184         }
185         TRACE("Unsupported interface !\n");
186         return E_FAIL;
187 }
188
189 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface)
190 {
191         ICOM_THIS(IDirectInputAImpl,iface);
192         return ++(This->ref);
193 }
194
195 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface)
196 {
197         ICOM_THIS(IDirectInputAImpl,iface);
198         if (!(--This->ref)) {
199                 HeapFree(GetProcessHeap(),0,This);
200                 return 0;
201         }
202         return This->ref;
203 }
204
205 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(
206         LPDIRECTINPUT7A iface,REFGUID rguid,LPDIRECTINPUTDEVICEA* pdev,
207         LPUNKNOWN punk
208 ) {
209         ICOM_THIS(IDirectInputAImpl,iface);
210         HRESULT ret_value = DIERR_DEVICENOTREG;
211         int i;
212
213         TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk);
214
215         /* Loop on all the devices to see if anyone matches the given GUID */
216         for (i = 0; i < nrof_dinput_devices; i++) {
217           HRESULT ret;
218           if ((ret = dinput_devices[i]->create_device(This, rguid, NULL, pdev)) == DI_OK)
219             return DI_OK;
220
221           if (ret == DIERR_NOINTERFACE)
222             ret_value = DIERR_NOINTERFACE;
223         }
224
225         return ret_value;
226 }
227
228 static HRESULT WINAPI IDirectInputAImpl_Initialize(
229         LPDIRECTINPUT7A iface,HINSTANCE hinst,DWORD x
230 ) {
231         return DIERR_ALREADYINITIALIZED;
232 }
233
234 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface,
235                                                         REFGUID rguid) {
236   ICOM_THIS(IDirectInputAImpl,iface);
237
238   FIXME("(%p)->(%s): stub\n",This,debugstr_guid(rguid));
239
240   return DI_OK;
241 }
242
243 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface,
244                                                         HWND hwndOwner,
245                                                         DWORD dwFlags) {
246   ICOM_THIS(IDirectInputAImpl,iface);
247   FIXME("(%p)->(%08lx,%08lx): stub\n",This, (DWORD) hwndOwner, dwFlags);
248
249   return DI_OK;
250 }
251
252 static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
253                                                     LPCSTR pszName, LPGUID pguidInstance) {
254   ICOM_THIS(IDirectInputAImpl,iface);
255   FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance);
256
257   return DI_OK;
258 }
259
260 static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid,
261                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
262 {
263   ICOM_THIS(IDirectInputAImpl,iface);
264   HRESULT ret_value = DIERR_DEVICENOTREG;
265   int i;
266
267   TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
268
269   /* Loop on all the devices to see if anyone matches the given GUID */
270   for (i = 0; i < nrof_dinput_devices; i++) {
271     HRESULT ret;
272     if ((ret = dinput_devices[i]->create_device(This, rguid, riid, (LPDIRECTINPUTDEVICEA*) pvOut)) == DI_OK)
273       return DI_OK;
274
275     if (ret == DIERR_NOINTERFACE)
276       ret_value = DIERR_NOINTERFACE;
277   }
278
279   return ret_value;
280 }
281
282 static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(
283       LPDIRECTINPUT8A iface,REFIID riid,LPVOID *ppobj
284 ) {
285       ICOM_THIS(IDirectInputAImpl,iface);
286
287       TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
288       if (IsEqualGUID(&IID_IUnknown,riid) ||
289           IsEqualGUID(&IID_IDirectInput8A,riid)) {
290               IDirectInputA_AddRef(iface);
291               *ppobj = This;
292               return 0;
293       }
294       TRACE("Unsupported interface !\n");
295       return E_FAIL;
296 }
297
298 static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
299       LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat,
300       LPDIENUMDEVICESBYSEMANTICSCBA lpCallback,
301       LPVOID pvRef, DWORD dwFlags
302 )
303 {
304       ICOM_THIS(IDirectInputAImpl,iface);
305
306       FIXME("(this=%p,%s,%p,%p,%p,%04lx): stub\n", This, ptszUserName, lpdiActionFormat,
307             lpCallback, pvRef, dwFlags);
308       return 0;
309 }
310
311 static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices(
312       LPDIRECTINPUT8A iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
313       LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
314 )
315 {
316       ICOM_THIS(IDirectInputAImpl,iface);
317
318       FIXME("(this=%p,%p,%p,%04lx,%p): stub\n", This, lpdiCallback, lpdiCDParams,
319             dwFlags, pvRefData);
320       return 0;
321 }
322
323 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
324 # define XCAST(fun)   (typeof(ddi7avt.fun))
325 #else
326 # define XCAST(fun)     (void*)
327 #endif
328
329 static ICOM_VTABLE(IDirectInput7A) ddi7avt = {
330         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
331         XCAST(QueryInterface)IDirectInputAImpl_QueryInterface,
332         XCAST(AddRef)IDirectInputAImpl_AddRef,
333         XCAST(Release)IDirectInputAImpl_Release,
334         XCAST(CreateDevice)IDirectInputAImpl_CreateDevice,
335         XCAST(EnumDevices)IDirectInputAImpl_EnumDevices,
336         XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus,
337         XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel,
338         XCAST(Initialize)IDirectInputAImpl_Initialize,
339         XCAST(FindDevice)IDirectInput2AImpl_FindDevice,
340         IDirectInput7AImpl_CreateDeviceEx
341 };
342 #undef XCAST
343
344 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
345 # define XCAST(fun)     (typeof(ddi8avt.fun))
346 #else
347 # define XCAST(fun)     (void*)
348 #endif
349
350 static ICOM_VTABLE(IDirectInput8A) ddi8avt = {
351         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
352         XCAST(QueryInterface)IDirectInput8AImpl_QueryInterface,
353         XCAST(AddRef)IDirectInputAImpl_AddRef,
354         XCAST(Release)IDirectInputAImpl_Release,
355         XCAST(CreateDevice)IDirectInputAImpl_CreateDevice,
356         XCAST(EnumDevices)IDirectInputAImpl_EnumDevices,
357         XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus,
358         XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel,
359         XCAST(Initialize)IDirectInputAImpl_Initialize,
360         XCAST(FindDevice)IDirectInput2AImpl_FindDevice,
361         IDirectInput8AImpl_EnumDevicesBySemantics,
362         IDirectInput8AImpl_ConfigureDevices
363 };
364 #undef XCAST
365
366 /***********************************************************************
367  *              DllCanUnloadNow (DINPUT.@)
368  */
369 HRESULT WINAPI DINPUT_DllCanUnloadNow(void)
370 {
371     FIXME("(void): stub\n");
372
373     return S_FALSE;
374 }
375
376 /***********************************************************************
377  *              DllGetClassObject (DINPUT.@)
378  */
379 HRESULT WINAPI DINPUT_DllGetClassObject(REFCLSID rclsid, REFIID riid,
380                                         LPVOID *ppv)
381 {
382     FIXME("(%p, %p, %p): stub\n", debugstr_guid(rclsid),
383           debugstr_guid(riid), ppv);
384
385     return CLASS_E_CLASSNOTAVAILABLE;
386 }
387
388 /***********************************************************************
389  *              DllRegisterServer (DINPUT.@)
390  */
391 HRESULT WINAPI DINPUT_DllRegisterServer(void)
392 {
393     FIXME("(void): stub\n");
394
395     return S_OK;
396 }
397
398 /***********************************************************************
399  *              DllUnregisterServer (DINPUT.@)
400  */
401 HRESULT WINAPI DINPUT_DllUnregisterServer(void)
402 {
403     FIXME("(void): stub\n");
404
405     return S_OK;
406 }