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