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