6ac5302529d4ca55a45995c77ccc415928c798ac
[reactos.git] / rosapps / cmd / cmdinput.c
1 /*
2 * CMDINPUT.C - handles command input (tab completion, history, etc.).
3 *
4 *
5 * History:
6 *
7 * 01/14/95 (Tim Norman)
8 * started.
9 *
10 * 08/08/95 (Matt Rains)
11 * i have cleaned up the source code. changes now bring this source
12 * into guidelines for recommended programming practice.
13 * i have added some constants to help making changes easier.
14 *
15 * 12/12/95 (Tim Norman)
16 * added findxy() function to get max x/y coordinates to display
17 * correctly on larger screens
18 *
19 * 12/14/95 (Tim Norman)
20 * fixed the Tab completion code that Matt Rains broke by moving local
21 * variables to a more global scope and forgetting to initialize them
22 * when needed
23 *
24 * 8/1/96 (Tim Norman)
25 * fixed a bug in tab completion that caused filenames at the beginning
26 * of the command-line to have their first letter truncated
27 *
28 * 9/1/96 (Tim Norman)
29 * fixed a silly bug using printf instead of fputs, where typing "%i"
30 * confused printf :)
31 *
32 * 6/14/97 (Steffan Kaiser)
33 * ctrl-break checking
34 *
35 * 6/7/97 (Marc Desrochers)
36 * recoded everything! now properly adjusts when text font is changed.
37 * removed findxy(), reposition(), and reprint(), as these functions
38 * were inefficient. added goxy() function as gotoxy() was buggy when
39 * the screen font was changed. the printf() problem with %i on the
40 * command line was fixed by doing printf("%s",str) instead of
41 * printf(str). Don't ask how I find em just be glad I do :)
42 *
43 * 7/12/97 (Tim Norman)
44 * Note: above changes pre-empted Steffan's ctrl-break checking.
45 *
46 * 7/7/97 (Marc Desrochers)
47 * rewrote a new findxy() because the new dir() used it. This
48 * findxy() simply returns the values of *maxx *maxy. In the
49 * future, please use the pointers, they will always be correct
50 * since they point to BIOS values.
51 *
52 * 7/8/97 (Marc Desrochers)
53 * once again removed findxy(), moved the *maxx, *maxy pointers
54 * global and included them as externs in command.h. Also added
55 * insert/overstrike capability
56 *
57 * 7/13/97 (Tim Norman)
58 * added different cursor appearance for insert/overstrike mode
59 *
60 * 7/13/97 (Tim Norman)
61 * changed my code to use _setcursortype until I can figure out why
62 * my code is crashing on some machines. It doesn't crash on mine :)
63 *
64 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
65 * added config.h include
66 *
67 * 28-Jul-1998 (John P Price <linux-guru@gcfl.net>)
68 * put ifdef's around filename completion code.
69 *
70 * 30-Jul-1998 (John P Price <linux-guru@gcfl.net>)
71 * moved filename completion code to filecomp.c
72 * made second TAB display list of filename matches
73 *
74 * 31-Jul-1998 (John P Price <linux-guru@gcfl.net>)
75 * Fixed bug where if you typed something, then hit HOME, then tried
76 * to type something else in insert mode, it crashed.
77 *
78 * 07-Aug-1998 (John P Price <linux-guru@gcfl.net>)
79 * Fixed carrage return output to better match MSDOS with echo
80 * on or off.(marked with "JPP 19980708")
81 *
82 * 13-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
83 * Added insert/overwrite cursor.
84 *
85 * 25-Jan-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
86 * Replaced CRT io functions by Win32 console io functions.
87 * This can handle <Shift>-<Tab> for 4NT filename completion.
88 * Unicode and redirection safe!
89 *
90 * 04-Feb-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
91 * Fixed input bug. A "line feed" character remined in the keyboard
92 * input queue when you pressed <RETURN>. This sometimes caused
93 * some very strange effects.
94 * Fixed some command line editing annoyances.
95 */
96
97 #define WIN32_LEAN_AND_MEAN
98
99 #include "config.h"
100
101 #include <windows.h>
102 #include <tchar.h>
103 #include <string.h>
104
105 #include "cmd.h"
106 #include "batch.h"
107
108
109
110 SHORT maxx;
111 SHORT maxy;
112
113 /*
114 * global command line insert/overwrite flag
115 */
116 static BOOL bInsert = TRUE;
117
118
119 static VOID
120 ClearCommandLine (LPTSTR str, INT maxlen, SHORT orgx, SHORT orgy)
121 {
122 INT count;
123
124 goxy (orgx, orgy);
125 for (count = 0; count < (INT)_tcslen (str); count++)
126 ConOutChar (_T(' '));
127 _tcsnset (str, _T('\0'), maxlen);
128 goxy (orgx, orgy);
129 }
130
131
132 /* read in a command line */
133 VOID ReadCommand (LPTSTR str, INT maxlen)
134 {
135 SHORT orgx; /* origin x/y */
136 SHORT orgy;
137 SHORT curx;
138 SHORT cury;
139 INT count;
140 INT current = 0;
141 INT charcount = 0;
142 INPUT_RECORD ir;
143 WORD wLastKey = 0;
144 TCHAR ch;
145
146 /* get screen size */
147 GetScreenSize (&maxx, &maxy);
148
149 /* JPP 19980807 - if echo off, don't print prompt */
150 if (bEcho)
151 PrintPrompt();
152
153 orgx = wherex ();
154 orgy = wherey ();
155
156 memset (str, 0, maxlen * sizeof (TCHAR));
157
158 SetCursorType (bInsert, TRUE);
159
160 do
161 {
162 ConInKey (&ir);
163
164 switch (ir.Event.KeyEvent.wVirtualKeyCode)
165 {
166 case VK_BACK:
167 /* <BACKSPACE> - delete character to left of cursor */
168 if (current > 0 && charcount > 0)
169 {
170 if (current == charcount)
171 {
172 /* if at end of line */
173 str[current - 1] = _T('\0');
174 if (wherex () != 0)
175 {
176 ConOutPrintf ("\b \b");
177 }
178 else
179 {
180 goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1));
181 ConOutChar (_T(' '));
182 goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1));
183 }
184 }
185 else
186 {
187 for (count = current - 1; count < charcount; count++)
188 str[count] = str[count + 1];
189 if (wherex () != 0)
190 goxy ((SHORT)(wherex () - 1), wherey ());
191 else
192 goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1));
193 curx = wherex ();
194 cury = wherey ();
195 ConOutPrintf (_T("%s "), &str[current - 1]);
196 goxy (curx, cury);
197 }
198 charcount--;
199 current--;
200 }
201 break;
202
203 case VK_INSERT:
204 /* toggle insert/overstrike mode */
205 bInsert ^= TRUE;
206 SetCursorType (bInsert, TRUE);
207 break;
208
209 case VK_DELETE:
210 /* delete character under cursor */
211 if (current != charcount && charcount > 0)
212 {
213 for (count = current; count < charcount; count++)
214 str[count] = str[count + 1];
215 charcount--;
216 curx = wherex ();
217 cury = wherey ();
218 ConOutPrintf (_T("%s "), &str[current]);
219 goxy (curx, cury);
220 }
221 break;
222
223 case VK_HOME:
224 /* goto beginning of string */
225 if (current != 0)
226 {
227 goxy (orgx, orgy);
228 current = 0;
229 }
230 break;
231
232 case VK_END:
233 /* goto end of string */
234 if (current != charcount)
235 {
236 goxy (orgx, orgy);
237 ConOutPrintf (_T("%s"), str);
238 current = charcount;
239 }
240 break;
241
242 case VK_TAB:
243 #ifdef FEATURE_UNIX_FILENAME_COMPLETION
244 /* expand current file name */
245 if (current == charcount) // only works at end of line
246 {
247 if (wLastKey != VK_TAB)
248 {
249 // if first TAB, complete filename
250 CompleteFilename (str, charcount);
251 charcount = _tcslen (str);
252 current = charcount;
253
254 goxy(orgx, orgy);
255 ConOutPrintf (_T("%s"), str);
256 if ((_tcslen (str) > (USHORT)(maxx - orgx)) && (orgy == maxy + 1))
257 orgy--;
258 }
259 else
260 {
261 //if second TAB, list matches
262 if (ShowCompletionMatches (str, charcount))
263 {
264 PrintPrompt ();
265 orgx = wherex ();
266 orgy = wherey ();
267 ConOutPrintf (_T("%s"), str);
268 }
269 }
270 }
271 else
272 {
273 MessageBeep (-1);
274 }
275 #endif
276 #ifdef FEATURE_4NT_FILENAME_COMPLETION
277 /* this is not implemented yet */
278 if (ir.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
279 {
280 /* get previous match */
281
282 }
283 else
284 {
285 /* get next match */
286
287 }
288 #endif
289 break;
290
291 case VK_RETURN:
292 /* end input, return to main */
293 #ifdef FEATURE_HISTORY
294 /* add to the history */
295 if (str[0])
296 History (0, str);
297 #endif
298 ConInDummy ();
299 ConOutChar (_T('\n'));
300 break;
301
302 case VK_ESCAPE:
303 /* clear str Make this callable! */
304 ClearCommandLine (str, maxlen, orgx, orgy);
305 current = charcount = 0;
306 break;
307
308 case VK_UP:
309 #ifdef FEATURE_HISTORY
310 /* get previous command from buffer */
311 ClearCommandLine (str, maxlen, orgx, orgy);
312 History (-1, str);
313 current = charcount = _tcslen (str);
314 ConOutPrintf (_T("%s"), str);
315 #endif
316 break;
317
318 case VK_DOWN:
319 #ifdef FEATURE_HISTORY
320 /* get next command from buffer */
321 ClearCommandLine (str, maxlen, orgx, orgy);
322 History (1, str);
323 current = charcount = _tcslen (str);
324 ConOutPrintf (_T("%s"), str);
325 #endif
326 break;
327
328 case VK_LEFT:
329 /* move cursor left */
330 if (current > 0)
331 {
332 current--;
333 if (wherex () == 0)
334 goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1));
335 else
336 goxy ((SHORT)(wherex () - 1), wherey ());
337 }
338 else
339 {
340 // Beep (440, 100);
341 MessageBeep (-1);
342 }
343 break;
344
345 case VK_RIGHT:
346 /* move cursor right */
347 if (current != charcount)
348 {
349 current++;
350 if (wherex () == maxx - 1)
351 goxy (0, (SHORT)(wherey () + 1));
352 else
353 goxy ((SHORT)(wherex () + 1), wherey ());
354 }
355 break;
356
357 default:
358 #ifdef _UNICODE
359 ch = ir.Event.KeyEvent.uChar.UnicodeChar;
360 #else
361 ch = ir.Event.KeyEvent.uChar.AsciiChar;
362 #endif
363 if ((ch >= 32 && ch <= 255) && (charcount != (maxlen - 2)))
364 {
365 /* insert character into string... */
366 if (bInsert && current != charcount)
367 {
368 for (count = charcount; count > current; count--)
369 str[count] = str[count - 1];
370 str[current++] = ch;
371 if (wherex () == maxx - 1)
372 {
373 curx = 0;
374 cury = wherey () + 1;
375 }
376 else
377 {
378 curx = wherex () + 1;
379 cury = wherey ();
380 }
381 ConOutPrintf (_T("%s"), &str[current - 1]);
382 if ((_tcslen (str) > (USHORT)(maxx - orgx)) && (orgy == maxy + 1))
383 cury--;
384 goxy (curx, cury);
385 charcount++;
386 }
387 else
388 {
389 if (current == charcount)
390 charcount++;
391 str[current++] = ch;
392 ConOutChar (ch);
393 }
394 if ((_tcslen (str) > (USHORT)(maxx - orgx)) && (orgy == maxy + 1))
395 orgy--;
396 }
397 #if 0
398 else
399 {
400 // Beep (440, 100);
401 MessageBeep (-1);
402 }
403 #endif
404 break;
405
406 }
407 wLastKey = ir.Event.KeyEvent.wVirtualKeyCode;
408 }
409 while (ir.Event.KeyEvent.wVirtualKeyCode != VK_RETURN);
410
411 SetCursorType (bInsert, TRUE);
412 }