uifw/EikStd/console/EIKCONCL.CPP
changeset 0 2f259fa3e83a
child 14 3320e4e6e8bb
equal deleted inserted replaced
-1:000000000000 0:2f259fa3e83a
       
     1 /*
       
     2 * Copyright (c) 1997-1999 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "EIKCONCL.H"
       
    20 #include "EIKCONCL.PAN"
       
    21 #include <eikconso.h>
       
    22 #include <eikenv.h>
       
    23 #include <eikappui.h>  
       
    24 #include <basched.h>
       
    25 #include <apgwgnam.h>
       
    26 #ifndef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    27 #include <eikdef.h>
       
    28 #else
       
    29 #include <eikdef.h>
       
    30 #include <uikon/eikdefmacros.h>
       
    31 #endif
       
    32 #include <avkon.hrh>
       
    33 #include <aknSctDialog.h>
       
    34 #include <avkon.rsg>
       
    35 #include <c32comm.h>
       
    36 #include <aknappui.h>
       
    37 
       
    38 GLDEF_C void Panic(TEikConClPanic aPanic)
       
    39 	{
       
    40 	_LIT(KPanicCat,"EIKON-CONCL");
       
    41 	User::Panic(KPanicCat,aPanic);
       
    42 	}
       
    43 
       
    44 class CEikConsMessager;
       
    45 
       
    46 class CCommsKeyReader : public CActive
       
    47 	{
       
    48 public:
       
    49 	CCommsKeyReader(RComm& aComm, CEikConsMessager* aMessager);
       
    50 	~CCommsKeyReader();
       
    51 
       
    52 private:
       
    53 	void RunL();
       
    54 	void DoCancel();
       
    55 	void Start();
       
    56 
       
    57 private:
       
    58 	RComm& iComm;
       
    59 	CEikConsMessager* iMessager;
       
    60 	TBuf8<1> iBuf;
       
    61 	TBuf8<4> iMatch;
       
    62 	};
       
    63 
       
    64 
       
    65 class CCommsKeyWriter : public CActive
       
    66 	{
       
    67 public:
       
    68 	CCommsKeyWriter(RComm& aComm);
       
    69 	~CCommsKeyWriter();
       
    70 
       
    71 	void Write(const TDesC& aDes);
       
    72 
       
    73 private:
       
    74 	void WriteIfReady();
       
    75 	void RunL();
       
    76 	void DoCancel();
       
    77 	void AppendBlocking(TText8 aChar);
       
    78 
       
    79 private:
       
    80 	RComm& iComm;
       
    81 	TBuf8<256> iBuf;
       
    82 	TBuf8<256> iWrite;
       
    83 	TBool iInFakeCancel;
       
    84 	};
       
    85 
       
    86 
       
    87 enum
       
    88 	{
       
    89 	EExit,
       
    90 	ERead,
       
    91 	EReadCancel,
       
    92 	EWrite,
       
    93 	ESetCursorPosAbs,
       
    94 	ESetCursorPosRel,
       
    95 	ESetCursorHeight,
       
    96 	ESetTitle,
       
    97 	EClearScreen,
       
    98 	EClearToEndOfLine
       
    99 	};
       
   100 
       
   101 
       
   102 struct TFepKey
       
   103 	{
       
   104 	TText iLong;
       
   105 	const TText* iLower;
       
   106 	const TText* iUpper;
       
   107 	};
       
   108 
       
   109 const TFepKey KFepKeyTable[] = 
       
   110 	{
       
   111 		{ '0', _S(" 0\r"), _S(" 0\r") },
       
   112 		{ '1', _S("\\.:1#*/-+=\"',()|`!$%^&_[]{};@~<>?"), _S("\\.:1#*/-+=\"',()|`!$%^&_[]{};@~<>?") },
       
   113 		{ '2', _S("abc2"), _S("ABC2") },
       
   114 		{ '3', _S("def3"), _S("DEF3") },
       
   115 		{ '4', _S("ghi4"), _S("GHI4") },
       
   116 		{ '5', _S("jkl5"), _S("JKL5") },
       
   117 		{ '6', _S("mno6"), _S("MNO6") },
       
   118 		{ '7', _S("pqrs7"), _S("PQRS7") },
       
   119 		{ '8', _S("tuv8"), _S("TUV8") },
       
   120 		{ '9', _S("wxyz9"), _S("WXYZ9") }
       
   121 	};
       
   122 
       
   123 const TText* const KModeNames[] = 
       
   124 	{
       
   125 	_S("Lower"),
       
   126 	_S("Caps"),
       
   127 	_S("Numeric")
       
   128 	};
       
   129 
       
   130 const TText* const KIOModeNames[] = 
       
   131 	{
       
   132 	_S("Screen"),
       
   133 	_S("Serial"),
       
   134 	_S("Ansi-Serial")
       
   135 	};
       
   136 
       
   137 _LIT(KCommModule, "IRCOMM");
       
   138 _LIT(KCommPort, "IRCOMM::0");
       
   139 
       
   140 //
       
   141 // class CEikConsMessager
       
   142 //
       
   143 
       
   144 class CEikConsMessager : public CActive
       
   145 	{
       
   146 public:
       
   147 	enum TMyFlags
       
   148 		{
       
   149 		EShift,
       
   150 		EDigitPressed
       
   151 		};
       
   152 	enum TKeyMode
       
   153 		{
       
   154 		ELower,
       
   155 		ECaps,
       
   156 		ENumeric,
       
   157 		ENumModes
       
   158 		};
       
   159 	enum TIOMode
       
   160 		{
       
   161 		EScreen,
       
   162 		ESerial,
       
   163 		EAnsi,
       
   164 		ENumIOModes
       
   165 		};
       
   166 public:
       
   167 	CEikConsMessager(CEikConsoleScreen* aScreen,RThread aParentThread);
       
   168 	~CEikConsMessager();
       
   169 	void ConstructL(CEikConsoleClient* aClient);
       
   170 	void HandleKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType);
       
   171 	void AddKeyEvent(const TKeyEvent& aKeyEvent);
       
   172 private: // overridden
       
   173 	void RunL();
       
   174 	void DoCancel();
       
   175 private: // internal
       
   176 	void CompleteReadRequest();
       
   177 private: // fep like stuff
       
   178 	void StartTimer();
       
   179 	static TInt TimerCallBack(TAny* aThis);
       
   180 	void DoTimer();
       
   181 	void LaunchSCTL();
       
   182 	void HandleDigit(const TKeyEvent& aKeyEvent, TEventCode aType);
       
   183 	void StartCommsL();
       
   184 	void StopComms();
       
   185 	void WriteComms(const TDesC& aMsg);
       
   186 
       
   187 private:
       
   188 	CEikConsoleScreen* iScreen;
       
   189 	RThread iParentThread;
       
   190 	TRequestStatus* iReadStatus;
       
   191 	TKeyEvent* iKeyEvent;
       
   192 	TInt iMessage;
       
   193 	const TAny* iParam;
       
   194 	TRequestStatus* iReplyStatus;
       
   195 	CCirBuf<TKeyEvent>* iKeyQ;
       
   196 
       
   197 	// fep like stuff
       
   198 	TKeyEvent iLastKey;
       
   199 	CPeriodic* iTimer;
       
   200 	TBitFlags iFlags;
       
   201 	TInt iMultiStep;
       
   202 	TKeyMode iKeyMode;
       
   203 	TIOMode iIOMode;
       
   204 	RCommServ iCommServ;
       
   205 	RComm iComm;
       
   206 	CCommsKeyReader* iReader;
       
   207 	CCommsKeyWriter* iWriter;
       
   208 	};
       
   209 
       
   210 CEikConsMessager::CEikConsMessager(CEikConsoleScreen* aScreen,RThread aParentThread)
       
   211 	: CActive(EActivePriorityIpcEventsHigh),
       
   212 	iParentThread(aParentThread)
       
   213 	{
       
   214 	iScreen=aScreen;
       
   215 	}
       
   216 
       
   217 CEikConsMessager::~CEikConsMessager()
       
   218 	{
       
   219 	StopComms();
       
   220 	delete iTimer;
       
   221 	iParentThread.Close();
       
   222 	delete iKeyQ;
       
   223 	}
       
   224 
       
   225 void CEikConsMessager::ConstructL(CEikConsoleClient* aClient)
       
   226 	{
       
   227 	iTimer = CPeriodic::NewL(EPriorityStandard);
       
   228 	iKeyQ=new(ELeave) CCirBuf<TKeyEvent>;
       
   229 	iKeyQ->SetLengthL(40);	// buffer length, too high? too low?
       
   230 	iKeyEvent=(&aClient->iKeyEvent);
       
   231 	aClient->iThreadStatus=(&iStatus);
       
   232 	aClient->iMessage=(&iMessage);
       
   233 	aClient->iParam=(&iParam);
       
   234 	aClient->iReplyStatus=(&iReplyStatus);
       
   235 	aClient->iScreen=iScreen;
       
   236 	CActiveScheduler::Add(this);
       
   237 	iStatus=KRequestPending;
       
   238 	SetActive();
       
   239 	}
       
   240 
       
   241 void CEikConsMessager::DoCancel()
       
   242 	{
       
   243 	}
       
   244 
       
   245 void CEikConsMessager::RunL()
       
   246 	{
       
   247 	switch (iMessage)
       
   248 		{
       
   249 	case EExit:
       
   250 		CBaActiveScheduler::Exit();
       
   251 		break;
       
   252 	case ERead:
       
   253 		if (iReadStatus)
       
   254 			Panic(EEikConClPanicReadAlreadyOutstanding);
       
   255 		iReadStatus=(TRequestStatus*)iParam;
       
   256 		if (iKeyQ->Count()>0) // already a buffered event
       
   257 			CompleteReadRequest();
       
   258 		break;
       
   259 	case EReadCancel:
       
   260 		if (iReadStatus)
       
   261 			iParentThread.RequestComplete(iReadStatus,KErrCancel);
       
   262 		break;
       
   263 	case EWrite:
       
   264 		iScreen->Write(*(const TDesC*)iParam);
       
   265 		if (iIOMode != EScreen)
       
   266 			WriteComms(*(const TDesC*)iParam);
       
   267 		break;
       
   268 	case ESetCursorPosAbs:
       
   269 		iScreen->SetCursorPosAbs(*(const TPoint*)iParam);
       
   270 		if (iIOMode == EAnsi)
       
   271 			{
       
   272 			TPoint point = iScreen->CursorPos();
       
   273 			TBuf<10> buf;
       
   274 			buf.Format(_L("\033[%d;%dH"), point.iY, point.iX);
       
   275 			WriteComms(buf);
       
   276 			}
       
   277 		break;
       
   278 	case ESetCursorPosRel:
       
   279 		iScreen->SetCursorPosRel(*(const TPoint*)iParam);
       
   280 		if (iIOMode == EAnsi)
       
   281 			{
       
   282 			TPoint point = iScreen->CursorPos();
       
   283 			TBuf<10> buf;
       
   284 			buf.Format(_L("\033[%d;%dH"), point.iY, point.iX);
       
   285 			WriteComms(buf);
       
   286 			}
       
   287 		break;
       
   288 	case ESetCursorHeight:
       
   289 		iScreen->SetCursorHeight((TInt)iParam);
       
   290 		break;
       
   291 	case EClearScreen:
       
   292 		iScreen->ClearScreen();
       
   293 		if (iIOMode == EAnsi)
       
   294 			{
       
   295 			WriteComms(_L("\033[2J"));
       
   296 			}
       
   297 		break;
       
   298 	case EClearToEndOfLine:
       
   299 		iScreen->ClearToEndOfLine();
       
   300 		if (iIOMode == EAnsi)
       
   301 			{
       
   302 			WriteComms(_L("\033[K"));
       
   303 			}
       
   304 		break;
       
   305 		}
       
   306 	iStatus=KRequestPending;
       
   307 	SetActive();
       
   308 	iParentThread.RequestComplete(iReplyStatus,0);
       
   309 	}
       
   310 
       
   311 void CEikConsMessager::CompleteReadRequest()
       
   312 	{
       
   313 	if (iReadStatus)
       
   314 		{ 
       
   315 		iKeyQ->Remove(iKeyEvent);;
       
   316 		iParentThread.RequestComplete(iReadStatus,0);
       
   317 		}
       
   318 	}
       
   319 
       
   320 void CEikConsMessager::HandleKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
       
   321 	{
       
   322 	iFlags.Assign(EShift, aKeyEvent.iModifiers & EModifierShift);
       
   323 
       
   324 	if ('0' <= aKeyEvent.iScanCode && aKeyEvent.iScanCode <= '9')
       
   325 		{
       
   326 		HandleDigit(aKeyEvent, aType);
       
   327 		}
       
   328 	else if (aKeyEvent.iScanCode == EStdKeyHash)
       
   329 		{
       
   330 		if (aType == EEventKeyDown)
       
   331 			{
       
   332 			if (iFlags[EShift])
       
   333 				{
       
   334 				iIOMode = TIOMode((iIOMode+1)%ENumIOModes);
       
   335 				User::InfoPrint(TPtrC(KIOModeNames[iIOMode]));
       
   336 				if (iIOMode == ESerial)
       
   337 					{
       
   338 					StartCommsL();
       
   339 					}
       
   340 				else if (iIOMode == EScreen)
       
   341 					StopComms();
       
   342 				}
       
   343 			else
       
   344 				{
       
   345 				iKeyMode = TKeyMode((iKeyMode+1)%ENumModes);
       
   346 				User::InfoPrint(TPtrC(KModeNames[iKeyMode]));
       
   347 				}
       
   348 			iTimer->Cancel();
       
   349 			}
       
   350 		}
       
   351 	else if (aType == EEventKey)
       
   352 		{
       
   353 		if (aKeyEvent.iCode == '*')
       
   354 			{
       
   355 			LaunchSCTL();
       
   356 			iTimer->Cancel();
       
   357 			}
       
   358 		else if (aKeyEvent.iCode != EKeyF21)
       
   359 			{
       
   360 			AddKeyEvent(aKeyEvent);
       
   361 			iTimer->Cancel();
       
   362 			}
       
   363 		}
       
   364 	}
       
   365 
       
   366 void CEikConsMessager::AddKeyEvent(const TKeyEvent& aKeyEvent)
       
   367 	{
       
   368 	TInt ret=iKeyQ->Add(&aKeyEvent);
       
   369 	if (ret==0)
       
   370 		CEikonEnv::Beep();
       
   371 	if (iKeyQ->Count()==1) // client may be waiting on this key event
       
   372 		CompleteReadRequest();
       
   373 	}
       
   374 
       
   375 void CEikConsMessager::LaunchSCTL()
       
   376 	{
       
   377     TBuf<8> specialChars;
       
   378     TBool shift = !COMPARE_BOOLS(iFlags[EShift], (iKeyMode==ECaps));
       
   379     TInt sctCase = (shift ? EAknSCTUpperCase : EAknSCTLowerCase);
       
   380     CAknCharMapDialog* dialog=new(ELeave) CAknCharMapDialog(sctCase, specialChars);
       
   381     if (dialog->ExecuteLD(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG))
       
   382         {
       
   383         TKeyEvent event =  { 0, 0, 0, 0 };
       
   384         for ( TInt ii = 0; ii < specialChars.Length(); ii++)
       
   385             {
       
   386             if ( specialChars[ii] == 0x000A ) // 0x000A is line feed
       
   387                 {
       
   388                 event.iCode = EKeyEnter;
       
   389                 event.iScanCode = EKeyEnter;
       
   390                 }
       
   391             else
       
   392                 {
       
   393                 event.iCode = specialChars[ii];
       
   394                 event.iScanCode = specialChars[ii];
       
   395                 }
       
   396             AddKeyEvent(event);
       
   397             }
       
   398         }
       
   399     }
       
   400 
       
   401 void CEikConsMessager::HandleDigit(const TKeyEvent& aKeyEvent, TEventCode aType)
       
   402 	{
       
   403 	TText digit = TText(aKeyEvent.iScanCode);
       
   404 	__ASSERT_DEBUG('0' <= digit && digit <= '9', Panic(EEikConClPanicIllegalFepChar));
       
   405 	TBool shift = !COMPARE_BOOLS(iFlags[EShift], (iKeyMode==ECaps));
       
   406 	const TFepKey& fepKey = KFepKeyTable[digit - '0'];
       
   407 	TPtrC keys(shift ? fepKey.iUpper : fepKey.iLower);
       
   408 
       
   409 	if (iKeyMode == ENumeric)
       
   410 		{
       
   411 		if (aType == EEventKey)
       
   412 			{
       
   413 			AddKeyEvent(aKeyEvent);
       
   414 			iTimer->Cancel();
       
   415 			}
       
   416 		}
       
   417 	else
       
   418 		{
       
   419 		if (aType == EEventKeyDown)
       
   420 			{
       
   421 			iFlags.Set(EDigitPressed);
       
   422 			if (digit == iLastKey.iScanCode)
       
   423 				{
       
   424 				iMultiStep = (iMultiStep + 1) % keys.Length();
       
   425 				TKeyEvent del = {EKeyBackspace, EStdKeyBackspace, 0, 0};
       
   426 				AddKeyEvent(del);
       
   427 				TKeyEvent event = {keys[iMultiStep], keys[iMultiStep], 0, 0};
       
   428 				AddKeyEvent(event);
       
   429 				}
       
   430 			else
       
   431 				{
       
   432 				iMultiStep = 0;
       
   433 				TKeyEvent event = {keys[iMultiStep], keys[iMultiStep], 0, 0};
       
   434 				AddKeyEvent(event);
       
   435 				}
       
   436 
       
   437 			StartTimer();
       
   438 			iLastKey = aKeyEvent;
       
   439 			}
       
   440 		else if (aType == EEventKeyUp)
       
   441 			{
       
   442 			iFlags.Clear(EDigitPressed);
       
   443 			}
       
   444 		}
       
   445 	}
       
   446 
       
   447 void CEikConsMessager::StartTimer()
       
   448 	{
       
   449 	iTimer->Cancel();
       
   450 	iTimer->Start(800000, 1000000, TCallBack(TimerCallBack, this));
       
   451 	}
       
   452 
       
   453 TInt CEikConsMessager::TimerCallBack(TAny* aThis)
       
   454 	{
       
   455 	((CEikConsMessager*)aThis)->DoTimer();
       
   456 	return 0;
       
   457 	}
       
   458 
       
   459 void CEikConsMessager::DoTimer()
       
   460 	{
       
   461 	if (iFlags[EDigitPressed])
       
   462 		{
       
   463 		TText digit = TText(iLastKey.iScanCode);
       
   464 		__ASSERT_DEBUG('0' <= digit && digit <= '9', Panic(EEikConClPanicIllegalFepChar));
       
   465 		TText key = KFepKeyTable[digit - '0'].iLong;
       
   466 		TKeyEvent del = {EKeyBackspace, EStdKeyBackspace, 0, 0};
       
   467 		AddKeyEvent(del);
       
   468 		TKeyEvent event = {key, key, 0, 0};
       
   469 		AddKeyEvent(event);
       
   470 		iFlags.Clear(EDigitPressed);
       
   471 		}
       
   472 
       
   473 	iLastKey.iScanCode = 0;
       
   474 	iMultiStep = 0;
       
   475 	}
       
   476 
       
   477 void CEikConsMessager::StartCommsL()
       
   478 	{
       
   479 	User::LeaveIfError(iCommServ.Connect());
       
   480 	User::LeaveIfError(iCommServ.LoadCommModule(KCommModule));
       
   481 	User::LeaveIfError(iComm.Open(iCommServ, KCommPort, ECommExclusive));
       
   482 	TCommConfig cBuf;
       
   483 	iComm.Config(cBuf);
       
   484 	TCommConfigV01& c=cBuf();
       
   485 	c.iRate=EBps115200;
       
   486 	c.iDataBits=EData8;
       
   487 	c.iStopBits=EStop1;
       
   488 	c.iParity=EParityNone;
       
   489 	User::LeaveIfError(iComm.SetConfig(cBuf));
       
   490 	delete iReader;
       
   491 	iReader=0;
       
   492 	iReader = new(ELeave) CCommsKeyReader(iComm, this);
       
   493 	delete iWriter;
       
   494 	iWriter=0;
       
   495 	iWriter = new(ELeave) CCommsKeyWriter(iComm);
       
   496 	}
       
   497 
       
   498 void CEikConsMessager::StopComms()
       
   499 	{
       
   500 	delete iWriter;
       
   501 	iWriter=0;
       
   502 	delete iReader;
       
   503 	iReader=0;
       
   504 	iComm.Close();
       
   505 	iCommServ.Close();
       
   506 	}
       
   507 
       
   508 void CEikConsMessager::WriteComms(const TDesC& aMsg)
       
   509 	{
       
   510 	if (iWriter)
       
   511 		{
       
   512 		iWriter->Write(aMsg);
       
   513 		}
       
   514 	}
       
   515 
       
   516 
       
   517 struct TEscSeq
       
   518 	{
       
   519 	TText8 iText[4];
       
   520 	TKeyCode iCode;
       
   521 	TStdScanCode iScanCode;
       
   522 	};
       
   523 
       
   524 const TEscSeq KEscSeqs[] =
       
   525 	{
       
   526 		{"[?D", EKeyLeftArrow, EStdKeyLeftArrow},
       
   527 		{"[?C", EKeyRightArrow, EStdKeyRightArrow},
       
   528 		{"[?A", EKeyUpArrow, EStdKeyUpArrow},
       
   529 		{"[?B", EKeyDownArrow, EStdKeyDownArrow}
       
   530 	};
       
   531 
       
   532 
       
   533 CCommsKeyReader::CCommsKeyReader(RComm& aComm, CEikConsMessager* aMessager)
       
   534 : CActive(EPriorityHigh), iComm(aComm), iMessager(aMessager)
       
   535 	{
       
   536 	CActiveScheduler::Add(this);
       
   537 	Start();
       
   538 	}
       
   539 
       
   540 CCommsKeyReader::~CCommsKeyReader()
       
   541 	{
       
   542 	Cancel();
       
   543 	}
       
   544 
       
   545 void CCommsKeyReader::RunL()
       
   546 	{
       
   547 	if (iStatus == KErrNone)
       
   548 		{
       
   549 		Start();
       
   550 		if (iMatch.Length() || iBuf[0]=='[')
       
   551 			{
       
   552 			iMatch.Append(iBuf[0]);
       
   553 			for (TInt i=0; i<4; i++)
       
   554 				{
       
   555 				if (iMatch.Match(TPtrC8(KEscSeqs[i].iText)) == 0)
       
   556 					{
       
   557 					TKeyEvent event = {KEscSeqs[i].iCode, KEscSeqs[i].iScanCode, 0, 0};
       
   558 					iMessager->AddKeyEvent(event);
       
   559 					iMatch.Zero();
       
   560 					return;
       
   561 					}
       
   562 				}
       
   563 			if (iMatch.Length() >= 3)
       
   564 				iMatch.Zero();
       
   565 			else
       
   566 				return;
       
   567 			}
       
   568 		TKeyEvent event = {iBuf[0], iBuf[0], 0, 0};
       
   569 		iMessager->AddKeyEvent(event);
       
   570 		}
       
   571 	}
       
   572 
       
   573 void CCommsKeyReader::DoCancel()
       
   574 	{
       
   575 	iComm.ReadCancel();
       
   576 	}
       
   577 
       
   578 void CCommsKeyReader::Start()
       
   579 	{
       
   580 	iComm.ReadOneOrMore(iStatus, iBuf);
       
   581 	SetActive();
       
   582 	}
       
   583 
       
   584 
       
   585 CCommsKeyWriter::CCommsKeyWriter(RComm& aComm)
       
   586 : CActive(EPriorityStandard), iComm(aComm), iInFakeCancel(EFalse)
       
   587 	{
       
   588 	CActiveScheduler::Add(this);
       
   589 	}
       
   590 
       
   591 CCommsKeyWriter::~CCommsKeyWriter()
       
   592 	{
       
   593 	Cancel();
       
   594 	}
       
   595 
       
   596 void CCommsKeyWriter::Write(const TDesC& aDes)
       
   597 	{
       
   598 	for (TInt i=0; i<aDes.Length(); i++)
       
   599 		{
       
   600 		if (aDes[i] == '\n')
       
   601 			{
       
   602 			AppendBlocking('\r');
       
   603 			}
       
   604 		AppendBlocking(TText8(aDes[i]));
       
   605 		}
       
   606 	WriteIfReady();
       
   607 	}
       
   608 
       
   609 void CCommsKeyWriter::WriteIfReady()
       
   610 	{
       
   611 	if (!IsActive() && iBuf.Length()>0)
       
   612 		{
       
   613 		iWrite=iBuf;
       
   614 		iBuf.Zero();
       
   615 		iComm.Write(iStatus, iWrite);
       
   616 		SetActive();
       
   617 		}
       
   618 	}
       
   619 
       
   620 void CCommsKeyWriter::AppendBlocking(TText8 aChar)
       
   621 	{
       
   622 	if (iBuf.Length() >= iBuf.MaxLength())
       
   623 		{
       
   624 		RTimer t;
       
   625 		t.CreateLocal();
       
   626 		TRequestStatus tR;
       
   627 		t.After(tR, 2000000);	// 2 second timeout
       
   628 		User::WaitForRequest(iStatus, tR);
       
   629 		if (iStatus != KRequestPending)
       
   630 			{
       
   631 			// write completed
       
   632 			t.Cancel();
       
   633 			User::WaitForRequest(tR);
       
   634 			
       
   635 			if (IsActive())
       
   636 			    {
       
   637                 iInFakeCancel = ETrue;
       
   638                 Cancel();
       
   639 			    }
       
   640 			
       
   641             iWrite.Zero();
       
   642             WriteIfReady();
       
   643             
       
   644 			}
       
   645 		else
       
   646 			{
       
   647 			// timeout, throw away the buffered data - sorry!
       
   648 			iBuf.Zero();
       
   649 			}
       
   650 		t.Close();
       
   651 		}
       
   652 
       
   653 	iBuf.Append(aChar);
       
   654 	}
       
   655 
       
   656 void CCommsKeyWriter::RunL()
       
   657 	{
       
   658 	iWrite.Zero();
       
   659 	WriteIfReady();
       
   660 	}
       
   661 
       
   662 void CCommsKeyWriter::DoCancel()
       
   663 	{
       
   664     if (iInFakeCancel == EFalse)    
       
   665         iComm.WriteCancel();
       
   666     
       
   667     iInFakeCancel = EFalse;
       
   668 	}
       
   669 
       
   670 
       
   671 
       
   672 //
       
   673 // class CEikConsAppUi
       
   674 //
       
   675 
       
   676 struct SCommandLine
       
   677 	{
       
   678 	RThread iParentThread;
       
   679 	TRequestStatus* iStatus;
       
   680 	CEikConsoleClient* iClient;
       
   681 	TSize iSize;
       
   682 	const TDesC* iTitle;
       
   683 	};
       
   684 
       
   685 class CEikConsAppUi : public CAknAppUi //CEikAppUi
       
   686 	{
       
   687 public:
       
   688     DECLARE_TYPE_ID(0x2001b26a)
       
   689 public:
       
   690 	void ConstructL(const SCommandLine* aComLine);
       
   691 	~CEikConsAppUi();
       
   692 private: // overridden
       
   693 	TKeyResponse HandleKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);
       
   694 	void HandleForegroundEventL(TBool aForeground);
       
   695 	void SetAndDrawFocus(TBool aFocus);
       
   696 protected:	// from MObjectProvider
       
   697 	virtual TTypeUid::Ptr MopSupplyObject(TTypeUid aId);
       
   698 	virtual MObjectProvider* MopNext();
       
   699 private:
       
   700 	CEikConsoleScreen* iScreen;
       
   701 	CEikConsoleControl* iControl;
       
   702 	CEikConsMessager* iMessager;
       
   703 	};
       
   704 
       
   705 CEikConsAppUi::~CEikConsAppUi()
       
   706 	{
       
   707 	delete(iScreen);
       
   708 	delete(iMessager);
       
   709 	}
       
   710 	
       
   711 void CEikConsAppUi::ConstructL(const SCommandLine* aComLine)
       
   712 	{
       
   713    // CEikAppUi::BaseConstructL(ENoAppResourceFile);
       
   714     CAknAppUi::BaseConstructL(ENoAppResourceFile | ENoScreenFurniture | EAknEnableMSK);
       
   715     iScreen=new(ELeave) CEikConsoleScreen;
       
   716 	iScreen->ConstructL(*(aComLine->iTitle),0);
       
   717 	iControl=iScreen->ConsoleControl();
       
   718 	iControl->SetFocus(ETrue,EDrawNow);
       
   719 	iMessager=new(ELeave) CEikConsMessager(iScreen,aComLine->iParentThread);
       
   720 	iMessager->ConstructL(aComLine->iClient);
       
   721 	RThread().SetPriority(EPriorityMore);
       
   722 	}
       
   723 
       
   724 void CEikConsAppUi::HandleForegroundEventL(TBool aForeground)
       
   725 	{
       
   726 	if (aForeground)
       
   727 		RThread().SetPriority(EPriorityMore);
       
   728 	CEikAppUi::HandleForegroundEventL(aForeground);
       
   729 	}
       
   730 
       
   731 void CEikConsAppUi::SetAndDrawFocus(TBool aFocus)
       
   732 	{
       
   733 	if (iControl)
       
   734 		iControl->SetFocus(aFocus,EDrawNow);
       
   735 	}
       
   736 
       
   737 TKeyResponse CEikConsAppUi::HandleKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
       
   738 	{
       
   739 	iMessager->HandleKeyEventL(aKeyEvent, aType);
       
   740 	return EKeyWasConsumed;
       
   741 	}
       
   742 
       
   743 TTypeUid::Ptr CEikConsAppUi::MopSupplyObject(TTypeUid aId)
       
   744 /** Retrieves an object of the same type as that encapsulated in aId.
       
   745 
       
   746 This function is used to allow to ask owners for access to 
       
   747 other objects that they own.
       
   748 
       
   749 Other than in the case where NULL is returned, the object returned must be 
       
   750 of the same object type - that is, the ETypeId member of the object pointed 
       
   751 to by the pointer returned by this function must be equal to the iUid member 
       
   752 of aId.
       
   753 
       
   754 @param aId An encapsulated object type ID.
       
   755 @return Encapsulates the pointer to the object provided. Note that the encapsulated 
       
   756 pointer may be NULL. */
       
   757 	{
       
   758     if (aId.iUid == ETypeId)
       
   759         {
       
   760         // Touch compatibility mode uses this to detect console application
       
   761         return aId.MakePtr(this);
       
   762         }
       
   763 	return TTypeUid::Null();
       
   764 	}
       
   765 
       
   766 MObjectProvider* CEikConsAppUi::MopNext()
       
   767 /** Retrieves the parent.
       
   768 
       
   769 @return A pointer to an object provider, or NULL if none is defined. 
       
   770 @publishedAll 
       
   771 @released */
       
   772 	{
       
   773 	CEikonEnv* env=(CEikonEnv*)iCoeEnv;
       
   774 	return env->AppUiFactory();
       
   775 	}
       
   776 
       
   777 //
       
   778 // class CConsEikonEnv
       
   779 //
       
   780 
       
   781 class CConsEikonEnv : public CEikonEnv
       
   782 	{
       
   783 public:
       
   784 	void ConstructConsoleEnvironmentL(const SCommandLine* aComLine);
       
   785 
       
   786 #if defined(SYMBIAN_UI_FRAMEWORKS_CONTROL_API_V2)
       
   787 private:
       
   788 	IMPORT_C virtual void CEikonEnv_Reserved_1();
       
   789 	IMPORT_C virtual void CEikonEnv_Reserved_2();
       
   790 	IMPORT_C virtual void CEikonEnv_Reserved_3();
       
   791 	IMPORT_C virtual void CEikonEnv_Reserved_4();
       
   792 	IMPORT_C virtual void CEikonEnv_Reserved_5();
       
   793 	IMPORT_C virtual void CEikonEnv_Reserved_6();
       
   794 	IMPORT_C virtual void CEikonEnv_Reserved_7();
       
   795 	IMPORT_C virtual void CEikonEnv_Reserved_8();
       
   796 	IMPORT_C virtual void CEikonEnv_Reserved_9();
       
   797 	IMPORT_C virtual void CEikonEnv_Reserved_10();	
       
   798 #endif	
       
   799 	};
       
   800 
       
   801 void CConsEikonEnv::ConstructConsoleEnvironmentL(const SCommandLine* aComLine)
       
   802 	{
       
   803 	ConstructL();
       
   804 	CEikConsAppUi* appUi=new(ELeave) CEikConsAppUi;
       
   805 	appUi->ConstructL(aComLine);
       
   806 	CApaWindowGroupName* wgName=CApaWindowGroupName::NewLC(iWsSession);
       
   807 	TPtrC caption=*(aComLine->iTitle);
       
   808 	wgName->SetCaptionL(caption);
       
   809 	wgName->SetRespondsToShutdownEvent(EFalse);
       
   810 	wgName->SetRespondsToSwitchFilesEvent(EFalse);
       
   811 	wgName->SetWindowGroupName(iRootWin);
       
   812 	CleanupStack::PopAndDestroy(); // wgName
       
   813 
       
   814 	User::RenameProcess(caption);
       
   815 	User::RenameThread(caption);
       
   816 	}
       
   817 	
       
   818 #if defined(SYMBIAN_UI_FRAMEWORKS_CONTROL_API_V2)
       
   819 EXPORT_C void CConsEikonEnv::CEikonEnv_Reserved_1()
       
   820 	{
       
   821 	}
       
   822 	
       
   823 EXPORT_C void CConsEikonEnv::CEikonEnv_Reserved_2()
       
   824 	{
       
   825 	}
       
   826 	
       
   827 EXPORT_C void CConsEikonEnv::CEikonEnv_Reserved_3()
       
   828 	{
       
   829 	}
       
   830 	
       
   831 EXPORT_C void CConsEikonEnv::CEikonEnv_Reserved_4()
       
   832 	{
       
   833 	}
       
   834 	
       
   835 EXPORT_C void CConsEikonEnv::CEikonEnv_Reserved_5()
       
   836 	{
       
   837 	}
       
   838 	
       
   839 EXPORT_C void CConsEikonEnv::CEikonEnv_Reserved_6()
       
   840 	{
       
   841 	}
       
   842 	
       
   843 EXPORT_C void CConsEikonEnv::CEikonEnv_Reserved_7()
       
   844 	{
       
   845 	}
       
   846 	
       
   847 EXPORT_C void CConsEikonEnv::CEikonEnv_Reserved_8()
       
   848 	{
       
   849 	}
       
   850 	
       
   851 EXPORT_C void CConsEikonEnv::CEikonEnv_Reserved_9()
       
   852 	{
       
   853 	}
       
   854 	
       
   855 EXPORT_C void CConsEikonEnv::CEikonEnv_Reserved_10()
       
   856 	{
       
   857 	}
       
   858 #endif
       
   859 
       
   860 TInt ConsoleClientStartFunction(TAny* aParam)
       
   861 	{
       
   862 	const SCommandLine* comLine=(const SCommandLine*)aParam;
       
   863 	TInt err=KErrNoMemory;
       
   864     CConsEikonEnv* coe=new CConsEikonEnv;
       
   865 	if (coe)
       
   866 		{
       
   867 		TRAP(err,coe->ConstructConsoleEnvironmentL(comLine));
       
   868 		}
       
   869 	TRequestStatus* pS=(comLine->iStatus);
       
   870 	comLine->iParentThread.RequestComplete(pS,err);
       
   871     if (!err)
       
   872         coe->ExecuteD();
       
   873 	return(0);
       
   874 	}
       
   875 
       
   876 //
       
   877 // class CEikConsoleClient
       
   878 //
       
   879 
       
   880 CEikConsoleClient::~CEikConsoleClient()
       
   881 	{
       
   882 	if (iLogonStatus.Int()==KRequestPending && iReplyStatus)
       
   883 		SendReceive(EExit,NULL);
       
   884 	iThread.Close();
       
   885 	}
       
   886 
       
   887 CEikConsoleClient::CEikConsoleClient()
       
   888 	{
       
   889 	}
       
   890 	
       
   891 const TInt KMaxHeapSize=0x1000*254; // chunks are a megabyte anyway
       
   892 
       
   893 TInt CEikConsoleClient::Create(const TDesC& aTitle,TSize aSize)
       
   894 	{ 
       
   895 	TInt err;
       
   896 	TRequestStatus status=KRequestPending;
       
   897 	SCommandLine comLine;
       
   898 	comLine.iStatus=(&status);
       
   899 	comLine.iClient=this;
       
   900 	comLine.iSize=aSize;
       
   901 	comLine.iTitle=&aTitle;
       
   902 	TBuf<20> threadName;
       
   903 	TInt num=0;
       
   904 	do
       
   905 		{
       
   906 		_LIT(KTemp,"UI%02d");
       
   907 		threadName.Format(KTemp,num++); // !! review the title
       
   908 		err=iThread.Create(threadName,ConsoleClientStartFunction,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&comLine,EOwnerThread);
       
   909 		} while(err==KErrAlreadyExists);
       
   910 	if (!err)
       
   911 		{
       
   912 		iThread.Logon(iLogonStatus);
       
   913 		comLine.iParentThread.Duplicate(iThread);
       
   914 		iThread.Resume();
       
   915 		User::WaitForRequest(status,iLogonStatus);
       
   916 		err=status.Int();
       
   917 		}
       
   918 	return(err);
       
   919 	}
       
   920 
       
   921 void CEikConsoleClient::SendReceive(TInt aMessage,const TAny* aParam)
       
   922 	{
       
   923 	if (iLogonStatus.Int()!=KRequestPending)
       
   924 		User::Exit(KErrCancel);
       
   925 	*iMessage=aMessage;
       
   926 	*iParam=aParam;
       
   927 	TRequestStatus replyStatus=KRequestPending;
       
   928 	*iReplyStatus=(&replyStatus);
       
   929 	TRequestStatus* pS=iThreadStatus;
       
   930 	iThread.RequestComplete(pS,0);
       
   931 	User::WaitForRequest(replyStatus,iLogonStatus);
       
   932 	}
       
   933 
       
   934 void CEikConsoleClient::Read(TRequestStatus& aStatus)
       
   935 	{
       
   936 	aStatus=KRequestPending;
       
   937 	SendReceive(ERead,&aStatus);
       
   938 	}
       
   939 
       
   940 void CEikConsoleClient::ReadCancel()
       
   941 	{
       
   942 	SendReceive(EReadCancel,NULL);
       
   943 	}
       
   944 
       
   945 void CEikConsoleClient::Write(const TDesC& aDes)
       
   946 	{
       
   947 	SendReceive(EWrite,&aDes);
       
   948 	}
       
   949 
       
   950 TPoint CEikConsoleClient::CursorPos() const
       
   951 	{
       
   952 	return(iScreen->CursorPos());
       
   953 	}
       
   954 
       
   955 void CEikConsoleClient::SetCursorPosAbs(const TPoint& aPosition)
       
   956 	{
       
   957 	SendReceive(ESetCursorPosAbs,&aPosition);
       
   958 	}
       
   959 
       
   960 void CEikConsoleClient::SetCursorPosRel(const TPoint &aVector)
       
   961 	{
       
   962 	SendReceive(ESetCursorPosRel,&aVector);
       
   963 	}
       
   964 
       
   965 void CEikConsoleClient::SetCursorHeight(TInt aPercentage)
       
   966 	{
       
   967 	SendReceive(ESetCursorHeight,aPercentage);
       
   968 	}
       
   969 		
       
   970 void CEikConsoleClient::SetTitle(const TDesC& aTitle)
       
   971 	{
       
   972 	SendReceive(ESetTitle,&aTitle);
       
   973 	}
       
   974 
       
   975 void CEikConsoleClient::ClearScreen()
       
   976 	{
       
   977 	SendReceive(EClearScreen,NULL);
       
   978 	}
       
   979 
       
   980 void CEikConsoleClient::ClearToEndOfLine()
       
   981 	{
       
   982 	SendReceive(EClearToEndOfLine,NULL);
       
   983 	}
       
   984 
       
   985 TSize CEikConsoleClient::ScreenSize() const
       
   986 	{
       
   987 	return(iScreen->ScreenSize() );
       
   988 	}
       
   989 
       
   990 TKeyCode CEikConsoleClient::KeyCode() const
       
   991 	{
       
   992 	return((TKeyCode)iKeyEvent.iCode);
       
   993 	}
       
   994 
       
   995 TUint CEikConsoleClient::KeyModifiers() const
       
   996 	{
       
   997 	return(iKeyEvent.iModifiers);
       
   998 	}
       
   999 
       
  1000 extern "C" {
       
  1001 EXPORT_C TAny* NewConsole()
       
  1002 	{
       
  1003 	return(new CEikConsoleClient);
       
  1004 	}
       
  1005 }