Quake II RTX doxygen  1.0 dev
dinput.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 2003-2006 Andrey Nazarov
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 //
20 // win_dinput.c - DirectInput 7 mouse driver
21 //
22 
23 #include "client.h"
24 
25 #define DIRECTINPUT_VERSION 0x0700
26 #include <dinput.h>
27 
28 #ifndef DIDFT_OPTIONAL
29 #define DIDFT_OPTIONAL 0x80000000
30 #endif
31 
32 static HMODULE hDirectInput;
33 
34 typedef HRESULT(WINAPI *LPDIRECTINPUTCREATE)(HINSTANCE, DWORD, LPDIRECTINPUT *, LPUNKNOWN);
35 
37 
38 static grab_t di_grabbed; // qfalse when not focus app
39 static qboolean di_initialized;
40 static LPDIRECTINPUT di;
41 static LPDIRECTINPUTDEVICE di_mouse;
42 
43 #define DEFINE_STATIC_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
44  static const GUID _##name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
45 
46 DEFINE_STATIC_GUID(GUID_SysMouse, 0x6F1D2B60, 0xD5A0, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
47 DEFINE_STATIC_GUID(GUID_XAxis, 0xA36D02E0, 0xC9F3, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
48 DEFINE_STATIC_GUID(GUID_YAxis, 0xA36D02E1, 0xC9F3, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
49 DEFINE_STATIC_GUID(GUID_ZAxis, 0xA36D02E2, 0xC9F3, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
50 
51 static const DIOBJECTDATAFORMAT mouseObjectDataFormat[] = {
52  { &_GUID_XAxis, DIMOFS_X, DIDFT_RELAXIS | DIDFT_ANYINSTANCE, 0 },
53  { &_GUID_YAxis, DIMOFS_Y, DIDFT_RELAXIS | DIDFT_ANYINSTANCE, 0 },
54  { &_GUID_ZAxis, DIMOFS_Z, DIDFT_RELAXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
55  { NULL, DIMOFS_BUTTON0, DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
56  { NULL, DIMOFS_BUTTON1, DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
57  { NULL, DIMOFS_BUTTON2, DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
58  { NULL, DIMOFS_BUTTON3, DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
59  { NULL, DIMOFS_BUTTON4, DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
60  { NULL, DIMOFS_BUTTON5, DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
61  { NULL, DIMOFS_BUTTON6, DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
62  { NULL, DIMOFS_BUTTON7, DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 }
63 };
64 
65 static const DIDATAFORMAT mouseDataFormat = {
66  sizeof(DIDATAFORMAT),
67  sizeof(DIOBJECTDATAFORMAT),
68  DIDF_RELAXIS,
69  sizeof(DIMOUSESTATE2),
70  q_countof(mouseObjectDataFormat),
71  (LPDIOBJECTDATAFORMAT)mouseObjectDataFormat
72 };
73 
74 static const DIPROPDWORD mouseBufferSize = {
75  {
76  sizeof(DIPROPDWORD),
77  sizeof(DIPROPHEADER),
78  0,
79  DIPH_DEVICE
80  },
81  32
82 };
83 
84 /*
85 ===========
86 DI_GetMouseEvents
87 ===========
88 */
89 static void DI_GetMouseEvents(void)
90 {
91  DIDEVICEOBJECTDATA data[16];
92  LPDIDEVICEOBJECTDATA p, last;
93  DWORD numElements, button;
94  int value;
95  HRESULT hr;
96 
97  if (di_grabbed != IN_GRAB) {
98  return;
99  }
100 
101  do {
102  numElements = 16;
103  hr = IDirectInputDevice_GetDeviceData(di_mouse, sizeof(data[0]), data, &numElements, 0);
104  if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) {
105  IDirectInputDevice_Acquire(di_mouse);
106  return;
107  }
108  if (FAILED(hr)) {
109  Com_EPrintf("GetDeviceData failed with error 0x%lX\n", hr);
110  return;
111  }
112  last = data + numElements;
113  for (p = data; p < last; p++) {
114  switch (p->dwOfs) {
115  case DIMOFS_BUTTON0:
116  case DIMOFS_BUTTON1:
117  case DIMOFS_BUTTON2:
118  case DIMOFS_BUTTON3:
119  case DIMOFS_BUTTON4:
120  case DIMOFS_BUTTON5:
121  case DIMOFS_BUTTON6:
122  case DIMOFS_BUTTON7:
123  button = p->dwOfs - DIMOFS_BUTTON0;
124  if (p->dwData & 0x80) {
125  Key_Event(K_MOUSE1 + button, qtrue, p->dwTimeStamp);
126  } else {
127  Key_Event(K_MOUSE1 + button, qfalse, p->dwTimeStamp);
128  }
129  break;
130  case DIMOFS_Z:
131  value = p->dwData;
132  if (!value) {
133  break;
134  }
135  if (value > 0) {
136  Key_Event(K_MWHEELUP, qtrue, p->dwTimeStamp);
137  Key_Event(K_MWHEELUP, qfalse, p->dwTimeStamp);
138  } else {
139  Key_Event(K_MWHEELDOWN, qtrue, p->dwTimeStamp);
140  Key_Event(K_MWHEELDOWN, qfalse, p->dwTimeStamp);
141  }
142  break;
143  default:
144  break;
145  }
146  }
147  } while (hr == DI_BUFFEROVERFLOW);
148 }
149 
150 /*
151 ===========
152 DI_GetMouseMotion
153 ===========
154 */
155 static qboolean DI_GetMouseMotion(int *dx, int *dy)
156 {
157  DIMOUSESTATE2 state;
158  HRESULT hr;
159 
160  if (di_grabbed != IN_GRAB) {
161  return qfalse;
162  }
163 
164  hr = IDirectInputDevice_GetDeviceState(di_mouse, sizeof(state), &state);
165  if (FAILED(hr)) {
166  Com_EPrintf("GetDeviceState failed with error 0x%lX\n", hr);
167  return qfalse;
168  }
169 
170  *dx = state.lX;
171  *dy = state.lY;
172  return qtrue;
173 }
174 
175 /*
176 ===========
177 DI_ShutdownMouse
178 ===========
179 */
180 static void DI_ShutdownMouse(void)
181 {
182  Com_Printf("Shutting down DirectInput\n");
183 
184  if (di_mouse) {
185  if (di_grabbed) {
186  IDirectInputDevice_Unacquire(di_mouse);
187  }
188  IDirectInputDevice_Release(di_mouse);
189  di_mouse = NULL;
190  }
191  if (di) {
192  IDirectInput_Release(di);
193  di = NULL;
194  }
195  di_grabbed = qfalse;
196  di_initialized = qfalse;
197 
198 }
199 
200 /*
201 ===========
202 DI_StartupMouse
203 ===========
204 */
205 static qboolean DI_InitMouse(void)
206 {
207  HRESULT hr;
208 
209  if (!win.wnd) {
210  return qfalse;
211  }
212 
213  Com_Printf("Initializing DirectInput\n");
214 
215  if (!hDirectInput) {
216  hDirectInput = LoadLibrary("dinput.dll");
217  if (!hDirectInput) {
218  Com_EPrintf("Failed to load dinput.dll\n");
219  return qfalse;
220  }
221 
223  GetProcAddress(hDirectInput, "DirectInputCreateA");
224  if (!pDirectInputCreate) {
225  Com_EPrintf("Failed to obtain DirectInputCreate\n");
226  goto fail;
227  }
228  }
229 
231  if (FAILED(hr)) {
232  Com_EPrintf("DirectInputCreate failed with error 0x%lX\n", hr);
233  goto fail;
234  }
235 
236  hr = IDirectInput_CreateDevice(di, &_GUID_SysMouse, &di_mouse, NULL);
237  if (FAILED(hr)) {
238  Com_EPrintf("CreateDevice failed with error 0x%lX\n", hr);
239  goto fail;
240  }
241 
242  hr = IDirectInputDevice_SetDataFormat(di_mouse, &mouseDataFormat);
243  if (FAILED(hr)) {
244  Com_EPrintf("SetDataFormat failed with error 0x%lX\n", hr);
245  goto fail;
246  }
247 
248  hr = IDirectInputDevice_SetCooperativeLevel(di_mouse, win.wnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
249  if (FAILED(hr)) {
250  Com_EPrintf("SetCooperativeLevel failed with error 0x%lX\n", hr);
251  goto fail;
252  }
253 
254  hr = IDirectInputDevice_SetProperty(di_mouse, DIPROP_BUFFERSIZE, &mouseBufferSize.diph);
255  if (FAILED(hr)) {
256  Com_EPrintf("SetProperty failed with error 0x%lX\n", hr);
257  goto fail;
258  }
259 
260  di_initialized = qtrue;
261 
262  return qtrue;
263 
264 fail:
265  if (di_mouse) {
266  IDirectInputDevice_Release(di_mouse);
267  di_mouse = NULL;
268  }
269  if (di) {
270  IDirectInput_Release(di);
271  di = NULL;
272  }
273  return qfalse;
274 }
275 
276 /*
277 ===========
278 DI_GrabMouse
279 ===========
280 */
281 static void DI_GrabMouse(grab_t grab)
282 {
283  HRESULT hr;
284 
285  if (!di_initialized) {
286  return;
287  }
288 
289  if (di_grabbed == grab) {
290  return;
291  }
292 
293  if (grab == IN_GRAB) {
294  Com_DPrintf("IDirectInputDevice_Acquire\n");
295  hr = IDirectInputDevice_Acquire(di_mouse);
296  if (FAILED(hr)) {
297  Com_EPrintf("Failed to acquire mouse, error 0x%lX\n", hr);
298  }
299  } else {
300  Com_DPrintf("IDirectInputDevice_Unacquire\n");
301  hr = IDirectInputDevice_Unacquire(di_mouse);
302  if (FAILED(hr)) {
303  Com_EPrintf("Failed to unacquire mouse, error 0x%lX\n", hr);
304  }
305  }
306 
307  di_grabbed = grab;
308 
309 }
310 
311 /*
312 @@@@@@@@@@@@@@@@@@@
313 DI_FillAPI
314 @@@@@@@@@@@@@@@@@@@
315 */
316 void DI_FillAPI(inputAPI_t *api)
317 {
318  api->Init = DI_InitMouse;
319  api->Shutdown = DI_ShutdownMouse;
320  api->Grab = DI_GrabMouse;
321  api->GetEvents = DI_GetMouseEvents;
322  api->GetMotion = DI_GetMouseMotion;
323 }
324 
DEFINE_STATIC_GUID
#define DEFINE_STATIC_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
Definition: dinput.c:43
DIRECTINPUT_VERSION
#define DIRECTINPUT_VERSION
Definition: dinput.c:25
mouseBufferSize
static const DIPROPDWORD mouseBufferSize
Definition: dinput.c:74
LPDIRECTINPUTCREATE
HRESULT(WINAPI * LPDIRECTINPUTCREATE)(HINSTANCE, DWORD, LPDIRECTINPUT *, LPUNKNOWN)
Definition: dinput.c:34
mouseObjectDataFormat
static const DIOBJECTDATAFORMAT mouseObjectDataFormat[]
Definition: dinput.c:51
hGlobalInstance
HINSTANCE hGlobalInstance
Definition: system.c:28
di_mouse
static LPDIRECTINPUTDEVICE di_mouse
Definition: dinput.c:41
client.h
di_grabbed
static grab_t di_grabbed
Definition: dinput.c:38
DI_GrabMouse
static void DI_GrabMouse(grab_t grab)
Definition: dinput.c:281
di
static LPDIRECTINPUT di
Definition: dinput.c:40
DI_GetMouseMotion
static qboolean DI_GetMouseMotion(int *dx, int *dy)
Definition: dinput.c:155
di_initialized
static qboolean di_initialized
Definition: dinput.c:39
mouseDataFormat
static const DIDATAFORMAT mouseDataFormat
Definition: dinput.c:65
Key_Event
void Key_Event(unsigned key, qboolean down, unsigned time)
Definition: keys.c:627
DI_FillAPI
void DI_FillAPI(inputAPI_t *api)
Definition: dinput.c:316
DI_ShutdownMouse
static void DI_ShutdownMouse(void)
Definition: dinput.c:180
hDirectInput
static HMODULE hDirectInput
Definition: dinput.c:32
pDirectInputCreate
static LPDIRECTINPUTCREATE pDirectInputCreate
Definition: dinput.c:36
DIDFT_OPTIONAL
#define DIDFT_OPTIONAL
Definition: dinput.c:29
DI_InitMouse
static qboolean DI_InitMouse(void)
Definition: dinput.c:205
win
win_state_t win
Definition: client.c:33
DI_GetMouseEvents
static void DI_GetMouseEvents(void)
Definition: dinput.c:89