1 //********************************************************************************************
2 //*
3 //*    This file is part of Egoboo.
4 //*
5 //*    Egoboo is free software: you can redistribute it and/or modify it
6 //*    under the terms of the GNU General Public License as published by
7 //*    the Free Software Foundation, either version 3 of the License, or
8 //*    (at your option) any later version.
9 //*
10 //*    Egoboo is distributed in the hope that it will be useful, but
11 //*    WITHOUT ANY WARRANTY; without even the implied warranty of
12 //*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 //*    General Public License for more details.
14 //*
15 //*    You should have received a copy of the GNU General Public License
16 //*    along with Egoboo.  If not, see <http://www.gnu.org/licenses/>.
17 //*
18 //********************************************************************************************
19 
20 /// @file egoboo_console.c
21 /// @brief Implementation of code for implementing a Quake-like console in Egoboo
22 /// @details
23 
24 #include "egoboo_console.inl"
25 
26 #include "egoboo_math.inl"
27 #include "egoboo_strutil.h"
28 #include "egoboo_vfs.h"
29 
30 #include "extensions/ogl_debug.h"
31 #include "extensions/SDL_extensions.h"
32 
33 #include "file_common.h"
34 
35 #include <string.h>
36 #include <SDL.h>
37 #include <SDL_opengl.h>
38 #include "egoboo_mem.h"
39 
40 //--------------------------------------------------------------------------------------------
41 //--------------------------------------------------------------------------------------------
42 egoboo_console_t * egoboo_console_top = NULL;
43 
44 Uint8  scancode_to_ascii[SDLK_LAST];
45 Uint8  scancode_to_ascii_shift[SDLK_LAST];
46 
47 //--------------------------------------------------------------------------------------------
48 //--------------------------------------------------------------------------------------------
49 
50 static void egoboo_console_add_output( egoboo_console_t * pcon, char * szNew );
51 static void egoboo_console_write( egoboo_console_t * pcon, const char *format, va_list args );
52 
53 static SDL_bool egoboo_console_draw( egoboo_console_t * pcon );
54 static SDL_bool egoboo_console_run( egoboo_console_t * pcon );
55 
56 //--------------------------------------------------------------------------------------------
57 //--------------------------------------------------------------------------------------------
egoboo_console_stack_unlink(egoboo_console_t * pcon)58 static SDL_bool egoboo_console_stack_unlink( egoboo_console_t * pcon )
59 {
60     SDL_bool retval = SDL_FALSE;
61 
62     if ( NULL == pcon ) return retval;
63 
64     if ( pcon == egoboo_console_top )
65     {
66         egoboo_console_top = pcon->pnext;
67         retval = SDL_TRUE;
68     }
69     else
70     {
71         egoboo_console_t * ptmp;
72 
73         // find the console that points to this one
74         ptmp = egoboo_console_top;
75         while ( NULL != ptmp && NULL != ptmp->pnext )
76         {
77             if ( ptmp->pnext == pcon )
78             {
79                 retval = SDL_TRUE;
80                 ptmp->pnext = pcon->pnext;
81                 break;
82             }
83             ptmp = ptmp->pnext;
84         }
85     }
86 
87     return retval;
88 }
89 
90 //--------------------------------------------------------------------------------------------
egoboo_console_stack_push_front(egoboo_console_t * pcon)91 static SDL_bool egoboo_console_stack_push_front( egoboo_console_t * pcon )
92 {
93     if ( NULL == pcon ) return SDL_FALSE;
94 
95     pcon->pnext = egoboo_console_top;
96     egoboo_console_top = pcon;
97 
98     return SDL_TRUE;
99 }
100 
101 //--------------------------------------------------------------------------------------------
102 //--------------------------------------------------------------------------------------------
egoboo_console_write(egoboo_console_t * pcon,const char * format,va_list args)103 void egoboo_console_write( egoboo_console_t * pcon, const char *format, va_list args )
104 {
105     char buffer[EGOBOO_CONSOLE_WRITE_LEN] = EMPTY_CSTR;
106 
107     if ( NULL != pcon )
108     {
109         vsnprintf( buffer, EGOBOO_CONSOLE_WRITE_LEN - 1, format, args );
110 
111         egoboo_console_add_output( pcon, buffer );
112     }
113 }
114 
115 //--------------------------------------------------------------------------------------------
egoboo_console_fprint(egoboo_console_t * pcon,const char * format,...)116 void egoboo_console_fprint( egoboo_console_t * pcon, const char *format, ... )
117 {
118     va_list args;
119 
120     va_start( args, format );
121     egoboo_console_write( pcon, format, args );
122     va_end( args );
123 }
124 
125 //--------------------------------------------------------------------------------------------
egoboo_console_add_output(egoboo_console_t * pcon,char * szNew)126 void egoboo_console_add_output( egoboo_console_t * pcon, char * szNew )
127 {
128     size_t out_len, copy_len;
129     char * src, * dst;
130 
131     if ( NULL == pcon ) return;
132 
133     // how many characters are we adding?
134     out_len = strlen( szNew );
135 
136     // initialize the pointers for the copy operation
137     src      = szNew;
138     dst      = pcon->output_buffer + pcon->output_carat;
139     copy_len = out_len;
140 
141     // check to make sure that the ranges are valid
142     if ( out_len > EGOBOO_CONSOLE_OUTPUT )
143     {
144         // we need to replace the entire output buffer with
145         // a portion of szNew
146 
147         size_t offset = out_len - EGOBOO_CONSOLE_OUTPUT - 1;
148 
149         // update the copy parameters
150         src      = szNew + offset;
151         copy_len = out_len - offset;
152     }
153     else if ( pcon->output_carat + out_len > EGOBOO_CONSOLE_OUTPUT )
154     {
155         // the length of the buffer after adding szNew would be too large
156         // get rid of some of the input buffer and then add szNew
157 
158         size_t offset = ( pcon->output_carat + out_len ) - EGOBOO_CONSOLE_OUTPUT - 1;
159 
160         // move the memory so that we create some space
161         memmove( pcon->output_buffer, pcon->output_buffer + offset, pcon->output_carat - offset );
162 
163         // update the copy parameters
164         pcon->output_carat -= offset;
165         dst = pcon->output_buffer - pcon->output_carat;
166     }
167 
168     pcon->output_carat += snprintf( dst, EGOBOO_CONSOLE_OUTPUT - pcon->output_carat, "%s", src );
169     pcon->output_buffer[EGOBOO_CONSOLE_OUTPUT-1] = CSTR_END;
170 }
171 
172 //--------------------------------------------------------------------------------------------
egoboo_console_ctor(egoboo_console_t * pcon,SDL_Rect Con_rect,egoboo_console_callback_t pcall,void * data)173 egoboo_console_t * egoboo_console_ctor( egoboo_console_t * pcon, SDL_Rect Con_rect, egoboo_console_callback_t pcall, void * data )
174 {
175     if ( NULL == pcon ) return NULL;
176 
177     // reset all the console data
178     memset( pcon, 0, sizeof( *pcon ) );
179 
180     // set the console's font
181     pcon->pfont = fnt_loadFont( vfs_resolveReadFilename( "mp_data/pc8x8.fon" ), 12 );
182 
183     // set the console's rectangle
184     pcon->rect = Con_rect;
185 
186     // register the "run" callback
187     pcon->run_func = pcall;
188     pcon->run_data = data;
189 
190     // insert the new console as the top console
191     egoboo_console_stack_push_front( pcon );
192 
193     return pcon;
194 }
195 
196 //--------------------------------------------------------------------------------------------
egoboo_console_create(egoboo_console_t * pcon,SDL_Rect Con_rect,egoboo_console_callback_t pcall,void * data)197 egoboo_console_t * egoboo_console_create( egoboo_console_t * pcon, SDL_Rect Con_rect, egoboo_console_callback_t pcall, void * data )
198 {
199     SDL_bool local_allocation = SDL_FALSE;
200 
201     if ( NULL == pcon )
202     {
203         local_allocation = SDL_TRUE;
204         pcon = EGOBOO_NEW( egoboo_console_t );
205     }
206 
207     return egoboo_console_ctor( pcon, Con_rect, pcall,  data );
208 }
209 
210 //--------------------------------------------------------------------------------------------
egoboo_console_run(egoboo_console_t * pcon)211 SDL_bool egoboo_console_run( egoboo_console_t * pcon )
212 {
213     SDL_bool retval = SDL_FALSE;
214 
215     if ( NULL == pcon ) return retval;
216 
217     if ( NULL != pcon->run_func )
218     {
219         retval = pcon->run_func( pcon, pcon->run_data );
220     }
221 
222     return retval;
223 }
224 
225 //--------------------------------------------------------------------------------------------
egoboo_console_dtor(egoboo_console_t * pcon)226 egoboo_console_t * egoboo_console_dtor( egoboo_console_t * pcon )
227 {
228     if ( NULL == pcon ) return NULL;
229 
230     fnt_freeFont( pcon->pfont );
231 
232     // remove the console from the stack
233     egoboo_console_stack_unlink( pcon );
234 
235     return pcon;
236 }
237 
238 //--------------------------------------------------------------------------------------------
egoboo_console_destroy(egoboo_console_t ** pcon,SDL_bool do_free)239 SDL_bool egoboo_console_destroy( egoboo_console_t ** pcon, SDL_bool do_free )
240 {
241     if ( NULL == pcon ) return SDL_FALSE;
242 
243     if ( NULL == egoboo_console_dtor( *pcon ) ) return SDL_FALSE;
244 
245     if ( do_free ) EGOBOO_DELETE( *pcon );
246 
247     return SDL_TRUE;
248 }
249 
250 //--------------------------------------------------------------------------------------------
egoboo_console_draw_begin()251 void egoboo_console_draw_begin()
252 {
253     // do not use the ATTRIB_PUSH macro, since the glPopAttrib() is in a different function
254     GL_DEBUG( glPushAttrib )( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT );
255 
256     // don't worry about hidden surfaces
257     GL_DEBUG( glDisable )( GL_DEPTH_TEST );                                        // GL_ENABLE_BIT
258 
259     // draw draw front and back faces of polygons
260     GL_DEBUG( glDisable )( GL_CULL_FACE );                                         // GL_ENABLE_BIT
261 
262     GL_DEBUG( glEnable )( GL_TEXTURE_2D );                                         // GL_ENABLE_BIT
263 
264     GL_DEBUG( glEnable )( GL_BLEND );                                              // GL_ENABLE_BIT
265     GL_DEBUG( glBlendFunc )( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );               // GL_COLOR_BUFFER_BIT
266 
267     GL_DEBUG( glViewport )( 0, 0, sdl_scr.x, sdl_scr.y );                          // GL_VIEWPORT_BIT
268 
269     // Set up an ortho projection for the gui to use.  Controls are free to modify this
270     // later, but most of them will need this, so it's done by default at the beginning
271     // of a frame
272 
273     // store the GL_PROJECTION matrix (this stack has a finite depth, minimum of 32)
274     GL_DEBUG( glMatrixMode )( GL_PROJECTION );
275     GL_DEBUG( glPushMatrix )();
276     GL_DEBUG( glLoadIdentity )();
277     GL_DEBUG( glOrtho )( 0, sdl_scr.x, sdl_scr.y, 0, -1, 1 );
278 
279     // store the GL_MODELVIEW matrix (this stack has a finite depth, minimum of 32)
280     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
281     GL_DEBUG( glPushMatrix )();
282     GL_DEBUG( glLoadIdentity )();
283 }
284 
285 //--------------------------------------------------------------------------------------------
egoboo_console_draw_end()286 void egoboo_console_draw_end()
287 {
288     // Restore the GL_PROJECTION matrix
289     GL_DEBUG( glMatrixMode )( GL_PROJECTION );
290     GL_DEBUG( glPopMatrix )();
291 
292     // Restore the GL_MODELVIEW matrix
293     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
294     GL_DEBUG( glPopMatrix )();
295 
296     // Re-enable any states disabled by gui_beginFrame
297     // do not use the ATTRIB_POP macro, since the glPushAttrib() is in a different function
298     GL_DEBUG( glPopAttrib )();
299 }
300 
301 //--------------------------------------------------------------------------------------------
egoboo_console_draw(egoboo_console_t * pcon)302 SDL_bool egoboo_console_draw( egoboo_console_t * pcon )
303 {
304     char   buffer[EGOBOO_CONSOLE_WRITE_LEN] = EMPTY_CSTR;
305     size_t console_line_count;
306     size_t console_line_offsets[1024];
307     size_t console_line_lengths[1024];
308     char * pstr;
309 
310     SDL_Rect * pwin;
311     SDL_Surface * surf = SDL_GetVideoSurface();
312 
313     if ( NULL == surf || NULL == pcon || !pcon->on ) return SDL_FALSE;
314 
315     pwin = &( pcon->rect );
316 
317     GL_DEBUG( glDisable )( GL_TEXTURE_2D );
318 
319     GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
320     GL_DEBUG( glLineWidth )( 5 );
321     GL_DEBUG( glBegin )( GL_LINE_LOOP );
322     {
323         GL_DEBUG( glVertex2i )( pwin->x,           pwin->y );
324         GL_DEBUG( glVertex2i )( pwin->x + pwin->w, pwin->y );
325         GL_DEBUG( glVertex2i )( pwin->x + pwin->w, pwin->y + pwin->h );
326         GL_DEBUG( glVertex2i )( pwin->x,           pwin->y + pwin->h );
327     }
328     GL_DEBUG_END();
329     GL_DEBUG( glLineWidth )( 1 );
330 
331     GL_DEBUG( glColor4f )( 0, 0, 0, 1 );
332     GL_DEBUG( glBegin )( GL_POLYGON );
333     {
334         GL_DEBUG( glVertex2i )( pwin->x,           pwin->y );
335         GL_DEBUG( glVertex2i )( pwin->x + pwin->w, pwin->y );
336         GL_DEBUG( glVertex2i )( pwin->x + pwin->w, pwin->y + pwin->h );
337         GL_DEBUG( glVertex2i )( pwin->x,           pwin->y + pwin->h );
338     }
339     GL_DEBUG_END();
340 
341     GL_DEBUG( glEnable )( GL_TEXTURE_2D );
342 
343     GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
344     ATTRIB_PUSH( __FUNCTION__, GL_SCISSOR_BIT | GL_ENABLE_BIT );
345     {
346         int text_w, text_h, height;
347 
348         // make the texture a "null" texture
349         GL_DEBUG( glBindTexture )( GL_TEXTURE_2D, ( GLuint )( ~0 ) );
350 
351         // clip the viewport
352         GL_DEBUG( glEnable )( GL_SCISSOR_TEST );
353         GL_DEBUG( glScissor )( pwin->x, surf->h - ( pwin->y + pwin->h ), pwin->w, pwin->h );
354 
355         height = pwin->h;
356 
357         // draw the current command line
358         buffer[0] = EGOBOO_CONSOLE_PROMPT;
359         buffer[1] = ' ';
360         buffer[2] = CSTR_END;
361 
362         strncat( buffer, pcon->buffer, 1022 );
363         buffer[1022] = CSTR_END;
364 
365         fnt_getTextSize( pcon->pfont, buffer, &text_w, &text_h );
366         height -= text_h;
367         fnt_drawText( pcon->pfont, NULL, pwin->x, height - text_h, buffer );
368 
369         if ( CSTR_END != pcon->output_buffer[0] )
370         {
371             int i;
372 
373             // grab the line offsets
374             console_line_count = 0;
375             pstr = pcon->output_buffer;
376             while ( NULL != pstr )
377             {
378                 size_t len;
379 
380                 len = strcspn( pstr, "\n" );
381 
382                 console_line_offsets[console_line_count] = pstr - pcon->output_buffer;
383                 console_line_lengths[console_line_count] = len;
384 
385                 if ( 0 == len ) break;
386 
387                 pstr += len + 1;
388                 console_line_count++;
389             }
390 
391             // draw the last output line and work backwards
392             for ( i = (( int )console_line_count ) - 1; i >= 0 && height > 0 ; i-- )
393             {
394                 size_t len = MIN( 1023, console_line_lengths[i] );
395 
396                 strncpy( buffer, pcon->output_buffer + console_line_offsets[i], len );
397                 buffer[len] = CSTR_END;
398 
399                 fnt_getTextSize( pcon->pfont, buffer, &text_w, &text_h );
400                 height -= text_h;
401                 fnt_drawText( pcon->pfont, NULL, pwin->x, height - text_h, buffer );
402             }
403         }
404 
405     };
406 
407     ATTRIB_POP( __FUNCTION__ );
408     return SDL_TRUE;
409 }
410 
411 //--------------------------------------------------------------------------------------------
egoboo_console_draw_all()412 void egoboo_console_draw_all()
413 {
414     egoboo_console_t * pcon = egoboo_console_top;
415 
416     if ( NULL == pcon ) return;
417 
418     egoboo_console_draw_begin();
419     {
420         for ( pcon = egoboo_console_top; NULL != pcon; pcon = pcon->pnext )
421         {
422             egoboo_console_draw( pcon );
423         }
424     }
425     egoboo_console_draw_end();
426 }
427 
428 //--------------------------------------------------------------------------------------------
egoboo_console_show(egoboo_console_t * pcon)429 void egoboo_console_show( egoboo_console_t * pcon )
430 {
431     if ( NULL != pcon )
432     {
433         // turn the console on
434         pcon->on = SDL_TRUE;
435     }
436 
437     // fix the keyrepeat
438     if ( NULL == egoboo_console_top )
439     {
440         SDL_EnableKeyRepeat( 0, SDL_DEFAULT_REPEAT_INTERVAL );
441     }
442     else
443     {
444         SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
445     }
446 }
447 
448 //--------------------------------------------------------------------------------------------
egoboo_console_hide(egoboo_console_t * pcon)449 void egoboo_console_hide( egoboo_console_t * pcon )
450 {
451     if ( NULL != pcon )
452     {
453         // turn the console on
454         pcon->on = SDL_FALSE;
455     }
456 
457     // fix the keyrepeat
458     if ( NULL == egoboo_console_top )
459     {
460         SDL_EnableKeyRepeat( 0, SDL_DEFAULT_REPEAT_INTERVAL );
461     }
462     else
463     {
464         SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
465     }
466 }
467 
468 //--------------------------------------------------------------------------------------------
egoboo_console_get_saved(egoboo_console_t * pcon)469 const char * egoboo_console_get_saved( egoboo_console_t * pcon )
470 {
471     if ( NULL == pcon ) return "";
472 
473     pcon->save_count = CLIP( pcon->save_count, 0, EGOBOO_CONSOLE_LINES );
474     pcon->save_index = CLIP( pcon->save_index, 0, pcon->save_count - 1 );
475 
476     return pcon->save_buffer[pcon->save_index];
477 }
478 
479 //--------------------------------------------------------------------------------------------
egoboo_console_add_saved(egoboo_console_t * pcon,char * str)480 void egoboo_console_add_saved( egoboo_console_t * pcon, char * str )
481 {
482     if ( NULL == pcon ) return;
483 
484     pcon->save_count = CLIP( pcon->save_count, 0, EGOBOO_CONSOLE_LINES );
485 
486     if ( pcon->save_count >= EGOBOO_CONSOLE_LINES )
487     {
488         int i;
489 
490         // bump all of the saved lines so that we can insert a new one
491         for ( i = 0; i < EGOBOO_CONSOLE_LINES - 1; i++ )
492         {
493             strncpy( pcon->save_buffer[i], pcon->save_buffer[i+1], EGOBOO_CONSOLE_LENGTH );
494         }
495         pcon->save_count--;
496     }
497 
498     strncpy( pcon->save_buffer[pcon->save_count], str, EGOBOO_CONSOLE_LENGTH );
499     pcon->save_count++;
500     pcon->save_index = pcon->save_count;
501 }
502 
503 //--------------------------------------------------------------------------------------------
egoboo_console_handle_events(SDL_Event * pevt)504 SDL_Event * egoboo_console_handle_events( SDL_Event * pevt )
505 {
506     egoboo_console_t     * pcon = egoboo_console_top;
507     SDLKey              vkey;
508 
509     Uint32 kmod;
510     SDL_bool is_alt, is_shift;
511 
512     if ( NULL == pcon || NULL == pevt ) return pevt;
513 
514     // only handle keyboard events
515     if ( SDL_KEYDOWN != pevt->type ) return pevt;
516 
517     // grab the virtual key code
518     vkey = pevt->key.keysym.sym;
519 
520     // get any keymods
521     kmod = SDL_GetModState();
522 
523     is_alt   = ( SDL_bool )HAS_SOME_BITS( kmod, KMOD_ALT | KMOD_CTRL );
524     is_shift = ( SDL_bool )HAS_SOME_BITS( kmod, KMOD_SHIFT );
525 
526     // start the top console
527     if ( !is_alt && !is_shift && SDLK_BACKQUOTE == vkey )
528     {
529         if ( !pcon->on )
530         {
531             pcon->on = SDL_TRUE;
532             pcon->buffer_carat = 0;
533             pcon->buffer[0]    = CSTR_END;
534 
535             SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_DELAY );
536             return NULL;
537         }
538     };
539 
540     // quit the top console. I would like escape, but it is getting confused with the ui "quit" command
541     if ( !is_alt && !is_shift && SDLK_BACKQUOTE == vkey )
542     {
543         if ( pcon->on )
544         {
545             pcon->on           = SDL_FALSE;
546             pcon->buffer_carat = 0;
547             pcon->buffer[0]    = CSTR_END;
548 
549             SDL_EnableKeyRepeat( 0, SDL_DEFAULT_REPEAT_DELAY );
550             return NULL;
551         }
552     };
553 
554     // Only grab the keycodes if the terminal is on
555     if ( !pcon->on ) return pevt;
556 
557     // handle any terminal commands
558     if ( NULL != pevt && !is_alt && !is_shift )
559     {
560         if ( SDLK_BACKSPACE == vkey )
561         {
562             if ( pcon->buffer_carat > 0 )
563             {
564                 pcon->buffer_carat--;
565             }
566             pcon->buffer[pcon->buffer_carat] = CSTR_END;
567 
568             pevt = NULL;
569         }
570         else if ( SDLK_UP == vkey )
571         {
572             pcon->save_index--;
573 
574             if ( pcon->save_index < 0 )
575             {
576                 // after the last command line. blank the line
577                 pcon->save_index   = 0;
578                 pcon->buffer[0]    = CSTR_END;
579                 pcon->buffer_carat = 0;
580             }
581             else
582             {
583                 pcon->save_index = CLIP( pcon->save_index, 0, pcon->save_count - 1 );
584 
585                 if ( pcon->save_count > 0 )
586                 {
587                     strncpy( pcon->buffer, pcon->save_buffer[pcon->save_index], SDL_arraysize( pcon->buffer ) );
588                     pcon->buffer_carat = strlen( pcon->buffer );
589                     pcon->buffer_carat = (( int )pcon->buffer_carat ) - 1;
590                 }
591             }
592 
593             pevt = NULL;
594         }
595         else if ( SDLK_DOWN == vkey )
596         {
597             pcon->save_index++;
598 
599             if ( pcon->save_index >= pcon->save_count )
600             {
601                 // before the first command line. blank the line
602                 pcon->save_index   = pcon->save_count;
603                 pcon->buffer[0]    = CSTR_END;
604                 pcon->buffer_carat = 0;
605             }
606             else
607             {
608                 pcon->save_index = CLIP( pcon->save_index, 0, pcon->save_count - 1 );
609 
610                 if ( pcon->save_count > 0 )
611                 {
612                     strncpy( pcon->buffer, pcon->save_buffer[pcon->save_index], EGOBOO_CONSOLE_LENGTH - 1 );
613                     pcon->buffer_carat = strlen( pcon->buffer );
614                     pcon->buffer_carat = (( int )pcon->buffer_carat ) - 1;
615                 }
616             }
617 
618             pevt = NULL;
619         }
620         else if ( SDLK_LEFT == vkey )
621         {
622             pcon->buffer_carat--;
623             pcon->buffer_carat = CLIP( pcon->buffer_carat, 0, EGOBOO_CONSOLE_LENGTH - 1 );
624 
625             pevt = NULL;
626         }
627 
628         else if ( SDLK_RIGHT == vkey )
629         {
630             pcon->buffer_carat++;
631             pcon->buffer_carat = CLIP( pcon->buffer_carat, 0, EGOBOO_CONSOLE_LENGTH - 1 );
632 
633             pevt = NULL;
634         }
635 
636         else if ( SDLK_RETURN == vkey || SDLK_KP_ENTER == vkey )
637         {
638             pcon->buffer[pcon->buffer_carat] = CSTR_END;
639 
640             // add this command to the "saved command list"
641             egoboo_console_add_saved( pcon, pcon->buffer );
642 
643             // add the command to the output buffer
644             egoboo_console_fprint( pcon, "%c %s\n", EGOBOO_CONSOLE_PROMPT, pcon->buffer );
645 
646             // actually execute the command
647             egoboo_console_run( pcon );
648 
649             // blank the command line
650             pcon->buffer_carat = 0;
651             pcon->buffer[0] = CSTR_END;
652 
653             pevt = NULL;
654         }
655     }
656 
657     // handle normal keystrokes
658     if ( NULL != pevt && !is_alt && vkey < SDLK_NUMLOCK )
659     {
660         if ( pcon->buffer_carat < EGOBOO_CONSOLE_LENGTH )
661         {
662             if ( is_shift )
663             {
664                 pcon->buffer[pcon->buffer_carat++] = scancode_to_ascii_shift[vkey];
665             }
666             else
667             {
668                 pcon->buffer[pcon->buffer_carat++] = scancode_to_ascii[vkey];
669             }
670             pcon->buffer[pcon->buffer_carat] = CSTR_END;
671 
672             pevt = NULL;
673         }
674     }
675 
676     return pevt;
677 }
678 
679 //--------------------------------------------------------------------------------------------
init_scancodes()680 void init_scancodes()
681 {
682     /// @details BB@> initialize the scancode translation
683 
684     int i;
685 
686     // do the basic translation
687     for ( i = 0; i < SDLK_LAST; i++ )
688     {
689         // SDL uses ascii values for it's virtual scancodes
690         scancode_to_ascii[i] = i;
691         if ( i < 255 )
692         {
693             scancode_to_ascii_shift[i] = toupper( i );
694         }
695         else
696         {
697             scancode_to_ascii_shift[i] = scancode_to_ascii[i];
698         }
699     }
700 
701     // fix the keymap
702     scancode_to_ascii_shift[SDLK_1]  = '!';
703     scancode_to_ascii_shift[SDLK_2]  = '@';
704     scancode_to_ascii_shift[SDLK_3]  = '#';
705     scancode_to_ascii_shift[SDLK_4]  = '$';
706     scancode_to_ascii_shift[SDLK_5]  = '%';
707     scancode_to_ascii_shift[SDLK_6]  = '^';
708     scancode_to_ascii_shift[SDLK_7]  = '&';
709     scancode_to_ascii_shift[SDLK_8]  = '*';
710     scancode_to_ascii_shift[SDLK_9]  = '(';
711     scancode_to_ascii_shift[SDLK_0]  = ')';
712 
713     scancode_to_ascii_shift[SDLK_QUOTE]        = '\"';
714     scancode_to_ascii_shift[SDLK_SEMICOLON]    = ':';
715     scancode_to_ascii_shift[SDLK_PERIOD]       = '>';
716     scancode_to_ascii_shift[SDLK_COMMA]        = '<';
717     scancode_to_ascii_shift[SDLK_BACKQUOTE]    = '~';
718     scancode_to_ascii_shift[SDLK_MINUS]        = '_';
719     scancode_to_ascii_shift[SDLK_EQUALS]       = '+';
720     scancode_to_ascii_shift[SDLK_LEFTBRACKET]  = '{';
721     scancode_to_ascii_shift[SDLK_RIGHTBRACKET] = '}';
722     scancode_to_ascii_shift[SDLK_BACKSLASH]    = '|';
723     scancode_to_ascii_shift[SDLK_SLASH]        = '?';
724 }
725