Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084/* * regexpl - Console Registry Explorer * * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */
// Console.cpp: implementation of the CConsole class.////////////////////////////////////////////////////////////////////////
#include "ph.h"#include "Console.h"
#define TAB_WIDTH 8#define MORE_STRING _T("-- Press space to view more. Press q or Ctrl+break to cancel.--")#define MORE_EMPTY_STRING _T(" ")
/*TCHAR * _tcsnchr(const TCHAR *string, TCHAR ch, int count){ while (count--) { if (*string == 0) return NULL; if (*string == ch) return const_cast <char *>(string); string++; } return NULL;}*/
//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////
CConsole::CConsole(){ m_hStdIn = INVALID_HANDLE_VALUE; m_hStdOut = INVALID_HANDLE_VALUE; m_blnInsetMode = TRUE; // Insert// m_blnInsetMode = FALSE; // Overwrite m_dwInsertModeCursorHeight = 15; m_dwOverwriteModeCursorHeight = 100;// m_Lines = 0; m_pchBuffer = NULL; m_pchBuffer1 = NULL; m_pchBuffer2 = NULL; m_pfReplaceCompletionCallback = NULL; m_blnMoreMode = TRUE; m_dwOldInputMode = 0; m_dwOldOutputMode = 0; m_blnOldInputModeSaved = FALSE; m_blnOldOutputModeSaved = FALSE;}
CConsole::~CConsole(){ if (m_pchBuffer) delete[] m_pchBuffer; if (m_pchBuffer1) delete[] m_pchBuffer1; if (m_pchBuffer2) delete[] m_pchBuffer2;
if (m_blnOldInputModeSaved) SetConsoleMode(m_hStdIn,m_dwOldInputMode); if (m_blnOldOutputModeSaved) SetConsoleMode(m_hStdOut,m_dwOldOutputMode);
if (m_hStdIn != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(m_hStdIn)); if (m_hStdOut != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(m_hStdOut));}
BOOL CConsole::Write(const TCHAR *p, DWORD dwChars){ if (m_hStdOut == INVALID_HANDLE_VALUE) return FALSE; if (m_hStdIn == INVALID_HANDLE_VALUE) return FALSE; if (p == NULL) { ASSERT(FALSE); return FALSE; } DWORD dwCharsToWrite = (dwChars)?dwChars:_tcslen(p); DWORD dwCharsWrittenAdd = 0; BOOL ret = TRUE; while (dwCharsToWrite && (!m_blnDisableWrite)) { switch(p[dwCharsWrittenAdd]) { case _T('\n'): m_CursorPosition.Y++; m_CursorPosition.X = 0; break; case _T('\r'): dwCharsWrittenAdd++; dwCharsToWrite--; continue; case _T('\t'): do { if (!Write(_T(" "))) return FALSE; } while ((m_CursorPosition.X % TAB_WIDTH) && (!m_blnDisableWrite)); dwCharsWrittenAdd++; dwCharsToWrite--; continue; default: { if (!WriteChar(p[dwCharsWrittenAdd])) return FALSE; m_CursorPosition.X++; } } if (m_CursorPosition.X == m_BufferSize.X) { m_CursorPosition.Y++; m_CursorPosition.X = 0; } if (m_CursorPosition.Y == m_BufferSize.Y) { ASSERT(m_CursorPosition.X == 0); SMALL_RECT Src; Src.Left = 0; Src.Right = (SHORT)(m_BufferSize.X-1); Src.Top = 1; Src.Bottom = (SHORT)(m_BufferSize.Y-1); CHAR_INFO ci;#ifdef UNICODE ci.Char.UnicodeChar = L' ';#else ci.Char.AsciiChar = ' ';#endif ci.Attributes = 0; COORD Dest; Dest.X = 0; Dest.Y = 0; if (!ScrollConsoleScreenBuffer(m_hStdOut,&Src,NULL,Dest,&ci)) return FALSE; m_CursorPosition.Y--; m_LinesScrolled++; } if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE; VERIFY(WriteChar(_T(' '))); if ((m_blnMoreMode)&&(m_CursorPosition.X == 0)) { m_Lines++; if (m_Lines >= m_BufferSize.Y-1) { ASSERT(m_Lines == m_BufferSize.Y-1); m_Lines = 0; VERIFY(WriteString(MORE_STRING,m_CursorPosition)); VERIFY(FlushInputBuffer());
CONSOLE_CURSOR_INFO cci; cci.bVisible = FALSE; cci.dwSize = 100; VERIFY(SetConsoleCursorInfo(m_hStdOut,&cci));
INPUT_RECORD InputRecord; DWORD dwRecordsReaded; while ((ret = ReadConsoleInput(m_hStdIn,&InputRecord,1,&dwRecordsReaded)) != FALSE) { ASSERT(dwRecordsReaded == 1); if (dwRecordsReaded != 1) break; if (InputRecord.EventType != KEY_EVENT) continue; if (!InputRecord.Event.KeyEvent.bKeyDown) continue;
if ((InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL)|| (InputRecord.Event.KeyEvent.wVirtualKeyCode == _T('Q'))) { VERIFY(GenerateConsoleCtrlEvent(CTRL_C_EVENT,0)); continue; }#ifdef UNICODE TCHAR ch = InputRecord.Event.KeyEvent.uChar.UnicodeChar;#else TCHAR ch = InputRecord.Event.KeyEvent.uChar.AsciiChar;#endif if (ch) break; }
// delete "more" msg VERIFY(WriteString(MORE_EMPTY_STRING,m_CursorPosition)); m_CursorPosition.X = 0;
cci.bVisible = TRUE; cci.dwSize = m_blnInsetMode?m_dwInsertModeCursorHeight:m_dwOverwriteModeCursorHeight; VERIFY(SetConsoleCursorInfo(m_hStdOut,&cci)); } } dwCharsWrittenAdd++; dwCharsToWrite--; } return ret;}
unsigned int CConsole::GetTabWidth(){ return TAB_WIDTH;}
BOOL CConsole::SetTitle(const TCHAR *p){ return SetConsoleTitle(p);}
BOOL CConsole::SetTextAttribute(WORD wAttributes){ m_wAttributes = wAttributes; return TRUE;}/*BOOL CConsole::SetInputMode(DWORD dwMode){ return SetConsoleMode(m_hStdIn,dwMode);}
BOOL CConsole::SetOutputMode(DWORD dwMode){ return SetConsoleMode(m_hStdOut,dwMode);}*/
BOOL CConsole::FlushInputBuffer(){ if (m_hStdIn == INVALID_HANDLE_VALUE) return FALSE; return FlushConsoleInputBuffer(m_hStdIn);}
BOOL CConsole::ReadLine(){ if (m_hStdIn == INVALID_HANDLE_VALUE) return FALSE; if (m_hStdOut == INVALID_HANDLE_VALUE) return FALSE; if (m_dwBufferSize == 0) { ASSERT(FALSE); return FALSE; } if (m_pchBuffer == NULL) { ASSERT(FALSE); return FALSE; } if (m_pchBuffer1 == NULL) { ASSERT(FALSE); return FALSE; } if (!FlushConsoleInputBuffer(m_hStdIn)) return FALSE;
COORD FristCharCursorPosition = m_CursorPosition;#define X_CURSOR_POSITION_FROM_OFFSET(ofs) USHORT(((FristCharCursorPosition.X + ofs)%m_BufferSize.X))#define Y_CURSOR_POSITION_FROM_OFFSET(ofs) USHORT((FristCharCursorPosition.Y + (FristCharCursorPosition.X + ofs)/m_BufferSize.X))//#define OFFSET_FROM_CURSOR_POSITION(pos) ((pos.Y-FristCharCursorPosition.Y)*m_BufferSize.X+pos.X-FristCharCursorPosition.X)
DWORD dwRecordsReaded; DWORD dwCurrentCharOffset = 0; DWORD dwLastCharOffset = 0; BOOL ret;
BOOL blnCompletionMode = FALSE;// unsigned __int64 nCompletionIndex = 0; unsigned long long nCompletionIndex = 0; DWORD dwCompletionOffset = 0; DWORD dwCompletionStringSize = 0; COORD CompletionPosition = FristCharCursorPosition;
m_LinesScrolled = 0; BOOL blnOldMoreMode = m_blnMoreMode; m_blnMoreMode = FALSE;
DWORD dwHistoryIndex = 0;
INPUT_RECORD InputRecord; while ((ret = ReadConsoleInput(m_hStdIn,&InputRecord,1,&dwRecordsReaded)) != FALSE) { ASSERT(dwRecordsReaded == 1); if (dwRecordsReaded != 1) return FALSE; if (InputRecord.EventType != KEY_EVENT) continue; if (!InputRecord.Event.KeyEvent.bKeyDown) continue;#ifdef UNICODE TCHAR ch = InputRecord.Event.KeyEvent.uChar.UnicodeChar;#else TCHAR ch = InputRecord.Event.KeyEvent.uChar.AsciiChar;#endifKeyRepeat: if (m_LinesScrolled) { if (m_LinesScrolled > FristCharCursorPosition.Y) return FALSE; FristCharCursorPosition.Y = SHORT(FristCharCursorPosition.Y - m_LinesScrolled); if (m_LinesScrolled > CompletionPosition.Y) return FALSE; CompletionPosition.Y = SHORT(CompletionPosition.Y - m_LinesScrolled); m_LinesScrolled = 0; }// char Buf[1024];// sprintf(Buf,"wVirtualKeyCode = %u\nchar = %u\n\n",InputRecord.Event.KeyEvent.wVirtualKeyCode,ch);// OutputDebugString(Buf);
#ifndef NO_PASTE if ((ch == 0x16)&&(InputRecord.Event.KeyEvent.wVirtualKeyCode == 'V')) { goto Paste; } else#endif if (ch == 0) {#ifndef NO_PASTE if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_INSERT) { if (!(InputRecord.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)) { VERIFY(SetInsertMode(!m_blnInsetMode)); } else { if (blnCompletionMode) blnCompletionMode = FALSE;
Paste: if (!IsClipboardFormatAvailable(#ifdef UNICODE CF_UNICODETEXT#else CF_TEXT#endif )) continue; if (!OpenClipboard(NULL)) continue;
const TCHAR *pch = NULL;
HANDLE hglb = GetClipboardData(#ifdef UNICODE CF_UNICODETEXT#else CF_TEXT#endif ); if (hglb != NULL) { LPTSTR lptstr = (LPTSTR)GlobalLock(hglb); if (lptstr != NULL) { _tcsncpy(m_pchBuffer1,lptstr,m_dwBufferSize); m_pchBuffer1[m_dwBufferSize-1] = 0; pch = m_pchBuffer1; GlobalUnlock(hglb); } } CloseClipboard();
if (pch == NULL) continue;
while (*pch) { if (_istprint(*pch)) { if (dwLastCharOffset >= m_dwBufferSize-1) { ASSERT(dwLastCharOffset == m_dwBufferSize-1); // Beep(1000,100); break; } TCHAR ch1; //if (m_blnInsetMode) ch1 = m_pchBuffer[dwCurrentCharOffset]; m_pchBuffer[dwCurrentCharOffset] = *pch; if ((m_blnInsetMode)||(dwCurrentCharOffset == dwLastCharOffset)) dwLastCharOffset++; dwCurrentCharOffset++; if (!Write(pch,1)) return FALSE; if (m_blnInsetMode) { COORD Cursor = m_CursorPosition; DWORD ofs = dwCurrentCharOffset;
while(ofs <= dwLastCharOffset) { ch = m_pchBuffer[ofs]; m_pchBuffer[ofs] = ch1; ch1 = ch; ofs++; }
if (dwCurrentCharOffset < dwLastCharOffset) { if (!Write(m_pchBuffer+dwCurrentCharOffset,dwLastCharOffset-dwCurrentCharOffset)) return FALSE;
if (m_LinesScrolled) { if (m_LinesScrolled > FristCharCursorPosition.Y) return FALSE; Cursor.Y = SHORT(Cursor.Y - m_LinesScrolled); } // Update cursor position m_CursorPosition = Cursor; if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE; } } } pch++; } } } else#endif if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_LEFT) { if (blnCompletionMode) blnCompletionMode = FALSE; if (dwCurrentCharOffset) { if (InputRecord.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) { TCHAR *pchWordBegin = m_pchBuffer+dwCurrentCharOffset-1;
while (pchWordBegin > m_pchBuffer) { if (!_istspace(*pchWordBegin)) break; pchWordBegin--; }
while (pchWordBegin > m_pchBuffer) { if (_istspace(*(pchWordBegin-1))) break; pchWordBegin--; }
ASSERT(pchWordBegin >= m_pchBuffer); dwCurrentCharOffset = pchWordBegin - m_pchBuffer;
ASSERT(dwCurrentCharOffset < dwLastCharOffset);
m_CursorPosition.X = X_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset); m_CursorPosition.Y = Y_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset); VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); } else { dwCurrentCharOffset--; if (m_CursorPosition.X) { m_CursorPosition.X--; } else { m_CursorPosition.X = SHORT(m_BufferSize.X-1); ASSERT(m_CursorPosition.Y); m_CursorPosition.Y--; } VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); } } } else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT) { if (blnCompletionMode) blnCompletionMode = FALSE; if (dwCurrentCharOffset < dwLastCharOffset) { if (InputRecord.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) { TCHAR *pchWordBegin = m_pchBuffer+dwCurrentCharOffset;
while ((DWORD)(pchWordBegin - m_pchBuffer) < dwLastCharOffset) { if (_istspace(*pchWordBegin)) break; pchWordBegin++; }
while ((DWORD)(pchWordBegin - m_pchBuffer) < dwLastCharOffset) { if (!_istspace(*pchWordBegin)) break; pchWordBegin++; }
dwCurrentCharOffset = pchWordBegin - m_pchBuffer; ASSERT(dwCurrentCharOffset <= dwLastCharOffset); m_CursorPosition.X = X_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset); m_CursorPosition.Y = Y_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset); VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); } else { dwCurrentCharOffset++; m_CursorPosition.X++; if (m_CursorPosition.X == m_BufferSize.X) { m_CursorPosition.Y++; m_CursorPosition.X = 0; } VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); } } } else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_HOME) { if (blnCompletionMode) blnCompletionMode = FALSE; dwCurrentCharOffset = 0; m_CursorPosition = FristCharCursorPosition; VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); } else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_END) { if (blnCompletionMode) blnCompletionMode = FALSE; dwCurrentCharOffset = dwLastCharOffset; m_CursorPosition.X = X_CURSOR_POSITION_FROM_OFFSET(dwLastCharOffset); m_CursorPosition.Y = Y_CURSOR_POSITION_FROM_OFFSET(dwLastCharOffset); VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); } else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_UP) { if (blnCompletionMode) blnCompletionMode = FALSE; dwHistoryIndex++; const TCHAR *pchHistoryLine = m_History.GetHistoryLine(dwHistoryIndex-1); if (pchHistoryLine) { if (dwLastCharOffset) { _tcsnset(m_pchBuffer,_T(' '),dwLastCharOffset); m_CursorPosition = FristCharCursorPosition; VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); VERIFY(Write(m_pchBuffer,dwLastCharOffset)); dwCurrentCharOffset = dwLastCharOffset = 0; m_CursorPosition = FristCharCursorPosition; VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); } dwCurrentCharOffset = dwLastCharOffset = _tcslen(pchHistoryLine); if (dwLastCharOffset >= m_dwBufferSize) { ASSERT(FALSE); return FALSE; } _tcscpy(m_pchBuffer,pchHistoryLine); if (!Write(m_pchBuffer)) return FALSE; } else { dwHistoryIndex--; } } else if (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_DOWN) { if (blnCompletionMode) blnCompletionMode = FALSE; if (dwHistoryIndex) { dwHistoryIndex--; const TCHAR *pchHistoryLine = m_History.GetHistoryLine(dwHistoryIndex-1); if (dwLastCharOffset) { _tcsnset(m_pchBuffer,_T(' '),dwLastCharOffset); m_CursorPosition = FristCharCursorPosition; VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); VERIFY(Write(m_pchBuffer,dwLastCharOffset)); dwCurrentCharOffset = dwLastCharOffset = 0; m_CursorPosition = FristCharCursorPosition; VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); } if (pchHistoryLine) { dwCurrentCharOffset = dwLastCharOffset = _tcslen(pchHistoryLine); if (dwLastCharOffset >= m_dwBufferSize) { ASSERT(FALSE); return FALSE; } _tcscpy(m_pchBuffer,pchHistoryLine); if (!Write(m_pchBuffer)) return FALSE; } } } else if ((InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)&& (dwLastCharOffset)) { // Move the characters if any... ASSERT(dwLastCharOffset); DWORD dwCharOffset = dwCurrentCharOffset; if (dwCharOffset < dwLastCharOffset) { while(dwCharOffset < dwLastCharOffset) { m_pchBuffer[dwCharOffset] = m_pchBuffer[dwCharOffset+1]; dwCharOffset++; }
m_pchBuffer[dwLastCharOffset-1] = _T(' ');
// Save cursor position COORD Cursor = m_CursorPosition;
if (!Write(m_pchBuffer+dwCurrentCharOffset,dwLastCharOffset-dwCurrentCharOffset)) return FALSE;
dwLastCharOffset--;
// Update cursor position m_CursorPosition = Cursor; if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE; }
}// else if ((InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE)&&// (InputRecord.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)))// {// if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,0)) return FALSE;// } } else if ((ch == 27) && dwLastCharOffset && (InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) { if (blnCompletionMode) blnCompletionMode = FALSE; _tcsnset(m_pchBuffer,_T(' '),dwLastCharOffset); m_CursorPosition = FristCharCursorPosition; VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); VERIFY(Write(m_pchBuffer,dwLastCharOffset)); dwCurrentCharOffset = dwLastCharOffset = 0; m_CursorPosition = FristCharCursorPosition; VERIFY(SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)); } else if (ch == _T('\r')) { // carriage return if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition = FristCharCursorPosition)) return FALSE; ASSERT(dwLastCharOffset <= m_dwBufferSize); m_pchBuffer[dwLastCharOffset] = 0; // terminate string in buffer ret = Write(m_pchBuffer); m_History.AddHistoryLine(m_pchBuffer); static TCHAR strLF[] = _T("\n"); ret = Write(strLF); break; } else if (ch == _T('\b')) { // backspace if (blnCompletionMode) blnCompletionMode = FALSE; if ((dwCurrentCharOffset) && ((m_CursorPosition.X != 0) || (m_CursorPosition.Y != 0))) { // Calculate new cursor position COORD NewCursorPosition; if (m_CursorPosition.X) { NewCursorPosition.X = SHORT(m_CursorPosition.X-1); NewCursorPosition.Y = m_CursorPosition.Y; } else { ASSERT(m_BufferSize.X); NewCursorPosition.X = SHORT(m_BufferSize.X-1); ASSERT(m_CursorPosition.Y); NewCursorPosition.Y = SHORT(m_CursorPosition.Y-1); }
// Move the characters if any... ASSERT(dwLastCharOffset); DWORD dwCharOffset = dwCurrentCharOffset-1; while(dwCharOffset < dwLastCharOffset-1) { m_pchBuffer[dwCharOffset] = m_pchBuffer[dwCharOffset+1]; dwCharOffset++; }
m_pchBuffer[dwLastCharOffset-1] = _T(' ');
dwCurrentCharOffset--; m_CursorPosition = NewCursorPosition; if (!Write(m_pchBuffer+dwCurrentCharOffset,dwLastCharOffset-dwCurrentCharOffset)) return FALSE;
// Update cursor position m_CursorPosition = NewCursorPosition; if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE;
dwLastCharOffset--; } } else if (ch == _T('\t')) { // Tab
if (!blnCompletionMode) // If tab was pressed after non-tab. We enter in completion mode. { // Initialize completion index if (InputRecord.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) // If shift was pressed nCompletionIndex = (unsigned long long) -1; // Last completion else nCompletionIndex = 0; // First completion
// Find completion offset. It points at char after first non-quoted whitespace. dwCompletionOffset = dwCurrentCharOffset; BOOL blnQuotedParameter = FALSE; while(dwCompletionOffset) { dwCompletionOffset--; if (m_pchBuffer[dwCompletionOffset] == _T('\"')) { blnQuotedParameter = !blnQuotedParameter; } else if (!blnQuotedParameter && _istspace(m_pchBuffer[dwCompletionOffset])) { // Found ! We are not inside quored parameter and we are on whitespace. dwCompletionOffset++; // dwCompletionOffset must point at char AFTER first non-quoted whitespace. break; } }
ASSERT(dwCompletionOffset <= dwCurrentCharOffset);
// Save not changing part (context) of completion in m_pchBuffer1
// FIXME: dwCompletionOffset is always 0 here // _tcsncpy(m_pchBuffer1,m_pchBuffer,dwCompletionOffset); m_pchBuffer1[dwCompletionOffset] = 0;
// Size of changing part dwCompletionStringSize = dwCurrentCharOffset-dwCompletionOffset;
// Save intial changing part of completion in m_pchBuffer2 if (dwCompletionStringSize) _tcsncpy(m_pchBuffer2,m_pchBuffer+dwCompletionOffset,dwCompletionStringSize); m_pchBuffer2[dwCompletionStringSize] = 0;
// Calculate cursor position of point between changing and not changing ports CompletionPosition.X = X_CURSOR_POSITION_FROM_OFFSET(dwCompletionOffset); CompletionPosition.Y = Y_CURSOR_POSITION_FROM_OFFSET(dwCompletionOffset); } // if first time tab
const TCHAR *pchCompletion = NULL;
// Direction BOOL blnForward = !(InputRecord.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED);
if (m_pfReplaceCompletionCallback) // If we are using replace completion callback pchCompletion = m_pfReplaceCompletionCallback(nCompletionIndex, blnCompletionMode?&blnForward:NULL, // If this is first time we call the completion callback, do not change completion index m_pchBuffer1,m_pchBuffer2);
if (pchCompletion) // If completion found { // Set cursor position to compeltion position m_CursorPosition = CompletionPosition; if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE;
// Calculate buffer free space ASSERT(m_dwBufferSize > dwCompletionOffset); DWORD dwFree = m_dwBufferSize - dwCompletionOffset - 1;
// Save old completion string size DWORD dwOldCompletionStringSize = dwCompletionStringSize;
// Write completion string to buffer dwCompletionStringSize = _tcslen(pchCompletion);
// If there is not enough space in buffer, so we truncate the completion if (dwCompletionStringSize > dwFree) dwCompletionStringSize = dwFree;
if (dwCompletionStringSize) { // Copy competion into main buffer _tcsncpy(m_pchBuffer+dwCompletionOffset,pchCompletion,dwCompletionStringSize);
// Write completion string to console if (!Write(m_pchBuffer+dwCompletionOffset,dwCompletionStringSize)) return FALSE;
// Set new offsets dwCurrentCharOffset = dwLastCharOffset = dwCompletionOffset + dwCompletionStringSize;
ASSERT(dwLastCharOffset < m_dwBufferSize); }
// Erase rest from previous completion string, if the new completion is shorter than old if (dwOldCompletionStringSize > dwCompletionStringSize) { _tcsnset(m_pchBuffer+dwCompletionOffset+dwCompletionStringSize,_T(' '), dwOldCompletionStringSize - dwCompletionStringSize);
// Save cursor position COORD pos = m_CursorPosition;
if (!Write(m_pchBuffer+dwCompletionOffset+dwCompletionStringSize, dwOldCompletionStringSize - dwCompletionStringSize)) return FALSE;
// Set cursor position m_CursorPosition = pos; if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE; } } // If completion found
// Ok, we are in completion mode blnCompletionMode = TRUE; } else if (_istprint(ch)) { if (blnCompletionMode) blnCompletionMode = FALSE; if (dwLastCharOffset >= m_dwBufferSize-1) { ASSERT(dwLastCharOffset == m_dwBufferSize-1);// Beep(1000,100); continue; } TCHAR ch1; //if (m_blnInsetMode) ch1 = m_pchBuffer[dwCurrentCharOffset]; m_pchBuffer[dwCurrentCharOffset] = ch; if ((m_blnInsetMode)||(dwCurrentCharOffset == dwLastCharOffset)) dwLastCharOffset++; dwCurrentCharOffset++; if (!Write(&ch,1)) return FALSE; if (m_blnInsetMode) { COORD Cursor = m_CursorPosition; DWORD ofs = dwCurrentCharOffset;
while(ofs <= dwLastCharOffset) { ch = m_pchBuffer[ofs]; m_pchBuffer[ofs] = ch1; ch1 = ch; ofs++; }
if (dwCurrentCharOffset < dwLastCharOffset) { if (!Write(m_pchBuffer+dwCurrentCharOffset,dwLastCharOffset-dwCurrentCharOffset)) return FALSE;
if (m_LinesScrolled) { if (m_LinesScrolled > FristCharCursorPosition.Y) return FALSE; Cursor.Y = SHORT(Cursor.Y - m_LinesScrolled); } // Update cursor position m_CursorPosition = Cursor; if (!SetConsoleCursorPosition(m_hStdOut,m_CursorPosition)) return FALSE; } } } ASSERT(InputRecord.Event.KeyEvent.wRepeatCount); if (!InputRecord.Event.KeyEvent.wRepeatCount) return FALSE; if (--InputRecord.Event.KeyEvent.wRepeatCount) goto KeyRepeat; } m_blnMoreMode = blnOldMoreMode; return TRUE;}
BOOL CConsole::GetTextAttribute(WORD& rwAttributes){ rwAttributes = m_wAttributes; return TRUE;}
// Parameters:// dwBufferSize - size in chars of the input line buffer//// Rerturns:// NULL - Failed.// pointer to the input bufferTCHAR * CConsole::Init(DWORD dwBufferSize, DWORD dwMaxHistoryLines){ if (m_hStdIn != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(m_hStdIn)); if (m_hStdOut != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(m_hStdOut));
m_hStdIn = GetStdHandle(STD_INPUT_HANDLE);
if (m_hStdIn == INVALID_HANDLE_VALUE) {// _ftprintf(stderr,_T("GetStdHandle(STD_INPUT_HANDLE) failed. GetLastError return 0x%X\n"),(unsigned)GetLastError()); goto Abort; }
m_hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (m_hStdOut == INVALID_HANDLE_VALUE) {// _ftprintf(stderr,_T("GetStdHandle(STD_OUTPUT_HANDLE) failed. GetLastError return 0x%X\n"),(unsigned)GetLastError()); goto Abort; }
CONSOLE_SCREEN_BUFFER_INFO info; if (!GetConsoleScreenBufferInfo(m_hStdOut,&info)) {// _ftprintf(stderr,_T("GetConsoleScreenBufferInfo(m_hStdOut,&info) failed. GetLastError return 0x%X\n"),(unsigned)GetLastError()); if (GetLastError() == 6) // redirected output _ftprintf(stderr,_T("Redirection is not supported.\n"));
goto Abort; } m_wAttributes = info.wAttributes;
if (!m_blnOldInputModeSaved) { if (!GetConsoleMode(m_hStdIn,&m_dwOldInputMode)) { if (GetLastError() == 6) // redirected input _ftprintf(stderr,_T("Redirection is not supported.\n"));// _ftprintf(stderr,_T("GetConsoleMode(0x%X,&m_dwOldINputMode) failed. GetLastError() returns 0x%X\n"),(int)m_hStdIn,GetLastError()); goto Abort; }
m_blnOldInputModeSaved = TRUE; }
// _ftprintf(stderr,_T("Calling GetConsoleMode(0x%X,&m_dwOldOutputMode) ...\n"),(int)m_hStdOut); if (!m_blnOldOutputModeSaved) { if (!GetConsoleMode(m_hStdOut,&m_dwOldOutputMode)) goto Abort;// _ftprintf(stderr,_T("Calling GetConsoleMode(0x%X,&m_dwOldOutputMode) done.\n"),(int)m_hStdOut); m_blnOldOutputModeSaved = TRUE; }
// _ftprintf(stderr,_T("Calling SetConsoleMode(0x%X,0) ...\n"),(int)m_hStdIn); if (!SetConsoleMode(m_hStdIn,0)) goto Abort; if (!SetConsoleMode(m_hStdOut,0)) goto Abort;
m_CursorPosition = info.dwCursorPosition; m_BufferSize = info.dwSize;
CONSOLE_CURSOR_INFO cci; cci.bVisible = TRUE; cci.dwSize = m_blnInsetMode?m_dwInsertModeCursorHeight:m_dwOverwriteModeCursorHeight;
if (!SetConsoleCursorInfo(m_hStdOut,&cci)) goto Abort;
m_dwBufferSize = dwBufferSize;
if (m_pchBuffer) delete m_pchBuffer; m_pchBuffer = NULL;
if (m_pchBuffer1) delete m_pchBuffer1; m_pchBuffer1 = NULL;
if (m_pchBuffer2) delete m_pchBuffer2; m_pchBuffer2 = NULL;
m_pchBuffer = new (std::nothrow) TCHAR [dwBufferSize]; if (!m_pchBuffer) goto Abort; m_pchBuffer[dwBufferSize-1] = 0;
m_pchBuffer1 = new (std::nothrow) TCHAR [dwBufferSize]; if (!m_pchBuffer1) goto Abort; m_pchBuffer1[dwBufferSize-1] = 0;
m_pchBuffer2 = new (std::nothrow) TCHAR [dwBufferSize]; if (!m_pchBuffer2) goto Abort; m_pchBuffer2[dwBufferSize-1] = 0;
if (dwMaxHistoryLines) { if (!m_History.Init(dwBufferSize,dwMaxHistoryLines)) goto Abort; }
return m_pchBuffer;
Abort: if (m_hStdIn != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(m_hStdIn)); m_hStdIn = INVALID_HANDLE_VALUE;
if (m_hStdOut != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(m_hStdOut)); m_hStdOut = INVALID_HANDLE_VALUE;
if (m_pchBuffer) delete[] m_pchBuffer; m_pchBuffer = NULL;
if (m_pchBuffer1) delete[] m_pchBuffer1; m_pchBuffer1 = NULL;
if (m_pchBuffer2) delete[] m_pchBuffer2; m_pchBuffer2 = NULL;
m_dwBufferSize = 0;
return NULL;}
BOOL CConsole::WriteChar(TCHAR ch){ CHAR_INFO ci; ci.Attributes = m_wAttributes;#ifdef UNICODE ci.Char.UnicodeChar = ch;#else ci.Char.AsciiChar = ch;#endif static COORD BufferSize = {1,1}; static COORD BufferCoord = {0,0}; SMALL_RECT Dest; Dest.Bottom = Dest.Top = m_CursorPosition.Y; Dest.Left = Dest.Right = m_CursorPosition.X; return WriteConsoleOutput(m_hStdOut,&ci,BufferSize,BufferCoord,&Dest);}
void CConsole::BeginScrollingOperation(){ m_Lines = 0;}
BOOL CConsole::WriteString(const TCHAR *pchString, COORD Position){ CHAR_INFO ciBuffer[256]; int nSize = _tcslen(pchString); if ((nSize > 256)||(nSize <= 0)) { ASSERT(FALSE); return FALSE; }
COORD BufferSize; BufferSize.X = (SHORT)nSize; BufferSize.Y = 1; static COORD BufferCoord = {0,0}; SMALL_RECT Dest; Dest.Bottom = Dest.Top = Position.Y; Dest.Right = SHORT((Dest.Left = Position.X) + nSize - 1);
while(nSize--) { ciBuffer[nSize].Attributes = m_wAttributes;#ifdef UNICODE ciBuffer[nSize].Char.UnicodeChar = pchString[nSize];#else ciBuffer[nSize].Char.AsciiChar = pchString[nSize];#endif }
return WriteConsoleOutput(m_hStdOut,ciBuffer,BufferSize,BufferCoord,&Dest);}
BOOL CConsole::SetInsertMode(BOOL blnInsetMode){ if (m_hStdOut == INVALID_HANDLE_VALUE) return FALSE;
CONSOLE_CURSOR_INFO cci; cci.bVisible = TRUE; cci.dwSize = blnInsetMode?m_dwInsertModeCursorHeight:m_dwOverwriteModeCursorHeight;
BOOL ret = SetConsoleCursorInfo(m_hStdOut,&cci); if (ret) m_blnInsetMode = blnInsetMode; return ret;}
void CConsole::SetReplaceCompletionCallback(ReplaceCompletionCallback pfCallback){ m_pfReplaceCompletionCallback = pfCallback;}
void CConsole::DisableWrite(){ m_blnDisableWrite = TRUE; INPUT_RECORD InputRecord; DWORD dwRecordsWriten; InputRecord.EventType = KEY_EVENT; InputRecord.Event.KeyEvent.bKeyDown = TRUE;#ifdef UNICODE InputRecord.Event.KeyEvent.uChar.UnicodeChar = L' ';#else InputRecord.Event.KeyEvent.uChar.AsciiChar = ' ';#endif BOOL ret = WriteConsoleInput(m_hStdIn,&InputRecord,1,&dwRecordsWriten); ASSERT(ret);}
void CConsole::EnableWrite(){ m_blnDisableWrite = FALSE;}