731 lines
19 KiB
C
731 lines
19 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1988-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
readcon.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Emulate NT console on Win9x
|
||
|
|
||
|
--*/
|
||
|
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// ReadCon.cpp
|
||
|
//
|
||
|
//
|
||
|
// ReadConsole implementation for Win95 that implements the command line editing
|
||
|
// keys, since Win95 console implementation does not.
|
||
|
//
|
||
|
|
||
|
#include "cmd.h"
|
||
|
|
||
|
#ifdef WIN95_CMD
|
||
|
|
||
|
// adv declarations....
|
||
|
extern BOOLEAN CtrlCSeen;
|
||
|
extern BOOL bInsertDefault;
|
||
|
void ShowBuf( TCHAR* pBuf, int nFromPos );
|
||
|
|
||
|
// some state variables.....
|
||
|
static int nConsoleWidth; // num columns
|
||
|
static int nConsoleHeight; // num rows
|
||
|
static COORD coordStart; // coord of first cmd char....
|
||
|
static COORD coordEnd; // coord of last cmd char....
|
||
|
static int nBufPos = 0; // buffer cursor position
|
||
|
static int nBufLen = 0; // length of current command
|
||
|
static BOOL bInsert; // insert mode
|
||
|
static HANDLE hOut; // output buffer handle
|
||
|
static TCHAR* pPrompt; // allocated buffer to store prompt
|
||
|
static int nPromptSize; // num chars in prompt buffer
|
||
|
static WORD wDefAttr; // default character attribute
|
||
|
static int nState = 0; // input state
|
||
|
|
||
|
static TCHAR history[50][2049]; // history list
|
||
|
static int nFirstCmd = -1; // index of first cmd
|
||
|
static int nLastCmd = -1; // index of last command entered
|
||
|
static int nHistNdx = -1; // index into history list....
|
||
|
static TCHAR* pSearchStr = 0; // search criteria buffer (allocated)
|
||
|
|
||
|
void
|
||
|
IncCoord(
|
||
|
COORD* coord,
|
||
|
int nDelta
|
||
|
)
|
||
|
{
|
||
|
coord->X += (SHORT)nDelta;
|
||
|
if ( coord->X < 0 )
|
||
|
{
|
||
|
coord->Y += coord->X/nConsoleWidth - 1;
|
||
|
coord->X = nConsoleWidth - (-coord->X)%nConsoleWidth;
|
||
|
}
|
||
|
else
|
||
|
if ( coord->X >= nConsoleWidth )
|
||
|
{
|
||
|
coord->Y += coord->X / nConsoleWidth;
|
||
|
coord->X %= nConsoleWidth;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
GetOffsetCoord(
|
||
|
TCHAR* pBuf,
|
||
|
int nOffset,
|
||
|
COORD* coord
|
||
|
)
|
||
|
{
|
||
|
int ndx;
|
||
|
|
||
|
// let's walk the buffer to find the correct coord....
|
||
|
*coord = coordStart;
|
||
|
for( ndx=0; ndx<nOffset; ++ndx )
|
||
|
{
|
||
|
if ( pBuf[ndx] == 9 )
|
||
|
{
|
||
|
int nTab;
|
||
|
for ( nTab=1; (nTab+coord->X)%8 ; ++nTab );
|
||
|
coord->X += nTab-1;
|
||
|
}
|
||
|
else
|
||
|
if ( pBuf[ndx] < 32 )
|
||
|
++coord->X;
|
||
|
IncCoord( coord, +1 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ScrollTo(
|
||
|
TCHAR* pBuf,
|
||
|
COORD* coord
|
||
|
)
|
||
|
{
|
||
|
int nLines = 0;
|
||
|
SMALL_RECT rectFrom;
|
||
|
COORD coordTo;
|
||
|
CHAR_INFO cBlank;
|
||
|
// get some data....
|
||
|
cBlank.Char.AsciiChar = ' ';
|
||
|
cBlank.Attributes = wDefAttr;
|
||
|
|
||
|
coordTo.X = 0;
|
||
|
rectFrom.Left = 0;
|
||
|
rectFrom.Right = nConsoleWidth - 1;
|
||
|
|
||
|
// scroll it....
|
||
|
if ( coord->Y < 0 )
|
||
|
{
|
||
|
// scroll down....
|
||
|
nLines = coord->Y;
|
||
|
rectFrom.Top = 0;
|
||
|
rectFrom.Bottom = nConsoleHeight + nLines - 1;
|
||
|
coordTo.Y = -nLines;
|
||
|
ScrollConsoleScreenBuffer( hOut, &rectFrom, NULL, coordTo, &cBlank );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// scroll up....
|
||
|
nLines = coord->Y - nConsoleHeight + 1;
|
||
|
rectFrom.Top = (SHORT)nLines;
|
||
|
rectFrom.Bottom = nConsoleHeight - 1;
|
||
|
coordTo.Y = 0;
|
||
|
ScrollConsoleScreenBuffer( hOut, &rectFrom, NULL, coordTo, &cBlank );
|
||
|
}
|
||
|
|
||
|
// adjust start/end coords and orig coord to reflect new scroll....
|
||
|
coordStart.Y -= (SHORT)nLines;
|
||
|
coordEnd.Y -= (SHORT)nLines;
|
||
|
coord->Y -= (SHORT)nLines;
|
||
|
|
||
|
// redraw the whole command AND the prompt.....
|
||
|
ShowBuf( pBuf, -1 );
|
||
|
|
||
|
return nLines;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AdjCursor(
|
||
|
TCHAR* pBuf
|
||
|
)
|
||
|
{
|
||
|
COORD coordCursor;
|
||
|
GetOffsetCoord( pBuf, nBufPos, &coordCursor );
|
||
|
if ( coordCursor.Y < 0 || coordCursor.Y >= nConsoleHeight )
|
||
|
{
|
||
|
// scroll it....
|
||
|
ScrollTo( pBuf, &coordCursor );
|
||
|
}
|
||
|
SetConsoleCursorPosition( hOut, coordCursor );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AdjCursorSize( void )
|
||
|
{
|
||
|
CONSOLE_CURSOR_INFO cci;
|
||
|
cci.bVisible = TRUE;
|
||
|
if ( bInsert == bInsertDefault )
|
||
|
cci.dwSize = 13;
|
||
|
else
|
||
|
cci.dwSize = 40;
|
||
|
SetConsoleCursorInfo( hOut, &cci );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AdvancePos(
|
||
|
TCHAR* pBuf,
|
||
|
int nDelta,
|
||
|
DWORD dwKeyState
|
||
|
)
|
||
|
{
|
||
|
// see if control key down....
|
||
|
if ( (dwKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) != 0 )
|
||
|
{
|
||
|
if ( nDelta > 0 )
|
||
|
{ // skip to NEXT word....
|
||
|
while ( nBufPos < nBufLen && !isspace(pBuf[nBufPos]) )
|
||
|
++nBufPos;
|
||
|
while ( nBufPos < nBufLen && isspace(pBuf[nBufPos]) )
|
||
|
++nBufPos;
|
||
|
}
|
||
|
else
|
||
|
{ // skip to PREVIOUS word....
|
||
|
// if already at beginning of word, back up one....
|
||
|
if ( nBufPos > 0 && isspace(pBuf[nBufPos-1]) )
|
||
|
--nBufPos;
|
||
|
// skip white space....
|
||
|
while ( nBufPos > 0 && isspace(pBuf[nBufPos]) )
|
||
|
--nBufPos;
|
||
|
// skip non-ws....
|
||
|
while ( nBufPos > 0 && !isspace(pBuf[nBufPos-1]) )
|
||
|
--nBufPos;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
nBufPos += nDelta;
|
||
|
|
||
|
AdjCursor( pBuf );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ShowBuf(
|
||
|
TCHAR* pBuf,
|
||
|
int nFromPos
|
||
|
)
|
||
|
{
|
||
|
DWORD cPrint;
|
||
|
COORD coord, cPrompt;
|
||
|
TCHAR temp[8];
|
||
|
int ndx;
|
||
|
|
||
|
// see if we want the prompt, too....
|
||
|
if ( nFromPos < 0 )
|
||
|
{
|
||
|
nFromPos = 0;
|
||
|
GetOffsetCoord( pBuf, 0, &coord );
|
||
|
cPrompt = coord;
|
||
|
cPrompt.X -= (SHORT)nPromptSize;
|
||
|
WriteConsoleOutputCharacter( hOut, pPrompt, nPromptSize, cPrompt, &cPrint );
|
||
|
}
|
||
|
else
|
||
|
GetOffsetCoord( pBuf, nFromPos, &coord );
|
||
|
|
||
|
// walk the rest of the buffer, displaying as we go....
|
||
|
for( ndx=nFromPos;ndx < nBufLen; ++ndx )
|
||
|
{
|
||
|
if ( pBuf[ndx] == 9 )
|
||
|
{
|
||
|
int nTab;
|
||
|
temp[0] = TEXT(' ');
|
||
|
for ( nTab=1; (nTab+coord.X)%8; ++nTab )
|
||
|
{
|
||
|
temp[nTab] = TEXT(' ');
|
||
|
}
|
||
|
WriteConsoleOutputCharacter( hOut, temp, nTab, coord, &cPrint );
|
||
|
coord.X += nTab-1;
|
||
|
}
|
||
|
else if ( pBuf[ndx] < 32 )
|
||
|
{
|
||
|
temp[0] = '^';
|
||
|
temp[1] = pBuf[ndx] + 'A' - 1;
|
||
|
WriteConsoleOutputCharacter( hOut, temp, 2, coord, &cPrint );
|
||
|
++coord.X;
|
||
|
}
|
||
|
else
|
||
|
WriteConsoleOutputCharacter( hOut, pBuf + ndx, 1, coord, &cPrint );
|
||
|
// advance cursor.....
|
||
|
IncCoord( &coord, +1 );
|
||
|
}
|
||
|
// now blank out the rest.....
|
||
|
temp[0] = TEXT(' ');
|
||
|
while ( coordEnd.Y > coord.Y || (coordEnd.Y == coord.Y && coordEnd.X >= coord.X) )
|
||
|
{
|
||
|
WriteConsoleOutputCharacter( hOut, temp, 1, coordEnd, &cPrint );
|
||
|
IncCoord( &coordEnd, -1 );
|
||
|
}
|
||
|
// save the new ending....
|
||
|
coordEnd = coord;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ShiftBuffer(
|
||
|
TCHAR* pBuf,
|
||
|
int cch,
|
||
|
int nFrom,
|
||
|
int nDelta
|
||
|
)
|
||
|
{
|
||
|
int ndx;
|
||
|
// which direction?
|
||
|
if ( nDelta > 0 )
|
||
|
{
|
||
|
// move all (including this character) out one place....
|
||
|
for( ndx = nBufLen; ndx > nFrom; --ndx )
|
||
|
pBuf[ndx] = pBuf[ndx-1];
|
||
|
++nBufLen;
|
||
|
}
|
||
|
else if ( nDelta < 0 )
|
||
|
{
|
||
|
// move all characters in one place (over this character)...
|
||
|
for( ndx = nFrom; ndx < nBufLen; ++ ndx )
|
||
|
pBuf[ndx] = pBuf[ndx+1];
|
||
|
--nBufLen;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
LoadHistory(
|
||
|
TCHAR* pBuf,
|
||
|
int cch,
|
||
|
TCHAR* pHist
|
||
|
)
|
||
|
{
|
||
|
// first go to the front of the line....
|
||
|
nBufPos = 0;
|
||
|
AdjCursor( pBuf );
|
||
|
// then blank-out the current buffer....
|
||
|
if ( nBufLen )
|
||
|
{
|
||
|
nBufLen = 0;
|
||
|
ShowBuf( pBuf, 0 );
|
||
|
}
|
||
|
// now copy in the new one (if there is one)....
|
||
|
if ( pHist )
|
||
|
{
|
||
|
_tcsncpy( pBuf, pHist, cch );
|
||
|
nBufLen = _tcslen( pHist );
|
||
|
// move to the end of the line....
|
||
|
nBufPos = nBufLen;
|
||
|
AdjCursor( pBuf );
|
||
|
// show the whole buffer from the start....
|
||
|
ShowBuf( pBuf, 0 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
SearchHist(
|
||
|
TCHAR* pBuf,
|
||
|
int cch
|
||
|
)
|
||
|
{
|
||
|
int ndx, nSearch, nStop;
|
||
|
// if we're in input mode, set ndx to AFTER last command....
|
||
|
if ( nState == 0 )
|
||
|
ndx = (nLastCmd+1)%50;
|
||
|
else
|
||
|
ndx = nHistNdx;
|
||
|
|
||
|
nStop = ndx; // don't search past here
|
||
|
|
||
|
// if not already in search mode, get a copy of the target....
|
||
|
if ( nState != 4 )
|
||
|
{
|
||
|
// if there already is a search string, get rid of it....
|
||
|
if ( pSearchStr )
|
||
|
free( pSearchStr );
|
||
|
// pSearchStr and copy a new search string....
|
||
|
pSearchStr = calloc( nBufLen+1, sizeof(TCHAR) );
|
||
|
if (pSearchStr == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
_tcsncpy( pSearchStr, pBuf, nBufLen );
|
||
|
pSearchStr[nBufLen] = 0;
|
||
|
}
|
||
|
nSearch = _tcslen( pSearchStr );
|
||
|
// enter search mode....
|
||
|
nState = 4;
|
||
|
do
|
||
|
{
|
||
|
// back up one cmd....
|
||
|
ndx = (ndx+49)%50;
|
||
|
// check it....
|
||
|
if ( _tcsncmp( history[ndx], pSearchStr, nSearch ) == 0 )
|
||
|
{
|
||
|
// found a match....
|
||
|
nHistNdx = ndx;
|
||
|
LoadHistory( pBuf, cch, history[ndx] );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} while ( ndx != nStop );
|
||
|
}
|
||
|
|
||
|
int touched = 1;
|
||
|
|
||
|
BOOL
|
||
|
ProcessKey(
|
||
|
const KEY_EVENT_RECORD* keyEvent,
|
||
|
TCHAR* pBuf,
|
||
|
int cch,
|
||
|
DWORD dwCtrlWakeupMask,
|
||
|
PBOOL bWakeupKeyHit
|
||
|
)
|
||
|
{
|
||
|
BOOL bDone = FALSE;
|
||
|
TCHAR ch;
|
||
|
|
||
|
*bWakeupKeyHit = FALSE;
|
||
|
ch = keyEvent->uChar.AsciiChar;
|
||
|
if ( keyEvent->wVirtualKeyCode == VK_SPACE )
|
||
|
ch = TEXT(' ');
|
||
|
|
||
|
switch ( keyEvent->wVirtualKeyCode )
|
||
|
{
|
||
|
case VK_RETURN:
|
||
|
bDone = TRUE;
|
||
|
// move cursor to end of cmd, if not already there....
|
||
|
if ( nBufPos != nBufLen )
|
||
|
{
|
||
|
nBufPos = nBufLen;
|
||
|
AdjCursor( pBuf );
|
||
|
}
|
||
|
// add the NLN to end of cmd....
|
||
|
pBuf[nBufLen] = _T('\n');
|
||
|
++nBufLen;
|
||
|
touched = 1;
|
||
|
break;
|
||
|
|
||
|
case VK_BACK:
|
||
|
if ( nBufPos > 0 )
|
||
|
{
|
||
|
// return to input state....
|
||
|
nState = 0;
|
||
|
// back up the cursor....
|
||
|
AdvancePos( pBuf, -1, 0 );
|
||
|
// shift over this character and print....
|
||
|
ShiftBuffer( pBuf, cch, nBufPos, -1 );
|
||
|
ShowBuf( pBuf, nBufPos );
|
||
|
touched = 1;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VK_END:
|
||
|
if ( nBufPos != nBufLen )
|
||
|
{
|
||
|
// doesn't affect state....
|
||
|
nBufPos = nBufLen;
|
||
|
AdjCursor( pBuf );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VK_HOME:
|
||
|
if ( nBufPos )
|
||
|
{
|
||
|
// doesn't affect state....
|
||
|
nBufPos = 0;
|
||
|
AdjCursor( pBuf );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VK_LEFT:
|
||
|
// doesn't affect state....
|
||
|
if ( nBufPos > 0 )
|
||
|
AdvancePos( pBuf, -1, keyEvent->dwControlKeyState );
|
||
|
break;
|
||
|
|
||
|
case VK_RIGHT:
|
||
|
// doesn't affect state....
|
||
|
if ( nBufPos < nBufLen )
|
||
|
AdvancePos( pBuf, +1, keyEvent->dwControlKeyState );
|
||
|
break;
|
||
|
|
||
|
case VK_INSERT:
|
||
|
// doesn't affect state....
|
||
|
bInsert = !bInsert;
|
||
|
AdjCursorSize();
|
||
|
break;
|
||
|
|
||
|
case VK_DELETE:
|
||
|
if ( nBufPos < nBufLen )
|
||
|
{
|
||
|
// fall back to input state....
|
||
|
nState = 0;
|
||
|
// shift over this character and print....
|
||
|
ShiftBuffer( pBuf, cch, nBufPos, -1 );
|
||
|
ShowBuf( pBuf, nBufPos );
|
||
|
touched = 1;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VK_F8:
|
||
|
// if there's something to match....
|
||
|
if ( nBufLen != 0 )
|
||
|
{
|
||
|
// if we're not already at the top of the list....
|
||
|
//if ( nHistNdx != nFirstCmd )
|
||
|
//{
|
||
|
// search backwards up the list....
|
||
|
SearchHist( pBuf, cch );
|
||
|
//}
|
||
|
touched = 1;
|
||
|
break;
|
||
|
}
|
||
|
// fall through if there's nothing to match with....
|
||
|
// same as pressing up arrow....
|
||
|
|
||
|
case VK_UP:
|
||
|
// if we're not already at the top of the list....
|
||
|
if ( nState == 0 || nHistNdx != nFirstCmd )
|
||
|
{
|
||
|
if ( nState == 0 )
|
||
|
nHistNdx = nLastCmd;
|
||
|
else
|
||
|
nHistNdx = (nHistNdx+49)%50;
|
||
|
|
||
|
LoadHistory( pBuf, cch, history[nHistNdx] );
|
||
|
// scrolling through history....
|
||
|
nState = 2;
|
||
|
touched = 1;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VK_DOWN:
|
||
|
if ( nState == 0 || nHistNdx == nLastCmd )
|
||
|
{
|
||
|
// blank out command buffer...
|
||
|
LoadHistory( pBuf, cch, NULL );
|
||
|
// return to input state....
|
||
|
nState = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// get the next one....
|
||
|
nHistNdx = (nHistNdx+1)%50;
|
||
|
LoadHistory( pBuf, cch, history[nHistNdx] );
|
||
|
// scrolling through history....
|
||
|
nState = 2;
|
||
|
}
|
||
|
touched = 1;
|
||
|
break;
|
||
|
|
||
|
case VK_ESCAPE:
|
||
|
// blank-out the command buffer....
|
||
|
LoadHistory( pBuf, cch, NULL );
|
||
|
// return to input....
|
||
|
nState = 0;
|
||
|
touched = 1;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// if printable character, let's add it in....
|
||
|
if ( ch >= 1 && ch <= 255 )
|
||
|
{
|
||
|
touched = 1;
|
||
|
// fall back to input state....
|
||
|
nState = 0;
|
||
|
// see if there's room....
|
||
|
if ( nBufPos >= cch || (bInsert && nBufLen >= cch) )
|
||
|
MessageBeep( MB_ICONEXCLAMATION );
|
||
|
else
|
||
|
{
|
||
|
if ( bInsert )
|
||
|
{
|
||
|
// shift the buffer out for the insert....
|
||
|
ShiftBuffer( pBuf, cch, nBufPos, +1 );
|
||
|
}
|
||
|
else
|
||
|
if ( nBufPos >= nBufLen )
|
||
|
++nBufLen;
|
||
|
|
||
|
// place the character in the buffer at the current pos....
|
||
|
pBuf[nBufPos] = ch;
|
||
|
|
||
|
if (ch < TEXT(' ') && (dwCtrlWakeupMask & (1 << ch))) {
|
||
|
*bWakeupKeyHit = TRUE;
|
||
|
AdjCursor(pBuf);
|
||
|
bDone = TRUE;
|
||
|
} else {
|
||
|
// show from this position on....
|
||
|
ShowBuf( pBuf, nBufPos );
|
||
|
// advance position/cursor....
|
||
|
AdvancePos( pBuf, +1, 0 );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bDone;
|
||
|
}
|
||
|
|
||
|
static UINT nOldIndex =0;
|
||
|
static DWORD cRead = 0;
|
||
|
static INPUT_RECORD ir[32];
|
||
|
BOOL bInsertDefault = FALSE;
|
||
|
|
||
|
BOOL
|
||
|
Win95ReadConsoleA(
|
||
|
HANDLE hIn,
|
||
|
LPSTR pBuf,
|
||
|
DWORD cch,
|
||
|
LPDWORD pcch,
|
||
|
LPVOID lpReserved
|
||
|
)
|
||
|
{
|
||
|
PCONSOLE_READCONSOLE_CONTROL pInputControl;
|
||
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||
|
const KEY_EVENT_RECORD* keyEvent;
|
||
|
BOOL bOk = TRUE; // return status value
|
||
|
DWORD dwc, dwOldMode;
|
||
|
DWORD dwCtrlWakeupMask;
|
||
|
BOOL bWakeupKeyHit;
|
||
|
|
||
|
// initialize the state variables....
|
||
|
nState = 0; // input mode
|
||
|
nBufPos = 0; // buffer cursor position
|
||
|
nBufLen = 0; // length of current command
|
||
|
bInsert = bInsertDefault; // insert mode
|
||
|
|
||
|
// set the appropriate console mode....
|
||
|
if (!GetConsoleMode( hIn, &dwOldMode ))
|
||
|
return FALSE;
|
||
|
SetConsoleMode( hIn, ENABLE_PROCESSED_INPUT );
|
||
|
|
||
|
// get the ouput buffer handle....
|
||
|
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||
|
if ( hOut == INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
DWORD dwErr = GetLastError();
|
||
|
hOut = CRTTONT( STDOUT );
|
||
|
}
|
||
|
|
||
|
// get the output console info....
|
||
|
if ( GetConsoleScreenBufferInfo( hOut, &csbi ) == FALSE )
|
||
|
return FALSE;
|
||
|
|
||
|
// save size and initial cursor pos and console width....
|
||
|
coordStart = coordEnd = csbi.dwCursorPosition;
|
||
|
nConsoleWidth = csbi.dwSize.X;
|
||
|
nConsoleHeight = csbi.dwSize.Y;
|
||
|
wDefAttr = csbi.wAttributes;
|
||
|
// allocate a buffer to hold whatever is before command....
|
||
|
nPromptSize = 0;
|
||
|
if ( coordStart.X > 0 )
|
||
|
{
|
||
|
COORD cPrompt;
|
||
|
DWORD dwRead;
|
||
|
|
||
|
nPromptSize = coordStart.X;
|
||
|
cPrompt = coordStart;
|
||
|
cPrompt.X = 0;
|
||
|
pPrompt = calloc( nPromptSize+1, sizeof(TCHAR) );
|
||
|
if (pPrompt == NULL) {
|
||
|
PutStdErr( MSG_NO_MEMORY, NOARGS );
|
||
|
Abort( );
|
||
|
}
|
||
|
// now copy the data....
|
||
|
ReadConsoleOutputCharacter( hOut, pPrompt, nPromptSize,
|
||
|
cPrompt, &dwRead );
|
||
|
// NULL-terminate it....
|
||
|
pPrompt[dwRead] = 0;
|
||
|
}
|
||
|
AdjCursorSize();
|
||
|
|
||
|
pInputControl = (PCONSOLE_READCONSOLE_CONTROL)lpReserved;
|
||
|
if (pInputControl != NULL && pInputControl->nLength == sizeof(*pInputControl)) {
|
||
|
dwCtrlWakeupMask = pInputControl->dwCtrlWakeupMask;
|
||
|
nBufLen = pInputControl->nInitialChars;
|
||
|
nBufPos = pInputControl->nInitialChars;
|
||
|
} else {
|
||
|
pInputControl = NULL;
|
||
|
dwCtrlWakeupMask = 0;
|
||
|
}
|
||
|
while ( !CtrlCSeen )
|
||
|
{
|
||
|
// get the next input record....
|
||
|
UINT ndx;
|
||
|
if( nOldIndex == 0 )
|
||
|
ReadConsoleInput( hIn, ir, sizeof(ir)/sizeof(INPUT_RECORD), &cRead );
|
||
|
|
||
|
// process all the records we just received....
|
||
|
for( ndx=nOldIndex; ndx < cRead; ++ndx )
|
||
|
{
|
||
|
// process only key down events....
|
||
|
keyEvent = &(ir[ndx].Event.KeyEvent);
|
||
|
if( ir[ndx].EventType == KEY_EVENT &&
|
||
|
keyEvent->bKeyDown &&
|
||
|
ProcessKey( keyEvent, pBuf, cch, dwCtrlWakeupMask, &bWakeupKeyHit )
|
||
|
)
|
||
|
{
|
||
|
if (pInputControl != NULL)
|
||
|
pInputControl->dwControlKeyState = keyEvent->dwControlKeyState;
|
||
|
goto donereading;
|
||
|
}
|
||
|
}
|
||
|
if( cRead == ndx ) {
|
||
|
nOldIndex = 0;
|
||
|
} else {
|
||
|
nOldIndex = ndx + 1;
|
||
|
}
|
||
|
}
|
||
|
donereading:
|
||
|
// clean-up....
|
||
|
if ( pPrompt ) {
|
||
|
free( pPrompt );
|
||
|
pPrompt = NULL;
|
||
|
}
|
||
|
if ( pSearchStr ) {
|
||
|
free( pSearchStr );
|
||
|
pSearchStr = NULL;
|
||
|
}
|
||
|
|
||
|
if (!bWakeupKeyHit) {
|
||
|
// not okay if we Ctrl-C'ed out....
|
||
|
if ( CtrlCSeen )
|
||
|
{
|
||
|
bOk = FALSE;
|
||
|
nBufPos = nBufLen;
|
||
|
AdjCursor( pBuf );
|
||
|
*pcch = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// save to history (less the NLN) if something entered....
|
||
|
if ( nBufLen > 1 )
|
||
|
{
|
||
|
nLastCmd = (nLastCmd+1)%50;
|
||
|
// adjust the first for wrap-around....
|
||
|
if ( nLastCmd == nFirstCmd || nFirstCmd == -1 )
|
||
|
nFirstCmd = (nFirstCmd+1)%50;
|
||
|
_tcsncpy( history[nLastCmd], pBuf, nBufLen-1 );
|
||
|
// null-terminate....
|
||
|
history[nLastCmd][nBufLen-1] = 0;
|
||
|
}
|
||
|
*pcch = nBufLen;
|
||
|
}
|
||
|
|
||
|
// go to next line....
|
||
|
WriteConsole( hOut, _T("\n\r"), 2, &dwc, NULL );
|
||
|
FlushConsoleInputBuffer( hIn );
|
||
|
} else {
|
||
|
*pcch = nBufLen;
|
||
|
}
|
||
|
|
||
|
// restore the console mode....
|
||
|
SetConsoleMode( hIn, dwOldMode );
|
||
|
|
||
|
return bOk;
|
||
|
}
|
||
|
|
||
|
#endif // ifdef WIN95_CMD
|