3 * regexpl - Console Registry Explorer
5 * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 // Console.cpp: implementation of the CConsole class.
25 //////////////////////////////////////////////////////////////////////
31 #define MORE_STRING _T("-- Press space to view more. Press q or Ctrl+break to cancel.--")
32 #define MORE_EMPTY_STRING _T(" ")
35 TCHAR * _tcsnchr(const TCHAR *string, TCHAR ch, int count)
39 if (*string == 0) return NULL;
40 if (*string == ch) return const_cast <char *>(string);
47 //////////////////////////////////////////////////////////////////////
48 // Construction/Destruction
49 //////////////////////////////////////////////////////////////////////
53 m_hStdIn
= INVALID_HANDLE_VALUE
;
54 m_hStdOut
= INVALID_HANDLE_VALUE
;
55 m_blnInsetMode
= TRUE
; // Insert
56 // m_blnInsetMode = FALSE; // Overwrite
57 m_dwInsertModeCursorHeight
= 15;
58 m_dwOverwriteModeCursorHeight
= 100;
63 m_pfReplaceCompletionCallback
= NULL
;
66 m_dwOldOutputMode
= 0;
67 m_blnOldInputModeSaved
= FALSE
;
68 m_blnOldOutputModeSaved
= FALSE
;
80 if (m_blnOldInputModeSaved
)
81 SetConsoleMode(m_hStdIn
,m_dwOldInputMode
);
82 if (m_blnOldOutputModeSaved
)
83 SetConsoleMode(m_hStdOut
,m_dwOldOutputMode
);
85 if (m_hStdIn
!= INVALID_HANDLE_VALUE
)
86 VERIFY(CloseHandle(m_hStdIn
));
87 if (m_hStdOut
!= INVALID_HANDLE_VALUE
)
88 VERIFY(CloseHandle(m_hStdOut
));
91 BOOL
CConsole::Write(const TCHAR
*p
, DWORD dwChars
)
93 if (m_hStdOut
== INVALID_HANDLE_VALUE
)
95 if (m_hStdIn
== INVALID_HANDLE_VALUE
)
102 DWORD dwCharsToWrite
= (dwChars
)?dwChars
:_tcslen(p
);
103 DWORD dwCharsWrittenAdd
= 0;
105 while (dwCharsToWrite
&& (!m_blnDisableWrite
))
107 switch(p
[dwCharsWrittenAdd
])
110 m_CursorPosition
.Y
++;
111 m_CursorPosition
.X
= 0;
120 if (!Write(_T(" "))) return FALSE
;
122 while ((m_CursorPosition
.X
% TAB_WIDTH
) && (!m_blnDisableWrite
));
128 if (!WriteChar(p
[dwCharsWrittenAdd
])) return FALSE
;
129 m_CursorPosition
.X
++;
132 if (m_CursorPosition
.X
== m_BufferSize
.X
)
134 m_CursorPosition
.Y
++;
135 m_CursorPosition
.X
= 0;
137 if (m_CursorPosition
.Y
== m_BufferSize
.Y
)
139 ASSERT(m_CursorPosition
.X
== 0);
142 Src
.Right
= (SHORT
)(m_BufferSize
.X
-1);
144 Src
.Bottom
= (SHORT
)(m_BufferSize
.Y
-1);
147 ci
.Char
.UnicodeChar
= L
' ';
149 ci
.Char
.AsciiChar
= ' ';
155 if (!ScrollConsoleScreenBuffer(m_hStdOut
,&Src
,NULL
,Dest
,&ci
)) return FALSE
;
156 m_CursorPosition
.Y
--;
159 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
)) return FALSE
;
160 VERIFY(WriteChar(_T(' ')));
161 if ((m_blnMoreMode
)&&(m_CursorPosition
.X
== 0))
164 if (m_Lines
>= m_BufferSize
.Y
-1)
166 ASSERT(m_Lines
== m_BufferSize
.Y
-1);
168 VERIFY(WriteString(MORE_STRING
,m_CursorPosition
));
169 VERIFY(FlushInputBuffer());
171 CONSOLE_CURSOR_INFO cci
;
172 cci
.bVisible
= FALSE
;
174 VERIFY(SetConsoleCursorInfo(m_hStdOut
,&cci
));
176 INPUT_RECORD InputRecord
;
177 DWORD dwRecordsReaded
;
178 while ((ret
= ReadConsoleInput(m_hStdIn
,&InputRecord
,1,&dwRecordsReaded
)) != FALSE
)
180 ASSERT(dwRecordsReaded
== 1);
181 if (dwRecordsReaded
!= 1)
183 if (InputRecord
.EventType
!= KEY_EVENT
)
185 if (!InputRecord
.Event
.KeyEvent
.bKeyDown
)
188 if ((InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_CANCEL
)||
189 (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== _T('Q')))
191 VERIFY(GenerateConsoleCtrlEvent(CTRL_C_EVENT
,0));
195 TCHAR ch
= InputRecord
.Event
.KeyEvent
.uChar
.UnicodeChar
;
197 TCHAR ch
= InputRecord
.Event
.KeyEvent
.uChar
.AsciiChar
;
204 VERIFY(WriteString(MORE_EMPTY_STRING
,m_CursorPosition
));
205 m_CursorPosition
.X
= 0;
208 cci
.dwSize
= m_blnInsetMode
?m_dwInsertModeCursorHeight
:m_dwOverwriteModeCursorHeight
;
209 VERIFY(SetConsoleCursorInfo(m_hStdOut
,&cci
));
218 unsigned int CConsole::GetTabWidth()
223 BOOL
CConsole::SetTitle(TCHAR
*p
)
225 return SetConsoleTitle(p
);
228 BOOL
CConsole::SetTextAttribute(WORD wAttributes
)
230 m_wAttributes
= wAttributes
;
234 BOOL CConsole::SetInputMode(DWORD dwMode)
236 return SetConsoleMode(m_hStdIn,dwMode);
239 BOOL CConsole::SetOutputMode(DWORD dwMode)
241 return SetConsoleMode(m_hStdOut,dwMode);
244 BOOL
CConsole::FlushInputBuffer()
246 if (m_hStdIn
== INVALID_HANDLE_VALUE
) return FALSE
;
247 return FlushConsoleInputBuffer(m_hStdIn
);
250 BOOL
CConsole::ReadLine()
252 if (m_hStdIn
== INVALID_HANDLE_VALUE
) return FALSE
;
253 if (m_hStdOut
== INVALID_HANDLE_VALUE
) return FALSE
;
254 if (m_dwBufferSize
== 0)
259 if (m_pchBuffer
== NULL
)
264 if (m_pchBuffer1
== NULL
)
269 if (!FlushConsoleInputBuffer(m_hStdIn
)) return FALSE
;
271 COORD FristCharCursorPosition
= m_CursorPosition
;
272 #define X_CURSOR_POSITION_FROM_OFFSET(ofs) USHORT(((FristCharCursorPosition.X + ofs)%m_BufferSize.X))
273 #define Y_CURSOR_POSITION_FROM_OFFSET(ofs) USHORT((FristCharCursorPosition.Y + (FristCharCursorPosition.X + ofs)/m_BufferSize.X))
274 //#define OFFSET_FROM_CURSOR_POSITION(pos) ((pos.Y-FristCharCursorPosition.Y)*m_BufferSize.X+pos.X-FristCharCursorPosition.X)
276 DWORD dwRecordsReaded
;
277 DWORD dwCurrentCharOffset
= 0;
278 DWORD dwLastCharOffset
= 0;
281 BOOL blnCompletionMode
= FALSE
;
282 // unsigned __int64 nCompletionIndex = 0;
283 unsigned long long nCompletionIndex
= 0;
284 DWORD dwCompletionOffset
= 0;
285 DWORD dwCompletionStringSize
= 0;
286 COORD CompletionPosition
= FristCharCursorPosition
;
289 BOOL blnOldMoreMode
= m_blnMoreMode
;
290 m_blnMoreMode
= FALSE
;
292 DWORD dwHistoryIndex
= 0;
294 INPUT_RECORD InputRecord
;
295 while ((ret
= ReadConsoleInput(m_hStdIn
,&InputRecord
,1,&dwRecordsReaded
)) != FALSE
)
297 ASSERT(dwRecordsReaded
== 1);
298 if (dwRecordsReaded
!= 1) return FALSE
;
299 if (InputRecord
.EventType
!= KEY_EVENT
) continue;
300 if (!InputRecord
.Event
.KeyEvent
.bKeyDown
) continue;
302 TCHAR ch
= InputRecord
.Event
.KeyEvent
.uChar
.UnicodeChar
;
304 TCHAR ch
= InputRecord
.Event
.KeyEvent
.uChar
.AsciiChar
;
309 if (m_LinesScrolled
> FristCharCursorPosition
.Y
) return FALSE
;
310 FristCharCursorPosition
.Y
= SHORT(FristCharCursorPosition
.Y
- m_LinesScrolled
);
311 if (m_LinesScrolled
> CompletionPosition
.Y
) return FALSE
;
312 CompletionPosition
.Y
= SHORT(CompletionPosition
.Y
- m_LinesScrolled
);
316 // sprintf(Buf,"wVirtualKeyCode = %u\nchar = %u\n\n",InputRecord.Event.KeyEvent.wVirtualKeyCode,ch);
317 // OutputDebugString(Buf);
320 if ((ch
== 0x16)&&(InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== 'V'))
329 if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_INSERT
)
331 if (!(InputRecord
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
))
333 VERIFY(SetInsertMode(!m_blnInsetMode
));
337 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
340 if (!IsClipboardFormatAvailable(
348 if (!OpenClipboard(NULL
))
351 const TCHAR
*pch
= NULL
;
353 HANDLE hglb
= GetClipboardData(
362 LPTSTR lptstr
= (LPTSTR
)GlobalLock(hglb
);
365 _tcsncpy(m_pchBuffer1
,lptstr
,m_dwBufferSize
);
366 m_pchBuffer1
[m_dwBufferSize
-1] = 0;
373 if (pch
== NULL
) continue;
379 if (dwLastCharOffset
>= m_dwBufferSize
-1)
381 ASSERT(dwLastCharOffset
== m_dwBufferSize
-1);
386 //if (m_blnInsetMode)
387 ch1
= m_pchBuffer
[dwCurrentCharOffset
];
388 m_pchBuffer
[dwCurrentCharOffset
] = *pch
;
389 if ((m_blnInsetMode
)||(dwCurrentCharOffset
== dwLastCharOffset
)) dwLastCharOffset
++;
390 dwCurrentCharOffset
++;
391 if (!Write(pch
,1)) return FALSE
;
394 COORD Cursor
= m_CursorPosition
;
395 DWORD ofs
= dwCurrentCharOffset
;
397 while(ofs
<= dwLastCharOffset
)
399 ch
= m_pchBuffer
[ofs
];
400 m_pchBuffer
[ofs
] = ch1
;
405 if (dwCurrentCharOffset
< dwLastCharOffset
)
407 if (!Write(m_pchBuffer
+dwCurrentCharOffset
,dwLastCharOffset
-dwCurrentCharOffset
)) return FALSE
;
411 if (m_LinesScrolled
> FristCharCursorPosition
.Y
) return FALSE
;
412 Cursor
.Y
= SHORT(Cursor
.Y
- m_LinesScrolled
);
414 // Update cursor position
415 m_CursorPosition
= Cursor
;
416 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
)) return FALSE
;
426 if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)
428 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
429 if (dwCurrentCharOffset
)
431 if (InputRecord
.Event
.KeyEvent
.dwControlKeyState
& (LEFT_CTRL_PRESSED
|RIGHT_CTRL_PRESSED
))
433 TCHAR
*pchWordBegin
= m_pchBuffer
+dwCurrentCharOffset
-1;
435 while (pchWordBegin
> m_pchBuffer
)
437 if (!_istspace(*pchWordBegin
)) break;
441 while (pchWordBegin
> m_pchBuffer
)
443 if (_istspace(*(pchWordBegin
-1))) break;
447 ASSERT(pchWordBegin
>= m_pchBuffer
);
448 dwCurrentCharOffset
= pchWordBegin
- m_pchBuffer
;
450 ASSERT(dwCurrentCharOffset
< dwLastCharOffset
);
452 m_CursorPosition
.X
= X_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset
);
453 m_CursorPosition
.Y
= Y_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset
);
454 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
458 dwCurrentCharOffset
--;
459 if (m_CursorPosition
.X
)
461 m_CursorPosition
.X
--;
465 m_CursorPosition
.X
= SHORT(m_BufferSize
.X
-1);
466 ASSERT(m_CursorPosition
.Y
);
467 m_CursorPosition
.Y
--;
469 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
473 else if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)
475 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
476 if (dwCurrentCharOffset
< dwLastCharOffset
)
478 if (InputRecord
.Event
.KeyEvent
.dwControlKeyState
& (LEFT_CTRL_PRESSED
|RIGHT_CTRL_PRESSED
))
480 TCHAR
*pchWordBegin
= m_pchBuffer
+dwCurrentCharOffset
;
482 while ((DWORD
)(pchWordBegin
- m_pchBuffer
) < dwLastCharOffset
)
484 if (_istspace(*pchWordBegin
)) break;
488 while ((DWORD
)(pchWordBegin
- m_pchBuffer
) < dwLastCharOffset
)
490 if (!_istspace(*pchWordBegin
)) break;
494 dwCurrentCharOffset
= pchWordBegin
- m_pchBuffer
;
495 ASSERT(dwCurrentCharOffset
<= dwLastCharOffset
);
496 m_CursorPosition
.X
= X_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset
);
497 m_CursorPosition
.Y
= Y_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset
);
498 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
502 dwCurrentCharOffset
++;
503 m_CursorPosition
.X
++;
504 if (m_CursorPosition
.X
== m_BufferSize
.X
)
506 m_CursorPosition
.Y
++;
507 m_CursorPosition
.X
= 0;
509 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
513 else if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)
515 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
516 dwCurrentCharOffset
= 0;
517 m_CursorPosition
= FristCharCursorPosition
;
518 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
520 else if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)
522 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
523 dwCurrentCharOffset
= dwLastCharOffset
;
524 m_CursorPosition
.X
= X_CURSOR_POSITION_FROM_OFFSET(dwLastCharOffset
);
525 m_CursorPosition
.Y
= Y_CURSOR_POSITION_FROM_OFFSET(dwLastCharOffset
);
526 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
528 else if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)
530 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
532 const TCHAR
*pchHistoryLine
= m_History
.GetHistoryLine(dwHistoryIndex
-1);
535 if (dwLastCharOffset
)
537 _tcsnset(m_pchBuffer
,_T(' '),dwLastCharOffset
);
538 m_CursorPosition
= FristCharCursorPosition
;
539 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
540 VERIFY(Write(m_pchBuffer
,dwLastCharOffset
));
541 dwCurrentCharOffset
= dwLastCharOffset
= 0;
542 m_CursorPosition
= FristCharCursorPosition
;
543 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
545 dwCurrentCharOffset
= dwLastCharOffset
= _tcslen(pchHistoryLine
);
546 if (dwLastCharOffset
>= m_dwBufferSize
)
551 _tcscpy(m_pchBuffer
,pchHistoryLine
);
552 if (!Write(m_pchBuffer
)) return FALSE
;
559 else if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)
561 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
565 const TCHAR
*pchHistoryLine
= m_History
.GetHistoryLine(dwHistoryIndex
-1);
566 if (dwLastCharOffset
)
568 _tcsnset(m_pchBuffer
,_T(' '),dwLastCharOffset
);
569 m_CursorPosition
= FristCharCursorPosition
;
570 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
571 VERIFY(Write(m_pchBuffer
,dwLastCharOffset
));
572 dwCurrentCharOffset
= dwLastCharOffset
= 0;
573 m_CursorPosition
= FristCharCursorPosition
;
574 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
578 dwCurrentCharOffset
= dwLastCharOffset
= _tcslen(pchHistoryLine
);
579 if (dwLastCharOffset
>= m_dwBufferSize
)
584 _tcscpy(m_pchBuffer
,pchHistoryLine
);
585 if (!Write(m_pchBuffer
)) return FALSE
;
589 else if ((InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)&&
592 // Move the characters if any...
593 ASSERT(dwLastCharOffset
);
594 DWORD dwCharOffset
= dwCurrentCharOffset
;
595 if (dwCharOffset
< dwLastCharOffset
)
597 while(dwCharOffset
< dwLastCharOffset
)
599 m_pchBuffer
[dwCharOffset
] = m_pchBuffer
[dwCharOffset
+1];
603 m_pchBuffer
[dwLastCharOffset
-1] = _T(' ');
605 // Save cursor position
606 COORD Cursor
= m_CursorPosition
;
608 if (!Write(m_pchBuffer
+dwCurrentCharOffset
,dwLastCharOffset
-dwCurrentCharOffset
)) return FALSE
;
612 // Update cursor position
613 m_CursorPosition
= Cursor
;
614 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
)) return FALSE
;
618 // else if ((InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE)&&
619 // (InputRecord.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)))
621 // if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,0)) return FALSE;
624 else if ((ch
== 27) && dwLastCharOffset
&&
625 (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
))
627 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
628 _tcsnset(m_pchBuffer
,_T(' '),dwLastCharOffset
);
629 m_CursorPosition
= FristCharCursorPosition
;
630 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
631 VERIFY(Write(m_pchBuffer
,dwLastCharOffset
));
632 dwCurrentCharOffset
= dwLastCharOffset
= 0;
633 m_CursorPosition
= FristCharCursorPosition
;
634 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
636 else if (ch
== _T('\r'))
638 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
= FristCharCursorPosition
)) return FALSE
;
639 ASSERT(dwLastCharOffset
<= m_dwBufferSize
);
640 m_pchBuffer
[dwLastCharOffset
] = 0; // terminate string in buffer
641 ret
= Write(m_pchBuffer
);
642 m_History
.AddHistoryLine(m_pchBuffer
);
643 TCHAR
*strLF
= _T("\n");
647 else if (ch
== _T('\b'))
649 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
650 if ((dwCurrentCharOffset
) && ((m_CursorPosition
.X
!= 0) || (m_CursorPosition
.Y
!= 0)))
652 // Calculate new cursor position
653 COORD NewCursorPosition
;
654 if (m_CursorPosition
.X
)
656 NewCursorPosition
.X
= SHORT(m_CursorPosition
.X
-1);
657 NewCursorPosition
.Y
= m_CursorPosition
.Y
;
661 ASSERT(m_BufferSize
.X
);
662 NewCursorPosition
.X
= SHORT(m_BufferSize
.X
-1);
663 ASSERT(m_CursorPosition
.Y
);
664 NewCursorPosition
.Y
= SHORT(m_CursorPosition
.Y
-1);
667 // Move the characters if any...
668 ASSERT(dwLastCharOffset
);
669 DWORD dwCharOffset
= dwCurrentCharOffset
-1;
670 while(dwCharOffset
< dwLastCharOffset
-1)
672 m_pchBuffer
[dwCharOffset
] = m_pchBuffer
[dwCharOffset
+1];
676 m_pchBuffer
[dwLastCharOffset
-1] = _T(' ');
678 dwCurrentCharOffset
--;
679 m_CursorPosition
= NewCursorPosition
;
680 if (!Write(m_pchBuffer
+dwCurrentCharOffset
,dwLastCharOffset
-dwCurrentCharOffset
)) return FALSE
;
682 // Update cursor position
683 m_CursorPosition
= NewCursorPosition
;
684 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
)) return FALSE
;
689 else if (ch
== _T('\t'))
692 if (!blnCompletionMode
) // If tab was pressed after non-tab. We enter in completion mode.
694 // Initialize completion index
695 if (InputRecord
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
) // If shift was pressed
696 nCompletionIndex
= (unsigned long long) -1; // Last completion
698 nCompletionIndex
= 0; // First completion
700 // Find completion offset. It points at char after first non-quoted whitespace.
701 dwCompletionOffset
= dwCurrentCharOffset
;
702 BOOL blnQuotedParameter
= FALSE
;
703 while(dwCompletionOffset
)
705 dwCompletionOffset
--;
706 if (m_pchBuffer
[dwCompletionOffset
] == _T('\"'))
708 blnQuotedParameter
= !blnQuotedParameter
;
710 else if (!blnQuotedParameter
&& _istspace(m_pchBuffer
[dwCompletionOffset
]))
711 { // Found ! We are not inside quored parameter and we are on whitespace.
712 dwCompletionOffset
++; // dwCompletionOffset must point at char AFTER first non-quoted whitespace.
717 ASSERT(dwCompletionOffset
<= dwCurrentCharOffset
);
719 // Save not changing part (context) of completion in m_pchBuffer1
720 _tcsncpy(m_pchBuffer1
,m_pchBuffer
,dwCompletionOffset
);
721 m_pchBuffer1
[dwCompletionOffset
] = 0;
723 // Size of changing part
724 dwCompletionStringSize
= dwCurrentCharOffset
-dwCompletionOffset
;
726 // Save intial changing part of completion in m_pchBuffer2
727 if (dwCompletionStringSize
)
728 _tcsncpy(m_pchBuffer2
,m_pchBuffer
+dwCompletionOffset
,dwCompletionStringSize
);
729 m_pchBuffer2
[dwCompletionStringSize
] = 0;
731 // Calculate cursor position of point between changing and not changing ports
732 CompletionPosition
.X
= X_CURSOR_POSITION_FROM_OFFSET(dwCompletionOffset
);
733 CompletionPosition
.Y
= Y_CURSOR_POSITION_FROM_OFFSET(dwCompletionOffset
);
734 } // if first time tab
736 const TCHAR
*pchCompletion
= NULL
;
739 BOOL blnForward
= !(InputRecord
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
);
741 if (m_pfReplaceCompletionCallback
) // If we are using replace completion callback
742 pchCompletion
= m_pfReplaceCompletionCallback(nCompletionIndex
,
743 blnCompletionMode
?&blnForward
:NULL
, // If this is first time we call the completion callback, do not change completion index
744 m_pchBuffer1
,m_pchBuffer2
);
746 if (pchCompletion
) // If completion found
748 // Set cursor position to compeltion position
749 m_CursorPosition
= CompletionPosition
;
750 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
))
753 // Calculate buffer free space
754 ASSERT(m_dwBufferSize
> dwCompletionOffset
);
755 DWORD dwFree
= m_dwBufferSize
- dwCompletionOffset
- 1;
757 // Save old completion string size
758 DWORD dwOldCompletionStringSize
= dwCompletionStringSize
;
760 // Write completion string to buffer
761 dwCompletionStringSize
= _tcslen(pchCompletion
);
763 // If there is not enough space in buffer, so we truncate the completion
764 if (dwCompletionStringSize
> dwFree
)
765 dwCompletionStringSize
= dwFree
;
767 if (dwCompletionStringSize
)
769 // Copy competion into main buffer
770 _tcsncpy(m_pchBuffer
+dwCompletionOffset
,pchCompletion
,dwCompletionStringSize
);
772 // Write completion string to console
773 if (!Write(m_pchBuffer
+dwCompletionOffset
,dwCompletionStringSize
))
777 dwCurrentCharOffset
= dwLastCharOffset
= dwCompletionOffset
+ dwCompletionStringSize
;
779 ASSERT(dwLastCharOffset
< m_dwBufferSize
);
782 // Erase rest from previous completion string, if the new completion is shorter than old
783 if (dwOldCompletionStringSize
> dwCompletionStringSize
)
785 _tcsnset(m_pchBuffer
+dwCompletionOffset
+dwCompletionStringSize
,_T(' '),
786 dwOldCompletionStringSize
- dwCompletionStringSize
);
788 // Save cursor position
789 COORD pos
= m_CursorPosition
;
791 if (!Write(m_pchBuffer
+dwCompletionOffset
+dwCompletionStringSize
,
792 dwOldCompletionStringSize
- dwCompletionStringSize
))
795 // Set cursor position
796 m_CursorPosition
= pos
;
797 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
))
800 } // If completion found
802 // Ok, we are in completion mode
803 blnCompletionMode
= TRUE
;
805 else if (_istprint(ch
))
807 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
808 if (dwLastCharOffset
>= m_dwBufferSize
-1)
810 ASSERT(dwLastCharOffset
== m_dwBufferSize
-1);
815 //if (m_blnInsetMode)
816 ch1
= m_pchBuffer
[dwCurrentCharOffset
];
817 m_pchBuffer
[dwCurrentCharOffset
] = ch
;
818 if ((m_blnInsetMode
)||(dwCurrentCharOffset
== dwLastCharOffset
)) dwLastCharOffset
++;
819 dwCurrentCharOffset
++;
820 if (!Write(&ch
,1)) return FALSE
;
823 COORD Cursor
= m_CursorPosition
;
824 DWORD ofs
= dwCurrentCharOffset
;
826 while(ofs
<= dwLastCharOffset
)
828 ch
= m_pchBuffer
[ofs
];
829 m_pchBuffer
[ofs
] = ch1
;
834 if (dwCurrentCharOffset
< dwLastCharOffset
)
836 if (!Write(m_pchBuffer
+dwCurrentCharOffset
,dwLastCharOffset
-dwCurrentCharOffset
)) return FALSE
;
840 if (m_LinesScrolled
> FristCharCursorPosition
.Y
) return FALSE
;
841 Cursor
.Y
= SHORT(Cursor
.Y
- m_LinesScrolled
);
843 // Update cursor position
844 m_CursorPosition
= Cursor
;
845 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
)) return FALSE
;
849 ASSERT(InputRecord
.Event
.KeyEvent
.wRepeatCount
);
850 if (!InputRecord
.Event
.KeyEvent
.wRepeatCount
) return FALSE
;
851 if (--InputRecord
.Event
.KeyEvent
.wRepeatCount
) goto KeyRepeat
;
853 m_blnMoreMode
= blnOldMoreMode
;
857 BOOL
CConsole::GetTextAttribute(WORD
& rwAttributes
)
859 rwAttributes
= m_wAttributes
;
864 // dwBufferSize - size in chars of the input line buffer
868 // pointer to the input buffer
869 TCHAR
* CConsole::Init(DWORD dwBufferSize
, DWORD dwMaxHistoryLines
)
871 if (m_hStdIn
!= INVALID_HANDLE_VALUE
) VERIFY(CloseHandle(m_hStdIn
));
872 if (m_hStdOut
!= INVALID_HANDLE_VALUE
) VERIFY(CloseHandle(m_hStdOut
));
874 m_hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
876 if (m_hStdIn
== INVALID_HANDLE_VALUE
)
878 // _ftprintf(stderr,_T("GetStdHandle(STD_INPUT_HANDLE) failed. GetLastError return 0x%X\n"),(unsigned)GetLastError());
882 m_hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
884 if (m_hStdOut
== INVALID_HANDLE_VALUE
)
886 // _ftprintf(stderr,_T("GetStdHandle(STD_OUTPUT_HANDLE) failed. GetLastError return 0x%X\n"),(unsigned)GetLastError());
890 CONSOLE_SCREEN_BUFFER_INFO info
;
891 if (!GetConsoleScreenBufferInfo(m_hStdOut
,&info
))
893 // _ftprintf(stderr,_T("GetConsoleScreenBufferInfo(m_hStdOut,&info) failed. GetLastError return 0x%X\n"),(unsigned)GetLastError());
894 if (GetLastError() == 6) // redirected output
895 _ftprintf(stderr
,_T("Redirection is not supported.\n"));
899 m_wAttributes
= info
.wAttributes
;
901 if (!m_blnOldInputModeSaved
)
903 if (!GetConsoleMode(m_hStdIn
,&m_dwOldInputMode
))
905 if (GetLastError() == 6) // redirected input
906 _ftprintf(stderr
,_T("Redirection is not supported.\n"));
907 // _ftprintf(stderr,_T("GetConsoleMode(0x%X,&m_dwOldINputMode) failed. GetLastError() returns 0x%X\n"),(int)m_hStdIn,GetLastError());
911 m_blnOldInputModeSaved
= TRUE
;
914 // _ftprintf(stderr,_T("Calling GetConsoleMode(0x%X,&m_dwOldOutputMode) ...\n"),(int)m_hStdOut);
915 if (!m_blnOldOutputModeSaved
)
917 if (!GetConsoleMode(m_hStdOut
,&m_dwOldOutputMode
))
919 // _ftprintf(stderr,_T("Calling GetConsoleMode(0x%X,&m_dwOldOutputMode) done.\n"),(int)m_hStdOut);
920 m_blnOldOutputModeSaved
= TRUE
;
923 // _ftprintf(stderr,_T("Calling SetConsoleMode(0x%X,0) ...\n"),(int)m_hStdIn);
924 if (!SetConsoleMode(m_hStdIn
,0))
926 if (!SetConsoleMode(m_hStdOut
,0))
929 m_CursorPosition
= info
.dwCursorPosition
;
930 m_BufferSize
= info
.dwSize
;
932 CONSOLE_CURSOR_INFO cci
;
934 cci
.dwSize
= m_blnInsetMode
?m_dwInsertModeCursorHeight
:m_dwOverwriteModeCursorHeight
;
936 if (!SetConsoleCursorInfo(m_hStdOut
,&cci
)) goto Abort
;
938 m_dwBufferSize
= dwBufferSize
;
940 if (m_pchBuffer
) delete m_pchBuffer
;
943 if (m_pchBuffer1
) delete m_pchBuffer1
;
946 if (m_pchBuffer2
) delete m_pchBuffer2
;
949 m_pchBuffer
= new TCHAR
[dwBufferSize
];
950 if (!m_pchBuffer
) goto Abort
;
951 m_pchBuffer
[dwBufferSize
-1] = 0;
953 m_pchBuffer1
= new TCHAR
[dwBufferSize
];
954 if (!m_pchBuffer1
) goto Abort
;
955 m_pchBuffer1
[dwBufferSize
-1] = 0;
957 m_pchBuffer2
= new TCHAR
[dwBufferSize
];
958 if (!m_pchBuffer2
) goto Abort
;
959 m_pchBuffer2
[dwBufferSize
-1] = 0;
961 if (dwMaxHistoryLines
)
963 if (!m_History
.Init(dwBufferSize
,dwMaxHistoryLines
)) goto Abort
;
969 if (m_hStdIn
!= INVALID_HANDLE_VALUE
) VERIFY(CloseHandle(m_hStdIn
));
970 m_hStdIn
= INVALID_HANDLE_VALUE
;
972 if (m_hStdOut
!= INVALID_HANDLE_VALUE
) VERIFY(CloseHandle(m_hStdOut
));
973 m_hStdOut
= INVALID_HANDLE_VALUE
;
975 if (m_pchBuffer
) delete m_pchBuffer
;
978 if (m_pchBuffer1
) delete m_pchBuffer1
;
981 if (m_pchBuffer2
) delete m_pchBuffer2
;
989 BOOL
CConsole::WriteChar(TCHAR ch
)
992 ci
.Attributes
= m_wAttributes
;
994 ci
.Char
.UnicodeChar
= ch
;
996 ci
.Char
.AsciiChar
= ch
;
998 static COORD BufferSize
= {1,1};
999 static COORD BufferCoord
= {0,0};
1001 Dest
.Bottom
= Dest
.Top
= m_CursorPosition
.Y
;
1002 Dest
.Left
= Dest
.Right
= m_CursorPosition
.X
;
1003 return WriteConsoleOutput(m_hStdOut
,&ci
,BufferSize
,BufferCoord
,&Dest
);
1006 void CConsole::BeginScrollingOperation()
1011 BOOL
CConsole::WriteString(TCHAR
*pchString
, COORD Position
)
1013 CHAR_INFO ciBuffer
[256];
1014 int nSize
= _tcslen(pchString
);
1015 if ((nSize
> 256)||(nSize
<= 0))
1022 BufferSize
.X
= (SHORT
)nSize
;
1024 static COORD BufferCoord
= {0,0};
1026 Dest
.Bottom
= Dest
.Top
= Position
.Y
;
1027 Dest
.Right
= SHORT((Dest
.Left
= Position
.X
) + nSize
- 1);
1031 ciBuffer
[nSize
].Attributes
= m_wAttributes
;
1033 ciBuffer
[nSize
].Char
.UnicodeChar
= pchString
[nSize
];
1035 ciBuffer
[nSize
].Char
.AsciiChar
= pchString
[nSize
];
1039 return WriteConsoleOutput(m_hStdOut
,ciBuffer
,BufferSize
,BufferCoord
,&Dest
);
1042 BOOL
CConsole::SetInsertMode(BOOL blnInsetMode
)
1044 if (m_hStdOut
== INVALID_HANDLE_VALUE
) return FALSE
;
1046 CONSOLE_CURSOR_INFO cci
;
1047 cci
.bVisible
= TRUE
;
1048 cci
.dwSize
= blnInsetMode
?m_dwInsertModeCursorHeight
:m_dwOverwriteModeCursorHeight
;
1050 BOOL ret
= SetConsoleCursorInfo(m_hStdOut
,&cci
);
1051 if (ret
) m_blnInsetMode
= blnInsetMode
;
1057 void CConsole::SetReplaceCompletionCallback(ReplaceCompletionCallback pfCallback
)
1059 m_pfReplaceCompletionCallback
= pfCallback
;
1063 void CConsole::DisableWrite()
1065 m_blnDisableWrite
= TRUE
;
1066 INPUT_RECORD InputRecord
;
1067 DWORD dwRecordsWriten
;
1068 InputRecord
.EventType
= KEY_EVENT
;
1069 InputRecord
.Event
.KeyEvent
.bKeyDown
= TRUE
;
1071 InputRecord
.Event
.KeyEvent
.uChar
.UnicodeChar
= L
' ';
1073 InputRecord
.Event
.KeyEvent
.uChar
.AsciiChar
= ' ';
1075 BOOL ret
= WriteConsoleInput(m_hStdIn
,&InputRecord
,1,&dwRecordsWriten
);
1079 void CConsole::EnableWrite()
1081 m_blnDisableWrite
= FALSE
;