c7baa43a0120cdebf2119a62bb748b5bc05d1d4e
[reactos.git] / rosapps / sysutils / regexpl / Console.cpp
1 /* $Id: Console.cpp,v 1.1 2000/10/04 21:04:30 ea Exp $
2 *
3 * regexpl - Console Registry Explorer
4 *
5 * Copyright (c) 1999-2000 Nedko Arnaoudov <nedkohome@atia.com>
6 *
7 * License: GNU GPL
8 *
9 */
10
11 // Console.cpp: implementation of the CConsole class.
12 //
13 //////////////////////////////////////////////////////////////////////
14
15 #include "ph.h"
16 #include "Console.h"
17 /*
18 TCHAR * _tcsnchr(const TCHAR *string, TCHAR ch, int count)
19 {
20 while (count--)
21 {
22 if (*string == 0) return NULL;
23 if (*string == ch) return const_cast <char *>(string);
24 string++;
25 }
26 return NULL;
27 }*/
28
29
30 //////////////////////////////////////////////////////////////////////
31 // Construction/Destruction
32 //////////////////////////////////////////////////////////////////////
33
34 CConsole::CConsole()
35 {
36 m_hStdIn = INVALID_HANDLE_VALUE;
37 m_hStdOut = INVALID_HANDLE_VALUE;
38 m_blnInsetMode = TRUE; // Insert
39 // m_blnInsetMode = FALSE; // Overwrite
40 m_dwInsertModeCursorHeight = 15;
41 m_dwOverwriteModeCursorHeight = 100;
42 // m_Lines = 0;
43 m_pchBuffer = NULL;
44 m_pchBuffer1 = NULL;
45 m_pchBuffer2 = NULL;
46 m_pfReplaceCompletionCallback = NULL;
47 m_blnMoreMode = TRUE;
48 }
49
50 CConsole::~CConsole()
51 {
52 if (m_hStdIn != INVALID_HANDLE_VALUE)
53 VERIFY(CloseHandle(m_hStdIn));
54 if (m_hStdOut != INVALID_HANDLE_VALUE)
55 VERIFY(CloseHandle(m_hStdOut));
56 if (m_pchBuffer)
57 delete m_pchBuffer;
58 if (m_pchBuffer1)
59 delete m_pchBuffer1;
60 if (m_pchBuffer2)
61 delete m_pchBuffer2;
62 }
63
64 BOOL CConsole::Write(const TCHAR *p, DWORD dwChars)
65 {
66 if (m_hStdOut == INVALID_HANDLE_VALUE)
67 return FALSE;
68 if (m_hStdIn == INVALID_HANDLE_VALUE)
69 return FALSE;
70 if (p == NULL)
71 {
72 ASSERT(FALSE);
73 return FALSE;
74 }
75 DWORD dwCharsToWrite = (dwChars)?dwChars:_tcslen(p);
76 DWORD dwCharsWrittenAdd = 0;
77 BOOL ret = TRUE;
78 while (dwCharsToWrite && (!m_blnDisableWrite))
79 {
80 switch(p[dwCharsWrittenAdd])
81 {
82 case _T('\n'):
83 m_CursorPosition.Y++;
84 m_CursorPosition.X = 0;
85 break;
86 case _T('\r'):
87 break;
88 case _T('\t'):
89 do
90 {
91 if (!Write(_T(" "))) return FALSE;
92 }
93 while ((m_CursorPosition.X % 8) && (!m_blnDisableWrite));
94 dwCharsWrittenAdd++;
95 dwCharsToWrite--;
96 continue;
97 default:
98 {
99 if (!WriteChar(p[dwCharsWrittenAdd])) return FALSE;
100 m_CursorPosition.X++;
101 }
102 }
103 if (m_CursorPosition.X == m_BufferSize.X)
104 {
105 m_CursorPosition.Y++;
106 m_CursorPosition.X = 0;
107 }
108 if (m_CursorPosition.Y == m_BufferSize.Y)
109 {
110 ASSERT(m_CursorPosition.X == 0);
111 SMALL_RECT Src;
112 Src.Left = 0;
113 Src.Right = (SHORT)(m_BufferSize.X-1);
114 Src.Top = 1;
115 Src.Bottom = (SHORT)(m_BufferSize.Y-1);
116 CHAR_INFO ci;
117 #ifdef UNICODE
118 ci.Char.UnicodeChar = L' ';
119 #else
120 ci.Char.AsciiChar = ' ';
121 #endif
122 ci.Attributes = 0;
123 COORD Dest;
124 Dest.X = 0;
125 Dest.Y = 0;
126 if (!ScrollConsoleScreenBuffer(m_hStdOut,&Src,NULL,Dest,&ci)) return FALSE;
127 m_CursorPosition.Y--;
128 m_LinesScrolled++;
129 }
130 if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE;
131 VERIFY(WriteChar(_T(' ')));
132 if ((m_blnMoreMode)&&(m_CursorPosition.X == 0))
133 {
134 m_Lines++;
135 if (m_Lines >= m_BufferSize.Y-1)
136 {
137 ASSERT(m_Lines == m_BufferSize.Y-1);
138 m_Lines = 0;
139 VERIFY(WriteString(_T("-- More --"),m_CursorPosition));
140 VERIFY(FlushInputBuffer());
141
142 CONSOLE_CURSOR_INFO cci;
143 cci.bVisible = FALSE;
144 cci.dwSize = 10;
145 VERIFY(SetConsoleCursorInfo(m_hStdOut,&cci));
146
147 INPUT_RECORD InputRecord;
148 DWORD dwRecordsReaded;
149 while ((ret = ReadConsoleInput(m_hStdIn,&InputRecord,1,&dwRecordsReaded)) != FALSE)
150 {
151 ASSERT(dwRecordsReaded == 1);
152 if (dwRecordsReaded != 1) break;
153 if (InputRecord.EventType != KEY_EVENT) continue;
154 if (!InputRecord.Event.KeyEvent.bKeyDown) continue;
155 #ifdef UNICODE
156 TCHAR ch = InputRecord.Event.KeyEvent.uChar.UnicodeChar;
157 #else
158 TCHAR ch = InputRecord.Event.KeyEvent.uChar.AsciiChar;
159 #endif
160 if (ch == VK_CANCEL)
161 {
162 VERIFY(GenerateConsoleCtrlEvent(CTRL_C_EVENT,0));
163 continue;
164 }
165 if (ch) break;
166 }
167 VERIFY(WriteString(_T(" "),m_CursorPosition));
168 m_CursorPosition.X = 0;
169
170 cci.bVisible = TRUE;
171 cci.dwSize = m_blnInsetMode?m_dwInsertModeCursorHeight:m_dwOverwriteModeCursorHeight;
172 VERIFY(SetConsoleCursorInfo(m_hStdOut,&cci));
173 }
174 }
175 dwCharsWrittenAdd++;
176 dwCharsToWrite--;
177 }
178 return ret;
179 }
180
181 BOOL CConsole::SetTitle(TCHAR *p)
182 {
183 return SetConsoleTitle(p);
184 }
185
186 BOOL CConsole::SetTextAttribute(WORD wAttributes)
187 {
188 m_wAttributes = wAttributes;
189 return TRUE;
190 }
191 /*
192 BOOL CConsole::SetInputMode(DWORD dwMode)
193 {
194 return SetConsoleMode(m_hStdIn,dwMode);
195 }
196
197 BOOL CConsole::SetOutputMode(DWORD dwMode)
198 {
199 return SetConsoleMode(m_hStdOut,dwMode);
200 }*/
201
202 BOOL CConsole::FlushInputBuffer()
203 {
204 if (m_hStdIn == INVALID_HANDLE_VALUE) return FALSE;
205 return FlushConsoleInputBuffer(m_hStdIn);
206 }
207
208 BOOL CConsole::ReadLine()
209 {
210 if (m_hStdIn == INVALID_HANDLE_VALUE) return FALSE;
211 if (m_hStdOut == INVALID_HANDLE_VALUE) return FALSE;
212 if (m_dwBufferSize == 0)
213 {
214 ASSERT(FALSE);
215 return FALSE;
216 }
217 if (m_pchBuffer == NULL)
218 {
219 ASSERT(FALSE);
220 return FALSE;
221 }
222 if (m_pchBuffer1 == NULL)
223 {
224 ASSERT(FALSE);
225 return FALSE;
226 }
227 if (!FlushConsoleInputBuffer(m_hStdIn)) return FALSE;
228
229 COORD FristCharCursorPosition = m_CursorPosition;
230 #define X_CURSOR_POSITION_FROM_OFFSET(ofs) USHORT(((FristCharCursorPosition.X + ofs)%m_BufferSize.X))
231 #define Y_CURSOR_POSITION_FROM_OFFSET(ofs) USHORT((FristCharCursorPosition.Y + (FristCharCursorPosition.X + ofs)/m_BufferSize.X))
232 //#define OFFSET_FROM_CURSOR_POSITION(pos) ((pos.Y-FristCharCursorPosition.Y)*m_BufferSize.X+pos.X-FristCharCursorPosition.X)
233
234 DWORD dwRecordsReaded;
235 DWORD dwCurrentCharOffset = 0;
236 DWORD dwLastCharOffset = 0;
237 BOOL ret;
238
239 BOOL blnCompletionMode = FALSE;
240 // unsigned __int64 nCompletionIndex = 0;
241 unsigned long long nCompletionIndex = 0;
242 DWORD dwCompletionOffset = 0;
243 DWORD dwCompletionStringSize = 0;
244 COORD CompletionPosition = FristCharCursorPosition;
245
246 m_LinesScrolled = 0;
247 BOOL blnOldMoreMode = m_blnMoreMode;
248 m_blnMoreMode = FALSE;
249
250 DWORD dwHistoryIndex = 0;
251
252 INPUT_RECORD InputRecord;
253 while ((ret = ReadConsoleInput(m_hStdIn,&InputRecord,1,&dwRecordsReaded)) != FALSE)
254 {
255 ASSERT(dwRecordsReaded == 1);
256 if (dwRecordsReaded != 1) return FALSE;
257 if (InputRecord.EventType != KEY_EVENT) continue;
258 if (!InputRecord.Event.KeyEvent.bKeyDown) continue;
259 #ifdef UNICODE
260 TCHAR ch = InputRecord.Event.KeyEvent.uChar.UnicodeChar;
261 #else
262 TCHAR ch = InputRecord.Event.KeyEvent.uChar.AsciiChar;
263 #endif
264 KeyRepeat:
265 if (m_LinesScrolled)
266 {
267 if (m_LinesScrolled > FristCharCursorPosition.Y) return FALSE;
268 FristCharCursorPosition.Y = SHORT(FristCharCursorPosition.Y - m_LinesScrolled);
269 if (m_LinesScrolled > CompletionPosition.Y) return FALSE;
270 CompletionPosition.Y = SHORT(CompletionPosition.Y - m_LinesScrolled);
271 m_LinesScrolled = 0;
272 }
273 // char Buf[1024];
274 // sprintf(Buf,"wVirtualKeyCode = %u\nchar = %u\n\n",InputRecord.Event.KeyEvent.wVirtualKeyCode,ch);
275 // OutputDebugString(Buf);
276 if ((ch == 0x16)&&(InputRecord.Event.KeyEvent.wVirtualKeyCode == 'V'))
277 {
278 goto Paste;
279 }
280 else if (ch == 0)
281 {
282 if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_INSERT)
283 {
284 if (!(InputRecord.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED))
285 {
286 VERIFY(SetInsertMode(!m_blnInsetMode));
287 }
288 else
289 {
290 if (blnCompletionMode) blnCompletionMode = FALSE;
291
292 Paste:
293 if (!IsClipboardFormatAvailable(
294 #ifdef UNICODE
295 CF_UNICODETEXT
296 #else
297 CF_TEXT
298 #endif
299 ))
300 continue;
301 if (!OpenClipboard(NULL))
302 continue;
303
304 const TCHAR *pch = NULL;
305
306 HANDLE hglb = GetClipboardData(
307 #ifdef UNICODE
308 CF_UNICODETEXT
309 #else
310 CF_TEXT
311 #endif
312 );
313 if (hglb != NULL)
314 {
315 LPTSTR lptstr = (LPTSTR)GlobalLock(hglb);
316 if (lptstr != NULL)
317 {
318 _tcsncpy(m_pchBuffer1,lptstr,m_dwBufferSize);
319 m_pchBuffer1[m_dwBufferSize-1] = 0;
320 pch = m_pchBuffer1;
321 GlobalUnlock(hglb);
322 }
323 }
324 CloseClipboard();
325
326 if (pch == NULL) continue;
327
328 while (*pch)
329 {
330 if (_istprint(*pch))
331 {
332 if (dwLastCharOffset >= m_dwBufferSize-1)
333 {
334 ASSERT(dwLastCharOffset == m_dwBufferSize-1);
335 // Beep(1000,100);
336 break;
337 }
338 TCHAR ch1;
339 //if (m_blnInsetMode)
340 ch1 = m_pchBuffer[dwCurrentCharOffset];
341 m_pchBuffer[dwCurrentCharOffset] = *pch;
342 if ((m_blnInsetMode)||(dwCurrentCharOffset == dwLastCharOffset)) dwLastCharOffset++;
343 dwCurrentCharOffset++;
344 if (!Write(pch,1)) return FALSE;
345 if (m_blnInsetMode)
346 {
347 COORD Cursor = m_CursorPosition;
348 DWORD ofs = dwCurrentCharOffset;
349
350 while(ofs <= dwLastCharOffset)
351 {
352 ch = m_pchBuffer[ofs];
353 m_pchBuffer[ofs] = ch1;
354 ch1 = ch;
355 ofs++;
356 }
357
358 if (dwCurrentCharOffset < dwLastCharOffset)
359 {
360 if (!Write(m_pchBuffer+dwCurrentCharOffset,dwLastCharOffset-dwCurrentCharOffset)) return FALSE;
361
362 if (m_LinesScrolled)
363 {
364 if (m_LinesScrolled > FristCharCursorPosition.Y) return FALSE;
365 Cursor.Y = SHORT(Cursor.Y - m_LinesScrolled);
366 }
367 // Update cursor position
368 m_CursorPosition = Cursor;
369 if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE;
370 }
371 }
372 }
373 pch++;
374 }
375 }
376 }
377 else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)
378 {
379 if (blnCompletionMode) blnCompletionMode = FALSE;
380 if (dwCurrentCharOffset)
381 {
382 if (InputRecord.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
383 {
384 TCHAR *pchWordBegin = m_pchBuffer+dwCurrentCharOffset-1;
385
386 while (pchWordBegin > m_pchBuffer)
387 {
388 if (!_istspace(*pchWordBegin)) break;
389 pchWordBegin--;
390 }
391
392 while (pchWordBegin > m_pchBuffer)
393 {
394 if (_istspace(*(pchWordBegin-1))) break;
395 pchWordBegin--;
396 }
397
398 ASSERT(pchWordBegin >= m_pchBuffer);
399 dwCurrentCharOffset = pchWordBegin - m_pchBuffer;
400
401 ASSERT(dwCurrentCharOffset < dwLastCharOffset);
402
403 m_CursorPosition.X = X_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset);
404 m_CursorPosition.Y = Y_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset);
405 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
406 }
407 else
408 {
409 dwCurrentCharOffset--;
410 if (m_CursorPosition.X)
411 {
412 m_CursorPosition.X--;
413 }
414 else
415 {
416 m_CursorPosition.X = SHORT(m_BufferSize.X-1);
417 ASSERT(m_CursorPosition.Y);
418 m_CursorPosition.Y--;
419 }
420 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
421 }
422 }
423 }
424 else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)
425 {
426 if (blnCompletionMode) blnCompletionMode = FALSE;
427 if (dwCurrentCharOffset < dwLastCharOffset)
428 {
429 if (InputRecord.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
430 {
431 TCHAR *pchWordBegin = m_pchBuffer+dwCurrentCharOffset;
432
433 while ((DWORD)(pchWordBegin - m_pchBuffer) < dwLastCharOffset)
434 {
435 if (_istspace(*pchWordBegin)) break;
436 pchWordBegin++;
437 }
438
439 while ((DWORD)(pchWordBegin - m_pchBuffer) < dwLastCharOffset)
440 {
441 if (!_istspace(*pchWordBegin)) break;
442 pchWordBegin++;
443 }
444
445 dwCurrentCharOffset = pchWordBegin - m_pchBuffer;
446 ASSERT(dwCurrentCharOffset <= dwLastCharOffset);
447 m_CursorPosition.X = X_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset);
448 m_CursorPosition.Y = Y_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset);
449 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
450 }
451 else
452 {
453 dwCurrentCharOffset++;
454 m_CursorPosition.X++;
455 if (m_CursorPosition.X == m_BufferSize.X)
456 {
457 m_CursorPosition.Y++;
458 m_CursorPosition.X = 0;
459 }
460 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
461 }
462 }
463 }
464 else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_HOME)
465 {
466 if (blnCompletionMode) blnCompletionMode = FALSE;
467 dwCurrentCharOffset = 0;
468 m_CursorPosition = FristCharCursorPosition;
469 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
470 }
471 else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_END)
472 {
473 if (blnCompletionMode) blnCompletionMode = FALSE;
474 dwCurrentCharOffset = dwLastCharOffset;
475 m_CursorPosition.X = X_CURSOR_POSITION_FROM_OFFSET(dwLastCharOffset);
476 m_CursorPosition.Y = Y_CURSOR_POSITION_FROM_OFFSET(dwLastCharOffset);
477 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
478 }
479 else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_UP)
480 {
481 if (blnCompletionMode) blnCompletionMode = FALSE;
482 dwHistoryIndex++;
483 const TCHAR *pchHistoryLine = m_History.GetHistoryLine(dwHistoryIndex-1);
484 if (pchHistoryLine)
485 {
486 if (dwLastCharOffset)
487 {
488 _tcsnset(m_pchBuffer,_T(' '),dwLastCharOffset);
489 m_CursorPosition = FristCharCursorPosition;
490 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
491 VERIFY(Write(m_pchBuffer,dwLastCharOffset));
492 dwCurrentCharOffset = dwLastCharOffset = 0;
493 m_CursorPosition = FristCharCursorPosition;
494 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
495 }
496 dwCurrentCharOffset = dwLastCharOffset = _tcslen(pchHistoryLine);
497 if (dwLastCharOffset >= m_dwBufferSize)
498 {
499 ASSERT(FALSE);
500 return FALSE;
501 }
502 _tcscpy(m_pchBuffer,pchHistoryLine);
503 if (!Write(m_pchBuffer)) return FALSE;
504 }
505 else
506 {
507 dwHistoryIndex--;
508 }
509 }
510 else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_DOWN)
511 {
512 if (blnCompletionMode) blnCompletionMode = FALSE;
513 if (dwHistoryIndex)
514 {
515 dwHistoryIndex--;
516 const TCHAR *pchHistoryLine = m_History.GetHistoryLine(dwHistoryIndex-1);
517 if (dwLastCharOffset)
518 {
519 _tcsnset(m_pchBuffer,_T(' '),dwLastCharOffset);
520 m_CursorPosition = FristCharCursorPosition;
521 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
522 VERIFY(Write(m_pchBuffer,dwLastCharOffset));
523 dwCurrentCharOffset = dwLastCharOffset = 0;
524 m_CursorPosition = FristCharCursorPosition;
525 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
526 }
527 if (pchHistoryLine)
528 {
529 dwCurrentCharOffset = dwLastCharOffset = _tcslen(pchHistoryLine);
530 if (dwLastCharOffset >= m_dwBufferSize)
531 {
532 ASSERT(FALSE);
533 return FALSE;
534 }
535 _tcscpy(m_pchBuffer,pchHistoryLine);
536 if (!Write(m_pchBuffer)) return FALSE;
537 }
538 }
539 }
540 else if ((InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)&&
541 (dwLastCharOffset))
542 {
543 // Move the characters if any...
544 ASSERT(dwLastCharOffset);
545 DWORD dwCharOffset = dwCurrentCharOffset;
546 if (dwCharOffset < dwLastCharOffset)
547 {
548 while(dwCharOffset < dwLastCharOffset)
549 {
550 m_pchBuffer[dwCharOffset] = m_pchBuffer[dwCharOffset+1];
551 dwCharOffset++;
552 }
553
554 m_pchBuffer[dwLastCharOffset-1] = _T(' ');
555
556 // Save cursor position
557 COORD Cursor = m_CursorPosition;
558
559 if (!Write(m_pchBuffer+dwCurrentCharOffset,dwLastCharOffset-dwCurrentCharOffset)) return FALSE;
560
561 dwLastCharOffset--;
562
563 // Update cursor position
564 m_CursorPosition = Cursor;
565 if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE;
566 }
567
568 }
569 // else if ((InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE)&&
570 // (InputRecord.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)))
571 // {
572 // if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,0)) return FALSE;
573 // }
574 }
575 else if ((ch == 27) && dwLastCharOffset &&
576 (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE))
577 {
578 if (blnCompletionMode) blnCompletionMode = FALSE;
579 _tcsnset(m_pchBuffer,_T(' '),dwLastCharOffset);
580 m_CursorPosition = FristCharCursorPosition;
581 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
582 VERIFY(Write(m_pchBuffer,dwLastCharOffset));
583 dwCurrentCharOffset = dwLastCharOffset = 0;
584 m_CursorPosition = FristCharCursorPosition;
585 VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition));
586 }
587 else if (ch == _T('\r'))
588 { // carriage return
589 if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition = FristCharCursorPosition)) return FALSE;
590 ASSERT(dwLastCharOffset <= m_dwBufferSize);
591 m_pchBuffer[dwLastCharOffset] = 0; // terminate string in buffer
592 ret = Write(m_pchBuffer);
593 m_History.AddHistoryLine(m_pchBuffer);
594 TCHAR *strLF = _T("\n");
595 ret = Write(strLF);
596 break;
597 }
598 else if (ch == _T('\b'))
599 { // backspace
600 if (blnCompletionMode) blnCompletionMode = FALSE;
601 if ((dwCurrentCharOffset) && ((m_CursorPosition.X != 0) || (m_CursorPosition.Y != 0)))
602 {
603 // Calculate new cursor position
604 COORD NewCursorPosition;
605 if (m_CursorPosition.X)
606 {
607 NewCursorPosition.X = SHORT(m_CursorPosition.X-1);
608 NewCursorPosition.Y = m_CursorPosition.Y;
609 }
610 else
611 {
612 ASSERT(m_BufferSize.X);
613 NewCursorPosition.X = SHORT(m_BufferSize.X-1);
614 ASSERT(m_CursorPosition.Y);
615 NewCursorPosition.Y = SHORT(m_CursorPosition.Y-1);
616 }
617
618 // Move the characters if any...
619 ASSERT(dwLastCharOffset);
620 DWORD dwCharOffset = dwCurrentCharOffset-1;
621 while(dwCharOffset < dwLastCharOffset-1)
622 {
623 m_pchBuffer[dwCharOffset] = m_pchBuffer[dwCharOffset+1];
624 dwCharOffset++;
625 }
626
627 m_pchBuffer[dwLastCharOffset-1] = _T(' ');
628
629 dwCurrentCharOffset--;
630 m_CursorPosition = NewCursorPosition;
631 if (!Write(m_pchBuffer+dwCurrentCharOffset,dwLastCharOffset-dwCurrentCharOffset)) return FALSE;
632
633 // Update cursor position
634 m_CursorPosition = NewCursorPosition;
635 if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE;
636
637 dwLastCharOffset--;
638 }
639 }
640 else if (ch == _T('\t'))
641 {
642 if (!blnCompletionMode)
643 {
644 if (InputRecord.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
645 // nCompletionIndex = 0xFFFFFFFFFFFFFFFF;
646 nCompletionIndex = (unsigned long long) -1;
647 else
648 nCompletionIndex = 0;
649 dwCompletionOffset = dwCurrentCharOffset;
650 BOOL b = FALSE;
651 while(dwCompletionOffset)
652 {
653 dwCompletionOffset--;
654 if (m_pchBuffer[dwCompletionOffset] == _T('\"'))
655 {
656 b = !b;
657 }
658 else if (!b && _istspace(m_pchBuffer[dwCompletionOffset]))
659 {
660 dwCompletionOffset++;
661 break;
662 }
663 }
664 ASSERT(dwCompletionOffset <= dwCurrentCharOffset);
665 _tcsncpy(m_pchBuffer1,m_pchBuffer,dwCompletionOffset);
666 m_pchBuffer1[dwCompletionOffset] = 0;
667 dwCompletionStringSize = dwCurrentCharOffset-dwCompletionOffset;
668 if (dwCompletionStringSize)
669 _tcsncpy(m_pchBuffer2,m_pchBuffer+dwCompletionOffset,dwCompletionStringSize);
670 m_pchBuffer2[dwCompletionStringSize] = 0;
671 CompletionPosition.X = X_CURSOR_POSITION_FROM_OFFSET(dwCompletionOffset);
672 CompletionPosition.Y = Y_CURSOR_POSITION_FROM_OFFSET(dwCompletionOffset);
673 // Beep(1000,500);
674 }
675 else
676 {
677 // Beep(1000,50);
678 // Beep(2000,50);
679 // Beep(3000,50);
680 // Beep(4000,50);
681 // Beep(3000,50);
682 // Beep(2000,50);
683 // Beep(1000,50);
684 }
685 const TCHAR *pchCompletion = NULL;
686 BOOL blnForward = !(InputRecord.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED);
687 if (m_pfReplaceCompletionCallback)
688 pchCompletion = m_pfReplaceCompletionCallback(nCompletionIndex,
689 blnCompletionMode?&blnForward:NULL,
690 m_pchBuffer1,m_pchBuffer2);
691 if (pchCompletion)
692 {
693 // Set cursor position
694 m_CursorPosition = CompletionPosition;
695 if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE;
696
697 // Calculate buffer free space
698 ASSERT(m_dwBufferSize > dwCompletionOffset);
699 DWORD dwFree = m_dwBufferSize - dwCompletionOffset - 1;
700
701 DWORD dwOldCompletionStringSize = dwCompletionStringSize;
702
703 // Write completion string to buffer
704 dwCompletionStringSize = _tcslen(pchCompletion);
705
706 if (dwCompletionStringSize > dwFree)
707 dwCompletionStringSize = dwFree;
708 if (dwCompletionStringSize)
709 {
710 _tcsncpy(m_pchBuffer+dwCompletionOffset,pchCompletion,dwCompletionStringSize);
711 // m_pchBuffer[dwCompletionOffset+dwCompletionStringSize] = 0;
712
713 // Write completion string to console
714 if (!Write(m_pchBuffer+dwCompletionOffset,dwCompletionStringSize)) return FALSE;
715 dwCurrentCharOffset = dwLastCharOffset = dwCompletionOffset + dwCompletionStringSize;
716 ASSERT(dwLastCharOffset < m_dwBufferSize);
717 }
718
719 // Erase rest from previous completion string
720 if (dwOldCompletionStringSize > dwCompletionStringSize)
721 {
722 _tcsnset(m_pchBuffer+dwCompletionOffset+dwCompletionStringSize,_T(' '),
723 dwOldCompletionStringSize - dwCompletionStringSize);
724
725 // Save cursor position
726 COORD pos = m_CursorPosition;
727
728 if (!Write(m_pchBuffer+dwCompletionOffset+dwCompletionStringSize,
729 dwOldCompletionStringSize - dwCompletionStringSize))
730 return FALSE;
731
732 // Set cursor position
733 m_CursorPosition = pos;
734 if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE;
735 }
736
737 }
738 else
739 {
740 /* if (InputRecord.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
741 {
742 nCompletionIndex++;
743 }
744 else
745 {
746 if (nCompletionIndex)
747 nCompletionIndex--;
748 }*/
749 }
750 blnCompletionMode = TRUE;
751 }
752 else if (_istprint(ch))
753 {
754 if (blnCompletionMode) blnCompletionMode = FALSE;
755 if (dwLastCharOffset >= m_dwBufferSize-1)
756 {
757 ASSERT(dwLastCharOffset == m_dwBufferSize-1);
758 // Beep(1000,100);
759 continue;
760 }
761 TCHAR ch1;
762 //if (m_blnInsetMode)
763 ch1 = m_pchBuffer[dwCurrentCharOffset];
764 m_pchBuffer[dwCurrentCharOffset] = ch;
765 if ((m_blnInsetMode)||(dwCurrentCharOffset == dwLastCharOffset)) dwLastCharOffset++;
766 dwCurrentCharOffset++;
767 if (!Write(&ch,1)) return FALSE;
768 if (m_blnInsetMode)
769 {
770 COORD Cursor = m_CursorPosition;
771 DWORD ofs = dwCurrentCharOffset;
772
773 while(ofs <= dwLastCharOffset)
774 {
775 ch = m_pchBuffer[ofs];
776 m_pchBuffer[ofs] = ch1;
777 ch1 = ch;
778 ofs++;
779 }
780
781 if (dwCurrentCharOffset < dwLastCharOffset)
782 {
783 if (!Write(m_pchBuffer+dwCurrentCharOffset,dwLastCharOffset-dwCurrentCharOffset)) return FALSE;
784
785 if (m_LinesScrolled)
786 {
787 if (m_LinesScrolled > FristCharCursorPosition.Y) return FALSE;
788 Cursor.Y = SHORT(Cursor.Y - m_LinesScrolled);
789 }
790 // Update cursor position
791 m_CursorPosition = Cursor;
792 if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE;
793 }
794 }
795 }
796 ASSERT(InputRecord.Event.KeyEvent.wRepeatCount);
797 if (!InputRecord.Event.KeyEvent.wRepeatCount) return FALSE;
798 if (--InputRecord.Event.KeyEvent.wRepeatCount) goto KeyRepeat;
799 }
800 m_blnMoreMode = blnOldMoreMode;
801 return TRUE;
802 }
803
804 BOOL CConsole::GetTextAttribute(WORD& rwAttributes)
805 {
806 rwAttributes = m_wAttributes;
807 return TRUE;
808 }
809
810 // Parameters:
811 // dwBufferSize - size in chars of the input line buffer
812 //
813 // Rerturns:
814 // NULL - Failed.
815 // pointer to the input buffer
816 TCHAR * CConsole::Init(DWORD dwBufferSize, DWORD dwMaxHistoryLines)
817 {
818 if (m_hStdIn != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(m_hStdIn));
819 if (m_hStdOut != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(m_hStdOut));
820
821 m_hStdIn = GetStdHandle(STD_INPUT_HANDLE);
822 if (m_hStdIn == INVALID_HANDLE_VALUE) goto Abort;
823
824 m_hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
825 if (m_hStdOut == INVALID_HANDLE_VALUE) goto Abort;
826
827 CONSOLE_SCREEN_BUFFER_INFO info;
828 if (!GetConsoleScreenBufferInfo(m_hStdOut,&info)) goto Abort;
829 m_wAttributes = info.wAttributes;
830
831 if (!SetConsoleMode(m_hStdIn,0)) goto Abort;
832 if (!SetConsoleMode(m_hStdOut,0)) goto Abort;
833
834 m_CursorPosition = info.dwCursorPosition;
835 m_BufferSize = info.dwSize;
836
837 CONSOLE_CURSOR_INFO cci;
838 cci.bVisible = TRUE;
839 cci.dwSize = m_blnInsetMode?m_dwInsertModeCursorHeight:m_dwOverwriteModeCursorHeight;
840
841 if (!SetConsoleCursorInfo(m_hStdOut,&cci)) goto Abort;
842
843 m_dwBufferSize = dwBufferSize;
844
845 if (m_pchBuffer) delete m_pchBuffer;
846 m_pchBuffer = NULL;
847
848 if (m_pchBuffer1) delete m_pchBuffer1;
849 m_pchBuffer1 = NULL;
850
851 if (m_pchBuffer2) delete m_pchBuffer2;
852 m_pchBuffer2 = NULL;
853
854 m_pchBuffer = new TCHAR [dwBufferSize];
855 if (!m_pchBuffer) goto Abort;
856 m_pchBuffer[dwBufferSize-1] = 0;
857
858 m_pchBuffer1 = new TCHAR [dwBufferSize];
859 if (!m_pchBuffer1) goto Abort;
860 m_pchBuffer1[dwBufferSize-1] = 0;
861
862 m_pchBuffer2 = new TCHAR [dwBufferSize];
863 if (!m_pchBuffer2) goto Abort;
864 m_pchBuffer2[dwBufferSize-1] = 0;
865
866 if (dwMaxHistoryLines)
867 {
868 if (!m_History.Init(dwBufferSize,dwMaxHistoryLines)) goto Abort;
869 }
870
871 return m_pchBuffer;
872
873 Abort:
874 if (m_hStdIn != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(m_hStdIn));
875 m_hStdIn = INVALID_HANDLE_VALUE;
876
877 if (m_hStdOut != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(m_hStdOut));
878 m_hStdOut = INVALID_HANDLE_VALUE;
879
880 if (m_pchBuffer) delete m_pchBuffer;
881 m_pchBuffer = NULL;
882
883 if (m_pchBuffer1) delete m_pchBuffer1;
884 m_pchBuffer1 = NULL;
885
886 if (m_pchBuffer2) delete m_pchBuffer2;
887 m_pchBuffer2 = NULL;
888
889 m_dwBufferSize = 0;
890
891 return NULL;
892 }
893
894 BOOL CConsole::WriteChar(TCHAR ch)
895 {
896 CHAR_INFO ci;
897 ci.Attributes = m_wAttributes;
898 #ifdef UNICODE
899 ci.Char.UnicodeChar = ch;
900 #else
901 ci.Char.AsciiChar = ch;
902 #endif
903 static COORD BufferSize = {1,1};
904 static COORD BufferCoord = {0,0};
905 SMALL_RECT Dest;
906 Dest.Bottom = Dest.Top = m_CursorPosition.Y;
907 Dest.Left = Dest.Right = m_CursorPosition.X;
908 return WriteConsoleOutput(m_hStdOut,&ci,BufferSize,BufferCoord,&Dest);
909 }
910
911 void CConsole::BeginScrollingOperation()
912 {
913 m_Lines = 0;
914 }
915
916 BOOL CConsole::WriteString(TCHAR *pchString, COORD Position)
917 {
918 CHAR_INFO ciBuffer[256];
919 int nSize = _tcslen(pchString);
920 if ((nSize > 256)||(nSize <= 0))
921 {
922 ASSERT(FALSE);
923 return FALSE;
924 }
925
926 COORD BufferSize;
927 BufferSize.X = (SHORT)nSize;
928 BufferSize.Y = 1;
929 static COORD BufferCoord = {0,0};
930 SMALL_RECT Dest;
931 Dest.Bottom = Dest.Top = Position.Y;
932 Dest.Right = SHORT((Dest.Left = Position.X) + nSize - 1);
933
934 while(nSize--)
935 {
936 ciBuffer[nSize].Attributes = m_wAttributes;
937 #ifdef UNICODE
938 ciBuffer[nSize].Char.UnicodeChar = pchString[nSize];
939 #else
940 ciBuffer[nSize].Char.AsciiChar = pchString[nSize];
941 #endif
942 }
943
944 return WriteConsoleOutput(m_hStdOut,ciBuffer,BufferSize,BufferCoord,&Dest);
945 }
946
947 BOOL CConsole::SetInsertMode(BOOL blnInsetMode)
948 {
949 if (m_hStdOut == INVALID_HANDLE_VALUE) return FALSE;
950
951 CONSOLE_CURSOR_INFO cci;
952 cci.bVisible = TRUE;
953 cci.dwSize = blnInsetMode?m_dwInsertModeCursorHeight:m_dwOverwriteModeCursorHeight;
954
955 BOOL ret = SetConsoleCursorInfo(m_hStdOut,&cci);
956 if (ret) m_blnInsetMode = blnInsetMode;
957 return ret;
958 }
959
960
961
962 void CConsole::SetReplaceCompletionCallback(ReplaceCompletionCallback pfCallback)
963 {
964 m_pfReplaceCompletionCallback = pfCallback;
965 }
966
967
968 void CConsole::DisableWrite()
969 {
970 m_blnDisableWrite = TRUE;
971 INPUT_RECORD InputRecord;
972 DWORD dwRecordsWriten;
973 InputRecord.EventType = KEY_EVENT;
974 InputRecord.Event.KeyEvent.bKeyDown = TRUE;
975 #ifdef UNICODE
976 InputRecord.Event.KeyEvent.uChar.UnicodeChar = L' ';
977 #else
978 InputRecord.Event.KeyEvent.uChar.AsciiChar = ' ';
979 #endif
980 BOOL ret = WriteConsoleInput(m_hStdIn,&InputRecord,1,&dwRecordsWriten);
981 ASSERT(ret);
982 }
983
984 void CConsole::EnableWrite()
985 {
986 m_blnDisableWrite = FALSE;
987 }
988
989 /* DWORD ofs = dwCurrentCharOffset;
990 DWORD nLines = (FristCharCursorPosition.X + dwLastCharOffset-1)/m_BufferSize.X;
991 for (DWORD nLine = 0 ; nLine <= nLines ; nLine++)
992 {
993 ASSERT(m_BufferSize.X > pos.X);
994 DWORD nChars = m_BufferSize.X - pos.X - 1;
995 if (nChars > dwLastCharOffset - ofs) nChars = dwLastCharOffset - ofs;
996 if (nChars)
997 { // We have some chars to move in this line
998 _tcsncpy(m_pchBuffer1,m_pchBuffer+ofs,nChars);
999 m_pchBuffer1[nChars] = 0;
1000 if (!WriteString(m_pchBuffer1,pos)) return FALSE;
1001 }
1002 pos.X = SHORT(pos.X + nChars);
1003 // if current line is not the last line
1004 // Move the first char in next line to end of current line
1005 if (nLine < nLines)
1006 {
1007 ofs += nChars;
1008 m_pchBuffer1[0] = m_pchBuffer[ofs];
1009 m_pchBuffer1[1] = 0;
1010 if (!WriteString(m_pchBuffer1,pos)) return FALSE;
1011 pos.Y++;
1012 pos.X = 0;
1013 ofs++;
1014 }
1015 else // Adjust end of read line
1016 {
1017 m_pchBuffer1[0] = _T(' ');
1018 m_pchBuffer1[1] = 0;
1019 if (!WriteString(m_pchBuffer1,pos)) return FALSE;
1020 }
1021 }*/