1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
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.
13 
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.
18 
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/>.
21 
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.
23 
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.
25 
26 ===========================================================================
27 */
28 
29 #include <SDL.h>
30 
31 #include "sys/platform.h"
32 #include "idlib/containers/List.h"
33 #include "idlib/Heap.h"
34 #include "framework/Common.h"
35 #include "framework/KeyInput.h"
36 #include "framework/Session.h"
37 #include "renderer/RenderSystem.h"
38 #include "renderer/tr_local.h"
39 
40 #include "sys/sys_public.h"
41 
42 #if !SDL_VERSION_ATLEAST(2, 0, 0)
43 #define SDL_Keycode SDLKey
44 #define SDLK_APPLICATION SDLK_COMPOSE
45 #define SDLK_SCROLLLOCK SDLK_SCROLLOCK
46 #define SDLK_LGUI SDLK_LSUPER
47 #define SDLK_RGUI SDLK_RSUPER
48 #define SDLK_KP_0 SDLK_KP0
49 #define SDLK_KP_1 SDLK_KP1
50 #define SDLK_KP_2 SDLK_KP2
51 #define SDLK_KP_3 SDLK_KP3
52 #define SDLK_KP_4 SDLK_KP4
53 #define SDLK_KP_5 SDLK_KP5
54 #define SDLK_KP_6 SDLK_KP6
55 #define SDLK_KP_7 SDLK_KP7
56 #define SDLK_KP_8 SDLK_KP8
57 #define SDLK_KP_9 SDLK_KP9
58 #define SDLK_NUMLOCKCLEAR SDLK_NUMLOCK
59 #define SDLK_PRINTSCREEN SDLK_PRINT
60 #endif
61 
62 const char *kbdNames[] = {
63 	"english", "french", "german", "italian", "spanish", "turkish", "norwegian", "brazilian", NULL
64 };
65 
66 idCVar in_kbd("in_kbd", "english", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "keyboard layout", kbdNames, idCmdSystem::ArgCompletion_String<kbdNames> );
67 
68 struct kbd_poll_t {
69 	int key;
70 	bool state;
71 
kbd_poll_tkbd_poll_t72 	kbd_poll_t() {
73 	}
74 
kbd_poll_tkbd_poll_t75 	kbd_poll_t(int k, bool s) {
76 		key = k;
77 		state = s;
78 	}
79 };
80 
81 struct mouse_poll_t {
82 	int action;
83 	int value;
84 
mouse_poll_tmouse_poll_t85 	mouse_poll_t() {
86 	}
87 
mouse_poll_tmouse_poll_t88 	mouse_poll_t(int a, int v) {
89 		action = a;
90 		value = v;
91 	}
92 };
93 
94 static idList<kbd_poll_t> kbd_polls;
95 static idList<mouse_poll_t> mouse_polls;
96 
mapkey(SDL_Keycode key)97 static byte mapkey(SDL_Keycode key) {
98 	switch (key) {
99 	case SDLK_BACKSPACE:
100 		return K_BACKSPACE;
101 	case SDLK_PAUSE:
102 		return K_PAUSE;
103 	}
104 
105 	if (key <= SDLK_z)
106 		return key & 0xff;
107 
108 	switch (key) {
109 	case SDLK_APPLICATION:
110 		return K_COMMAND;
111 	case SDLK_CAPSLOCK:
112 		return K_CAPSLOCK;
113 	case SDLK_SCROLLLOCK:
114 		return K_SCROLL;
115 	case SDLK_POWER:
116 		return K_POWER;
117 
118 	case SDLK_UP:
119 		return K_UPARROW;
120 	case SDLK_DOWN:
121 		return K_DOWNARROW;
122 	case SDLK_LEFT:
123 		return K_LEFTARROW;
124 	case SDLK_RIGHT:
125 		return K_RIGHTARROW;
126 
127 	case SDLK_LGUI:
128 		return K_LWIN;
129 	case SDLK_RGUI:
130 		return K_RWIN;
131 	case SDLK_MENU:
132 		return K_MENU;
133 
134 	case SDLK_LALT:
135 	case SDLK_RALT:
136 		return K_ALT;
137 	case SDLK_RCTRL:
138 	case SDLK_LCTRL:
139 		return K_CTRL;
140 	case SDLK_RSHIFT:
141 	case SDLK_LSHIFT:
142 		return K_SHIFT;
143 	case SDLK_INSERT:
144 		return K_INS;
145 	case SDLK_DELETE:
146 		return K_DEL;
147 	case SDLK_PAGEDOWN:
148 		return K_PGDN;
149 	case SDLK_PAGEUP:
150 		return K_PGUP;
151 	case SDLK_HOME:
152 		return K_HOME;
153 	case SDLK_END:
154 		return K_END;
155 
156 	case SDLK_F1:
157 		return K_F1;
158 	case SDLK_F2:
159 		return K_F2;
160 	case SDLK_F3:
161 		return K_F3;
162 	case SDLK_F4:
163 		return K_F4;
164 	case SDLK_F5:
165 		return K_F5;
166 	case SDLK_F6:
167 		return K_F6;
168 	case SDLK_F7:
169 		return K_F7;
170 	case SDLK_F8:
171 		return K_F8;
172 	case SDLK_F9:
173 		return K_F9;
174 	case SDLK_F10:
175 		return K_F10;
176 	case SDLK_F11:
177 		return K_F11;
178 	case SDLK_F12:
179 		return K_F12;
180 	// K_INVERTED_EXCLAMATION;
181 	case SDLK_F13:
182 		return K_F13;
183 	case SDLK_F14:
184 		return K_F14;
185 	case SDLK_F15:
186 		return K_F15;
187 
188 	case SDLK_KP_7:
189 		return K_KP_HOME;
190 	case SDLK_KP_8:
191 		return K_KP_UPARROW;
192 	case SDLK_KP_9:
193 		return K_KP_PGUP;
194 	case SDLK_KP_4:
195 		return K_KP_LEFTARROW;
196 	case SDLK_KP_5:
197 		return K_KP_5;
198 	case SDLK_KP_6:
199 		return K_KP_RIGHTARROW;
200 	case SDLK_KP_1:
201 		return K_KP_END;
202 	case SDLK_KP_2:
203 		return K_KP_DOWNARROW;
204 	case SDLK_KP_3:
205 		return K_KP_PGDN;
206 	case SDLK_KP_ENTER:
207 		return K_KP_ENTER;
208 	case SDLK_KP_0:
209 		return K_KP_INS;
210 	case SDLK_KP_PERIOD:
211 		return K_KP_DEL;
212 	case SDLK_KP_DIVIDE:
213 		return K_KP_SLASH;
214 	// K_SUPERSCRIPT_TWO;
215 	case SDLK_KP_MINUS:
216 		return K_KP_MINUS;
217 	// K_ACUTE_ACCENT;
218 	case SDLK_KP_PLUS:
219 		return K_KP_PLUS;
220 	case SDLK_NUMLOCKCLEAR:
221 		return K_KP_NUMLOCK;
222 	case SDLK_KP_MULTIPLY:
223 		return K_KP_STAR;
224 	case SDLK_KP_EQUALS:
225 		return K_KP_EQUALS;
226 
227 	// K_MASCULINE_ORDINATOR;
228 	// K_GRAVE_A;
229 	// K_AUX1;
230 	// K_CEDILLA_C;
231 	// K_GRAVE_E;
232 	// K_AUX2;
233 	// K_AUX3;
234 	// K_AUX4;
235 	// K_GRAVE_I;
236 	// K_AUX5;
237 	// K_AUX6;
238 	// K_AUX7;
239 	// K_AUX8;
240 	// K_TILDE_N;
241 	// K_GRAVE_O;
242 	// K_AUX9;
243 	// K_AUX10;
244 	// K_AUX11;
245 	// K_AUX12;
246 	// K_AUX13;
247 	// K_AUX14;
248 	// K_GRAVE_U;
249 	// K_AUX15;
250 	// K_AUX16;
251 
252 	case SDLK_PRINTSCREEN:
253 		return K_PRINT_SCR;
254 	case SDLK_MODE:
255 		return K_RIGHT_ALT;
256 	}
257 
258 	return 0;
259 }
260 
PushConsoleEvent(const char * s)261 static void PushConsoleEvent(const char *s) {
262 	char *b;
263 	size_t len;
264 
265 	len = strlen(s) + 1;
266 	b = (char *)Mem_Alloc(len);
267 	strcpy(b, s);
268 
269 	SDL_Event event;
270 
271 	event.type = SDL_USEREVENT;
272 	event.user.code = SE_CONSOLE;
273 	event.user.data1 = (void *)len;
274 	event.user.data2 = b;
275 
276 	SDL_PushEvent(&event);
277 }
278 
279 /*
280 =================
281 Sys_InitInput
282 =================
283 */
Sys_InitInput()284 void Sys_InitInput() {
285 	kbd_polls.SetGranularity(64);
286 	mouse_polls.SetGranularity(64);
287 
288 #if !SDL_VERSION_ATLEAST(2, 0, 0)
289 	SDL_EnableUNICODE(1);
290 	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
291 #endif
292 
293 	in_kbd.SetModified();
294 }
295 
296 /*
297 =================
298 Sys_ShutdownInput
299 =================
300 */
Sys_ShutdownInput()301 void Sys_ShutdownInput() {
302 	kbd_polls.Clear();
303 	mouse_polls.Clear();
304 }
305 
306 /*
307 ===========
308 Sys_InitScanTable
309 ===========
310 */
311 // Windows has its own version due to the tools
312 #ifndef _WIN32
Sys_InitScanTable()313 void Sys_InitScanTable() {
314 }
315 #endif
316 
317 /*
318 ===============
319 Sys_GetConsoleKey
320 ===============
321 */
Sys_GetConsoleKey(bool shifted)322 unsigned char Sys_GetConsoleKey(bool shifted) {
323 	static unsigned char keys[2] = { '`', '~' };
324 
325 	if (in_kbd.IsModified()) {
326 		idStr lang = in_kbd.GetString();
327 
328 		if (lang.Length()) {
329 			if (!lang.Icmp("french")) {
330 				keys[0] = '<';
331 				keys[1] = '>';
332 			} else if (!lang.Icmp("german")) {
333 				keys[0] = '^';
334 				keys[1] = 176; // °
335 			} else if (!lang.Icmp("italian")) {
336 				keys[0] = '\\';
337 				keys[1] = '|';
338 			} else if (!lang.Icmp("spanish")) {
339 				keys[0] = 186; // º
340 				keys[1] = 170; // ª
341 			} else if (!lang.Icmp("turkish")) {
342 				keys[0] = '"';
343 				keys[1] = 233; // é
344 			} else if (!lang.Icmp("norwegian")) {
345 				keys[0] = 124; // |
346 				keys[1] = 167; // §
347 			} else if (!lang.Icmp("brazilian")) {
348 				keys[0] = '\'';
349 				keys[1] = '"';
350 			}
351 		}
352 
353 		in_kbd.ClearModified();
354 	}
355 
356 	return shifted ? keys[1] : keys[0];
357 }
358 
359 /*
360 ===============
361 Sys_MapCharForKey
362 ===============
363 */
Sys_MapCharForKey(int key)364 unsigned char Sys_MapCharForKey(int key) {
365 	return key & 0xff;
366 }
367 
368 /*
369 ===============
370 Sys_GrabMouseCursor
371 ===============
372 */
Sys_GrabMouseCursor(bool grabIt)373 void Sys_GrabMouseCursor(bool grabIt) {
374 	int flags;
375 
376 	if (grabIt)
377 		flags = GRAB_ENABLE | GRAB_HIDECURSOR | GRAB_SETSTATE;
378 	else
379 		flags = GRAB_SETSTATE;
380 
381 	GLimp_GrabInput(flags);
382 }
383 
384 /*
385 ================
386 Sys_GetEvent
387 ================
388 */
Sys_GetEvent()389 sysEvent_t Sys_GetEvent() {
390 	SDL_Event ev;
391 	sysEvent_t res = { };
392 	byte key;
393 
394 	static const sysEvent_t res_none = { SE_NONE, 0, 0, 0, NULL };
395 
396 #if SDL_VERSION_ATLEAST(2, 0, 0)
397 	static char s[SDL_TEXTINPUTEVENT_TEXT_SIZE] = {0};
398 	static size_t s_pos = 0;
399 
400 	if (s[0] != '\0') {
401 		res.evType = SE_CHAR;
402 		res.evValue = s[s_pos];
403 
404 		++s_pos;
405 
406 		if (!s[s_pos] || s_pos == SDL_TEXTINPUTEVENT_TEXT_SIZE) {
407 			memset(s, 0, sizeof(s));
408 			s_pos = 0;
409 		}
410 
411 		return res;
412 	}
413 #endif
414 
415 	static byte c = 0;
416 
417 	if (c) {
418 		res.evType = SE_CHAR;
419 		res.evValue = c;
420 
421 		c = 0;
422 
423 		return res;
424 	}
425 
426 	// loop until there is an event we care about (will return then) or no more events
427 	while(SDL_PollEvent(&ev)) {
428 		switch (ev.type) {
429 #if SDL_VERSION_ATLEAST(2, 0, 0)
430 		case SDL_WINDOWEVENT:
431 			switch (ev.window.event) {
432 				case SDL_WINDOWEVENT_FOCUS_GAINED: {
433 						// unset modifier, in case alt-tab was used to leave window and ALT is still set
434 						// as that can cause fullscreen-toggling when pressing enter...
435 						SDL_Keymod currentmod = SDL_GetModState();
436 
437 						int newmod = KMOD_NONE;
438 						if (currentmod & KMOD_CAPS) // preserve capslock
439 							newmod |= KMOD_CAPS;
440 
441 						SDL_SetModState((SDL_Keymod)newmod);
442 					} // new context because visual studio complains about newmod and currentmod not initialized because of the case SDL_WINDOWEVENT_FOCUS_LOST
443 
444 
445 					common->ActivateTool( false );
446 					GLimp_GrabInput(GRAB_ENABLE | GRAB_REENABLE | GRAB_HIDECURSOR); // FIXME: not sure this is still needed after the ActivateTool()-call
447 
448 					// start playing the game sound world again (when coming from editor)
449 					session->SetPlayingSoundWorld();
450 
451 					break;
452 				case SDL_WINDOWEVENT_FOCUS_LOST:
453 					GLimp_GrabInput(0);
454 					break;
455 			}
456 
457 			continue; // handle next event
458 #else
459 		case SDL_ACTIVEEVENT:
460 			{
461 				int flags = 0;
462 
463 				if (ev.active.gain) {
464 					flags = GRAB_ENABLE | GRAB_REENABLE | GRAB_HIDECURSOR;
465 
466 					// unset modifier, in case alt-tab was used to leave window and ALT is still set
467 					// as that can cause fullscreen-toggling when pressing enter...
468 					SDLMod currentmod = SDL_GetModState();
469 					int newmod = KMOD_NONE;
470 					if (currentmod & KMOD_CAPS) // preserve capslock
471 						newmod |= KMOD_CAPS;
472 
473 					SDL_SetModState((SDLMod)newmod);
474 				}
475 
476 				GLimp_GrabInput(flags);
477 			}
478 
479 			continue; // handle next event
480 
481 		case SDL_VIDEOEXPOSE:
482 			continue; // handle next event
483 #endif
484 
485 		case SDL_KEYDOWN:
486 			if (ev.key.keysym.sym == SDLK_RETURN && (ev.key.keysym.mod & KMOD_ALT) > 0) {
487 				cvarSystem->SetCVarBool("r_fullscreen", !renderSystem->IsFullScreen());
488 				PushConsoleEvent("vid_restart");
489 				return res_none;
490 			}
491 
492 			// fall through
493 		case SDL_KEYUP:
494 #if !SDL_VERSION_ATLEAST(2, 0, 0)
495 			key = mapkey(ev.key.keysym.sym);
496 			if (!key) {
497 				unsigned char c;
498 				// check if its an unmapped console key
499 				if (ev.key.keysym.unicode == (c = Sys_GetConsoleKey(false))) {
500 					key = c;
501 				} else if (ev.key.keysym.unicode == (c = Sys_GetConsoleKey(true))) {
502 					key = c;
503 				} else {
504 					if (ev.type == SDL_KEYDOWN)
505 						common->Warning("unmapped SDL key %d (0x%x)", ev.key.keysym.sym, ev.key.keysym.unicode);
506 					continue; // handle next event
507 				}
508 			}
509 #else
510 		{
511 			// workaround for AZERTY-keyboards, which don't have 1, 2, ..., 9, 0 in first row:
512 			// always map those physical keys (scancodes) to those keycodes anyway
513 			// see also https://bugzilla.libsdl.org/show_bug.cgi?id=3188
514 			SDL_Scancode sc = ev.key.keysym.scancode;
515 			if(sc == SDL_SCANCODE_0)
516 			{
517 				key = '0';
518 			}
519 			else if(sc >= SDL_SCANCODE_1 && sc <= SDL_SCANCODE_9)
520 			{
521 				// note that the SDL_SCANCODEs are SDL_SCANCODE_1, _2, ..., _9, SDL_SCANCODE_0
522 				// while in ASCII it's '0', '1', ..., '9' => handle 0 and 1-9 separately
523 				// (doom3 uses the ASCII values for those keys)
524 				key = '1' + (sc - SDL_SCANCODE_1);
525 			}
526 			else
527 			{
528 				key = mapkey(ev.key.keysym.sym);
529 			}
530 
531 			if(!key) {
532 				if (ev.key.keysym.scancode == SDL_SCANCODE_GRAVE) { // TODO: always do this check?
533 					key = Sys_GetConsoleKey(true);
534 				} else {
535 					if (ev.type == SDL_KEYDOWN) {
536 						common->Warning("unmapped SDL key %d", ev.key.keysym.sym);
537 					}
538 					continue; // handle next event
539 				}
540 			}
541 		}
542 #endif
543 
544 			res.evType = SE_KEY;
545 			res.evValue = key;
546 			res.evValue2 = ev.key.state == SDL_PRESSED ? 1 : 0;
547 
548 			kbd_polls.Append(kbd_poll_t(key, ev.key.state == SDL_PRESSED));
549 
550 #if SDL_VERSION_ATLEAST(2, 0, 0)
551 			if (key == K_BACKSPACE && ev.key.state == SDL_PRESSED)
552 				c = key;
553 #else
554 			if (ev.key.state == SDL_PRESSED && (ev.key.keysym.unicode & 0xff00) == 0)
555 				c = ev.key.keysym.unicode & 0xff;
556 #endif
557 
558 			return res;
559 
560 #if SDL_VERSION_ATLEAST(2, 0, 0)
561 		case SDL_TEXTINPUT:
562 			if (ev.text.text[0]) {
563 				res.evType = SE_CHAR;
564 				res.evValue = ev.text.text[0];
565 
566 				if (ev.text.text[1] != '\0')
567 				{
568 					memcpy(s, ev.text.text, SDL_TEXTINPUTEVENT_TEXT_SIZE);
569 					s_pos = 1; // pos 0 is returned
570 				}
571 				return res;
572 			}
573 
574 			continue; // handle next event
575 
576 		case SDL_TEXTEDITING:
577 			// on windows we get this event whenever the window gains focus.. just ignore it.
578 			continue;
579 #endif
580 
581 		case SDL_MOUSEMOTION:
582 			res.evType = SE_MOUSE;
583 			res.evValue = ev.motion.xrel;
584 			res.evValue2 = ev.motion.yrel;
585 
586 			mouse_polls.Append(mouse_poll_t(M_DELTAX, ev.motion.xrel));
587 			mouse_polls.Append(mouse_poll_t(M_DELTAY, ev.motion.yrel));
588 
589 			return res;
590 
591 #if SDL_VERSION_ATLEAST(2, 0, 0)
592 		case SDL_MOUSEWHEEL:
593 			res.evType = SE_KEY;
594 
595 			if (ev.wheel.y > 0) {
596 				res.evValue = K_MWHEELUP;
597 				mouse_polls.Append(mouse_poll_t(M_DELTAZ, 1));
598 			} else {
599 				res.evValue = K_MWHEELDOWN;
600 				mouse_polls.Append(mouse_poll_t(M_DELTAZ, -1));
601 			}
602 
603 			res.evValue2 = 1;
604 
605 			return res;
606 #endif
607 
608 		case SDL_MOUSEBUTTONDOWN:
609 		case SDL_MOUSEBUTTONUP:
610 			res.evType = SE_KEY;
611 
612 			switch (ev.button.button) {
613 			case SDL_BUTTON_LEFT:
614 				res.evValue = K_MOUSE1;
615 				mouse_polls.Append(mouse_poll_t(M_ACTION1, ev.button.state == SDL_PRESSED ? 1 : 0));
616 				break;
617 			case SDL_BUTTON_MIDDLE:
618 				res.evValue = K_MOUSE3;
619 				mouse_polls.Append(mouse_poll_t(M_ACTION3, ev.button.state == SDL_PRESSED ? 1 : 0));
620 				break;
621 			case SDL_BUTTON_RIGHT:
622 				res.evValue = K_MOUSE2;
623 				mouse_polls.Append(mouse_poll_t(M_ACTION2, ev.button.state == SDL_PRESSED ? 1 : 0));
624 				break;
625 
626 #if !SDL_VERSION_ATLEAST(2, 0, 0)
627 			case SDL_BUTTON_WHEELUP:
628 				res.evValue = K_MWHEELUP;
629 				if (ev.button.state == SDL_PRESSED)
630 					mouse_polls.Append(mouse_poll_t(M_DELTAZ, 1));
631 				break;
632 			case SDL_BUTTON_WHEELDOWN:
633 				res.evValue = K_MWHEELDOWN;
634 				if (ev.button.state == SDL_PRESSED)
635 					mouse_polls.Append(mouse_poll_t(M_DELTAZ, -1));
636 				break;
637 #endif
638 			default:
639 #if SDL_VERSION_ATLEAST(2, 0, 0)
640 				// handle X1 button and above
641 				if( ev.button.button < SDL_BUTTON_LEFT + 8 ) // doesn't support more than 8 mouse buttons
642 				{
643 					int buttonIndex = ev.button.button - SDL_BUTTON_LEFT;
644 					res.evValue = K_MOUSE1 + buttonIndex;
645 					mouse_polls.Append( mouse_poll_t( M_ACTION1 + buttonIndex, ev.button.state == SDL_PRESSED ? 1 : 0 ) );
646 				}
647 				else
648 #endif
649 				continue; // handle next event
650 			}
651 
652 			res.evValue2 = ev.button.state == SDL_PRESSED ? 1 : 0;
653 
654 			return res;
655 
656 		case SDL_QUIT:
657 			PushConsoleEvent("quit");
658 			return res_none;
659 
660 		case SDL_USEREVENT:
661 			switch (ev.user.code) {
662 			case SE_CONSOLE:
663 				res.evType = SE_CONSOLE;
664 				res.evPtrLength = (intptr_t)ev.user.data1;
665 				res.evPtr = ev.user.data2;
666 				return res;
667 			default:
668 				common->Warning("unknown user event %u", ev.user.code);
669 				continue; // handle next event
670 			}
671 		default:
672 			// ok, I don't /really/ care about unknown SDL events. only uncomment this for debugging.
673 			// common->Warning("unknown SDL event 0x%x", ev.type);
674 			continue; // handle next event
675 		}
676 	}
677 
678 	return res_none;
679 }
680 
681 /*
682 ================
683 Sys_ClearEvents
684 ================
685 */
Sys_ClearEvents()686 void Sys_ClearEvents() {
687 	SDL_Event ev;
688 
689 	while (SDL_PollEvent(&ev))
690 		;
691 
692 	kbd_polls.SetNum(0, false);
693 	mouse_polls.SetNum(0, false);
694 }
695 
696 /*
697 ================
698 Sys_GenerateEvents
699 ================
700 */
Sys_GenerateEvents()701 void Sys_GenerateEvents() {
702 	char *s = Sys_ConsoleInput();
703 
704 	if (s)
705 		PushConsoleEvent(s);
706 
707 	SDL_PumpEvents();
708 }
709 
710 /*
711 ================
712 Sys_PollKeyboardInputEvents
713 ================
714 */
Sys_PollKeyboardInputEvents()715 int Sys_PollKeyboardInputEvents() {
716 	return kbd_polls.Num();
717 }
718 
719 /*
720 ================
721 Sys_ReturnKeyboardInputEvent
722 ================
723 */
Sys_ReturnKeyboardInputEvent(const int n,int & key,bool & state)724 int Sys_ReturnKeyboardInputEvent(const int n, int &key, bool &state) {
725 	if (n >= kbd_polls.Num())
726 		return 0;
727 
728 	key = kbd_polls[n].key;
729 	state = kbd_polls[n].state;
730 	return 1;
731 }
732 
733 /*
734 ================
735 Sys_EndKeyboardInputEvents
736 ================
737 */
Sys_EndKeyboardInputEvents()738 void Sys_EndKeyboardInputEvents() {
739 	kbd_polls.SetNum(0, false);
740 }
741 
742 /*
743 ================
744 Sys_PollMouseInputEvents
745 ================
746 */
Sys_PollMouseInputEvents()747 int Sys_PollMouseInputEvents() {
748 	return mouse_polls.Num();
749 }
750 
751 /*
752 ================
753 Sys_ReturnMouseInputEvent
754 ================
755 */
Sys_ReturnMouseInputEvent(const int n,int & action,int & value)756 int	Sys_ReturnMouseInputEvent(const int n, int &action, int &value) {
757 	if (n >= mouse_polls.Num())
758 		return 0;
759 
760 	action = mouse_polls[n].action;
761 	value = mouse_polls[n].value;
762 	return 1;
763 }
764 
765 /*
766 ================
767 Sys_EndMouseInputEvents
768 ================
769 */
Sys_EndMouseInputEvents()770 void Sys_EndMouseInputEvents() {
771 	mouse_polls.SetNum(0, false);
772 }
773