2828
2929#if defined(_WIN32 ) || defined(WIN32 )
3030#define OS_WINDOWS
31+ #define WIN32_LEAN_AND_MEAN
3132#include <windows.h>
3233#else
3334#include <sys/ioctl.h>
@@ -111,10 +112,30 @@ char *output_buffer;
111112size_t output_buffer_size ;
112113struct timespec ts_init ;
113114
114- char input_buffer [INPUT_BUFFER_LEN ];
115+ unsigned char input_buffer [INPUT_BUFFER_LEN ];
115116uint16_t event_buffer [EVENT_BUFFER_LEN ];
116117uint16_t * event_buf_loc ;
117118
119+ void DG_AtExit (void )
120+ {
121+ #ifdef OS_WINDOWS
122+ DWORD mode ;
123+ const HANDLE hInputHandle = GetStdHandle (STD_INPUT_HANDLE );
124+ if (UNLIKELY (hInputHandle == INVALID_HANDLE_VALUE ))
125+ return ;
126+ if (UNLIKELY (!GetConsoleMode (hInputHandle , & mode )))
127+ return ;
128+ mode |= ENABLE_ECHO_INPUT ;
129+ SetConsoleMode (hInputHandle , mode );
130+ #else
131+ struct termios t ;
132+ if (UNLIKELY (tcgetattr (STDIN_FILENO , & t )))
133+ return ;
134+ t .c_lflag |= ECHO ;
135+ tcsetattr (STDIN_FILENO , TCSANOW , & t );
136+ #endif
137+ }
138+
118139void DG_Init ()
119140{
120141#ifdef OS_WINDOWS
@@ -128,9 +149,16 @@ void DG_Init()
128149 const HANDLE hInputHandle = GetStdHandle (STD_INPUT_HANDLE );
129150 WINDOWS_CALL (hInputHandle == INVALID_HANDLE_VALUE , "DG_Init: %s" );
130151 WINDOWS_CALL (!GetConsoleMode (hInputHandle , & mode ), "DG_Init: %s" );
131- mode &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT | ENABLE_QUICK_EDIT_MODE );
152+ mode &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT | ENABLE_QUICK_EDIT_MODE | ENABLE_ECHO_INPUT );
132153 WINDOWS_CALL (!SetConsoleMode (hInputHandle , mode ), "DG_Init: %s" );
154+ #else
155+ struct termios t ;
156+ CALL (tcgetattr (STDIN_FILENO , & t ), "DG_Init: tcgetattr error %d" );
157+ t .c_lflag &= ~(ECHO );
158+ CALL (tcsetattr (STDIN_FILENO , TCSANOW , & t ), "DG_Init: tcsetattr error %d" );
133159#endif
160+ atexit (& DG_AtExit );
161+
134162 /* Longest SGR code: \033[38;2;RRR;GGG;BBBm (length 19)
135163 * Maximum 21 bytes per pixel: SGR + 2 x char
136164 * 1 Newline character per line
@@ -220,11 +248,105 @@ uint32_t DG_GetTicksMs()
220248 return (ts .tv_sec - ts_init .tv_sec ) * 1000 + (ts .tv_nsec - ts_init .tv_nsec ) / 1000000 ;
221249}
222250
223- char convertToDoomKey (char * * buf )
251+ #ifdef OS_WINDOWS
252+ unsigned char convertToDoomKey (WORD wVirtualKeyCode , CHAR AsciiChar )
253+ {
254+ switch (wVirtualKeyCode ) {
255+ case VK_RETURN :
256+ return KEY_ENTER ;
257+ case VK_LEFT :
258+ return KEY_LEFTARROW ;
259+ case VK_UP :
260+ return KEY_UPARROW ;
261+ case VK_RIGHT :
262+ return KEY_RIGHTARROW ;
263+ case VK_DOWN :
264+ return KEY_DOWNARROW ;
265+ case VK_SPACE :
266+ return KEY_FIRE ;
267+ case VK_TAB :
268+ return KEY_TAB ;
269+ case VK_F1 :
270+ return KEY_F1 ;
271+ case VK_F2 :
272+ return KEY_F2 ;
273+ case VK_F3 :
274+ return KEY_F3 ;
275+ case VK_F4 :
276+ return KEY_F4 ;
277+ case VK_F5 :
278+ return KEY_F5 ;
279+ case VK_F6 :
280+ return KEY_F6 ;
281+ case VK_F7 :
282+ return KEY_F7 ;
283+ case VK_F8 :
284+ return KEY_F8 ;
285+ case VK_F9 :
286+ return KEY_F9 ;
287+ case VK_F10 :
288+ return KEY_F10 ;
289+ case VK_F11 :
290+ return KEY_F11 ;
291+ case VK_F12 :
292+ return KEY_F12 ;
293+ case VK_BACK :
294+ return KEY_BACKSPACE ;
295+ case VK_PAUSE :
296+ return KEY_PAUSE ;
297+ case VK_RSHIFT :
298+ return KEY_RSHIFT ;
299+ case VK_RCONTROL :
300+ return KEY_RCTRL ;
301+ case VK_CAPITAL :
302+ return KEY_CAPSLOCK ;
303+ case VK_NUMLOCK :
304+ return KEY_NUMLOCK ;
305+ case VK_SCROLL :
306+ return KEY_SCRLCK ;
307+ case VK_SNAPSHOT :
308+ return KEY_PRTSCR ;
309+ case VK_HOME :
310+ return KEY_HOME ;
311+ case VK_END :
312+ return KEY_END ;
313+ case VK_PRIOR :
314+ return KEY_PGUP ;
315+ case VK_NEXT :
316+ return KEY_PGDN ;
317+ case VK_INSERT :
318+ return KEY_INS ;
319+ case VK_DELETE :
320+ return KEY_DEL ;
321+ case VK_NUMPAD0 :
322+ return KEYP_0 ;
323+ case VK_NUMPAD1 :
324+ return KEYP_1 ;
325+ case VK_NUMPAD2 :
326+ return KEYP_2 ;
327+ case VK_NUMPAD3 :
328+ return KEYP_3 ;
329+ case VK_NUMPAD4 :
330+ return KEYP_4 ;
331+ case VK_NUMPAD5 :
332+ return KEYP_5 ;
333+ case VK_NUMPAD6 :
334+ return KEYP_6 ;
335+ case VK_NUMPAD7 :
336+ return KEYP_7 ;
337+ case VK_NUMPAD8 :
338+ return KEYP_8 ;
339+ case VK_NUMPAD9 :
340+ return KEYP_9 ;
341+ default :
342+ return tolower (AsciiChar );
343+ }
344+ }
345+ #else
346+ unsigned char convertToDoomKey (char * * buf )
224347{
225348 switch (* * buf ) {
226349 case '\012' :
227- (* buf )++ ;
228350 return KEY_ENTER ;
229351 case '\033' :
230352 (* buf )++ ;
@@ -233,57 +355,109 @@ char convertToDoomKey(char **buf)
233355 (* buf )++ ;
234356 switch (* * buf ) {
235357 case 'A' :
236- (* buf )++ ;
237358 return KEY_UPARROW ;
238359 case 'B' :
239- (* buf )++ ;
240360 return KEY_DOWNARROW ;
241361 case 'C' :
242- (* buf )++ ;
243362 return KEY_RIGHTARROW ;
244363 case 'D' :
245- (* buf )++ ;
246364 return KEY_LEFTARROW ;
365+ case 'H' :
366+ return KEY_HOME ;
367+ case 'F' :
368+ return KEY_END ;
369+ case '1' :
370+ (* buf )++ ;
371+ switch (* * buf ) {
372+ case '5' :
373+ if (* (++ (* buf )) == '~' )
374+ return KEY_F5 ;
375+ break ;
376+ case '7' :
377+ if (* (++ (* buf )) == '~' )
378+ return KEY_F6 ;
379+ break ;
380+ case '8' :
381+ if (* (++ (* buf )) == '~' )
382+ return KEY_F7 ;
383+ break ;
384+ case '9' :
385+ if (* (++ (* buf )) == '~' )
386+ return KEY_F8 ;
387+ break ;
388+ }
389+ break ;
390+ case '2' :
391+ (* buf )++ ;
392+ switch (* * buf ) {
393+ case '0' :
394+ if (* (++ (* buf )) == '~' )
395+ return KEY_F9 ;
396+ break ;
397+ case '1' :
398+ if (* (++ (* buf )) == '~' )
399+ return KEY_F10 ;
400+ break ;
401+ case '3' :
402+ if (* (++ (* buf )) == '~' )
403+ return KEY_F11 ;
404+ break ;
405+ case '4' :
406+ if (* (++ (* buf )) == '~' )
407+ return KEY_F12 ;
408+ break ;
409+ case '~' :
410+ return KEY_INS ;
411+ }
412+ break ;
413+ case '3' :
414+ if (* (++ (* buf )) == '~' )
415+ return KEY_DEL ;
416+ break ;
417+ case '5' :
418+ if (* (++ (* buf )) == '~' )
419+ return KEY_PGUP ;
420+ break ;
421+ case '6' :
422+ if (* (++ (* buf )) == '~' )
423+ return KEY_PGDN ;
424+ break ;
247425 }
426+ break ;
427+ case 'O' :
428+ (* buf )++ ;
429+ switch (* * buf ) {
430+ case 'P' :
431+ return KEY_F1 ;
432+ case 'Q' :
433+ return KEY_F2 ;
434+ case 'R' :
435+ return KEY_F3 ;
436+ case 'S' :
437+ return KEY_F4 ;
438+ }
439+ break ;
248440 default :
249441 return KEY_ESCAPE ;
250442 }
251443 case ' ' :
252- (* buf )++ ;
253444 return KEY_FIRE ;
254445 default :
255- return tolower (* (( * buf ) ++ ) );
446+ return tolower (* * buf );
256447 }
448+ return '\0' ;
257449}
450+ #endif
258451
259452void DG_ReadInput (void )
260453{
261- static char prev_input_buffer [INPUT_BUFFER_LEN ];
262- static char raw_input_buffer [INPUT_BUFFER_LEN ];
454+ static unsigned char prev_input_buffer [INPUT_BUFFER_LEN ];
263455
264456 memcpy (prev_input_buffer , input_buffer , INPUT_BUFFER_LEN );
265- memset (raw_input_buffer , '\0' , INPUT_BUFFER_LEN );
266457 memset (input_buffer , '\0' , INPUT_BUFFER_LEN );
267458 memset (event_buffer , '\0' , 2u * EVENT_BUFFER_LEN );
268459 event_buf_loc = event_buffer ;
269- #if defined(__unix__ ) || defined(__unix ) || (defined(__APPLE__ ) && defined(__MACH__ ))
270- struct termios oldt , newt ;
271-
272- /* Disable canonical mode */
273- CALL (tcgetattr (STDIN_FILENO , & oldt ), "DG_DrawFrame: tcgetattr error %d" );
274- newt = oldt ;
275- newt .c_lflag &= ~(ICANON );
276- newt .c_cc [VMIN ] = 0 ;
277- newt .c_cc [VTIME ] = 0 ;
278- CALL (tcsetattr (STDIN_FILENO , TCSANOW , & newt ), "DG_DrawFrame: tcsetattr error %d" );
279-
280- CALL (read (2 , raw_input_buffer , INPUT_BUFFER_LEN - 1u ) < 0 , "DG_DrawFrame: read error %d" );
281-
282- CALL (tcsetattr (STDIN_FILENO , TCSANOW , & oldt ), "DG_DrawFrame: tcsetattr error %d" );
283-
284- /* Flush input buffer to prevent read of previous unread input */
285- CALL (tcflush (STDIN_FILENO , TCIFLUSH ), "DG_DrawFrame: tcflush error %d" );
286- #else /* defined(OS_WINDOWS) */
460+ #ifdef OS_WINDOWS
287461 const HANDLE hInputHandle = GetStdHandle (STD_INPUT_HANDLE );
288462 WINDOWS_CALL (hInputHandle == INVALID_HANDLE_VALUE , "DG_ReadInput: %s" );
289463
@@ -306,21 +480,46 @@ void DG_ReadInput(void)
306480 DWORD i ;
307481 for (i = 0 ; i < event_cnt ; i ++ ) {
308482 if (input_records [i ].Event .KeyEvent .bKeyDown && input_records [i ].EventType == KEY_EVENT ) {
309- raw_input_buffer [input_count ++ ] = input_records [i ].Event .KeyEvent .uChar .AsciiChar ;
310- if (input_count == INPUT_BUFFER_LEN - 1u )
311- break ;
483+ unsigned char inp = convertToDoomKey (input_records [i ].Event .KeyEvent .wVirtualKeyCode , input_records [i ].Event .KeyEvent .uChar .AsciiChar );
484+ if (inp ) {
485+ input_buffer [input_count ++ ] = inp ;
486+ if (input_count == INPUT_BUFFER_LEN - 1u )
487+ break ;
488+ }
312489 }
313490 }
314491 }
315492
316493 WINDOWS_CALL (!SetConsoleMode (hInputHandle , old_mode ), "DG_ReadInput: %s" );
317- #endif
494+ #else /* defined(OS_WINDOWS) */
495+ static char raw_input_buffer [INPUT_BUFFER_LEN ];
496+ struct termios oldt , newt ;
497+
498+ memset (raw_input_buffer , '\0' , INPUT_BUFFER_LEN );
499+
500+ /* Disable canonical mode */
501+ CALL (tcgetattr (STDIN_FILENO , & oldt ), "DG_DrawFrame: tcgetattr error %d" );
502+ newt = oldt ;
503+ newt .c_lflag &= ~(ICANON );
504+ newt .c_cc [VMIN ] = 0 ;
505+ newt .c_cc [VTIME ] = 0 ;
506+ CALL (tcsetattr (STDIN_FILENO , TCSANOW , & newt ), "DG_DrawFrame: tcsetattr error %d" );
507+
508+ CALL (read (2 , raw_input_buffer , INPUT_BUFFER_LEN - 1u ) < 0 , "DG_DrawFrame: read error %d" );
509+
510+ CALL (tcsetattr (STDIN_FILENO , TCSANOW , & oldt ), "DG_DrawFrame: tcsetattr error %d" );
511+
512+ /* Flush input buffer to prevent read of previous unread input */
513+ CALL (tcflush (STDIN_FILENO , TCIFLUSH ), "DG_DrawFrame: tcflush error %d" );
514+
318515 /* create input buffer */
319516 char * raw_input_buf_loc = raw_input_buffer ;
320- char * input_buf_loc = input_buffer ;
321- while (* raw_input_buf_loc )
517+ unsigned char * input_buf_loc = input_buffer ;
518+ while (* raw_input_buf_loc ) {
322519 * input_buf_loc ++ = convertToDoomKey (& raw_input_buf_loc );
323-
520+ raw_input_buf_loc ++ ;
521+ }
522+ #endif
324523 /* construct event array */
325524 int i , j ;
326525 for (i = 0 ; input_buffer [i ]; i ++ ) {
0 commit comments