1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // console.c
21
22 #include "client.h"
23 #include "prompt.h"
24 #include "version.h"
25
26 #define CON_TIMES 4
27 #define CON_TIMES_MASK ( CON_TIMES - 1 )
28
29 #define CON_TOTALLINES 1024 // total lines in console scrollback
30 #define CON_TOTALLINES_MASK ( CON_TOTALLINES - 1 )
31
32 /* max chars in a single line.
33 * this should be large enough to hold (maxscreenwidth / charwidth) chars,
34 * plus some extra color escape codes
35 */
36 #define CON_LINEWIDTH 512
37
38 typedef struct console_s {
39 qboolean initialized;
40
41 char text[CON_TOTALLINES][CON_LINEWIDTH];
42 int current; // line where next message will be printed
43 int x; // offset in current line for next print
44 int display; // bottom of console displays this line
45
46 int linewidth; // characters across screen
47 int vidWidth, vidHeight;
48 float scale;
49
50 int times[CON_TIMES]; // cls.realtime time the line was generated
51 // for transparent notify lines
52 qboolean addToNotify;
53
54 qhandle_t conbackImage;
55 qhandle_t charsetImage;
56
57 int charWidth, charHeight;
58
59 float currentHeight; // aproaches scr_conlines at scr_conspeed
60 float destHeight; // 0.0 to 1.0 lines of console to display
61 float maxHeight;
62
63 inputField_t chatField;
64 commandPrompt_t prompt;
65
66 qboolean chatTeam;
67 } console_t;
68
69 static console_t con;
70
71 static cvar_t *con_notifytime;
72 static cvar_t *con_clock;
73 static cvar_t *con_height;
74 static cvar_t *con_speed;
75 static cvar_t *con_chat;
76 static cvar_t *con_alpha;
77 static cvar_t *con_scale;
78 static cvar_t *con_font;
79 static cvar_t *con_background;
80
81 // ============================================================================
82
83 /*
84 ================
85 Con_AddToNotify
86 ================
87 */
Con_AddToNotify(qboolean add)88 void Con_AddToNotify( qboolean add ) {
89 con.addToNotify = add;
90 }
91
92 /*
93 ================
94 Con_ClearTyping
95 ================
96 */
Con_ClearTyping(void)97 void Con_ClearTyping( void ) {
98 // clear any typing
99 IF_Clear( &con.prompt.inputLine );
100 }
101
102 /*
103 ================
104 Con_Close
105 ================
106 */
Con_Close(void)107 void Con_Close( void ) {
108 Key_SetDest( cls.key_dest & ~KEY_CONSOLE );
109 con.currentHeight = 0;
110
111 Con_ClearTyping();
112 Con_ClearNotify_f();
113
114 Cvar_Set( "cl_paused", "0" );
115 }
116
117 /*
118 ================
119 Con_ToggleConsole_f
120 ================
121 */
Con_ToggleConsole_f(void)122 void Con_ToggleConsole_f( void ) {
123 if( sv_running->integer && cl.attractLoop == ATR_DEMO && !cls.demoplayback )
124 {
125 Cbuf_AddText( "killserver\n" );
126 //return;
127 }
128
129 Con_ClearTyping();
130 Con_ClearNotify_f();
131
132 if( cls.key_dest & KEY_CONSOLE ) {
133 Key_SetDest( cls.key_dest & ~KEY_CONSOLE );
134 //Cvar_Set( "cl_paused", "0" );
135 return;
136 }
137
138 // FIXME: use old q2 style
139 Key_SetDest( ( cls.key_dest | KEY_CONSOLE ) & ~KEY_MESSAGE );
140
141 // only pause in single player
142 //if( Cvar_VariableInteger( "maxclients" ) == 1 ) {
143 // Cvar_Set( "cl_paused", "1" );
144 //}
145
146 }
147
148 /*
149 ================
150 Con_Clear_f
151 ================
152 */
Con_Clear_f(void)153 void Con_Clear_f( void ) {
154 memset( con.text, 0, sizeof( con.text ) );
155 con.display = con.current;
156 }
157
Con_Dump_g(const char * partial,int state)158 static const char *Con_Dump_g( const char *partial, int state ) {
159 return Com_FileNameGenerator( "", ".txt", partial, qtrue, state );
160 }
161
162 /*
163 ================
164 Con_Dump_f
165
166 Save the console contents out to a file
167 ================
168 */
Con_Dump_f(void)169 void Con_Dump_f( void ) {
170 int l;
171 char *line;
172 fileHandle_t f;
173 char buffer[CON_LINEWIDTH];
174 char name[MAX_QPATH];
175
176 if( Cmd_Argc() != 2 ) {
177 Com_Printf( "Usage: %s <filename>\n", Cmd_Argv( 0 ) );
178 return;
179 }
180
181 Cmd_ArgvBuffer( 1, name, sizeof( name ) );
182 COM_DefaultExtension( name, ".txt", sizeof( buffer ) );
183
184 FS_FOpenFile( name, &f, FS_MODE_WRITE );
185 if( !f ) {
186 Com_EPrintf( "Couldn't open %s for writing.\n", name );
187 return;
188 }
189
190 // skip empty lines
191 for( l = con.current - CON_TOTALLINES + 1 ; l <= con.current ; l++ ) {
192 if( con.text[l & CON_TOTALLINES_MASK][0] ) {
193 break;
194 }
195 }
196
197 // write the remaining lines
198 for( ; l <= con.current ; l++ ) {
199 line = con.text[l & CON_TOTALLINES_MASK];
200 Q_CleanColorStr( line, buffer, sizeof( buffer ) );
201
202 FS_FPrintf( f, "%s\n", buffer );
203 }
204
205 FS_FCloseFile( f );
206
207 Com_Printf( "Dumped console text to %s.\n", name );
208 }
209
210
211 /*
212 ================
213 Con_ClearNotify_f
214 ================
215 */
Con_ClearNotify_f(void)216 void Con_ClearNotify_f( void ) {
217 int i;
218
219 for( i = 0; i < CON_TIMES; i++ )
220 con.times[i] = 0;
221 }
222
223
224 /*
225 ================
226 Con_MessageMode_f
227 ================
228 */
Con_MessageMode_f(void)229 void Con_MessageMode_f( void ) {
230 con.chatTeam = qfalse;
231 Key_SetDest( cls.key_dest | KEY_MESSAGE );
232 }
233
234 /*
235 ================
236 Con_MessageMode2_f
237 ================
238 */
Con_MessageMode2_f(void)239 void Con_MessageMode2_f( void ) {
240 con.chatTeam = qtrue;
241 Key_SetDest( cls.key_dest | KEY_MESSAGE );
242 }
243
244 /*
245 ================
246 Con_CheckResize
247
248 If the line width has changed, reformat the buffer.
249 ================
250 */
Con_CheckResize(void)251 void Con_CheckResize( void ) {
252 int width;
253
254 con.vidWidth = scr_glconfig.vidWidth * con.scale;
255 con.vidHeight = scr_glconfig.vidHeight * con.scale;
256
257 width = ( con.vidWidth / con.charWidth ) - 2;
258
259 if( width == con.linewidth )
260 return;
261
262 con.linewidth = width > CON_LINEWIDTH ? CON_LINEWIDTH : width;
263 con.prompt.inputLine.visibleChars = con.linewidth;
264 con.prompt.widthInChars = con.linewidth;
265 con.chatField.visibleChars = con.linewidth;
266 }
267
268
269 /*
270 ================
271 Con_OnChangeVar
272 ================
273 */
Con_OnChangeVar(cvar_t * self,void * arg)274 static void Con_OnChangeVar( cvar_t *self, void *arg ) {
275 if( con.initialized && cls.ref_initialized ) {
276 Con_SetupDC();
277 }
278 }
279
280
281 /*
282 ================
283 Con_Init
284 ================
285 */
Con_Init(void)286 void Con_Init( void ) {
287 memset( &con, 0, sizeof( con ) );
288
289 //
290 // register our commands
291 //
292 con_notifytime = Cvar_Get( "con_notifytime", "3", 0 );
293 con_clock = Cvar_Get( "con_clock", "0", CVAR_ARCHIVE );
294 con_height = Cvar_Get( "con_height", "0.5", CVAR_ARCHIVE );
295 con_speed = Cvar_Get( "scr_conspeed", "3", 0 );
296 con_chat = Cvar_Get( "con_chat", "0", 0 );
297 con_alpha = Cvar_Get( "con_alpha", "1", CVAR_ARCHIVE );
298 con_scale = Cvar_Get( "con_scale", "1", CVAR_ARCHIVE );
299 con_font = Cvar_Get( "con_font", "conchars", CVAR_ARCHIVE );
300 con_font->changedFunc = Con_OnChangeVar;
301 con_background = Cvar_Get( "con_background", "conback", CVAR_ARCHIVE );
302 con_background->changedFunc = Con_OnChangeVar;
303
304 Cmd_AddCommand( "toggleconsole", Con_ToggleConsole_f );
305 Cmd_AddCommand( "messagemode", Con_MessageMode_f );
306 Cmd_AddCommand( "messagemode2", Con_MessageMode2_f );
307 Cmd_AddCommand( "clear", Con_Clear_f );
308 Cmd_AddCommand( "clearnotify", Con_ClearNotify_f );
309 Cmd_AddCommandEx( "condump", Con_Dump_f, Con_Dump_g );
310
311 IF_Init( &con.prompt.inputLine, 1, MAX_FIELD_TEXT );
312 IF_Init( &con.chatField, 1, MAX_FIELD_TEXT );
313
314 con.prompt.Printf = Con_Printf;
315
316 con.addToNotify = qtrue;
317
318 // use default width if no video initialized yet
319 scr_glconfig.vidWidth = 640;
320 scr_glconfig.vidHeight = 480;
321 con.linewidth = -1;
322 con.charWidth = 8;
323 con.charHeight = 8;
324 con.maxHeight = 1;
325 con.scale = 1;
326
327 Con_CheckResize();
328
329 con.initialized = qtrue;
330
331 Com_Printf( "Console initialized.\n" );
332 }
333
334 /*
335 ================
336 Con_Shutdown
337 ================
338 */
Con_Shutdown(void)339 void Con_Shutdown( void ) {
340 Prompt_Clear( &con.prompt );
341 }
342
343
344 /*
345 ===============
346 Con_Linefeed
347 ===============
348 */
Con_Linefeed(void)349 void Con_Linefeed( void ) {
350 con.x = 0;
351
352 if( con.display == con.current )
353 con.display++;
354 con.current++;
355
356 memset( con.text[con.current & CON_TOTALLINES_MASK], 0,
357 sizeof( con.text[0] ) );
358 }
359
360 /*
361 ================
362 Con_Print
363
364 Handles cursor positioning, line wrapping, etc
365 All console printing must go through this in order to be displayed on screen
366 If no console is visible, the text will appear at the top of the game window
367 ================
368 */
Con_Print(const char * txt)369 void Con_Print( const char *txt ) {
370 int color;
371 static qboolean cr;
372 char *p;
373 int l;
374
375 if( !con.initialized )
376 return;
377
378 color = 0;
379 while( *txt ) {
380 // count word length
381 l = 0;
382 p = ( char * )txt;
383 while( *p > 32 || *p == Q_COLOR_ESCAPE ) {
384 if( Q_IsColorString( p ) ) {
385 p += 2;
386 } else {
387 l++; p++;
388 }
389 }
390
391 // word wrap
392 p = con.text[con.current & CON_TOTALLINES_MASK];
393 if( l < con.linewidth && ( Q_DrawStrlen( p ) + l > con.linewidth ) )
394 con.x = 0;
395
396 if( cr ) {
397 cr = qfalse;
398 con.current--;
399 }
400
401 if( !con.x ) {
402 Con_Linefeed();
403
404 // add color from last line
405 if( color ) {
406 p = con.text[con.current & CON_TOTALLINES_MASK];
407 p[con.x++] = Q_COLOR_ESCAPE;
408 p[con.x++] = color;
409 }
410 }
411
412 switch( *txt ) {
413 case '\r':
414 cr = qtrue;
415 case '\n':
416 con.x = 0;
417 //color = 0;
418 break;
419 case Q_COLOR_ESCAPE:
420 if( !txt[1] ) {
421 break;
422 }
423 txt++;
424 color = *txt;
425 p = con.text[con.current & CON_TOTALLINES_MASK];
426 p[con.x++] = Q_COLOR_ESCAPE;
427 p[con.x++] = color;
428 break;
429 default: // display character and advance
430 p = con.text[con.current & CON_TOTALLINES_MASK];
431 p[con.x++] = *txt;
432 if( Q_DrawStrlen( p ) > con.linewidth )
433 con.x = 0;
434 break;
435 }
436
437 txt++;
438
439 }
440
441 // mark time for transparent overlay
442 // mark every time something is printed,
443 // so long lines don't disappear to early
444 if( con.current >= 0 && con.addToNotify )
445 con.times[con.current & CON_TIMES_MASK] = cls.realtime;
446 }
447
448 /*
449 ================
450 Con_Printf
451
452 Useful for printing text to graphical console only,
453 bypassing system console and logfiles
454 ================
455 */
Con_Printf(const char * fmt,...)456 void Con_Printf( const char *fmt, ... ) {
457 va_list argptr;
458 char msg[MAXPRINTMSG];
459
460 va_start( argptr, fmt );
461 Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
462 va_end( argptr );
463
464 Con_Print( msg );
465 }
466
467 /*
468 ================
469 Con_SetupDC
470 ================
471 */
Con_SetupDC(void)472 void Con_SetupDC( void ) {
473 if( !( con.charsetImage = ref.RegisterFont( con_font->string ) ) ) {
474 /* fall back to default */
475 Com_WPrintf( "Couldn't load %s, falling back to default...\n", con_font->string );
476 con.charsetImage = ref.RegisterFont( "conchars" );
477 }
478 if( !con.charsetImage ) {
479 Com_Error( ERR_FATAL, "Couldn't load pics/conchars.pcx" );
480 }
481 ref.DrawGetFontSize( &con.charWidth, &con.charHeight, con.charsetImage );
482
483 con.conbackImage = ref.RegisterPic( con_background->string );
484
485 }
486
487 /*
488 ==============================================================================
489
490 DRAWING
491
492 ==============================================================================
493 */
494
495 #define CON_PRESTEP ( 10 + con.charHeight * 2 )
496
497 /*
498 ================
499 Con_DrawNotify
500
501 Draws the last few lines of output transparently over the game top
502 ================
503 */
Con_DrawNotify(void)504 void Con_DrawNotify( void ) {
505 int v;
506 char *text;
507 int i;
508 int time;
509 int skip;
510 float alpha;
511 int flags;
512
513 /* only draw notify in game */
514 if( cls.state != ca_active ) {
515 return;
516 }
517 if( cls.key_dest & ( KEY_MENU|KEY_CONSOLE ) ) {
518 return;
519 }
520 if( con.currentHeight ) {
521 return;
522 }
523
524 flags = 0;
525
526 v = 0;
527 for( i = con.current - CON_TIMES + 1; i <= con.current; i++ ) {
528 if( i < 0 )
529 continue;
530 time = con.times[i & CON_TIMES_MASK];
531 if( time == 0 )
532 continue;
533 // alpha fade the last string left on screen
534 alpha = SCR_FadeAlpha( time, con_notifytime->value * 1000, 300 );
535 if( !alpha )
536 continue;
537 text = con.text[i & CON_TOTALLINES_MASK];
538
539 if( v || i != con.current ) {
540 alpha = 1; // don't fade
541 }
542
543 ref.SetColor( DRAW_COLOR_ALPHA, ( byte * )&alpha );
544 ref.DrawString( con.charWidth, v, flags, con.linewidth, text,
545 con.charsetImage );
546
547 v += con.charHeight;
548 }
549
550 ref.SetColor( DRAW_COLOR_CLEAR, NULL );
551
552 if( cls.key_dest & KEY_MESSAGE ) {
553 if( con.chatTeam ) {
554 text = "say_team:";
555 skip = 11;
556 } else {
557 text = "say:";
558 skip = 5;
559 }
560
561 ref.DrawString( con.charWidth, v, flags, MAX_STRING_CHARS, text,
562 con.charsetImage );
563 IF_Draw( &con.chatField, skip * con.charWidth, v,
564 flags | UI_DRAWCURSOR, con.charsetImage );
565
566 }
567
568
569 }
570
571 /*
572 ================
573 Con_DrawSolidConsole
574
575 Draws the console with the solid background
576 ================
577 */
Con_DrawSolidConsole(void)578 void Con_DrawSolidConsole( void ) {
579 int i, y;
580 int rows;
581 char *text;
582 int row;
583 char buffer[CON_LINEWIDTH];
584 int vislines;
585 float alpha;
586 int flags;
587 clipRect_t clip;
588
589 vislines = con.vidHeight * con.currentHeight;
590 if( vislines <= 0 )
591 return;
592
593 if( vislines > con.vidHeight )
594 vislines = con.vidHeight;
595
596 // setup transparency
597 if( cls.state == ca_active &&
598 con_alpha->value &&
599 ( cls.key_dest & KEY_MENU ) == 0 )
600 {
601 alpha = 0.5f + 0.5f * ( con.currentHeight / con_height->value );
602
603 Cvar_ClampValue( con_alpha, 0, 1 );
604 alpha *= con_alpha->value;
605
606 ref.SetColor( DRAW_COLOR_ALPHA, ( byte * )&alpha );
607 }
608
609 clip.left = 0;
610 clip.top = 0;
611 clip.right = 0;
612 clip.bottom = 0;
613 ref.SetClipRect( DRAW_CLIP_TOP, &clip );
614
615 // draw the background
616 if( cls.state != ca_active || ( cls.key_dest & KEY_MENU ) || con_alpha->value ) {
617 ref.DrawStretchPic( 0, vislines - con.vidHeight,
618 con.vidWidth, con.vidHeight, con.conbackImage );
619 }
620
621 // setup text rendering flags
622 flags = 0;
623
624 ref.SetColor( DRAW_COLOR_RGBA, colorCyan );
625
626 // draw clock
627 if( con_clock->integer ) {
628 extern void Com_Time_m( char *buffer, int bufferSize );
629
630 Com_Time_m( buffer, sizeof( buffer ) );
631
632 UIS_DrawStringEx( con.vidWidth - 8,
633 vislines - CON_PRESTEP, flags | UI_RIGHT, MAX_STRING_CHARS,
634 buffer, con.charsetImage );
635 }
636
637 // draw version
638 UIS_DrawStringEx( con.vidWidth - 8,
639 vislines - CON_PRESTEP + con.charHeight, flags | UI_RIGHT,
640 MAX_STRING_CHARS, APPLICATION " " VERSION, con.charsetImage );
641
642
643 // draw the text
644 y = vislines - CON_PRESTEP;
645 rows = y / con.charHeight + 1; // rows of text to draw
646
647 // draw arrows to show the buffer is backscrolled
648 if( con.display != con.current ) {
649 ref.SetColor( DRAW_COLOR_RGBA, colorRed );
650 for( i = 1; i < con.linewidth; i += 4 ) {
651 ref.DrawChar( i * con.charWidth, y, flags, '^', con.charsetImage );
652 }
653
654 y -= con.charHeight;
655 rows--;
656 }
657
658 // draw from the bottom up
659 ref.SetColor( DRAW_COLOR_CLEAR, NULL );
660 row = con.display;
661 for( i = 0; i < rows; i++ ) {
662 if( row < 0 )
663 break;
664 if( con.current - row > CON_TOTALLINES - 1 )
665 break; // past scrollback wrap point
666
667 text = con.text[row & CON_TOTALLINES_MASK];
668
669 ref.DrawString( con.charWidth, y, flags, con.linewidth, text,
670 con.charsetImage );
671
672 y -= con.charHeight;
673 row--;
674
675 }
676
677 //ZOID
678 // draw the download bar
679 // figure out width
680 if( cls.download ) {
681 int x, n, j;
682
683 if( ( text = strrchr( cls.downloadname, '/') ) != NULL )
684 text++;
685 else
686 text = cls.downloadname;
687
688 x = con.linewidth - ( ( con.linewidth * 7 ) / 40 );
689 y = x - strlen( text ) - 8;
690 i = con.linewidth / 3;
691 if ( strlen( text ) > i ) {
692 y = x - i - 11;
693 strncpy( buffer, text, i );
694 buffer[i] = 0;
695 strcat( buffer, "..." );
696 } else {
697 strcpy( buffer, text );
698 }
699 strcat( buffer, ": " );
700 i = strlen( buffer );
701 buffer[i++] = '\x80';
702 // where's the dot go?
703 n = y * cls.downloadpercent / 100;
704 for ( j = 0; j < y; j++ ) {
705 if ( j == n ) {
706 buffer[i++] = '\x83';
707 } else {
708 buffer[i++] = '\x81';
709 }
710 }
711 buffer[i++] = '\x82';
712 buffer[i] = 0;
713
714 sprintf( buffer + i, " %02d%%", cls.downloadpercent );
715
716 // draw it
717 y = vislines - 10;
718 ref.DrawString( con.charWidth, y, 0, CON_LINEWIDTH, buffer, con.charsetImage );
719 }
720 //ZOID
721
722 // draw the input prompt, user text, and cursor if desired
723 if( cls.key_dest & KEY_CONSOLE ) {
724 y = vislines - CON_PRESTEP + con.charHeight;
725
726 // draw it
727 IF_Draw( &con.prompt.inputLine, 2 * con.charWidth, y,
728 flags | UI_DRAWCURSOR, con.charsetImage );
729
730 // draw command prompt
731 ref.SetColor( DRAW_COLOR_RGBA, colorYellow );
732 ref.DrawChar( con.charWidth, y, flags, 17, con.charsetImage );
733 }
734
735 // restore rendering parameters
736 ref.SetColor( DRAW_COLOR_CLEAR, NULL );
737 ref.SetClipRect( DRAW_CLIP_DISABLED, NULL );
738
739 }
740
741 //=============================================================================
742
Con_SetMaxHeight(float frac)743 void Con_SetMaxHeight( float frac ) {
744 con.maxHeight = frac;
745 }
746
747 /*
748 ==================
749 Con_RunConsole
750
751 Scroll it up or down
752 ==================
753 */
Con_RunConsole(void)754 void Con_RunConsole( void ) {
755 Cvar_ClampValue( con_height, 0.1f, con.maxHeight );
756
757 if( cls.state == ca_disconnected && !( cls.key_dest & KEY_MENU ) ) {
758 /* draw fullscreen console */
759 con.destHeight = con.maxHeight;
760 con.currentHeight = con.destHeight;
761 return;
762 }
763
764 if( cls.state > ca_disconnected && cls.state < ca_active ) {
765 if( !cls.ui_initialized ) {
766 /* draw half-screen console */
767 con.destHeight = min( con.maxHeight, 0.5f );
768 con.currentHeight = con.destHeight;
769 return;
770 }
771 }
772
773 // decide on the height of the console
774 if( cls.key_dest & KEY_CONSOLE ) {
775 con.destHeight = con_height->value; // half screen
776 } else {
777 con.destHeight = 0; // none visible
778 }
779
780 if( con.currentHeight > con.destHeight ) {
781 con.currentHeight -= con_speed->value * cls.frametime;
782 if( con.currentHeight < con.destHeight ) {
783 con.currentHeight = con.destHeight;
784 }
785 } else if( con.currentHeight < con.destHeight ) {
786 con.currentHeight += con_speed->value * cls.frametime;
787 if( con.currentHeight > con.destHeight ) {
788 con.currentHeight = con.destHeight;
789 }
790 }
791 }
792
793 /*
794 ==================
795 SCR_DrawConsole
796 ==================
797 */
Con_DrawConsole(void)798 void Con_DrawConsole( void ) {
799 Cvar_ClampValue( con_scale, 1, 9 );
800
801 con.scale = 1.0f / con_scale->value;
802 ref.SetScale( &con.scale );
803
804 Con_CheckResize();
805 Con_DrawSolidConsole();
806 Con_DrawNotify();
807
808 ref.SetScale( NULL );
809
810 }
811
812
813 /*
814 ==============================================================================
815
816 LINE TYPING INTO THE CONSOLE AND COMMAND COMPLETION
817
818 ==============================================================================
819 */
820
821 /*
822 ====================
823 Key_Console
824
825 Interactive line editing and console scrollback
826 ====================
827 */
Key_Console(int key)828 void Key_Console( int key ) {
829 if( key == 'l' && Key_IsDown( K_CTRL ) ) {
830 Con_Clear_f();
831 return;
832 }
833
834 if( key == K_ENTER || key == K_KP_ENTER ) {
835 char *cmd;
836
837 if( !( cmd = Prompt_Action( &con.prompt ) ) ) {
838 Con_Printf( "]\n" );
839 return;
840 }
841
842 // backslash text are commands, else chat
843 if( cmd[0] == '\\' || cmd[0] == '/' ) {
844 Cbuf_AddText( cmd + 1 ); // skip slash
845 } else {
846 if( cls.state == ca_active && con_chat->integer ) {
847 Cbuf_AddText( va( "cmd say \"%s\"", cmd ) );
848 } else {
849 Cbuf_AddText( cmd );
850 }
851 }
852 Cbuf_AddText( "\n" );
853
854 Con_Printf( "]%s\n", cmd );
855
856 if( cls.state == ca_disconnected ) {
857 SCR_UpdateScreen (); // force an update, because the command
858 // may take some time
859 }
860 return;
861 }
862
863 if( key == K_TAB ) {
864 Prompt_CompleteCommand( &con.prompt, qtrue );
865 return;
866 }
867
868 if( key == K_UPARROW ||
869 ( key == 'p' && Key_IsDown( K_CTRL ) ) )
870 {
871 Prompt_HistoryUp( &con.prompt );
872 return;
873 }
874
875 if( key == K_DOWNARROW ||
876 ( key == 'n' && Key_IsDown( K_CTRL ) ) )
877 {
878 Prompt_HistoryDown( &con.prompt );
879 return;
880 }
881
882
883 if( key == K_PGUP || key == K_MWHEELUP ) {
884 if( Key_IsDown( K_CTRL ) ) {
885 con.display -= 6;
886 } else {
887 con.display -= 2;
888 }
889
890 if( con.display < 1 ) {
891 con.display = 1;
892 }
893 return;
894 }
895
896 if( key == K_PGDN || key == K_MWHEELDOWN ) {
897 if( Key_IsDown( K_CTRL ) ) {
898 con.display += 6;
899 } else {
900 con.display += 2;
901 }
902 if( con.display > con.current ) {
903 con.display = con.current;
904 }
905 return;
906 }
907
908
909 if( key == K_HOME && Key_IsDown( K_CTRL ) ) {
910 con.display = 1;
911 return;
912 }
913
914 if( key == K_END && Key_IsDown( K_CTRL ) ) {
915 con.display = con.current;
916 return;
917 }
918
919 IF_KeyEvent( &con.prompt.inputLine, key );
920
921 }
922
Char_Console(int key)923 void Char_Console( int key ) {
924 IF_CharEvent( &con.prompt.inputLine, key );
925 }
926
927 /*
928 ====================
929 Key_Message
930 ====================
931 */
Key_Message(int key)932 void Key_Message( int key ) {
933 if( key == 'l' && Key_IsDown( K_CTRL ) ) {
934 IF_Clear( &con.chatField );
935 return;
936 }
937
938 if( key == K_ENTER || key == K_KP_ENTER ) {
939 Cbuf_AddText( con.chatTeam ? "say_team \"" : "say \"" );
940 Cbuf_AddText( con.chatField.text );
941 Cbuf_AddText( "\"\n" );
942
943 Key_SetDest( cls.key_dest & ~KEY_MESSAGE );
944 IF_Clear( &con.chatField );
945 return;
946 }
947
948 if( key == K_ESCAPE ) {
949 Key_SetDest( cls.key_dest & ~KEY_MESSAGE );
950 IF_Clear( &con.chatField );
951 return;
952 }
953
954 IF_KeyEvent( &con.chatField, key );
955 }
956
Char_Message(int key)957 void Char_Message( int key ) {
958 IF_CharEvent( &con.chatField, key );
959 }
960
961
962
963