// TEIKCON1.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <e32std.h>
#include <e32base.h>
#include <e32cons.h>

#define CTRL(x) (x-'a'+1) // not an inline function since that can't be put as the case of a switch statement
CConsoleBase* console;

//
// class CTestKeyReader
//

class CTestKeyReader : public CActive
	{
public:
	~CTestKeyReader();
	static CTestKeyReader* NewL();
	void QueueKeyRead();
protected:// virtual
	virtual void RunL();
	virtual void DoCancel();
protected:
	inline CTestKeyReader() : CActive(EPriorityUserInput) { } 
	void Construct();
	void HandleKey(TKeyCode aCode);
protected:
	};

CTestKeyReader::~CTestKeyReader()
	{
	Cancel();
	}

CTestKeyReader* CTestKeyReader::NewL()
	{
	CTestKeyReader* reader=new(ELeave) CTestKeyReader;
	reader->Construct();
	return reader;
	}

void CTestKeyReader::QueueKeyRead()
	{
	console->Read(iStatus);
	SetActive();
	}

void CTestKeyReader::Construct()
	{
	CActiveScheduler::Add(this);
	QueueKeyRead();
	}

void CTestKeyReader::RunL()
	{
	TKeyCode lastKey=console->KeyCode();
	HandleKey(lastKey);
	QueueKeyRead();
	}

void CTestKeyReader::HandleKey(TKeyCode aCode)
	{
	TBuf<1> key;
	switch (aCode)
		{
	case CTRL('e'):
		CActiveScheduler::Stop();
		return;
	case EKeyUpArrow:
		console->SetCursorPosRel(TPoint(0, -1));
		break;
	case EKeyDownArrow:
		console->SetCursorPosRel(TPoint(0, 1));
		break;
	case EKeyLeftArrow:
		console->SetCursorPosRel(TPoint(-1, 0));
		break;
	case EKeyRightArrow:
		console->SetCursorPosRel(TPoint(1, 0));
		break;
	case EKeyBackspace:
		console->SetCursorPosRel(TPoint(-1, 0));
		key.Format(_L("%c"), EKeySpace);
		console->Write(key);
		console->SetCursorPosRel(TPoint(-1, 0));
		break;
	case EKeyEscape:
		break;
	case EKeyEnter:
		key.Format(_L("%c"), EKeyLineFeed);
		console->Write(key);
		// deliberate fall through
	default:
		key.Format(_L("%c"), aCode);
		console->Write(key);
		break;
		}
	}

void CTestKeyReader::DoCancel()
	{
	console->ReadCancel();
	}

//
// class CTestTimer
//

class CTestTimer : public CTimer
	{
public:
	static CTestTimer* NewL(CTestKeyReader* aReader);
	void QueueTimer();
protected:
	inline CTestTimer(CTestKeyReader* aReader) :
		CTimer(EPriorityHigh),
		iRead(ETrue),
		iReader(aReader) { }
	void DoConstructL();
protected: // virtual
	virtual void RunL();
protected:
	TBool iRead;
	CTestKeyReader* iReader;
	};

CTestTimer* CTestTimer::NewL(CTestKeyReader* aReader)
	{
	CTestTimer* timer=new(ELeave) CTestTimer(aReader);
	timer->DoConstructL();
	return timer;
	}	  

void CTestTimer::DoConstructL()
	{
	ConstructL();
	CActiveScheduler::Add(this);
	QueueTimer();
	}

void CTestTimer::QueueTimer()
	{
	After(TTimeIntervalMicroSeconds32(10000000)); // 10 secs
	}

void CTestTimer::RunL()
	{
	iRead=!iRead;
	if (iRead)
		{
		console->Write(_L("\nKeyboard read enabled - asynchronous Read() queued\n"));
		iReader->QueueKeyRead();
		}
	else
		{
		console->Write(_L("\nKeyboard read disabled - outstanding Read() request cancelled\n"));
		iReader->Cancel();
		}
	QueueTimer();
	}

//
// Global functions
//

void CreateConsoleL()
	{
	console=Console::NewL(_L("TEIKCON1"),TSize(KDefaultConsWidth,KDefaultConsHeight));
	for (TInt ii=0; ii<300; ii++)
		console->Write(_L("TEIKCON1 - Asynchronous keyboard echo test.  CTRL+E to exit\n"));
	}

void RunTestsL()
	{
	CActiveScheduler* aS=new(ELeave) CActiveScheduler;
	CActiveScheduler::Install(aS);
	CreateConsoleL();
	CTestKeyReader* reader=CTestKeyReader::NewL(); // adds to aS
	CTestTimer* timer=CTestTimer::NewL(reader);
	CActiveScheduler::Start();
	delete timer;
	delete reader;
	delete console;
	delete aS;
	}

#if defined(__WINS__)
EXPORT_C TInt EntryPoint()
#else
GLDEF_C TInt E32Main()
#endif
	{
	__UHEAP_MARK;
    CTrapCleanup *cleanup=CTrapCleanup::New();
    TRAPD(err,RunTestsL());
    delete(cleanup);
	__UHEAP_MARKEND;
    return(0);
	}

#if defined(__WINS__)
GLDEF_C TInt E32Dll(TDllReason)
	{
	return(KErrNone);
	}
#endif
