2 * Code for controlling the console
3 * Based on an early version of SDL_Console
5 * Written By: Garrett Banuk <mongoose@mongeese.org>
6 * Code Cleanup and heavily extended by: Clemens Wacha <reflex-2000@gmx.net>
7 * Ported to use native Descent interfaces by: Bradley Bell <btb@icculus.org>
9 * This is free, just be sure to give us credit when using it
10 * in any of your programs.
27 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
29 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
30 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
31 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
33 #define CON_NUM_LINES 128
34 // Cut the buffer line if it becomes longer than this
35 #define CON_CHARS_PER_LINE 128
36 // Cursor blink frequency in ms
37 #define CON_BLINK_RATE 500
38 // Border in pixels from the most left to the first letter
39 #define CON_CHAR_BORDER 4
40 // Default prompt used at the commandline
41 #define CON_DEFAULT_PROMPT "]"
42 // Cursor shown if we are in insert mode
43 #define CON_INS_CURSOR "_"
44 // Cursor shown if we are in overwrite mode
45 #define CON_OVR_CURSOR "|"
48 /* The console's data */
49 static char **CommandLines; // List of all the past commands
50 static int TotalCommands; // Number of commands in the Back Commands
51 static int LineBuffer; // The number of visible lines in the console (autocalculated)
52 static int VChars; // The number of visible characters in one console line (autocalculated)
53 static char *Prompt; // Prompt displayed in command line
54 static char Command[CON_CHARS_PER_LINE]; // current command in command line = lcommand + rcommand
55 static char LCommand[CON_CHARS_PER_LINE]; // right hand side of cursor
56 static char RCommand[CON_CHARS_PER_LINE]; // left hand side of cursor
57 static char VCommand[CON_CHARS_PER_LINE]; // current visible command line
58 static int CursorPos; // Current cursor position in CurrentCommand
59 static int Offset; // CommandOffset (first visible char of command) - if command is too long to fit into console
60 int InsMode; // Insert or Overwrite characters?
61 static int CommandScrollBack; // How much the users scrolled back in the command lines
64 /* Frees all the memory loaded by the console */
65 static void CON_Free(void);
66 /* shift command history (the one you can switch with the up/down keys) */
67 static void CON_NewLineCommand(void);
70 /* Initializes the console */
79 CommandScrollBack = 0;
80 Prompt = d_strdup(CON_DEFAULT_PROMPT);
82 VChars = CON_CHARS_PER_LINE - 1;
83 LineBuffer = CON_NUM_LINES;
85 CommandLines = (char **)d_malloc(sizeof(char *) * LineBuffer);
86 for (loop = 0; loop <= LineBuffer - 1; loop++) {
87 CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
89 memset(Command, 0, CON_CHARS_PER_LINE);
90 memset(LCommand, 0, CON_CHARS_PER_LINE);
91 memset(RCommand, 0, CON_CHARS_PER_LINE);
92 memset(VCommand, 0, CON_CHARS_PER_LINE);
98 /* Frees all the memory loaded by the console */
99 static void CON_Free(void)
103 for (i = 0; i <= LineBuffer - 1; i++) {
104 d_free(CommandLines[i]);
106 d_free(CommandLines);
114 /* Increments the command lines */
115 static void CON_NewLineCommand(void)
120 temp = CommandLines[LineBuffer - 1];
122 for (loop = LineBuffer - 1; loop > 0; loop--)
123 CommandLines[loop] = CommandLines[loop - 1];
125 CommandLines[0] = temp;
127 memset(CommandLines[0], 0, CON_CHARS_PER_LINE);
128 if (TotalCommands < LineBuffer - 1)
133 /* Draws the command line the user is typing in to the screen */
134 /* completely rewritten by C.Wacha */
135 void DrawCommandLine(int y)
139 static unsigned int LastBlinkTime = 0; // Last time the consoles cursor blinked
140 static int LastCursorPos = 0; // Last Cursor Position
141 static int Blink = 0; // Is the cursor currently blinking
143 commandbuffer = VChars - (int)strlen(Prompt) - 1; // -1 to make cursor visible
145 // Concatenate the left and right side to command
146 strcpy(Command, LCommand);
147 strncat(Command, RCommand, strlen(RCommand));
149 //calculate display offset from current cursor position
150 if (Offset < CursorPos - commandbuffer)
151 Offset = CursorPos - commandbuffer;
152 if(Offset > CursorPos)
155 // first add prompt to visible part
156 strcpy(VCommand, Prompt);
158 // then add the visible part of the command
159 strncat(VCommand, &Command[Offset], strlen(&Command[Offset]));
161 // now display the result
162 gr_string(CON_CHAR_BORDER, y - grd_curfont->ft_h, VCommand);
164 // at last add the cursor
165 // check if the blink period is over
166 if (get_msecs() > LastBlinkTime) {
167 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
174 // check if cursor has moved - if yes display cursor anyway
175 if (CursorPos != LastCursorPos) {
176 LastCursorPos = CursorPos;
177 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
182 int prompt_width, cmd_width, h, w;
184 gr_get_string_size(Prompt, &prompt_width, &h, &w);
185 gr_get_string_size(LCommand + Offset, &cmd_width, &h, &w);
186 x = CON_CHAR_BORDER + prompt_width + cmd_width;
188 gr_string(x, y - grd_curfont->ft_h, CON_INS_CURSOR);
190 gr_string(x, y - grd_curfont->ft_h, CON_OVR_CURSOR);
195 /* Sets the Prompt for console */
196 void CON_SetPrompt(char* newprompt) {
197 // check length so we can still see at least 1 char :-)
198 if (strlen(newprompt) < VChars) {
200 Prompt = d_strdup(newprompt);
202 CON_Out("prompt too long. (max. %i chars)\n", VChars - 1);
206 /* Executes the command entered */
207 void CON_Execute(void)
209 if(strlen(Command) > 0) {
210 CON_NewLineCommand();
212 // copy the input into the past commands strings
213 strcpy(CommandLines[0], Command);
215 // display the command including the prompt
216 CON_Out("%s%s\n", Prompt, Command);
221 CommandScrollBack = -1;
226 void CON_TabCompletion(void)
231 command = cmd_complete(LCommand);
234 return; // no tab completion took place so return silently
236 j = (int)strlen(command);
237 if (j > CON_CHARS_PER_LINE - 2)
238 j = CON_CHARS_PER_LINE-1;
240 memset(LCommand, 0, CON_CHARS_PER_LINE);
243 for (i = 0; i < j; i++) {
245 LCommand[i] = command[i];
247 // add a trailing space
250 LCommand[j+1] = '\0';
254 void Cursor_Left(void)
256 char temp[CON_CHARS_PER_LINE];
260 strcpy(temp, RCommand);
261 strcpy(RCommand, &LCommand[strlen(LCommand)-1]);
262 strcat(RCommand, temp);
263 LCommand[strlen(LCommand)-1] = '\0';
268 void Cursor_Right(void)
270 char temp[CON_CHARS_PER_LINE];
272 if(CursorPos < strlen(Command)) {
274 strncat(LCommand, RCommand, 1);
275 strcpy(temp, RCommand);
276 strcpy(RCommand, &temp[1]);
281 void Cursor_Home(void)
283 char temp[CON_CHARS_PER_LINE];
286 strcpy(temp, RCommand);
287 strcpy(RCommand, LCommand);
288 strncat(RCommand, temp, strlen(temp));
289 memset(LCommand, 0, CON_CHARS_PER_LINE);
293 void Cursor_End(void)
295 CursorPos = (int)strlen(Command);
296 strncat(LCommand, RCommand, strlen(RCommand));
297 memset(RCommand, 0, CON_CHARS_PER_LINE);
301 void Cursor_Del(void)
303 char temp[CON_CHARS_PER_LINE];
305 if (strlen(RCommand) > 0) {
306 strcpy(temp, RCommand);
307 strcpy(RCommand, &temp[1]);
311 void Cursor_BSpace(void)
318 LCommand[strlen(LCommand)-1] = '\0';
323 void Cursor_Add(char character)
325 if (strlen(Command) < CON_CHARS_PER_LINE - 1)
328 LCommand[strlen(LCommand)] = character;
329 LCommand[strlen(LCommand)] = '\0';
334 void Clear_Command(void)
337 memset( Command, 0, CON_CHARS_PER_LINE);
338 memset(LCommand, 0, CON_CHARS_PER_LINE);
339 memset(RCommand, 0, CON_CHARS_PER_LINE);
340 memset(VCommand, 0, CON_CHARS_PER_LINE);
344 void Command_Up(void)
346 if(CommandScrollBack < TotalCommands - 1) {
347 /* move back a line in the command strings and copy the command to the current input string */
349 memset(RCommand, 0, CON_CHARS_PER_LINE);
351 strcpy(LCommand, CommandLines[CommandScrollBack]);
352 CursorPos = (int)strlen(CommandLines[CommandScrollBack]);
357 void Command_Down(void)
359 if(CommandScrollBack > -1) {
360 /* move forward a line in the command strings and copy the command to the current input string */
362 memset(RCommand, 0, CON_CHARS_PER_LINE);
363 memset(LCommand, 0, CON_CHARS_PER_LINE);
365 if(CommandScrollBack > -1)
366 strcpy(LCommand, CommandLines[CommandScrollBack]);
367 CursorPos = (int)strlen(LCommand);