plugins/consoles/vt100cons/src/vt100/vtc_controller.cpp
changeset 0 7f656887cf89
child 100 706c7a69e448
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/consoles/vt100cons/src/vt100/vtc_controller.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,883 @@
+// vtc_controller.cpp
+// 
+// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+// 
+// Initial Contributors:
+// Accenture - Initial contribution
+//
+
+#include <e32base.h>
+#include <fshell/common.mmh>
+#include "vtc_controller.h"
+#include "vtc_cursor_tracker.h"
+
+
+//
+// Constants.
+//
+
+_LIT(KAttSupportAttributes, "support_attributes");
+_LIT(KAttForegroundColor, "foreground_color");
+_LIT(KAttBackgroundColor, "background_color");
+
+class TEscapeMapping
+	{
+public:
+	TUint8 iEscapeChar;
+	TKeyCode iKeyCode;
+	};
+
+class TLongerEscapeMapping
+	{
+public:
+	TUint8 iEscapeChar1;
+	TUint8 iEscapeChar2;
+	TKeyCode iKeyCode;
+	};
+
+
+const TEscapeMapping KEscapeMappings[] = 
+	{
+		{ 'A', EKeyUpArrow },
+		{ 'B', EKeyDownArrow },
+		{ 'C', EKeyRightArrow },
+		{ 'D', EKeyLeftArrow },
+		{ 'H', EKeyHome },
+		{ 'K', EKeyEnd },
+	};
+const TInt KNumEscapeMappings(sizeof(KEscapeMappings) / sizeof(TEscapeMapping));
+
+const TEscapeMapping KFunctionKeyMappings[] =
+	{
+		{ 'P', EKeyF1 },
+		{ 'Q', EKeyF2 },
+		{ 'R', EKeyF3 },
+		{ 'S', EKeyF4 },
+	};
+const TInt KNumEscapeFunctionMappings(sizeof(KFunctionKeyMappings) / sizeof(TEscapeMapping));
+
+// The following are for VT220 support, which is needed to get function keys understood from teraterm. They use ESC [xx~ where xx is given by the below table
+// See http://aperiodic.net/phil/archives/Geekery/term-function-keys.html for the reference I used
+const TLongerEscapeMapping KExtendedEscapeMappings[] = 
+	{
+		{ '1', '1', EKeyF1 },
+		{ '1', '2', EKeyF2 },
+		{ '1', '3', EKeyF3 },
+		{ '1', '4', EKeyF4 },
+		{ '1', '5', EKeyF5 },
+		// '1' '6' isn't used
+		{ '1', '7', EKeyF6 },
+		{ '1', '8', EKeyF7 },
+		{ '1', '9', EKeyF8 },
+		{ '2', '0', EKeyF9 },
+		{ '2', '1', EKeyF10 },
+		// '2' '2' isn't used
+		{ '2', '3', EKeyF11 },
+		{ '2', '4', EKeyF12 },
+
+		// ESC [1~ is Home key according to http://www.zaik.uni-koeln.de/~ftp/elfi/etc/telnet.key
+		{ '1', 0, EKeyHome },
+		{ '4', 0, EKeyEnd },
+		{ '5', 0, EKeyPageUp },
+		{ '6', 0, EKeyPageDown },
+		{ '2', 0, EKeyInsert },
+		{ '3', 0, EKeyDelete },
+	};
+const TInt KNumExtendedEscapeMappings = sizeof(KExtendedEscapeMappings) / sizeof(TLongerEscapeMapping);
+
+static const TUint8 KEscapeChar1 = 0x1b;
+static const TUint8 KEscapeChar2 = '[';
+static const TUint8 KEscapeChar2Func = 'O';
+
+static const TInt KEscapeTimeoutMicros = 200000; // 1/5th second
+
+
+//______________________________________________________________________________
+//						TKeyPress
+EXPORT_C TKeyPress::TKeyPress()
+	: iCode(EKeyNull), iModifiers(0)
+	{
+	}
+
+EXPORT_C TKeyPress::TKeyPress(TKeyCode aCode, TUint aModifiers)
+	: iCode(aCode), iModifiers(aModifiers)
+	{
+	}
+
+//______________________________________________________________________________
+//						CVtConsoleOutputController
+EXPORT_C CVtConsoleOutputController* CVtConsoleOutputController::NewL(MConsoleOutput& aOutput, LtkUtils::CIniFile& aIniFile, const TSize& aScreenSize)
+	{
+	CVtConsoleOutputController* self = new(ELeave)CVtConsoleOutputController(aOutput, aIniFile);
+	CleanupStack::PushL(self);
+	User::LeaveIfError(self->Construct(aScreenSize));
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+EXPORT_C CVtConsoleOutputController* CVtConsoleOutputController::New(MConsoleOutput& aOutput, LtkUtils::CIniFile& aIniFile, const TSize& aScreenSize)
+	{
+	CVtConsoleOutputController* self = new CVtConsoleOutputController(aOutput, aIniFile);
+	TInt err = self->Construct(aScreenSize);
+	if (err!=KErrNone)
+		{
+		delete self;
+		self = NULL;
+		}
+	return self;
+	}
+
+class TAttributeBuf : public TBuf8<64>
+	{
+public:
+	enum TColorType
+		{
+		EForeground,
+		EBackground
+		};
+public:
+	TAttributeBuf(LtkUtils::CIniFile& aIniFile);
+	void Add(TUint aAttributes);
+	void Add(ConsoleAttributes::TColor aColor, TColorType aType);
+	void Finalize();
+	TBool SomethingAdded() const;
+private:
+	void Add(const TDesC8& aAttribute);
+private:
+	LtkUtils::CIniFile& iIniFile;
+	TBool iSomethingAdded;
+	};
+
+_LIT8(KPrefix, "\x1b[");
+TAttributeBuf::TAttributeBuf(LtkUtils::CIniFile& aIniFile)
+	: TBuf8<64>(KPrefix), iIniFile(aIniFile), iSomethingAdded(EFalse)
+	{
+	}
+
+void TAttributeBuf::Add(const TDesC8& aAttribute)
+	{
+	if (iSomethingAdded)
+		{
+		Append(';');
+		}
+	Append(aAttribute);
+	iSomethingAdded = ETrue;
+	}
+
+void TAttributeBuf::Finalize()
+	{
+	ASSERT(iSomethingAdded);
+	Append('m');
+	}
+
+TBool TAttributeBuf::SomethingAdded() const
+	{
+	return iSomethingAdded;
+	}
+
+void TAttributeBuf::Add(TUint aAttributes)
+	{
+	_LIT8(KAttReset,		"0");
+	_LIT8(KAttBold,			"1");
+	_LIT8(KAttUnderscore,	"4");
+	_LIT8(KAttBlink,		"5");
+	_LIT8(KAttInverse,		"7");
+	_LIT8(KAttConceal,		"8");
+
+	if (aAttributes & ConsoleAttributes::ENone)
+		{
+		Add(KAttReset);
+		Add((ConsoleAttributes::TColor)iIniFile.GetInt(KAttForegroundColor), TAttributeBuf::EForeground);
+		Add((ConsoleAttributes::TColor)iIniFile.GetInt(KAttBackgroundColor), TAttributeBuf::EBackground);
+		}
+	if (aAttributes & ConsoleAttributes::EBold)
+		{
+		Add(KAttBold);
+		}
+	if (aAttributes & ConsoleAttributes::EUnderscore)
+		{
+		Add(KAttUnderscore);
+		}
+	if (aAttributes & ConsoleAttributes::EBlink)
+		{
+		Add(KAttBlink);
+		}
+	if (aAttributes & ConsoleAttributes::EInverse)
+		{
+		Add(KAttInverse);
+		}
+	if (aAttributes & ConsoleAttributes::EConceal)
+		{
+		Add(KAttConceal);
+		}
+	}
+
+void TAttributeBuf::Add(ConsoleAttributes::TColor aColor, TColorType aType)
+	{
+	_LIT8(KFgBlack,			"30");
+	_LIT8(KFgRed,			"31");
+	_LIT8(KFgGreen,			"32");
+	_LIT8(KFgYellow,		"33");
+	_LIT8(KFgBlue,			"34");
+	_LIT8(KFgMagenta,		"35");
+	_LIT8(KFgCyan,			"36");
+	_LIT8(KFgWhite,			"37");
+	_LIT8(KFgReset,			"39");
+	_LIT8(KBgBlack,			"40");
+	_LIT8(KBgRed,			"41");
+	_LIT8(KBgGreen,			"42");
+	_LIT8(KBgYellow,		"43");
+	_LIT8(KBgBlue,			"44");
+	_LIT8(KBgMagenta,		"45");
+	_LIT8(KBgCyan,			"46");
+	_LIT8(KBgWhite,			"47");
+	_LIT8(KBgReset,			"49");
+
+	if (aType == EForeground)
+		{
+		switch (aColor)
+			{
+			default:
+			case ConsoleAttributes::EUnchanged:
+				{
+				// Do nothing.
+				break;
+				}
+			case ConsoleAttributes::EBlack:
+				{
+				Add(KFgBlack);
+				break;
+				}
+			case ConsoleAttributes::ERed:
+				{
+				Add(KFgRed);
+				break;
+				}
+			case ConsoleAttributes::EGreen:
+				{
+				Add(KFgGreen);
+				break;
+				}
+			case ConsoleAttributes::EYellow:
+				{
+				Add(KFgYellow);
+				break;
+				}
+			case ConsoleAttributes::EBlue:
+				{
+				Add(KFgBlue);
+				break;
+				}
+			case ConsoleAttributes::EMagenta:
+				{
+				Add(KFgMagenta);
+				break;
+				}
+			case ConsoleAttributes::ECyan:
+				{
+				Add(KFgCyan);
+				break;
+				}
+			case ConsoleAttributes::EWhite:
+				{
+				Add(KFgWhite);
+				break;
+				}
+			case ConsoleAttributes::EReset:
+				{
+				Add(KFgReset);
+				break;
+				}
+			}
+		}
+	else
+		{
+		switch (aColor)
+			{
+			default:
+			case ConsoleAttributes::EUnchanged:
+				{
+				// Do nothing.
+				break;
+				}
+			case ConsoleAttributes::EBlack:
+				{
+				Add(KBgBlack);
+				break;
+				}
+			case ConsoleAttributes::ERed:
+				{
+				Add(KBgRed);
+				break;
+				}
+			case ConsoleAttributes::EGreen:
+				{
+				Add(KBgGreen);
+				break;
+				}
+			case ConsoleAttributes::EYellow:
+				{
+				Add(KBgYellow);
+				break;
+				}
+			case ConsoleAttributes::EBlue:
+				{
+				Add(KBgBlue);
+				break;
+				}
+			case ConsoleAttributes::EMagenta:
+				{
+				Add(KBgMagenta);
+				break;
+				}
+			case ConsoleAttributes::ECyan:
+				{
+				Add(KBgCyan);
+				break;
+				}
+			case ConsoleAttributes::EWhite:
+				{
+				Add(KBgWhite);
+				break;
+				}
+			case ConsoleAttributes::EReset:
+				{
+				Add(KBgReset);
+				break;
+				}
+			}
+		}
+	}
+
+EXPORT_C TInt CVtConsoleOutputController::ResetAttributes()
+	{
+	if (iIniFile.GetBool(KAttSupportAttributes))
+		{
+		TAttributeBuf buf(iIniFile);
+		buf.Add(ConsoleAttributes::ENone);
+		buf.Finalize();
+		return iOutput.Output(buf);
+		}
+
+	return KErrNone;
+	}
+
+EXPORT_C TInt CVtConsoleOutputController::SetAttributes(TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor)
+	{
+	if (iIniFile.GetBool(KAttSupportAttributes))
+		{
+		TAttributeBuf buf(iIniFile);
+		buf.Add(aAttributes);
+		buf.Add(aForegroundColor, TAttributeBuf::EForeground);
+		buf.Add(aBackgroundColor, TAttributeBuf::EBackground);
+
+		if (buf.SomethingAdded())
+			{
+			buf.Finalize();
+			return iOutput.Output(buf);
+			}
+
+		return KErrNone;
+		}
+
+	return KErrNotSupported;
+	}
+	
+CVtConsoleOutputController::CVtConsoleOutputController(MConsoleOutput& aOutput, LtkUtils::CIniFile& aIniFile)
+	: iOutput(aOutput), iIniFile(aIniFile), iMode(ConsoleMode::EText)
+	{
+	}
+
+TInt CVtConsoleOutputController::Construct(const TSize& aScreenSize)
+	{
+	iCursorTracker = new TCursorTracker(aScreenSize);
+	if (!iCursorTracker) return KErrNoMemory;
+	return KErrNone;
+	}
+
+EXPORT_C CVtConsoleOutputController::~CVtConsoleOutputController()
+	{
+	delete iCursorTracker;
+	iOutputBuf.Close();
+	}
+
+TInt CVtConsoleOutputController::GetCursorPos(TPoint& aPos) const
+	{
+	aPos = iCursorTracker->CursorPos();
+	return KErrNone;
+	}
+
+
+TInt CVtConsoleOutputController::SetCursorPosAbs(const TPoint& aPos)
+	{
+	TInt err = KErrInUse;
+	if (iMode == ConsoleMode::EText)
+		{
+		_LIT8(KEscapeSetCursorPosAbs, "\x1b[%u;%uH");
+		TBuf8<32> buf;
+		buf.Format(KEscapeSetCursorPosAbs, aPos.iY + 1, aPos.iX + 1);
+		err = iOutput.Output(buf);
+		if (err == KErrNone)
+			{
+			iCursorTracker->SetCursorPosAbs(aPos);
+			}
+		}
+	return err;
+	}
+
+TInt CVtConsoleOutputController::SetCursorPosRel(const TPoint& aPoint)
+	{
+	TInt err = KErrInUse;
+	if (iMode == ConsoleMode::EText)
+		{
+		TBuf8<32> buf;
+
+		if (aPoint.iY == 0)
+			{
+			// Do nothing.
+			}
+		else if (aPoint.iY < 0)
+			{
+			// Move cursor up.
+			_LIT8(KEscapeCursorUp, "\x1b[%uA");
+			buf.AppendFormat(KEscapeCursorUp, -aPoint.iY);
+			}
+		else if (aPoint.iY > 0)
+			{
+			// Move cursor down.
+			_LIT8(KEscapeCursorDown, "\x1b[%uB");
+			buf.AppendFormat(KEscapeCursorDown, aPoint.iY);
+			}
+
+		if (aPoint.iX == 0)
+			{
+			// Do nothing.
+			}
+		else if (aPoint.iX < 0)
+			{
+			// Move cursor left.
+			_LIT8(KEscapeCursorLeft, "\x1b[%uD");
+			buf.AppendFormat(KEscapeCursorLeft, -aPoint.iY);
+			}
+		else if (aPoint.iX > 0)
+			{
+			// Move cursor right.
+			_LIT8(KEscapeCursorRight, "\x1b[%uC");
+			buf.AppendFormat(KEscapeCursorRight, aPoint.iY);
+			}
+		
+		err = KErrNone;
+		if (buf.Length() > 0)
+			{
+			err = iOutput.Output(buf);
+			if (err == KErrNone)
+				{
+				iCursorTracker->SetCursorPosRel(aPoint);
+				}
+			}
+		}
+	return err;
+	}
+
+TInt CVtConsoleOutputController::SetCursorHeight(TInt aPercentage)
+	{
+	TInt err = KErrInUse;
+	if (iMode == ConsoleMode::EText)
+		{
+		_LIT8(KEscapeHideCursor, "\x1b[?25l");
+		_LIT8(KEscapeSeeCursor, "\x1b[?25h");
+		if (aPercentage == 0)
+			{
+			err = iOutput.Output(KEscapeHideCursor);
+			}
+		else
+			{
+			err = iOutput.Output(KEscapeSeeCursor);
+			}
+		}
+	return err;
+	}
+
+TInt CVtConsoleOutputController::SetTitle(const TDesC&)
+	{
+	return KErrNone;
+	}
+
+TInt CVtConsoleOutputController::ClearScreen()
+	{
+	TInt err = KErrInUse;
+	if (iMode == ConsoleMode::EText)
+		{
+		_LIT8(KResetTerminal, "\x1b" "c" "\x1b" "[?7h"); // reset console, then enable line wrapping
+		err = iOutput.Output(KResetTerminal);
+		if (err == KErrNone)
+			{
+			User::After(100000); // It seems that TeraTerm doesn't like receiving attribute changes too soon after a terminal reset (tends to ignore the attributes).
+			err = ResetAttributes();
+			if (err == KErrNone)
+				{
+				_LIT8(KEscapeClearScreen, "\x1b[2J\x1b[01;01H");
+				err = iOutput.Output(KEscapeClearScreen);
+				if (err == KErrNone)
+					{
+					iCursorTracker->Reset();
+					}
+				}
+			}
+		}
+	return err;
+	}
+
+TInt CVtConsoleOutputController::ClearToEndOfLine()
+	{
+	TInt err = KErrInUse;
+	if (iMode == ConsoleMode::EText)
+		{
+		_LIT8(KEscapeClearToEndOfLine, "\x1b[K");
+		err = iOutput.Output(KEscapeClearToEndOfLine);
+		}
+	return err;
+	}
+
+TInt CVtConsoleOutputController::GetScreenSize(TSize& aSize) const
+	{
+	aSize = iCursorTracker->ConsoleSize();
+	return KErrNone;
+	}
+
+TInt CVtConsoleOutputController::Write(const TDesC& aDes)
+	{
+	TInt err = KErrNone;
+	if (iMode == ConsoleMode::EBinary)
+		{
+		// staight collapse to 8 bit, no cleverness
+		TBuf8<256> buf;
+		TInt offset = 0;
+		while ((offset < aDes.Length()) && (err == KErrNone))
+			{
+			buf.Copy(aDes.Mid(offset, Min(aDes.Length() - offset, buf.MaxLength())));
+			offset += buf.Length();
+			err = iOutput.Output(buf);
+			}
+		}
+	else
+		{
+		// In text mode we do a UTF-16 -> UTF-8 conversion
+		TRAP(err, iOutputBuf.CopyAsUtf8L(aDes));
+		if (err == KErrNone)
+			{
+			err = iOutput.Output(iOutputBuf);
+			if (err == KErrNone)
+				{
+				iCursorTracker->Write(aDes);
+				}
+			}
+		}
+	return err;
+	}
+	
+TInt CVtConsoleOutputController::Write(const TDesC8& aDes)
+	{
+	TInt err = iOutput.Output(aDes);
+	if ((err == KErrNone) && (iMode == ConsoleMode::EText))
+		{
+		iCursorTracker->Write(aDes);
+		}
+	return err;
+	}
+
+void CVtConsoleOutputController::SetMode(ConsoleMode::TMode aMode)
+	{
+	iMode = aMode;
+	}
+
+//______________________________________________________________________________
+//						CVtConsoleInputController
+
+EXPORT_C CVtConsoleInputController* CVtConsoleInputController::New(MConsoleInput& aConsoleInput, LtkUtils::CIniFile& aIniFile)
+	{
+	CVtConsoleInputController* self = NULL;
+	TRAPD(err, self = NewL(aConsoleInput, aIniFile));
+	if (err == KErrNone)
+		{
+		return self;
+		}
+	return NULL;
+	}
+
+EXPORT_C  CVtConsoleInputController* CVtConsoleInputController::NewL(MConsoleInput& aConsoleInput, LtkUtils::CIniFile& aIniFile)
+	{
+	CVtConsoleInputController* self = NewLC(aConsoleInput, aIniFile);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+EXPORT_C  CVtConsoleInputController* CVtConsoleInputController::NewLC(MConsoleInput& aConsoleInput, LtkUtils::CIniFile& aIniFile)
+	{
+	CVtConsoleInputController* self = new(ELeave)CVtConsoleInputController(aConsoleInput, aIniFile);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+CVtConsoleInputController::CVtConsoleInputController(MConsoleInput& aConsoleInput, LtkUtils::CIniFile& aIniFile)
+	: CActive(CActive::EPriorityStandard), iConsoleInput(aConsoleInput), iIniFile(aIniFile), iMode(ConsoleMode::EText)
+	{
+	CActiveScheduler::Add(this);
+	}
+	
+void CVtConsoleInputController::ConstructL()
+	{
+	iEscapeTimer = CPeriodic::NewL(CActive::EPriorityLow);
+	}
+	
+CVtConsoleInputController::~CVtConsoleInputController()
+	{
+	Reset();
+	delete iEscapeTimer;
+	}
+
+EXPORT_C void CVtConsoleInputController::GetKeyPress(TKeyPress& aKeyPress, TRequestStatus& aStatus)
+	{
+	ASSERT((iClientKeyPress == NULL) && (iClientRequestStatus == NULL));
+	iClientKeyPress = &aKeyPress;
+	iClientRequestStatus = &aStatus;
+	*iClientRequestStatus = KRequestPending;
+	if (iKeyCodePending)
+		{
+		iKeyCodePending = EFalse;
+		CompleteKeyPressRequest(iPendingKeyCode);
+		}
+	else if (iInputError)
+		{
+		CompleteKeyPressRequest(iInputError);
+		iInputError = KErrNone;
+		}
+	else
+		{
+		ReadKeyPress();
+		}
+	}
+
+EXPORT_C void CVtConsoleInputController::CancelGetKeyPress()
+	{
+	Cancel();
+	if (iClientRequestStatus)
+		{
+		CompleteKeyPressRequest(KErrCancel);
+		}
+	}
+
+EXPORT_C void CVtConsoleInputController::SetMode(ConsoleMode::TMode aMode)
+	{
+	Reset();
+	iMode = aMode;
+	}
+
+void CVtConsoleInputController::ReadKeyPress()
+	{
+	iEscapeTimer->Cancel();
+
+	while (iClientRequestStatus && (iBufPos < iBuf.Length()))
+		{
+		TUint8 c = iBuf[iBufPos++];
+		if (iMode == ConsoleMode::EBinary)
+			{
+			CompleteKeyPressRequest((TKeyCode)c);
+			}
+		else
+			{
+			switch (iState)
+				{
+			case ENormal:
+				if (c == KEscapeChar1)
+					{
+					iState = EWaitingForEscapeChar2;
+					if (iBufPos == iBuf.Length())
+						{
+						iEscapeTimer->Start(KEscapeTimeoutMicros, KEscapeTimeoutMicros, TCallBack(EscapeTimeoutS, this));
+						}
+					}
+				else
+					{
+					CompleteKeyPressRequest((TKeyCode)c);
+					}
+				break;
+			case EWaitingForEscapeChar2:
+				if (c == KEscapeChar2)
+					{
+					iState = EWaitingForEscapeChar3;
+					}
+				else if (c == KEscapeChar2Func)
+					{
+					iState = EWaitingForEscapeChar3Func;
+					}
+				else
+					{
+					CompleteKeyPressRequest(EKeyEscape, (TKeyCode)c);
+					iState = ENormal;
+					}
+				break;
+			case EWaitingForEscapeChar3:
+				if (c >= '0' && c <= '9')
+					{
+					iState = EWaitingForExtendedFunc;
+					iExtendedEscapeBuf.Zero();
+					iExtendedEscapeBuf.Append(c);
+					}
+				else
+					{
+					DoEscapeKeyL(c, KEscapeMappings, KNumEscapeMappings);
+					}
+				break;
+			case EWaitingForEscapeChar3Func:
+				DoEscapeKeyL(c, KFunctionKeyMappings, KNumEscapeFunctionMappings);
+				break;
+			case EWaitingForExtendedFunc:
+				if (iExtendedEscapeBuf.Length() < iExtendedEscapeBuf.MaxLength() && ((c >= '0' && c <= '9') || c == ';'))
+					{
+					iExtendedEscapeBuf.Append(c);
+					// Stay in this state until you see a '~'
+					}
+				else if (c == '~')
+					{
+					DoExtendedEscapeKey();
+					}
+				else
+					{
+					// Gone off the rails, bail
+					iState = ENormal;
+					CompleteKeyPressRequest((TKeyCode)c);
+					}
+				break;
+				}
+			}
+		}
+
+	ReadInput();
+	}
+
+void CVtConsoleInputController::CompleteKeyPressRequest(TInt aError)
+	{
+	ASSERT(iClientKeyPress && iClientRequestStatus);
+	iClientKeyPress = NULL;
+	User::RequestComplete(iClientRequestStatus, aError);
+	}
+
+void CVtConsoleInputController::CompleteKeyPressRequest(TKeyCode aKeyCode)
+	{
+	ASSERT(iClientKeyPress && iClientRequestStatus);
+	iClientKeyPress->iCode = (TKeyCode)aKeyCode;
+	iClientKeyPress->iModifiers = 0;
+	iClientKeyPress = NULL;
+	User::RequestComplete(iClientRequestStatus, KErrNone);
+	}
+
+void CVtConsoleInputController::CompleteKeyPressRequest(TKeyCode aKeyCode1, TKeyCode aKeyCode2)
+	{
+	ASSERT(!iKeyCodePending);
+	// Store the second key-code in a member variable to be used the next time GetKeyPress is called.
+	iKeyCodePending = ETrue;
+	iPendingKeyCode = aKeyCode2;
+	CompleteKeyPressRequest(aKeyCode1);
+	}
+
+void CVtConsoleInputController::Reset()
+	{
+	Cancel();
+	iEscapeTimer->Cancel();
+	iState = ENormal;
+	iKeyCodePending = EFalse;
+	}
+
+void CVtConsoleInputController::ReadInput()
+	{
+	if (iClientRequestStatus && !IsActive()) // Note, if the escape timer expired we could already be active.
+		{
+		ASSERT(iBufPos == iBuf.Length());
+		iBufPos = 0;
+		iBuf.Zero();
+		iConsoleInput.Input(iBuf, iStatus);
+		SetActive();
+		}
+	}
+
+void CVtConsoleInputController::RunL()
+	{
+	TInt err = iStatus.Int();
+#ifdef FSHELL_PLATFORM_OPP
+	if (err == KErrAbort)
+		{
+		ReadInput();
+		return;
+		}
+#endif
+	if (err == KErrNone)
+		{
+		ReadKeyPress();
+		}
+	else if (iClientRequestStatus)
+		{
+		CompleteKeyPressRequest(err);
+		}
+	else
+		{
+		// Report the error next time the client requests a key.
+		iInputError = err;
+		}
+	}
+
+void CVtConsoleInputController::DoCancel()
+	{
+	iConsoleInput.CancelInput(iStatus);
+	}
+
+void CVtConsoleInputController::DoEscapeKeyL(TUint8 aChar, const TEscapeMapping* aMappings, TInt aMappingCount)
+	{
+	iState = ENormal;
+	for (TInt j = 0; j < aMappingCount; ++j)
+		{
+		if (aChar == aMappings[j].iEscapeChar)
+			{
+			CompleteKeyPressRequest(aMappings[j].iKeyCode);
+			return;
+			}
+		}
+	}
+	
+TInt CVtConsoleInputController::EscapeTimeout()
+	{
+	ASSERT(iState == EWaitingForEscapeChar2);
+	iState = ENormal;
+	CompleteKeyPressRequest(EKeyEscape);
+	return KErrNone;
+	}
+
+TInt CVtConsoleInputController::EscapeTimeoutS(TAny* aSelf)
+	{
+	return ((CVtConsoleInputController*)aSelf)->EscapeTimeout();
+	}
+
+	
+void CVtConsoleInputController::DoExtendedEscapeKey()
+	{
+	iState = ENormal;
+	TUint8 escape1 = 0;
+	TUint8 escape2 = 0;
+	if (iExtendedEscapeBuf.Length()) escape1 = iExtendedEscapeBuf[0];
+	if (iExtendedEscapeBuf.Length() > 1) escape2 = iExtendedEscapeBuf[1];
+
+	for (TInt j = 0; j < KNumExtendedEscapeMappings; ++j)
+		{
+		const TLongerEscapeMapping& mapping = KExtendedEscapeMappings[j];
+		if (escape1 == mapping.iEscapeChar1 && escape2 == mapping.iEscapeChar2)
+			{
+			CompleteKeyPressRequest(mapping.iKeyCode);
+			return;
+			}
+		}
+	}