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_NUM_LINES 128
30 // Cut the buffer line if it becomes longer than this
31 #define CON_CHARS_PER_LINE 128
32 // Cursor blink frequency in ms
33 #define CON_BLINK_RATE 500
34 // Border in pixels from the most left to the first letter
35 #define CON_CHAR_BORDER 4
36 // Default prompt used at the commandline
37 #define CON_DEFAULT_PROMPT "]"
38 // Cursor shown if we are in insert mode
39 #define CON_INS_CURSOR "_"
40 // Cursor shown if we are in overwrite mode
41 #define CON_OVR_CURSOR "|"
44 /* The console's data */
45 static char **CommandLines; // List of all the past commands
46 static int TotalCommands; // Number of commands in the Back Commands
47 static int LineBuffer; // The number of visible lines in the console (autocalculated)
48 static int VChars; // The number of visible characters in one console line (autocalculated)
49 static char *Prompt; // Prompt displayed in command line
50 static char Command[CON_CHARS_PER_LINE]; // current command in command line = lcommand + rcommand
51 static char LCommand[CON_CHARS_PER_LINE]; // right hand side of cursor
52 static char RCommand[CON_CHARS_PER_LINE]; // left hand side of cursor
53 static char VCommand[CON_CHARS_PER_LINE]; // current visible command line
54 static int CursorPos; // Current cursor position in CurrentCommand
55 static int Offset; // CommandOffset (first visible char of command) - if command is too long to fit into console
56 int InsMode; // Insert or Overwrite characters?
57 static int CommandScrollBack; // How much the users scrolled back in the command lines
60 /* Frees all the memory loaded by the console */
61 static void CON_Free(void);
62 /* shift command history (the one you can switch with the up/down keys) */
63 static void CON_NewLineCommand(void);
66 /* Initializes the console */
75 CommandScrollBack = 0;
76 Prompt = d_strdup(CON_DEFAULT_PROMPT);
78 VChars = CON_CHARS_PER_LINE - 1;
79 LineBuffer = CON_NUM_LINES;
81 CommandLines = (char **)d_malloc(sizeof(char *) * LineBuffer);
82 for (loop = 0; loop <= LineBuffer - 1; loop++) {
83 CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
85 memset(Command, 0, CON_CHARS_PER_LINE);
86 memset(LCommand, 0, CON_CHARS_PER_LINE);
87 memset(RCommand, 0, CON_CHARS_PER_LINE);
88 memset(VCommand, 0, CON_CHARS_PER_LINE);
94 /* Frees all the memory loaded by the console */
95 static void CON_Free(void)
99 for (i = 0; i <= LineBuffer - 1; i++) {
100 d_free(CommandLines[i]);
102 d_free(CommandLines);
110 /* Increments the command lines */
111 static void CON_NewLineCommand(void)
116 temp = CommandLines[LineBuffer - 1];
118 for (loop = LineBuffer - 1; loop > 0; loop--)
119 CommandLines[loop] = CommandLines[loop - 1];
121 CommandLines[0] = temp;
123 memset(CommandLines[0], 0, CON_CHARS_PER_LINE);
124 if (TotalCommands < LineBuffer - 1)
129 /* Draws the command line the user is typing in to the screen */
130 /* completely rewritten by C.Wacha */
131 void DrawCommandLine(int y)
135 static unsigned int LastBlinkTime = 0; // Last time the consoles cursor blinked
136 static int LastCursorPos = 0; // Last Cursor Position
137 static int Blink = 0; // Is the cursor currently blinking
139 commandbuffer = VChars - (int)strlen(Prompt) - 1; // -1 to make cursor visible
141 // Concatenate the left and right side to command
142 strcpy(Command, LCommand);
143 strncat(Command, RCommand, strlen(RCommand));
145 //calculate display offset from current cursor position
146 if (Offset < CursorPos - commandbuffer)
147 Offset = CursorPos - commandbuffer;
148 if(Offset > CursorPos)
151 // first add prompt to visible part
152 strcpy(VCommand, Prompt);
154 // then add the visible part of the command
155 strncat(VCommand, &Command[Offset], strlen(&Command[Offset]));
157 // now display the result
158 gr_string(CON_CHAR_BORDER, y - grd_curfont->ft_h, VCommand);
160 // at last add the cursor
161 // check if the blink period is over
162 if (get_msecs() > LastBlinkTime) {
163 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
170 // check if cursor has moved - if yes display cursor anyway
171 if (CursorPos != LastCursorPos) {
172 LastCursorPos = CursorPos;
173 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
178 int prompt_width, cmd_width, h, w;
180 gr_get_string_size(Prompt, &prompt_width, &h, &w);
181 gr_get_string_size(LCommand + Offset, &cmd_width, &h, &w);
182 x = CON_CHAR_BORDER + prompt_width + cmd_width;
184 gr_string(x, y - grd_curfont->ft_h, CON_INS_CURSOR);
186 gr_string(x, y - grd_curfont->ft_h, CON_OVR_CURSOR);
191 /* Sets the Prompt for console */
192 void CON_SetPrompt(char* newprompt) {
193 // check length so we can still see at least 1 char :-)
194 if (strlen(newprompt) < VChars) {
196 Prompt = d_strdup(newprompt);
198 CON_Out("prompt too long. (max. %i chars)\n", VChars - 1);
202 /* Executes the command entered */
203 void CON_Execute(void)
205 if(strlen(Command) > 0) {
206 CON_NewLineCommand();
208 // copy the input into the past commands strings
209 strcpy(CommandLines[0], Command);
211 // display the command including the prompt
212 CON_Out("%s%s\n", Prompt, Command);
217 CommandScrollBack = -1;
222 void CON_TabCompletion(void)
227 command = cmd_complete(LCommand);
230 return; // no tab completion took place so return silently
232 j = (int)strlen(command);
233 if (j > CON_CHARS_PER_LINE - 2)
234 j = CON_CHARS_PER_LINE-1;
236 memset(LCommand, 0, CON_CHARS_PER_LINE);
239 for (i = 0; i < j; i++) {
241 LCommand[i] = command[i];
243 // add a trailing space
246 LCommand[j+1] = '\0';
250 void Cursor_Left(void)
252 char temp[CON_CHARS_PER_LINE];
256 strcpy(temp, RCommand);
257 strcpy(RCommand, &LCommand[strlen(LCommand)-1]);
258 strcat(RCommand, temp);
259 LCommand[strlen(LCommand)-1] = '\0';
264 void Cursor_Right(void)
266 char temp[CON_CHARS_PER_LINE];
268 if(CursorPos < strlen(Command)) {
270 strncat(LCommand, RCommand, 1);
271 strcpy(temp, RCommand);
272 strcpy(RCommand, &temp[1]);
277 void Cursor_Home(void)
279 char temp[CON_CHARS_PER_LINE];
282 strcpy(temp, RCommand);
283 strcpy(RCommand, LCommand);
284 strncat(RCommand, temp, strlen(temp));
285 memset(LCommand, 0, CON_CHARS_PER_LINE);
289 void Cursor_End(void)
291 CursorPos = (int)strlen(Command);
292 strncat(LCommand, RCommand, strlen(RCommand));
293 memset(RCommand, 0, CON_CHARS_PER_LINE);
297 void Cursor_Del(void)
299 char temp[CON_CHARS_PER_LINE];
301 if (strlen(RCommand) > 0) {
302 strcpy(temp, RCommand);
303 strcpy(RCommand, &temp[1]);
307 void Cursor_BSpace(void)
314 LCommand[strlen(LCommand)-1] = '\0';
319 void Cursor_Add(char character)
321 if (strlen(Command) < CON_CHARS_PER_LINE - 1)
324 LCommand[strlen(LCommand)] = character;
325 LCommand[strlen(LCommand)] = '\0';
330 void Clear_Command(void)
333 memset( Command, 0, CON_CHARS_PER_LINE);
334 memset(LCommand, 0, CON_CHARS_PER_LINE);
335 memset(RCommand, 0, CON_CHARS_PER_LINE);
336 memset(VCommand, 0, CON_CHARS_PER_LINE);
340 void Command_Up(void)
342 if(CommandScrollBack < TotalCommands - 1) {
343 /* move back a line in the command strings and copy the command to the current input string */
345 memset(RCommand, 0, CON_CHARS_PER_LINE);
347 strcpy(LCommand, CommandLines[CommandScrollBack]);
348 CursorPos = (int)strlen(CommandLines[CommandScrollBack]);
353 void Command_Down(void)
355 if(CommandScrollBack > -1) {
356 /* move forward a line in the command strings and copy the command to the current input string */
358 memset(RCommand, 0, CON_CHARS_PER_LINE);
359 memset(LCommand, 0, CON_CHARS_PER_LINE);
361 if(CommandScrollBack > -1)
362 strcpy(LCommand, CommandLines[CommandScrollBack]);
363 CursorPos = (int)strlen(LCommand);