1 //
2 //	ID Engine
3 //	ID_IN.c - Input Manager
4 //	v1.0d1
5 //	By Jason Blochowiak
6 //
7 
8 //
9 //	This module handles dealing with the various input devices
10 //
11 //	Depends on: Memory Mgr (for demo recording), Sound Mgr (for timing stuff),
12 //				User Mgr (for command line parms)
13 //
14 //	Globals:
15 //		LastScan - The keyboard scan code of the last key pressed
16 //		LastASCII - The ASCII value of the last key pressed
17 //	DEBUG - there are more globals
18 //
19 
20 
21 #include "wl_def.h"
22 #include "c_cvars.h"
23 #include "id_sd.h"
24 #include "id_in.h"
25 #include "id_vl.h"
26 #include "id_vh.h"
27 #include "config.h"
28 #include "wl_play.h"
29 
30 
31 #if !SDL_VERSION_ATLEAST(1,3,0)
32 #define SDLK_KP_0 SDLK_KP0
33 #define SDLK_KP_1 SDLK_KP1
34 #define SDLK_KP_2 SDLK_KP2
35 #define SDLK_KP_3 SDLK_KP3
36 #define SDLK_KP_4 SDLK_KP4
37 #define SDLK_KP_5 SDLK_KP5
38 #define SDLK_KP_6 SDLK_KP6
39 #define SDLK_KP_7 SDLK_KP7
40 #define SDLK_KP_8 SDLK_KP8
41 #define SDLK_KP_9 SDLK_KP9
42 #define SDLK_SCROLLLOCK SDLK_SCROLLOCK
43 #define SDL_NUM_SCANCODES SDLK_LAST
44 typedef SDLMod SDL_Keymod;
45 
SDL_SetRelativeMouseMode(bool enabled)46 inline void SDL_SetRelativeMouseMode(bool enabled)
47 {
48 	SDL_WM_GrabInput(enabled ? SDL_GRAB_ON : SDL_GRAB_OFF);
49 }
SDL_WarpMouseInWindow(struct SDL_Window * window,int x,int y)50 inline void SDL_WarpMouseInWindow(struct SDL_Window* window, int x, int y)
51 {
52 	SDL_WarpMouse(x, y);
53 }
54 #endif
55 
56 #ifdef _WIN32
57 // SDL doesn't track the real state of the numlock or capslock key, so we need
58 // to query the system. It's probably like this since Linux and OS X don't
59 // appear to have nice APIs for this.
60 void I_CheckKeyMods();
61 #endif
62 
63 /*
64 =============================================================================
65 
66 					GLOBAL VARIABLES
67 
68 =============================================================================
69 */
70 
71 
72 //
73 // configuration variables
74 //
75 bool MousePresent;
76 
77 
78 // 	Global variables
79 volatile bool		Keyboard[SDL_NUM_SCANCODES];
80 volatile unsigned short Paused;
81 volatile char		LastASCII;
82 volatile ScanCode	LastScan;
83 
84 static KeyboardDef KbdDefs = {
85 	sc_Control,             // button0
86 	sc_Alt,                 // button1
87 	sc_Home,                // upleft
88 	sc_UpArrow,             // up
89 	sc_PgUp,                // upright
90 	sc_LeftArrow,           // left
91 	sc_RightArrow,          // right
92 	sc_End,                 // downleft
93 	sc_DownArrow,           // down
94 	sc_PgDn                 // downright
95 };
96 
97 static SDL_Joystick *Joystick;
98 #if SDL_VERSION_ATLEAST(2,0,0)
99 static SDL_GameController *GameController;
100 // Flip the right stick axes to match usual mapping of Joystick API.
101 static SDL_GameControllerAxis GameControllerAxisMap[SDL_CONTROLLER_AXIS_MAX] = {
102 	SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTY, // X, Y
103 	SDL_CONTROLLER_AXIS_RIGHTY, SDL_CONTROLLER_AXIS_RIGHTX, // Z, R
104 	SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_CONTROLLER_AXIS_TRIGGERRIGHT
105 };
106 #endif
107 JoystickSens *JoySensitivity;
108 int JoyNumButtons;
109 int JoyNumAxes;
110 static int JoyNumHats;
111 
112 static bool GrabInput = false;
113 
114 /*
115 =============================================================================
116 
117 					LOCAL VARIABLES
118 
119 =============================================================================
120 */
121 static	bool		IN_Started;
122 
123 static	Direction	DirTable[] =		// Quick lookup for total direction
124 {
125 	dir_NorthWest,	dir_North,	dir_NorthEast,
126 	dir_West,		dir_None,	dir_East,
127 	dir_SouthWest,	dir_South,	dir_SouthEast
128 };
129 
130 
131 ///////////////////////////////////////////////////////////////////////////
132 //
133 //	INL_GetMouseButtons() - Gets the status of the mouse buttons from the
134 //		mouse driver
135 //
136 ///////////////////////////////////////////////////////////////////////////
137 static int
INL_GetMouseButtons(void)138 INL_GetMouseButtons(void)
139 {
140 	int buttons = SDL_GetMouseState(NULL, NULL);
141 	int middlePressed = buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE);
142 	int rightPressed = buttons & SDL_BUTTON(SDL_BUTTON_RIGHT);
143 	buttons &= ~(SDL_BUTTON(SDL_BUTTON_MIDDLE) | SDL_BUTTON(SDL_BUTTON_RIGHT));
144 	if(middlePressed) buttons |= 1 << 2;
145 	if(rightPressed) buttons |= 1 << 1;
146 
147 	return buttons;
148 }
149 
150 ///////////////////////////////////////////////////////////////////////////
151 //
152 //	IN_GetJoyDelta() - Returns the relative movement of the specified
153 //		joystick (from +/-127)
154 //
155 ///////////////////////////////////////////////////////////////////////////
IN_GetJoyDelta(int * dx,int * dy)156 void IN_GetJoyDelta(int *dx,int *dy)
157 {
158 	if(!IN_JoyPresent())
159 	{
160 		*dx = *dy = 0;
161 		return;
162 	}
163 
164 	int x, y;
165 #if SDL_VERSION_ATLEAST(2,0,0)
166 	if(GameController)
167 	{
168 		SDL_GameControllerUpdate();
169 		x = SDL_GameControllerGetAxis(GameController, SDL_CONTROLLER_AXIS_LEFTX) >> 8;
170 		y = SDL_GameControllerGetAxis(GameController, SDL_CONTROLLER_AXIS_LEFTY) >> 8;
171 
172 		if(SDL_GameControllerGetButton(GameController, SDL_CONTROLLER_BUTTON_DPAD_RIGHT))
173 			x += 127;
174 		else if(SDL_GameControllerGetButton(GameController, SDL_CONTROLLER_BUTTON_DPAD_LEFT))
175 			x -= 127;
176 		if(SDL_GameControllerGetButton(GameController, SDL_CONTROLLER_BUTTON_DPAD_DOWN))
177 			y += 127;
178 		else if(SDL_GameControllerGetButton(GameController, SDL_CONTROLLER_BUTTON_DPAD_UP))
179 			y -= 127;
180 	}
181 	else
182 #endif
183 	{
184 		SDL_JoystickUpdate();
185 		x = SDL_JoystickGetAxis(Joystick, 0) >> 8;
186 		y = SDL_JoystickGetAxis(Joystick, 1) >> 8;
187 
188 		if(param_joystickhat != -1)
189 		{
190 			uint8_t hatState = SDL_JoystickGetHat(Joystick, param_joystickhat);
191 			if(hatState & SDL_HAT_RIGHT)
192 				x += 127;
193 			else if(hatState & SDL_HAT_LEFT)
194 				x -= 127;
195 			if(hatState & SDL_HAT_DOWN)
196 				y += 127;
197 			else if(hatState & SDL_HAT_UP)
198 				y -= 127;
199 		}
200 	}
201 
202 	if(x < -128) x = -128;
203 	else if(x > 127) x = 127;
204 
205 	if(y < -128) y = -128;
206 	else if(y > 127) y = 127;
207 
208 	*dx = x;
209 	*dy = y;
210 }
211 
IN_GetJoyAxis(int axis)212 int IN_GetJoyAxis(int axis)
213 {
214 #if SDL_VERSION_ATLEAST(2,0,0)
215 	if(GameController)
216 		return SDL_GameControllerGetAxis(GameController, GameControllerAxisMap[axis]);
217 #endif
218 	return SDL_JoystickGetAxis(Joystick, axis);
219 }
220 
221 /*
222 ===================
223 =
224 = IN_JoyButtons
225 =
226 ===================
227 */
228 
IN_JoyButtons()229 int IN_JoyButtons()
230 {
231 #if SDL_VERSION_ATLEAST(2,0,0)
232 	if(GameController)
233 	{
234 		SDL_GameControllerUpdate();
235 
236 		int res = 0;
237 		for(int i = 0; i < JoyNumButtons; ++i)
238 		{
239 			if(SDL_GameControllerGetButton(GameController, (SDL_GameControllerButton)i))
240 			{
241 				// Attempt to allow controllers using the game controller API
242 				// to enter the menu.
243 				if(i == SDL_CONTROLLER_BUTTON_START)
244 					buttonstate[bt_esc] = true;
245 				else
246 					res |= 1<<i;
247 			}
248 		}
249 		return res;
250 	}
251 #endif
252 
253 	if(!Joystick) return 0;
254 
255 	SDL_JoystickUpdate();
256 
257 	int res = 0;
258 	int i;
259 	for(i = 0; i < JoyNumButtons && i < 32; i++)
260 		res |= SDL_JoystickGetButton(Joystick, i) << i;
261 
262 	// Need four buttons for hat
263 	if(i < 28 && param_joystickhat != -1)
264 	{
265 		uint8_t hatState = SDL_JoystickGetHat(Joystick, param_joystickhat);
266 		if(hatState & SDL_HAT_UP)
267 			res |= 0x1 << i;
268 		else if(hatState & SDL_HAT_DOWN)
269 			res |= 0x4 << i;
270 		if(hatState & SDL_HAT_RIGHT)
271 			res |= 0x2 << i;
272 		else if(hatState & SDL_HAT_LEFT)
273 			res |= 0x8 << i;
274 	}
275 	return res;
276 }
277 
IN_JoyAxes()278 int IN_JoyAxes()
279 {
280 #if SDL_VERSION_ATLEAST(2,0,0)
281 	if(GameController)
282 	{
283 		SDL_GameControllerUpdate();
284 		int res = 0;
285 		for(int i = 0; i < JoyNumAxes; ++i)
286 		{
287 			SWORD pos = SDL_GameControllerGetAxis(GameController, (SDL_GameControllerAxis)GameControllerAxisMap[i]);
288 			if(pos <= -0x1000)
289 				res |= 1 << (i*2);
290 			else if(pos >= 0x1000)
291 				res |= 1 << (i*2+1);
292 		}
293 		return res;
294 	}
295 #endif
296 	if(!Joystick) return 0;
297 
298 	SDL_JoystickUpdate();
299 
300 	int res = 0;
301 	for(int i = 0; i < JoyNumAxes && i < 16; ++i)
302 	{
303 		SWORD pos = SDL_JoystickGetAxis(Joystick, i);
304 		if(pos <= -0x1000)
305 			res |= 1 << (i*2);
306 		else if(pos >= 0x1000)
307 			res |= 1 << (i*2+1);
308 	}
309 	return res;
310 }
311 
IN_JoyPresent()312 bool IN_JoyPresent()
313 {
314 	return Joystick != NULL
315 #if SDL_VERSION_ATLEAST(2,0,0)
316 		|| GameController != NULL
317 #endif
318 	;
319 }
320 
321 #ifdef __ANDROID__
322 static bool ShadowKey = false;
323 bool ShadowingEnabled = false;
324 extern "C" int hasHardwareKeyboard();
325 #endif
326 
processEvent(SDL_Event * event)327 static void processEvent(SDL_Event *event)
328 {
329 	switch (event->type)
330 	{
331 		// exit if the window is closed
332 		case SDL_QUIT:
333 			Quit(NULL);
334 
335 		// ASCII (Unicode) text entry for saves and stuff like that.
336 #if SDL_VERSION_ATLEAST(1,3,0)
337 		case SDL_TEXTINPUT:
338 		{
339 			LastASCII = event->text.text[0];
340 			break;
341 		}
342 #endif
343 
344 		// check for keypresses
345 		case SDL_KEYDOWN:
346 		{
347 			if(event->key.keysym.sym==SDLK_SCROLLLOCK)
348 			{
349 				GrabInput = !GrabInput;
350 				SDL_SetRelativeMouseMode(GrabInput ? SDL_TRUE : SDL_FALSE);
351 				return;
352 			}
353 
354 #if SDL_VERSION_ATLEAST(1,3,0)
355 			LastScan = event->key.keysym.scancode;
356 #else
357 			LastScan = event->key.keysym.sym;
358 #endif
359 			SDL_Keymod mod = SDL_GetModState();
360 			if(Keyboard[sc_Alt])
361 			{
362 				if(LastScan==SDLx_SCANCODE(F4))
363 					Quit(NULL);
364 			}
365 
366 			if(LastScan == SDLx_SCANCODE(KP_ENTER)) LastScan = SDLx_SCANCODE(RETURN);
367 			else if(LastScan == SDLx_SCANCODE(RSHIFT)) LastScan = SDLx_SCANCODE(LSHIFT);
368 			else if(LastScan == SDLx_SCANCODE(RALT)) LastScan = SDLx_SCANCODE(LALT);
369 			else if(LastScan == SDLx_SCANCODE(RCTRL)) LastScan = SDLx_SCANCODE(LCTRL);
370 			else
371 			{
372 				if((mod & KMOD_NUM) == 0)
373 				{
374 					switch(LastScan)
375 					{
376 						case SDLx_SCANCODE(KP_2): LastScan = SDLx_SCANCODE(DOWN); break;
377 						case SDLx_SCANCODE(KP_4): LastScan = SDLx_SCANCODE(LEFT); break;
378 						case SDLx_SCANCODE(KP_6): LastScan = SDLx_SCANCODE(RIGHT); break;
379 						case SDLx_SCANCODE(KP_8): LastScan = SDLx_SCANCODE(UP); break;
380 					}
381 				}
382 			}
383 
384 #if !SDL_VERSION_ATLEAST(1,3,0)
385 			static const byte ASCIINames[] = // Unshifted ASCII for scan codes       // TODO: keypad
386 			{
387 			//	 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
388 				0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,8  ,9  ,0  ,0  ,0  ,13 ,0  ,0  ,	// 0
389 				0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,27 ,0  ,0  ,0  ,	// 1
390 				' ',0  ,0  ,0  ,0  ,0  ,0  ,39 ,0  ,0  ,'*','+',',','-','.','/',	// 2
391 				'0','1','2','3','4','5','6','7','8','9',0  ,';',0  ,'=',0  ,0  ,	// 3
392 				'`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',	// 4
393 				'p','q','r','s','t','u','v','w','x','y','z','[',92 ,']',0  ,0  ,	// 5
394 				0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 6
395 				0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0		// 7
396 			};
397 			static const byte ShiftNames[] = // Shifted ASCII for scan codes
398 			{
399 			//	 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
400 				0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,8  ,9  ,0  ,0  ,0  ,13 ,0  ,0  ,	// 0
401 				0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,27 ,0  ,0  ,0  ,	// 1
402 				' ',0  ,0  ,0  ,0  ,0  ,0  ,34 ,0  ,0  ,'*','+','<','_','>','?',	// 2
403 				')','!','@','#','$','%','^','&','*','(',0  ,':',0  ,'+',0  ,0  ,	// 3
404 				'~','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',	// 4
405 				'P','Q','R','S','T','U','V','W','X','Y','Z','{','|','}',0  ,0  ,	// 5
406 				0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,	// 6
407 				0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0		// 7
408 			};
409 
410 			int sym = event->key.keysym.sym;
411 			if(sym >= 'a' && sym <= 'z')
412 				sym -= 32;  // convert to uppercase
413 
414 			if(mod & KMOD_SHIFT)
415 			{
416 				if((unsigned)sym < lengthof(ShiftNames) && ShiftNames[sym])
417 					LastASCII = ShiftNames[sym];
418 			}
419 			else
420 			{
421 				if((unsigned)sym < lengthof(ASCIINames) && ASCIINames[sym])
422 					LastASCII = ASCIINames[sym];
423 			}
424 			if(LastASCII && sym >= 'A' && sym <= 'Z' && (mod & KMOD_CAPS))
425 				LastASCII ^= 0x20;
426 #endif
427 
428 			if(LastScan<SDL_NUM_SCANCODES)
429 				Keyboard[LastScan] = 1;
430 			if(LastScan == SDLx_SCANCODE(PAUSE))
431 				Paused |= 1;
432 			break;
433 		}
434 
435 		case SDL_KEYUP:
436 		{
437 #if SDL_VERSION_ATLEAST(1,3,0)
438 			int key = event->key.keysym.scancode;
439 #else
440 			int key = event->key.keysym.sym;
441 #endif
442 			if(key == SDLx_SCANCODE(KP_ENTER)) key = SDLx_SCANCODE(RETURN);
443 			else if(key == SDLx_SCANCODE(RSHIFT)) key = SDLx_SCANCODE(LSHIFT);
444 			else if(key == SDLx_SCANCODE(RALT)) key = SDLx_SCANCODE(LALT);
445 			else if(key == SDLx_SCANCODE(RCTRL)) key = SDLx_SCANCODE(LCTRL);
446 			else
447 			{
448 				if((SDL_GetModState() & KMOD_NUM) == 0)
449 				{
450 					switch(key)
451 					{
452 						case SDLx_SCANCODE(KP_2): key = SDLx_SCANCODE(DOWN); break;
453 						case SDLx_SCANCODE(KP_4): key = SDLx_SCANCODE(LEFT); break;
454 						case SDLx_SCANCODE(KP_6): key = SDLx_SCANCODE(RIGHT); break;
455 						case SDLx_SCANCODE(KP_8): key = SDLx_SCANCODE(UP); break;
456 					}
457 				}
458 			}
459 
460 #ifdef __ANDROID__
461 			if(ShadowKey && LastScan == event->key.keysym.scancode)
462 			{
463 				ShadowKey = false;
464 				break;
465 			}
466 #endif
467 
468 			if(key<SDL_NUM_SCANCODES)
469 				Keyboard[key] = 0;
470 			break;
471 		}
472 
473 #if !SDL_VERSION_ATLEAST(1,3,0)
474 		case SDL_ACTIVEEVENT:
475 		{
476 			if (!fullscreen && forcegrabmouse && (event->active.state & SDL_APPINPUTFOCUS || event->active.state & SDL_APPACTIVE))
477 			{
478 					// Release the mouse if we lose input focus, grab it again
479 					// when we gain input focus.
480 				if (event->active.gain == 1)
481 				{
482 					IN_GrabMouse();
483 				}
484 				else
485 				{
486 					IN_ReleaseMouse();
487 				}
488 			}
489 			break;
490 		}
491 #else
492 #ifdef _WIN32
493 		case SDL_WINDOWEVENT:
494 			if (event->window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
495 				I_CheckKeyMods();
496 			break;
497 #endif
498 #endif
499 	}
500 }
501 
IN_WaitAndProcessEvents()502 void IN_WaitAndProcessEvents()
503 {
504 	SDL_Event event;
505 	if(!SDL_WaitEvent(&event)) return;
506 	do
507 	{
508 		processEvent(&event);
509 	}
510 	while(SDL_PollEvent(&event));
511 }
512 
IN_ProcessEvents()513 void IN_ProcessEvents()
514 {
515 	SDL_Event event;
516 
517 #ifdef __ANDROID__
518 	if(ShadowingEnabled)
519 	{
520 		if(!ShadowKey)
521 			Keyboard[LastScan] = 0;
522 		ShadowKey = true;
523 	}
524 #endif
525 
526 	while (SDL_PollEvent(&event))
527 	{
528 		processEvent(&event);
529 	}
530 }
531 
532 
533 ///////////////////////////////////////////////////////////////////////////
534 //
535 //	IN_Startup() - Starts up the Input Mgr
536 //
537 ///////////////////////////////////////////////////////////////////////////
538 void
IN_Startup(void)539 IN_Startup(void)
540 {
541 	if (IN_Started)
542 		return;
543 
544 #ifdef __ANDROID__
545 	ShadowingEnabled = !hasHardwareKeyboard();
546 #endif
547 
548 #ifdef _WIN32
549 	I_CheckKeyMods();
550 #else
551 	// Turn numlock on by default since that's probably what most people want.
552 	SDL_SetModState(SDL_Keymod(SDL_GetModState()|KMOD_NUM));
553 #endif
554 
555 	IN_ClearKeysDown();
556 
557 	if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) == 0 &&
558 		param_joystickindex >= 0 && param_joystickindex < SDL_NumJoysticks())
559 	{
560 #if SDL_VERSION_ATLEAST(2,0,0)
561 		if(SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == 0 && SDL_IsGameController(param_joystickindex))
562 		{
563 			GameController = SDL_GameControllerOpen(param_joystickindex);
564 			if(GameController)
565 			{
566 				Printf("Using game controller: %s\n", SDL_GameControllerName(GameController));
567 				SDL_GameControllerEventState(SDL_IGNORE);
568 				JoyNumButtons = SDL_CONTROLLER_BUTTON_MAX;
569 				JoyNumAxes = SDL_CONTROLLER_AXIS_MAX;
570 				JoyNumHats = 0;
571 
572 				JoySensitivity = new JoystickSens[JoyNumAxes];
573 			}
574 		}
575 		else
576 #endif
577 		{
578 			Joystick = SDL_JoystickOpen(param_joystickindex);
579 			if(Joystick)
580 			{
581 				JoyNumButtons = SDL_JoystickNumButtons(Joystick);
582 				if(JoyNumButtons > 32) JoyNumButtons = 32;      // only up to 32 buttons are supported
583 				JoyNumAxes = SDL_JoystickNumAxes(Joystick);
584 				JoyNumHats = SDL_JoystickNumHats(Joystick);
585 				if(param_joystickhat >= JoyNumHats)
586 					Quit("The joystickhat param must be between 0 and %i!", JoyNumHats - 1);
587 				else if(param_joystickhat < 0 && JoyNumHats > 0) // Default to hat 0
588 					param_joystickhat = 0;
589 
590 				JoySensitivity = new JoystickSens[JoyNumAxes];
591 			}
592 		}
593 
594 		if(JoySensitivity)
595 		{
596 			for(int i = 0;i < JoyNumAxes;++i)
597 			{
598 				FString settingName;
599 				settingName.Format("JoyAxis%dSensitivity", i);
600 				config.CreateSetting(settingName, 10);
601 				JoySensitivity[i].sensitivity = config.GetSetting(settingName)->GetInteger();
602 				settingName.Format("JoyAxis%dDeadzone", i);
603 				config.CreateSetting(settingName, 2);
604 				JoySensitivity[i].deadzone = config.GetSetting(settingName)->GetInteger();
605 			}
606 		}
607 	}
608 
609 	SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
610 
611 	IN_GrabMouse();
612 
613 	// I didn't find a way to ask libSDL whether a mouse is present, yet...
614 	MousePresent = true;
615 
616 	IN_Started = true;
617 }
618 
619 ///////////////////////////////////////////////////////////////////////////
620 //
621 //	IN_Shutdown() - Shuts down the Input Mgr
622 //
623 ///////////////////////////////////////////////////////////////////////////
624 void
IN_Shutdown(void)625 IN_Shutdown(void)
626 {
627 	if (!IN_Started)
628 		return;
629 
630 	if(JoySensitivity)
631 	{
632 		for(int i = 0;i < JoyNumAxes;++i)
633 		{
634 			FString settingName;
635 			settingName.Format("JoyAxis%dSensitivity", i);
636 			config.GetSetting(settingName)->SetValue(JoySensitivity[i].sensitivity);
637 			settingName.Format("JoyAxis%dDeadzone", i);
638 			config.GetSetting(settingName)->SetValue(JoySensitivity[i].deadzone);
639 		}
640 		delete[] JoySensitivity;
641 	}
642 
643 	if(Joystick)
644 		SDL_JoystickClose(Joystick);
645 #if SDL_VERSION_ATLEAST(2,0,0)
646 	if(GameController)
647 		SDL_GameControllerClose(GameController);
648 #endif
649 
650 	IN_Started = false;
651 }
652 
653 ///////////////////////////////////////////////////////////////////////////
654 //
655 //	IN_ClearKeysDown() - Clears the keyboard array
656 //
657 ///////////////////////////////////////////////////////////////////////////
658 void
IN_ClearKeysDown(void)659 IN_ClearKeysDown(void)
660 {
661 	LastScan = sc_None;
662 	LastASCII = key_None;
663 	memset ((void *) Keyboard,0,sizeof(Keyboard));
664 }
665 
666 
667 ///////////////////////////////////////////////////////////////////////////
668 //
669 //	IN_ReadControl() - Reads the device associated with the specified
670 //		player and fills in the control info struct
671 //
672 ///////////////////////////////////////////////////////////////////////////
673 void
IN_ReadControl(int player,ControlInfo * info)674 IN_ReadControl(int player,ControlInfo *info)
675 {
676 	word		buttons;
677 	int			dx,dy;
678 	Motion		mx,my;
679 
680 	dx = dy = 0;
681 	mx = my = motion_None;
682 	buttons = 0;
683 
684 	IN_ProcessEvents();
685 
686 	if (Keyboard[KbdDefs.upleft])
687 		mx = motion_Left,my = motion_Up;
688 	else if (Keyboard[KbdDefs.upright])
689 		mx = motion_Right,my = motion_Up;
690 	else if (Keyboard[KbdDefs.downleft])
691 		mx = motion_Left,my = motion_Down;
692 	else if (Keyboard[KbdDefs.downright])
693 		mx = motion_Right,my = motion_Down;
694 
695 	if (Keyboard[KbdDefs.up])
696 		my = motion_Up;
697 	else if (Keyboard[KbdDefs.down])
698 		my = motion_Down;
699 
700 	if (Keyboard[KbdDefs.left])
701 		mx = motion_Left;
702 	else if (Keyboard[KbdDefs.right])
703 		mx = motion_Right;
704 
705 	if (Keyboard[KbdDefs.button0])
706 		buttons += 1 << 0;
707 	if (Keyboard[KbdDefs.button1])
708 		buttons += 1 << 1;
709 
710 	dx = mx * 127;
711 	dy = my * 127;
712 
713 	info->x = dx;
714 	info->xaxis = mx;
715 	info->y = dy;
716 	info->yaxis = my;
717 	info->button0 = (buttons & (1 << 0)) != 0;
718 	info->button1 = (buttons & (1 << 1)) != 0;
719 	info->button2 = (buttons & (1 << 2)) != 0;
720 	info->button3 = (buttons & (1 << 3)) != 0;
721 	info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
722 }
723 
724 ///////////////////////////////////////////////////////////////////////////
725 //
726 //	IN_WaitForKey() - Waits for a scan code, then clears LastScan and
727 //		returns the scan code
728 //
729 ///////////////////////////////////////////////////////////////////////////
730 ScanCode
IN_WaitForKey(void)731 IN_WaitForKey(void)
732 {
733 	ScanCode	result;
734 
735 	while ((result = LastScan)==0)
736 		IN_WaitAndProcessEvents();
737 	LastScan = 0;
738 	return(result);
739 }
740 
741 ///////////////////////////////////////////////////////////////////////////
742 //
743 //	IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and
744 //		returns the ASCII value
745 //
746 ///////////////////////////////////////////////////////////////////////////
747 char
IN_WaitForASCII(void)748 IN_WaitForASCII(void)
749 {
750 	char		result;
751 
752 	while ((result = LastASCII)==0)
753 		IN_WaitAndProcessEvents();
754 	LastASCII = '\0';
755 	return(result);
756 }
757 
758 ///////////////////////////////////////////////////////////////////////////
759 //
760 //	IN_Ack() - waits for a button or key press.  If a button is down, upon
761 // calling, it must be released for it to be recognized
762 //
763 ///////////////////////////////////////////////////////////////////////////
764 
765 bool	btnstate[NUMBUTTONS];
766 
IN_StartAck(void)767 void IN_StartAck(void)
768 {
769 	IN_ProcessEvents();
770 //
771 // get initial state of everything
772 //
773 	IN_ClearKeysDown();
774 	memset(btnstate, 0, sizeof(btnstate));
775 
776 	int buttons = IN_JoyButtons() << 4;
777 
778 	if(MousePresent)
779 		buttons |= IN_MouseButtons();
780 
781 	for(int i = 0; i < NUMBUTTONS; i++, buttons >>= 1)
782 		if(buttons & 1)
783 			btnstate[i] = true;
784 }
785 
786 
IN_CheckAck(void)787 bool IN_CheckAck (void)
788 {
789 	IN_ProcessEvents();
790 //
791 // see if something has been pressed
792 //
793 	if(LastScan)
794 		return true;
795 
796 	int buttons = IN_JoyButtons() << 4;
797 
798 	if(MousePresent)
799 		buttons |= IN_MouseButtons();
800 
801 	for(int i = 0; i < NUMBUTTONS; i++, buttons >>= 1)
802 	{
803 		if(buttons & 1)
804 		{
805 			if(!btnstate[i])
806 			{
807 				// Wait until button has been released
808 				do
809 				{
810 					IN_WaitAndProcessEvents();
811 					buttons = IN_JoyButtons() << 4;
812 
813 					if(MousePresent)
814 						buttons |= IN_MouseButtons();
815 				}
816 				while(buttons & (1 << i));
817 
818 				return true;
819 			}
820 		}
821 		else
822 			btnstate[i] = false;
823 	}
824 
825 	return false;
826 }
827 
828 
IN_Ack(void)829 void IN_Ack (void)
830 {
831 	IN_StartAck ();
832 
833 	do
834 	{
835 		IN_WaitAndProcessEvents();
836 	}
837 	while(!IN_CheckAck ());
838 }
839 
840 
841 ///////////////////////////////////////////////////////////////////////////
842 //
843 //	IN_UserInput() - Waits for the specified delay time (in ticks) or the
844 //		user pressing a key or a mouse button. If the clear flag is set, it
845 //		then either clears the key or waits for the user to let the mouse
846 //		button up.
847 //
848 ///////////////////////////////////////////////////////////////////////////
IN_UserInput(longword delay)849 bool IN_UserInput(longword delay)
850 {
851 	longword	lasttime;
852 
853 	lasttime = GetTimeCount();
854 	IN_StartAck ();
855 	do
856 	{
857 		IN_ProcessEvents();
858 		if (IN_CheckAck())
859 			return true;
860 		SDL_Delay(5);
861 	} while (GetTimeCount() - lasttime < delay);
862 	return(false);
863 }
864 
865 //===========================================================================
866 
867 /*
868 ===================
869 =
870 = IN_MouseButtons
871 =
872 ===================
873 */
IN_MouseButtons(void)874 int IN_MouseButtons (void)
875 {
876 	if (MousePresent)
877 		return INL_GetMouseButtons();
878 	else
879 		return 0;
880 }
881 
IN_ReleaseMouse()882 void IN_ReleaseMouse()
883 {
884 	GrabInput = false;
885 	SDL_SetRelativeMouseMode(SDL_FALSE);
886 }
887 
IN_GrabMouse()888 void IN_GrabMouse()
889 {
890 	if(fullscreen || forcegrabmouse)
891 	{
892 		GrabInput = true;
893 		SDL_SetRelativeMouseMode(SDL_TRUE);
894 	}
895 }
896 
IN_AdjustMouse()897 void IN_AdjustMouse()
898 {
899 	if (mouseenabled && (forcegrabmouse || fullscreen))
900 		IN_GrabMouse();
901 	else if (!fullscreen)
902 		IN_ReleaseMouse();
903 }
904 
IN_IsInputGrabbed()905 bool IN_IsInputGrabbed()
906 {
907 	return GrabInput;
908 }
909 
IN_CenterMouse()910 void IN_CenterMouse()
911 {
912 	// Clear out relative mouse movement
913 	int x, y;
914 	SDL_GetRelativeMouseState(&x, &y);
915 }
916