start of removing #ifdef __Reactos__ in cmd. __Reactos__ = 1 works fine on windows...
[reactos.git] / reactos / subsys / system / 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 remained 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 * 30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
97 * Fixed problems when the screen was scrolled away.
98 */
99
100 #include <precomp.h>
101 #include "resource.h"
102
103
104 SHORT maxx;
105 SHORT maxy;
106
107 /*
108 * global command line insert/overwrite flag
109 */
110 static BOOL bInsert = TRUE;
111
112
113 static VOID
114 ClearCommandLine (LPTSTR str, INT maxlen, SHORT orgx, SHORT orgy)
115 {
116 INT count;
117
118 SetCursorXY (orgx, orgy);
119 for (count = 0; count < (INT)_tcslen (str); count++)
120 ConOutChar (_T(' '));
121 _tcsnset (str, _T('\0'), maxlen);
122 SetCursorXY (orgx, orgy);
123 }
124
125
126 /* read in a command line */
127 VOID ReadCommand (LPTSTR str, INT maxlen)
128 {
129 SHORT orgx; /* origin x/y */
130 SHORT orgy;
131 SHORT curx; /*current x/y cursor position*/
132 SHORT cury;
133 SHORT tempscreen;
134 INT count; /*used in some for loops*/
135 INT current = 0; /*the position of the cursor in the string (str)*/
136 INT charcount = 0;/*chars in the string (str)*/
137 INPUT_RECORD ir;
138 WORD wLastKey = 0;
139 TCHAR ch;
140 BOOL bContinue=FALSE;/*is TRUE the second case will not be executed*/
141 TCHAR szPath[MAX_PATH];
142
143 /* get screen size */
144 GetScreenSize (&maxx, &maxy);
145
146 /* JPP 19980807 - if echo off, don't print prompt */
147 if (bEcho)
148 PrintPrompt();
149
150 GetCursorXY (&orgx, &orgy);
151 GetCursorXY (&curx, &cury);
152
153 memset (str, 0, maxlen * sizeof (TCHAR));
154
155 SetCursorType (bInsert, TRUE);
156
157 do
158 {
159 ConInKey (&ir);
160
161 if (ir.Event.KeyEvent.dwControlKeyState &
162 (RIGHT_ALT_PRESSED|RIGHT_ALT_PRESSED|
163 RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED) )
164 {
165
166 switch (ir.Event.KeyEvent.wVirtualKeyCode)
167 {
168
169 #ifdef FEATURE_HISTORY
170
171 case 'K':
172 /*add the current command line to the history*/
173 if (ir.Event.KeyEvent.dwControlKeyState &
174 (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
175 {
176
177 if (str[0])
178 History(0,str);
179
180 ClearCommandLine (str, maxlen, orgx, orgy);
181 current = charcount = 0;
182 curx = orgx;
183 cury = orgy;
184 bContinue=TRUE;
185 break;
186 }
187
188 case 'D':
189 /*delete current history entry*/
190 if (ir.Event.KeyEvent.dwControlKeyState &
191 (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
192 {
193 ClearCommandLine (str, maxlen, orgx, orgy);
194 History_del_current_entry(str);
195 current = charcount = _tcslen (str);
196 ConOutPrintf (_T("%s"), str);
197 GetCursorXY (&curx, &cury);
198 bContinue=TRUE;
199 break;
200 }
201
202 #endif/*FEATURE_HISTORY*/
203 }
204
205
206
207
208 }
209
210 //if (bContinue)
211 // continue;
212
213
214
215 switch (ir.Event.KeyEvent.wVirtualKeyCode)
216 {
217 case VK_BACK:
218 /* <BACKSPACE> - delete character to left of cursor */
219 if (current > 0 && charcount > 0)
220 {
221 if (current == charcount)
222 {
223 /* if at end of line */
224 str[current - 1] = _T('\0');
225 if (GetCursorX () != 0)
226 {
227 ConOutPrintf (_T("\b \b"));
228 curx--;
229 }
230 else
231 {
232 SetCursorXY ((SHORT)(maxx - 1), (SHORT)(GetCursorY () - 1));
233 ConOutChar (_T(' '));
234 SetCursorXY ((SHORT)(maxx - 1), (SHORT)(GetCursorY () - 1));
235 cury--;
236 curx = maxx - 1;
237 }
238 }
239 else
240 {
241 for (count = current - 1; count < charcount; count++)
242 str[count] = str[count + 1];
243 if (GetCursorX () != 0)
244 {
245 SetCursorXY ((SHORT)(GetCursorX () - 1), GetCursorY ());
246 curx--;
247 }
248 else
249 {
250 SetCursorXY ((SHORT)(maxx - 1), (SHORT)(GetCursorY () - 1));
251 cury--;
252 curx = maxx - 1;
253 }
254 GetCursorXY (&curx, &cury);
255 ConOutPrintf (_T("%s "), &str[current - 1]);
256 SetCursorXY (curx, cury);
257 }
258 charcount--;
259 current--;
260 }
261 break;
262
263 case VK_INSERT:
264 /* toggle insert/overstrike mode */
265 bInsert ^= TRUE;
266 SetCursorType (bInsert, TRUE);
267 break;
268
269 case VK_DELETE:
270 /* delete character under cursor */
271 if (current != charcount && charcount > 0)
272 {
273 for (count = current; count < charcount; count++)
274 str[count] = str[count + 1];
275 charcount--;
276 GetCursorXY (&curx, &cury);
277 ConOutPrintf (_T("%s "), &str[current]);
278 SetCursorXY (curx, cury);
279 }
280 break;
281
282 case VK_HOME:
283 /* goto beginning of string */
284 if (current != 0)
285 {
286 SetCursorXY (orgx, orgy);
287 curx = orgx;
288 cury = orgy;
289 current = 0;
290 }
291 break;
292
293 case VK_END:
294 /* goto end of string */
295 if (current != charcount)
296 {
297 SetCursorXY (orgx, orgy);
298 ConOutPrintf (_T("%s"), str);
299 GetCursorXY (&curx, &cury);
300 current = charcount;
301 }
302 break;
303
304 case VK_TAB:
305 #ifdef FEATURE_UNIX_FILENAME_COMPLETION
306 /* expand current file name */
307 if ((current == charcount) ||
308 (current == charcount - 1 &&
309 str[current] == _T('"'))) /* only works at end of line*/
310 {
311 if (wLastKey != VK_TAB)
312 {
313 /* if first TAB, complete filename*/
314 tempscreen = charcount;
315 CompleteFilename (str, charcount);
316 charcount = _tcslen (str);
317 current = charcount;
318
319 SetCursorXY (orgx, orgy);
320 ConOutPrintf (_T("%s"), str);
321
322 if (tempscreen > charcount)
323 {
324 GetCursorXY (&curx, &cury);
325 for (count = tempscreen - charcount; count--; )
326 ConOutChar (_T(' '));
327 SetCursorXY (curx, cury);
328 }
329 else
330 {
331 if (((charcount + orgx) / maxx) + orgy > maxy - 1)
332 orgy += maxy - ((charcount + orgx) / maxx + orgy + 1);
333 }
334
335 /* set cursor position */
336 SetCursorXY ((orgx + current) % maxx,
337 orgy + (orgx + current) / maxx);
338 GetCursorXY (&curx, &cury);
339 }
340 else
341 {
342 /*if second TAB, list matches*/
343 if (ShowCompletionMatches (str, charcount))
344 {
345 PrintPrompt ();
346 GetCursorXY (&orgx, &orgy);
347 ConOutPrintf (_T("%s"), str);
348
349 /* set cursor position */
350 SetCursorXY ((orgx + current) % maxx,
351 orgy + (orgx + current) / maxx);
352 GetCursorXY (&curx, &cury);
353 }
354
355 }
356 }
357 else
358 {
359 MessageBeep (-1);
360 }
361 #endif
362 #ifdef FEATURE_4NT_FILENAME_COMPLETION
363
364 /* used to later see if we went down to the next line */
365 tempscreen = charcount;
366 szPath[0]=_T('\0');
367
368 /* str is the whole things that is on the current line
369 that is and and out. arg 2 is weather it goes back
370 one file or forward one file */
371 CompleteFilename(str, !(ir.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED), szPath, current);
372 /* Attempt to clear the line */
373 ClearCommandLine (str, maxlen, orgx, orgy);
374 curx = orgx;
375 cury = orgy;
376 current = charcount = 0;
377 //str[0]=_T('\0');
378
379 /* Everything is deleted, lets add it back in */
380 _tcscpy(str,szPath);
381
382 /* Figure out where cusor is going to be after we print it */
383 charcount = _tcslen (str);
384 current = charcount;
385
386 SetCursorXY (orgx, orgy);
387 /* Print out what we have now */
388 ConOutPrintf (_T("%s"), str);
389
390 /* Move cursor accordingly */
391 if(tempscreen > charcount)
392 {
393 GetCursorXY (&curx, &cury);
394 for(count = tempscreen - charcount; count--; )
395 ConOutChar (_T(' '));
396 SetCursorXY (curx, cury);
397 }
398 else
399 {
400 if(((charcount + orgx) / maxx) + orgy > maxy - 1)
401 orgy += maxy - ((charcount + orgx) / maxx + orgy + 1);
402 }
403 SetCursorXY((short)(((int)orgx + current) % maxx), (short)((int)orgy + ((int)orgx + current) / maxx));
404 GetCursorXY(&curx, &cury);
405
406 #endif
407 break;
408
409 case VK_RETURN:
410 /* end input, return to main */
411 #ifdef FEATURE_HISTORY
412 /* add to the history */
413 if (str[0])
414 History (0, str);
415 #endif
416 ConInDummy ();
417 ConOutChar (_T('\n'));
418 break;
419
420 case VK_ESCAPE:
421 /* clear str Make this callable! */
422 ClearCommandLine (str, maxlen, orgx, orgy);
423 curx = orgx;
424 cury = orgy;
425 current = charcount = 0;
426 break;
427
428 #ifdef FEATURE_HISTORY
429 case VK_F3:
430 History_move_to_bottom();
431 #endif
432 case VK_UP:
433 #ifdef FEATURE_HISTORY
434 /* get previous command from buffer */
435 ClearCommandLine (str, maxlen, orgx, orgy);
436 History (-1, str);
437 current = charcount = _tcslen (str);
438 if (((charcount + orgx) / maxx) + orgy > maxy - 1)
439 orgy += maxy - ((charcount + orgx) / maxx + orgy + 1);
440 ConOutPrintf (_T("%s"), str);
441 GetCursorXY (&curx, &cury);
442 #endif
443 break;
444
445 case VK_DOWN:
446 #ifdef FEATURE_HISTORY
447 /* get next command from buffer */
448 ClearCommandLine (str, maxlen, orgx, orgy);
449 History (1, str);
450 current = charcount = _tcslen (str);
451 if (((charcount + orgx) / maxx) + orgy > maxy - 1)
452 orgy += maxy - ((charcount + orgx) / maxx + orgy + 1);
453 ConOutPrintf (_T("%s"), str);
454 GetCursorXY (&curx, &cury);
455 #endif
456 break;
457
458 case VK_LEFT:
459 /* move cursor left */
460 if (current > 0)
461 {
462 current--;
463 if (GetCursorX () == 0)
464 {
465 SetCursorXY ((SHORT)(maxx - 1), (SHORT)(GetCursorY () - 1));
466 curx = maxx - 1;
467 cury--;
468 }
469 else
470 {
471 SetCursorXY ((SHORT)(GetCursorX () - 1), GetCursorY ());
472 curx--;
473 }
474 }
475 else
476 {
477 MessageBeep (-1);
478 }
479 break;
480
481 case VK_RIGHT:
482 /* move cursor right */
483 if (current != charcount)
484 {
485 current++;
486 if (GetCursorX () == maxx - 1)
487 {
488 SetCursorXY (0, (SHORT)(GetCursorY () + 1));
489 curx = 0;
490 cury++;
491 }
492 else
493 {
494 SetCursorXY ((SHORT)(GetCursorX () + 1), GetCursorY ());
495 curx++;
496 }
497 }
498 break;
499
500 default:
501 #ifdef _UNICODE
502 ch = ir.Event.KeyEvent.uChar.UnicodeChar;
503 if ((ch >= 32 && ch <= 255) && (charcount != (maxlen - 2)))
504 #else
505 ch = ir.Event.KeyEvent.uChar.AsciiChar;
506 if ((UCHAR)ch >= 32 && (charcount != (maxlen - 2)))
507 #endif /* _UNICODE */
508 {
509 /* insert character into string... */
510 if (bInsert && current != charcount)
511 {
512 /* If this character insertion will cause screen scrolling,
513 * adjust the saved origin of the command prompt. */
514 tempscreen = _tcslen(str + current) + curx;
515 if ((tempscreen % maxx) == (maxx - 1) &&
516 (tempscreen / maxx) + cury == (maxy - 1))
517 {
518 orgy--;
519 cury--;
520 }
521
522 for (count = charcount; count > current; count--)
523 str[count] = str[count - 1];
524 str[current++] = ch;
525 if (curx == maxx - 1)
526 curx = 0, cury++;
527 else
528 curx++;
529 ConOutPrintf (_T("%s"), &str[current - 1]);
530 SetCursorXY (curx, cury);
531 charcount++;
532 }
533 else
534 {
535 if (current == charcount)
536 charcount++;
537 str[current++] = ch;
538 if (GetCursorX () == maxx - 1 && GetCursorY () == maxy - 1)
539 orgy--, cury--;
540 if (GetCursorX () == maxx - 1)
541 curx = 0, cury++;
542 else
543 curx++;
544 ConOutChar (ch);
545 }
546 }
547 #if 0
548 else
549 {
550 MessageBeep (-1);
551 }
552 #endif
553 break;
554
555 }
556 wLastKey = ir.Event.KeyEvent.wVirtualKeyCode;
557 }
558 while (ir.Event.KeyEvent.wVirtualKeyCode != VK_RETURN);
559
560 SetCursorType (bInsert, TRUE);
561 }