2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
32 #include "win_local.h"
35 #define DINPUT_BUFFERSIZE 256
37 #define CHAR_FIRSTREPEAT 200
38 #define CHAR_REPEAT 100
40 typedef struct MYDATA {
41 LONG lX; // X axis goes here
42 LONG lY; // Y axis goes here
43 LONG lZ; // Z axis goes here
44 BYTE bButtonA; // One button goes here
45 BYTE bButtonB; // Another button goes here
46 BYTE bButtonC; // Another button goes here
47 BYTE bButtonD; // Another button goes here
50 static DIOBJECTDATAFORMAT rgodf[] = {
51 { &GUID_XAxis, FIELD_OFFSET(MYDATA, lX), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
52 { &GUID_YAxis, FIELD_OFFSET(MYDATA, lY), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
53 { &GUID_ZAxis, FIELD_OFFSET(MYDATA, lZ), 0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
54 { 0, FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
55 { 0, FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
56 { 0, FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
57 { 0, FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
60 //==========================================================================
62 static const unsigned char s_scantokey[256] = {
65 0, 27, '1', '2', '3', '4', '5', '6',
66 '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0
67 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
68 'o', 'p', '[', ']', K_ENTER,K_CTRL, 'a', 's', // 1
69 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
70 '\'', '`', K_SHIFT, '\\', 'z', 'x', 'c', 'v', // 2
71 'b', 'n', 'm', ',', '.', '/', K_SHIFT, K_KP_STAR,
72 K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
73 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
74 K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
75 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, 0, K_F11,
76 K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
77 0, 0, 0, 0, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0, // 6
79 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0, // 7
82 0, 27, '!', '@', '#', '$', '%', '^',
83 '&', '*', '(', ')', '_', '+', K_BACKSPACE, 9, // 0
84 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
85 'o', 'p', '[', ']', K_ENTER,K_CTRL, 'a', 's', // 1
86 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
87 '\'', '~', K_SHIFT, '\\', 'z', 'x', 'c', 'v', // 2
88 'b', 'n', 'm', ',', '.', '/', K_SHIFT, K_KP_STAR,
89 K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
90 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
91 K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
92 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, 0, K_F11,
93 K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
94 0, 0, 0, 0, 0, 0, 0, 0,
95 0, 0, 0, 0, 0, 0, 0, 0, // 6
96 0, 0, 0, 0, 0, 0, 0, 0,
97 0, 0, 0, 0, 0, 0, 0, 0 // 7
100 static const unsigned char s_scantokey_german[256] = {
103 0, 27, '1', '2', '3', '4', '5', '6',
104 '7', '8', '9', '0', '?', '\'', K_BACKSPACE, 9, // 0
105 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i',
106 'o', 'p', '=', '+', K_ENTER,K_CTRL, 'a', 's', // 1
107 'd', 'f', 'g', 'h', 'j', 'k', 'l', '[',
108 ']', '`', K_SHIFT, '#', 'y', 'x', 'c', 'v', // 2
109 'b', 'n', 'm', ',', '.', '-', K_SHIFT, K_KP_STAR,
110 K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
111 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
112 K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
113 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, '<', K_F11,
114 K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
115 0, 0, 0, 0, 0, 0, 0, 0,
116 0, 0, 0, 0, 0, 0, 0, 0, // 6
117 0, 0, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 0, 0, 0, // 7
120 0, 27, '1', '2', '3', '4', '5', '6',
121 '7', '8', '9', '0', '?', '\'', K_BACKSPACE, 9, // 0
122 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i',
123 'o', 'p', '=', '+', K_ENTER,K_CTRL, 'a', 's', // 1
124 'd', 'f', 'g', 'h', 'j', 'k', 'l', '[',
125 ']', '`', K_SHIFT, '#', 'y', 'x', 'c', 'v', // 2
126 'b', 'n', 'm', ',', '.', '-', K_SHIFT, K_KP_STAR,
127 K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
128 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
129 K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
130 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, '<', K_F11,
131 K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
132 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0, // 6
134 0, 0, 0, 0, 0, 0, 0, 0,
135 0, 0, 0, 0, 0, 0, 0, 0 // 7
138 static const unsigned char s_scantokey_french[256] = {
141 0, 27, '1', '2', '3', '4', '5', '6',
142 '7', '8', '9', '0', ')', '=', K_BACKSPACE, 9, // 0
143 'a', 'z', 'e', 'r', 't', 'y', 'u', 'i',
144 'o', 'p', '^', '$', K_ENTER,K_CTRL, 'q', 's', // 1
145 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm',
146 'ù', '`', K_SHIFT, '*', 'w', 'x', 'c', 'v', // 2
147 'b', 'n', ',', ';', ':', '!', K_SHIFT, K_KP_STAR,
148 K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
149 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
150 K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
151 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, '<', K_F11,
152 K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
153 0, 0, 0, 0, 0, 0, 0, 0,
154 0, 0, 0, 0, 0, 0, 0, 0, // 6
155 0, 0, 0, 0, 0, 0, 0, 0,
156 0, 0, 0, 0, 0, 0, 0, 0, // 7
158 0, 27, '&', 'é', '\"', '\'', '(', '-',
159 'è', '_', 'ç', 'à ', '°', '+', K_BACKSPACE, 9, // 0
160 'a', 'z', 'e', 'r', 't', 'y', 'u', 'i',
161 'o', 'p', '^', '$', K_ENTER,K_CTRL, 'q', 's', // 1
162 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm',
163 'ù', 0, K_SHIFT, '*', 'w', 'x', 'c', 'v', // 2
164 'b', 'n', ',', ';', ':', '!', K_SHIFT, K_KP_STAR,
165 K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
166 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
167 K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
168 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, '<', K_F11,
169 K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
170 0, 0, 0, 0, 0, 0, 0, 0,
171 0, 0, 0, 0, 0, 0, 0, 0, // 6
172 0, 0, 0, 0, 0, 0, 0, 0,
173 0, 0, 0, 0, 0, 0, 0, 0 // 7
176 static const unsigned char s_scantokey_spanish[256] = {
179 0, 27, '1', '2', '3', '4', '5', '6',
180 '7', '8', '9', '0', '\'', '¡', K_BACKSPACE, 9, // 0
181 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
182 'o', 'p', '`', '+', K_ENTER,K_CTRL, 'a', 's', // 1
183 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ñ',
184 '´', 'º', K_SHIFT, 'ç', 'z', 'x', 'c', 'v', // 2
185 'b', 'n', 'm', ',', '.', '-', K_SHIFT, K_KP_STAR,
186 K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
187 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
188 K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
189 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, '<', K_F11,
190 K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
191 0, 0, 0, 0, 0, 0, 0, 0,
192 0, 0, 0, 0, 0, 0, 0, 0, // 6
193 0, 0, 0, 0, 0, 0, 0, 0,
194 0, 0, 0, 0, 0, 0, 0, 0, // 7
196 0, 27, '!', '\"', '·', '$', '%', '&',
197 '/', '(', ')', '=', '?', '¿', K_BACKSPACE, 9, // 0
198 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
199 'o', 'p', '^', '*', K_ENTER,K_CTRL, 'a', 's', // 1
200 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'Ñ',
201 '¨', 'ª', K_SHIFT, 'Ç', 'z', 'x', 'c', 'v', // 2
202 'b', 'n', 'm', ',', '.', '-', K_SHIFT, K_KP_STAR,
203 K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
204 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
205 K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
206 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, '<', K_F11,
207 K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
208 0, 0, 0, 0, 0, 0, 0, 0,
209 0, 0, 0, 0, 0, 0, 0, 0, // 6
210 0, 0, 0, 0, 0, 0, 0, 0,
211 0, 0, 0, 0, 0, 0, 0, 0 // 7
214 static const unsigned char s_scantokey_italian[256] = {
217 0, 27, '1', '2', '3', '4', '5', '6',
218 '7', '8', '9', '0', '\'', 'ì', K_BACKSPACE, 9, // 0
219 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
220 'o', 'p', 'è', '+', K_ENTER,K_CTRL, 'a', 's', // 1
221 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ò',
222 'à ', '\\', K_SHIFT, 'ù', 'z', 'x', 'c', 'v', // 2
223 'b', 'n', 'm', ',', '.', '-', K_SHIFT, K_KP_STAR,
224 K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
225 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
226 K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
227 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, '<', K_F11,
228 K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
229 0, 0, 0, 0, 0, 0, 0, 0,
230 0, 0, 0, 0, 0, 0, 0, 0, // 6
231 0, 0, 0, 0, 0, 0, 0, 0,
232 0, 0, 0, 0, 0, 0, 0, 0, // 7
234 0, 27, '!', '\"', '£', '$', '%', '&',
235 '/', '(', ')', '=', '?', '^', K_BACKSPACE, 9, // 0
236 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
237 'o', 'p', 'é', '*', K_ENTER,K_CTRL, 'a', 's', // 1
238 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ç',
239 '°', '|', K_SHIFT, '§', 'z', 'x', 'c', 'v', // 2
240 'b', 'n', 'm', ',', '.', '-', K_SHIFT, K_KP_STAR,
241 K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
242 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
243 K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
244 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, '<', K_F11,
245 K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
246 0, 0, 0, 0, 0, 0, 0, 0,
247 0, 0, 0, 0, 0, 0, 0, 0, // 6
248 0, 0, 0, 0, 0, 0, 0, 0,
249 0, 0, 0, 0, 0, 0, 0, 0 // 7
254 static const unsigned char *keyScanTable = s_scantokey;
256 // this should be part of the scantables and the scan tables should be 512 bytes
257 // (256 scan codes, shifted and unshifted). Changing everything to use 512 byte
258 // scan tables now might introduce bugs in tested code. Since we only need to fix
259 // the right-alt case for non-US keyboards, we're just using a special-case table
260 // for it. Eventually, the tables above should be fixed to handle all possible
261 // scan codes instead of just the first 128.
262 static unsigned char rightAltKey = K_ALT;
264 #define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0]))
266 static DIDATAFORMAT df = {
267 sizeof(DIDATAFORMAT), // this structure
268 sizeof(DIOBJECTDATAFORMAT), // size of object data format
269 DIDF_RELAXIS, // absolute axis coordinates
270 sizeof(MYDATA), // device data size
271 NUM_OBJECTS, // number of objects
272 rgodf, // and here they are
276 ============================================================
278 DIRECT INPUT KEYBOARD CONTROL
280 ============================================================
283 bool IN_StartupKeyboard( void ) {
288 bool bDisableWindowsKey;
292 common->Printf("keyboard: DirectInput has not been started\n");
296 if (win32.g_pKeyboard) {
297 win32.g_pKeyboard->Release();
298 win32.g_pKeyboard = NULL;
301 // Detrimine where the buffer would like to be allocated
305 bDisableWindowsKey = true;
308 dwCoopFlags = DISCL_EXCLUSIVE;
310 dwCoopFlags = DISCL_NONEXCLUSIVE;
313 dwCoopFlags |= DISCL_FOREGROUND;
315 dwCoopFlags |= DISCL_BACKGROUND;
317 // Disabling the windows key is only allowed only if we are in foreground nonexclusive
318 if( bDisableWindowsKey && !bExclusive && bForeground )
319 dwCoopFlags |= DISCL_NOWINKEY;
321 // Obtain an interface to the system keyboard device.
322 if( FAILED( hr = win32.g_pdi->CreateDevice( GUID_SysKeyboard, &win32.g_pKeyboard, NULL ) ) ) {
323 common->Printf("keyboard: couldn't find a keyboard device\n");
327 // Set the data format to "keyboard format" - a predefined data format
329 // A data format specifies which controls on a device we
330 // are interested in, and how they should be reported.
332 // This tells DirectInput that we will be passing an array
333 // of 256 bytes to IDirectInputDevice::GetDeviceState.
334 if( FAILED( hr = win32.g_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
337 // Set the cooperativity level to let DirectInput know how
338 // this device should interact with the system and with other
339 // DirectInput applications.
340 hr = win32.g_pKeyboard->SetCooperativeLevel( win32.hWnd, dwCoopFlags );
341 if( hr == DIERR_UNSUPPORTED && !bForeground && bExclusive ) {
342 common->Printf("keyboard: SetCooperativeLevel() returned DIERR_UNSUPPORTED.\nFor security reasons, background exclusive keyboard access is not allowed.\n");
351 // IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
353 // DirectInput uses unbuffered I/O (buffer size = 0) by default.
354 // If you want to read buffered data, you need to set a nonzero
357 // Set the buffer size to DINPUT_BUFFERSIZE (defined above) elements.
359 // The buffer size is a DWORD property associated with the device.
362 dipdw.diph.dwSize = sizeof(DIPROPDWORD);
363 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
364 dipdw.diph.dwObj = 0;
365 dipdw.diph.dwHow = DIPH_DEVICE;
366 dipdw.dwData = DINPUT_BUFFERSIZE; // Arbitary buffer size
368 if( FAILED( hr = win32.g_pKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ) ) )
372 // Acquire the newly created device
373 win32.g_pKeyboard->Acquire();
375 common->Printf( "keyboard: DirectInput initialized.\n");
383 Map from windows to quake keynums
385 FIXME: scan code tables should include the upper 128 scan codes instead
386 of having to special-case them here. The current code makes it difficult
387 to special-case conversions for non-US keyboards. Currently the only
388 special-case is for right alt.
391 int IN_DIMapKey (int key) {
418 case DIK_NUMPADENTER:
420 case DIK_NUMPADEQUALS:
446 return K_KP_LEFTARROW;
450 return K_KP_RIGHTARROW;
454 return K_KP_DOWNARROW;
470 return keyScanTable[key];
477 ==========================
478 IN_DeactivateKeyboard
479 ==========================
481 void IN_DeactivateKeyboard( void ) {
482 if (!win32.g_pKeyboard) {
485 win32.g_pKeyboard->Unacquire( );
489 ============================================================
491 DIRECT INPUT MOUSE CONTROL
493 ============================================================
497 ========================
499 ========================
502 void IN_InitDirectInput( void ) {
505 common->Printf( "Initializing DirectInput...\n" );
507 if ( win32.g_pdi != NULL ) {
508 win32.g_pdi->Release(); // if the previous window was destroyed we need to do this
512 // Register with the DirectInput subsystem and get a pointer
513 // to a IDirectInput interface we can use.
514 // Create the base DirectInput object
515 if ( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&win32.g_pdi, NULL ) ) ) {
516 common->Printf ("DirectInputCreate failed\n");
521 ========================
523 ========================
525 bool IN_InitDIMouse( void ) {
528 if ( win32.g_pdi == NULL) {
532 // obtain an interface to the system mouse device.
533 hr = win32.g_pdi->CreateDevice( GUID_SysMouse, &win32.g_pMouse, NULL);
536 common->Printf ("mouse: Couldn't open DI mouse device\n");
540 // Set the data format to "mouse format" - a predefined data format
542 // A data format specifies which controls on a device we
543 // are interested in, and how they should be reported.
545 // This tells DirectInput that we will be passing a
546 // DIMOUSESTATE2 structure to IDirectInputDevice::GetDeviceState.
547 if( FAILED( hr = win32.g_pMouse->SetDataFormat( &c_dfDIMouse2 ) ) ) {
548 common->Printf ("mouse: Couldn't set DI mouse format\n");
552 // set the cooperativity level.
553 hr = win32.g_pMouse->SetCooperativeLevel( win32.hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
556 common->Printf ("mouse: Couldn't set DI coop level\n");
561 // IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
563 // DirectInput uses unbuffered I/O (buffer size = 0) by default.
564 // If you want to read buffered data, you need to set a nonzero
567 // Set the buffer size to SAMPLE_BUFFER_SIZE (defined above) elements.
569 // The buffer size is a DWORD property associated with the device.
571 dipdw.diph.dwSize = sizeof(DIPROPDWORD);
572 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
573 dipdw.diph.dwObj = 0;
574 dipdw.diph.dwHow = DIPH_DEVICE;
575 dipdw.dwData = DINPUT_BUFFERSIZE; // Arbitary buffer size
577 if( FAILED( hr = win32.g_pMouse->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ) ) ) {
578 common->Printf ("mouse: Couldn't set DI buffersize\n");
584 // clear any pending samples
585 Sys_PollMouseInputEvents();
587 common->Printf( "mouse: DirectInput initialized.\n");
593 ==========================
595 ==========================
597 void IN_ActivateMouse( void ) {
601 if ( !win32.in_mouse.GetBool() || win32.mouseGrabbed || !win32.g_pMouse ) {
605 win32.mouseGrabbed = true;
606 for ( i = 0; i < 10; i++ ) {
607 if ( ::ShowCursor( false ) < 0 ) {
612 // we may fail to reacquire if the window has been recreated
613 hr = win32.g_pMouse->Acquire();
618 // set the cooperativity level.
619 hr = win32.g_pMouse->SetCooperativeLevel( win32.hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
623 ==========================
625 ==========================
627 void IN_DeactivateMouse( void ) {
630 if (!win32.g_pMouse || !win32.mouseGrabbed ) {
634 win32.g_pMouse->Unacquire();
636 for ( i = 0; i < 10; i++ ) {
637 if ( ::ShowCursor( true ) >= 0 ) {
641 win32.mouseGrabbed = false;
645 ==========================
646 IN_DeactivateMouseIfWindowed
647 ==========================
649 void IN_DeactivateMouseIfWindowed( void ) {
650 if ( !win32.cdsFullscreen ) {
651 IN_DeactivateMouse();
656 ============================================================
660 ============================================================
669 void Sys_ShutdownInput( void ) {
670 IN_DeactivateMouse();
671 IN_DeactivateKeyboard();
672 if ( win32.g_pKeyboard ) {
673 win32.g_pKeyboard->Release();
674 win32.g_pKeyboard = NULL;
677 if ( win32.g_pMouse ) {
678 win32.g_pMouse->Release();
679 win32.g_pMouse = NULL;
683 win32.g_pdi->Release();
693 void Sys_InitInput( void ) {
694 common->Printf ("\n------- Input Initialization -------\n");
695 IN_InitDirectInput();
696 if ( win32.in_mouse.GetBool() ) {
698 // don't grab the mouse on initialization
699 Sys_GrabMouseCursor( false );
701 common->Printf ("Mouse control not active.\n");
703 IN_StartupKeyboard();
704 common->Printf ("------------------------------------\n");
705 win32.in_mouse.ClearModified();
713 void Sys_InitScanTable( void ) {
714 idStr lang = cvarSystem->GetCVarString( "sys_lang" );
715 if ( lang.Length() == 0 ) {
718 if ( lang.Icmp( "english" ) == 0 ) {
719 keyScanTable = s_scantokey;
720 // the only reason that english right alt binds as K_ALT is so that
721 // users who were using right-alt before the patch don't suddenly find
722 // that only left-alt is working.
724 } else if ( lang.Icmp( "spanish" ) == 0 ) {
725 keyScanTable = s_scantokey_spanish;
726 rightAltKey = K_RIGHT_ALT;
727 } else if ( lang.Icmp( "french" ) == 0 ) {
728 keyScanTable = s_scantokey_french;
729 rightAltKey = K_RIGHT_ALT;
730 } else if ( lang.Icmp( "german" ) == 0 ) {
731 keyScanTable = s_scantokey_german;
732 rightAltKey = K_RIGHT_ALT;
733 } else if ( lang.Icmp( "italian" ) == 0 ) {
734 keyScanTable = s_scantokey_italian;
735 rightAltKey = K_RIGHT_ALT;
744 const unsigned char *Sys_GetScanTable( void ) {
753 unsigned char Sys_GetConsoleKey( bool shifted ) {
754 return keyScanTable[41 + ( shifted ? 128 : 0 )];
761 Called every frame, even if not generating commands
764 void IN_Frame( void ) {
765 bool shouldGrab = true;
767 if ( !win32.in_mouse.GetBool() ) {
770 // if fullscreen, we always want the mouse
771 if ( !win32.cdsFullscreen ) {
772 if ( win32.mouseReleased ) {
775 if ( win32.movingWindow ) {
778 if ( !win32.activeApp ) {
783 if ( shouldGrab != win32.mouseGrabbed ) {
784 if ( win32.mouseGrabbed ) {
785 IN_DeactivateMouse();
789 #if 0 // if we can't reacquire, try reinitializing
790 if ( !IN_InitDIMouse() ) {
791 win32.in_mouse.SetBool( false );
800 void Sys_GrabMouseCursor( bool grabIt ) {
802 win32.mouseReleased = !grabIt;
804 // release it right now
810 //=====================================================================================
812 static DIDEVICEOBJECTDATA polled_didod[ DINPUT_BUFFERSIZE ]; // Receives buffered data
815 static byte toggleFetch[2][ 256 ];
819 // I tried doing the full-state get to address a keyboard problem on one system,
820 // but it didn't make any difference
824 Sys_PollKeyboardInputEvents
827 int Sys_PollKeyboardInputEvents( void ) {
831 if( win32.g_pKeyboard == NULL ) {
835 dwElements = DINPUT_BUFFERSIZE;
836 hr = win32.g_pKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
837 polled_didod, &dwElements, 0 );
840 // We got an error or we got DI_BUFFEROVERFLOW.
842 // Either way, it means that continuous contact with the
843 // device has been lost, either due to an external
844 // interruption, or because the buffer overflowed
845 // and some events were lost.
846 hr = win32.g_pKeyboard->Acquire();
852 //Bug 951: The following command really clears the garbage input.
853 //The original will still process keys in the buffer and was causing
855 win32.g_pKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), NULL, &dwElements, 0 );
858 // hr may be DIERR_OTHERAPPHASPRIO or other errors. This
859 // may occur when the app is minimized or in the process of
860 // switching, so just try again later
874 Sys_PollKeyboardInputEvents
876 Fake events by getting the entire device state
877 and checking transitions
880 int Sys_PollKeyboardInputEvents( void ) {
883 if( win32.g_pKeyboard == NULL ) {
887 hr = win32.g_pKeyboard->GetDeviceState( sizeof( toggleFetch[ diFetch ] ), toggleFetch[ diFetch ] );
890 // We got an error or we got DI_BUFFEROVERFLOW.
892 // Either way, it means that continuous contact with the
893 // device has been lost, either due to an external
894 // interruption, or because the buffer overflowed
895 // and some events were lost.
896 hr = win32.g_pKeyboard->Acquire();
900 hr = win32.g_pKeyboard->GetDeviceState( sizeof( toggleFetch[ diFetch ] ), toggleFetch[ diFetch ] );
902 // hr may be DIERR_OTHERAPPHASPRIO or other errors. This
903 // may occur when the app is minimized or in the process of
904 // switching, so just try again later
911 // build faked events
914 for ( int i = 0 ; i < 256 ; i++ ) {
915 if ( toggleFetch[0][i] != toggleFetch[1][i] ) {
916 polled_didod[ numChanges ].dwOfs = i;
917 polled_didod[ numChanges ].dwData = toggleFetch[ diFetch ][i] ? 0x80 : 0;
931 Sys_PollKeyboardInputEvents
934 int Sys_ReturnKeyboardInputEvent( const int n, int &ch, bool &state ) {
935 ch = IN_DIMapKey( polled_didod[ n ].dwOfs );
936 state = (polled_didod[ n ].dwData & 0x80) == 0x80;
937 if ( ch == K_PRINT_SCR || ch == K_CTRL || ch == K_ALT || ch == K_RIGHT_ALT ) {
938 // for windows, add a keydown event for print screen here, since
939 // windows doesn't send keydown events to the WndProc for this key.
940 // ctrl and alt are handled here to get around windows sending ctrl and
941 // alt messages when the right-alt is pressed on non-US 102 keyboards.
942 Sys_QueEvent( GetTickCount(), SE_KEY, ch, state, 0, NULL );
948 void Sys_EndKeyboardInputEvents( void ) {
951 void Sys_QueMouseEvents( int dwElements ) {
954 for( i = 0; i < dwElements; i++ ) {
955 if ( polled_didod[i].dwOfs >= DIMOFS_BUTTON0 && polled_didod[i].dwOfs <= DIMOFS_BUTTON7 ) {
956 value = (polled_didod[i].dwData & 0x80) == 0x80;
957 Sys_QueEvent( polled_didod[i].dwTimeStamp, SE_KEY, K_MOUSE1 + ( polled_didod[i].dwOfs - DIMOFS_BUTTON0 ), value, 0, NULL );
959 switch (polled_didod[i].dwOfs) {
961 value = polled_didod[i].dwData;
962 Sys_QueEvent( polled_didod[i].dwTimeStamp, SE_MOUSE, value, 0, 0, NULL );
965 value = polled_didod[i].dwData;
966 Sys_QueEvent( polled_didod[i].dwTimeStamp, SE_MOUSE, 0, value, 0, NULL );
969 value = ( (int) polled_didod[i].dwData ) / WHEEL_DELTA;
970 int key = value < 0 ? K_MWHEELDOWN : K_MWHEELUP;
971 value = abs( value );
972 while( value-- > 0 ) {
973 Sys_QueEvent( polled_didod[i].dwTimeStamp, SE_KEY, key, true, 0, NULL );
974 Sys_QueEvent( polled_didod[i].dwTimeStamp, SE_KEY, key, false, 0, NULL );
982 //=====================================================================================
984 int Sys_PollMouseInputEvents( void ) {
988 if ( !win32.g_pMouse || !win32.mouseGrabbed ) {
992 dwElements = DINPUT_BUFFERSIZE;
993 hr = win32.g_pMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), polled_didod, &dwElements, 0 );
996 hr = win32.g_pMouse->Acquire();
999 win32.g_pMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), polled_didod, &dwElements, 0 );
1007 Sys_QueMouseEvents( dwElements );
1012 int Sys_ReturnMouseInputEvent( const int n, int &action, int &value ) {
1013 int diaction = polled_didod[n].dwOfs;
1015 if ( diaction >= DIMOFS_BUTTON0 && diaction <= DIMOFS_BUTTON7 ) {
1016 value = (polled_didod[n].dwData & 0x80) == 0x80;
1017 action = M_ACTION1 + ( diaction - DIMOFS_BUTTON0 );
1021 switch( diaction ) {
1023 value = polled_didod[n].dwData;
1027 value = polled_didod[n].dwData;
1031 // mouse wheel actions are impulses, without a specific up / down
1032 value = ( (int) polled_didod[n].dwData ) / WHEEL_DELTA;
1034 // a value of zero here should never happen
1043 void Sys_EndMouseInputEvents( void ) { }
1045 unsigned char Sys_MapCharForKey( int key ) {
1046 return (unsigned char)key;