sl@0: // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // Keyboard repeat test
sl@0: // 
sl@0: //
sl@0: 
sl@0: #include <e32std.h>
sl@0: #include <e32svr.h>
sl@0: #include "W32STD.H"
sl@0: #include "../tlib/testbase.h"
sl@0: #include "TMAN.H"
sl@0: 
sl@0: class CRKWindow;
sl@0: 
sl@0: class TKRepeatTest : public CTestBase
sl@0: 	{
sl@0: public:
sl@0: 	TKRepeatTest();
sl@0: 	~TKRepeatTest();
sl@0: 	TestState DoTestL();
sl@0: 	void ConstructL();
sl@0: 	void TestKeyboardRepeatRateL(const TTimeIntervalMicroSeconds32 &aInitialTime, const TTimeIntervalMicroSeconds32 &aTime);
sl@0: 	TBool CheckReportL();
sl@0: public:
sl@0: 	TBool iAbort;
sl@0: private:
sl@0: 	TTimeIntervalMicroSeconds32 iOldInitialTime;
sl@0: 	TTimeIntervalMicroSeconds32 iOldTime;
sl@0: 	CRKWindow *iWin;
sl@0: 	TSize iWinSize;
sl@0: 	TInt iState;
sl@0: 	};
sl@0: 
sl@0: class CRKWindow : public CTWin
sl@0: 	{
sl@0: 	enum TRKStates {
sl@0: 		EStateWaitingForKeyDown,
sl@0: 		EStateWaitingForKeyCode,
sl@0: 		EStateWaitingForFirstRepeat,
sl@0: 		EStateWaitingForNthRepeat,
sl@0: 		EStateWaitingForKeyUp,
sl@0: 		EStateInactive,
sl@0: 		EStateError,
sl@0: 		};
sl@0: public:
sl@0: 	CRKWindow(TKRepeatTest *aTest);
sl@0: 	void SetUpL(TPoint pos,TSize size,CTWinBase *parent, CWindowGc &aGc);
sl@0: 	void SetState(TRKStates aState);
sl@0: 	void SetKeyboardRepeatRate(const TTimeIntervalMicroSeconds32 &aInitialTime, const TTimeIntervalMicroSeconds32 &aTime);
sl@0: 	void WinKeyL(const TKeyEvent &,const TTime &);
sl@0: 	void KeyUpL(const TKeyEvent &aKey,const TTime &aTime);
sl@0: 	void KeyDownL(const TKeyEvent &aKey,const TTime &aTime);
sl@0: 	void Draw();
sl@0: 	TDesC& Report();
sl@0: 	TBool CheckResults();
sl@0: protected:
sl@0: 	TInt iConnIndex;
sl@0: 	TKRepeatTest *iTest;
sl@0: 	TRgb iBack;
sl@0: 	TRKStates iState;
sl@0: 	TInt iDownCode;
sl@0: 	TInt iRepCount;
sl@0: 	TTimeIntervalMicroSeconds32 iInitialRepeatSet;
sl@0: 	TTimeIntervalMicroSeconds32 iRepeatSet;
sl@0: 	TTime iPrevTime;
sl@0: 	TTimeIntervalMicroSeconds32 iInitialGap;
sl@0: 	TTimeIntervalMicroSeconds32 iTotalGap;
sl@0: 	TTimeIntervalMicroSeconds32 iMinGap;
sl@0: 	TTimeIntervalMicroSeconds32 iMaxGap;
sl@0: 	TBuf<0x40> iReport;
sl@0: 	};
sl@0: 
sl@0: GLDEF_C CTestBase *CreateKRepeatTest()
sl@0: 	{
sl@0: 	return(new(ELeave) TKRepeatTest());
sl@0: 	}
sl@0: 
sl@0: //
sl@0: // CRKWindow, class //
sl@0: //
sl@0: 
sl@0: CRKWindow::CRKWindow(TKRepeatTest *aTest) : CTWin(), iTest(aTest)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: void CRKWindow::SetUpL(TPoint pos,TSize size,CTWinBase *parent, CWindowGc &aGc)
sl@0: 	{
sl@0: 	ConstructExtLD(*parent,pos,size);
sl@0: 	iWin.SetBackgroundColor(TRgb::Gray256(230));
sl@0: 	Activate();
sl@0: 	AssignGC(aGc);
sl@0: 	}
sl@0: 
sl@0: void CRKWindow::Draw()
sl@0: 	{
sl@0: 	iGc->Clear();
sl@0: 	switch(iState)
sl@0: 		{
sl@0: 		case EStateWaitingForKeyDown:
sl@0: 			iGc->DrawText(_L("Press and hold the space bar"), TPoint(10,20));
sl@0: 			break;
sl@0: 		case EStateWaitingForFirstRepeat:
sl@0: 		case EStateWaitingForNthRepeat:
sl@0: 			{
sl@0: 			TBuf<0x40> buf;
sl@0: 			buf.Format(TRefByValue<const TDesC>(_L("Keep space bar down (%d repeats so far)")),iRepCount);
sl@0: 			iGc->DrawText(buf, TPoint(10,20));
sl@0: 			}
sl@0: 			break;
sl@0: 		case EStateWaitingForKeyUp:
sl@0: 			iGc->DrawText(_L("Release space bar"), TPoint(10,20));
sl@0: 		default:
sl@0: 			break;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void CRKWindow::SetState(TRKStates aState)
sl@0: 	{
sl@0: 	iState=aState;
sl@0: 	DrawNow();
sl@0: 	}
sl@0: 
sl@0: TBool CRKWindow::CheckResults()
sl@0: 	{
sl@0: //
sl@0: // Checks repeat results, first convert everything to 10th's as that what is actually used 
sl@0: // for the timer in the window server.
sl@0: //
sl@0: // Return ETrue if the inacuracy in the average time is greater than 1/10th either way
sl@0: // Allow initial 2/10ths either
sl@0: // Allow min 2/10ths below
sl@0: // Allow max 2/10ths above
sl@0: //
sl@0: 	if (iState!=EStateInactive)
sl@0: 		return(ETrue);
sl@0: 	TInt initial=iInitialGap.Int()/100000;
sl@0: 	TInt initialX=iInitialRepeatSet.Int()/100000;
sl@0: 	if (initialX==0)
sl@0: 		initialX=1;
sl@0: 	TInt average=(iTotalGap.Int()/100000)/(iRepCount-1);
sl@0: 	TInt repeatX=iRepeatSet.Int()/100000;
sl@0: 	if (repeatX==0)
sl@0: 		repeatX=1;
sl@0: 	TInt min=iMinGap.Int()/100000;
sl@0: 	TInt max=iMaxGap.Int()/100000;
sl@0: 	if (average>(repeatX+1) || average<(repeatX-1))
sl@0: 		return(ETrue);
sl@0: 	if (initial>(initialX+2) || initial<(initialX-2))
sl@0: 		return(ETrue);
sl@0: 	if (min>(repeatX+1) || min<(repeatX-2))
sl@0: 		return(ETrue);
sl@0: 	if (max>(repeatX+3) || max<repeatX)
sl@0: 		return(ETrue);
sl@0: 	return(EFalse);
sl@0: 	}
sl@0: 
sl@0: TDesC& CRKWindow::Report()
sl@0: 	{
sl@0: 	if (iState!=EStateInactive)
sl@0: 		{
sl@0: 		iReport.Format(_L("Error, test not completed"));
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		TInt initial=iInitialGap.Int()/10000;
sl@0: 		TInt initialX=iInitialRepeatSet.Int()/10000;
sl@0: 		TInt average=(iTotalGap.Int()/10000/(iRepCount-1));
sl@0: 		TInt repeatX=iRepeatSet.Int()/10000;
sl@0: 		TInt min=iMinGap.Int()/10000;
sl@0: 		TInt max=iMaxGap.Int()/10000;
sl@0: 		iReport.Format(TRefByValue<const TDesC>(_L("Initial=%d [%d], Av=%d [%d], Min=%d, Max=%d")),initial,initialX,average,repeatX,min,max);
sl@0: 		}
sl@0: 	return(iReport);
sl@0: 	}
sl@0: 
sl@0: void CRKWindow::KeyDownL(const TKeyEvent &aKey,const TTime &)
sl@0: 	{
sl@0: 	switch(iState)
sl@0: 		{
sl@0: 		case EStateWaitingForKeyDown:
sl@0: 			SetState(EStateWaitingForKeyCode);
sl@0: 			iDownCode=aKey.iScanCode;
sl@0: 			break;
sl@0: 		default:;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void CRKWindow::KeyUpL(const TKeyEvent &aKey,const TTime &)
sl@0: 	{
sl@0: 	if (aKey.iScanCode==iDownCode)
sl@0: 		{
sl@0: 		switch(iState)
sl@0: 			{
sl@0: 			case EStateWaitingForKeyUp:
sl@0: 				SetState(EStateInactive);
sl@0: 				break;
sl@0: 			default:
sl@0: 				SetState(EStateError);
sl@0: 				break;
sl@0: 			}
sl@0: 		CActiveScheduler::Stop();
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void CRKWindow::WinKeyL(const TKeyEvent &aKey,const TTime &aTime)
sl@0: 	{
sl@0: 	if (aKey.iCode==EKeyEscape)
sl@0: 		{
sl@0: 		CActiveScheduler::Stop();
sl@0: 		iTest->iAbort=ETrue;
sl@0: 		}
sl@0: 	if (aKey.iCode==32)
sl@0: 		{
sl@0: 		switch(iState)
sl@0: 			{
sl@0: 			case EStateWaitingForKeyCode:
sl@0: 				SetState(EStateWaitingForFirstRepeat);
sl@0: 				iPrevTime=aTime;
sl@0: 				break;
sl@0: 			case EStateWaitingForFirstRepeat:
sl@0: 				iRepCount=1;
sl@0: 				iInitialGap = I64LOW(aTime.MicroSecondsFrom(iPrevTime).Int64());
sl@0: 				SetState(EStateWaitingForNthRepeat);
sl@0: 				break;
sl@0: 			case EStateWaitingForNthRepeat:
sl@0: 				if (iRepCount==5)
sl@0: 					SetState(EStateWaitingForKeyUp);
sl@0: 				else
sl@0: 					{
sl@0: 					TTimeIntervalMicroSeconds32 gap(I64LOW(aTime.MicroSecondsFrom(iPrevTime).Int64()));
sl@0: 					if (gap<iMinGap)
sl@0: 						iMinGap=gap;
sl@0: 					if (gap>iMaxGap)
sl@0: 						iMaxGap=gap;
sl@0: 					iTotalGap=iTotalGap.Int()+gap.Int();	// Horrible way to do a +=
sl@0: 					iRepCount++;
sl@0: 					SetState(EStateWaitingForNthRepeat);
sl@0: 					}
sl@0: 			case EStateWaitingForKeyUp: 	// Do nothing here
sl@0: 				break;
sl@0: 			default:
sl@0: 				iTest->TestL(EFalse);
sl@0: 			}
sl@0: 		iPrevTime=aTime;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void CRKWindow::SetKeyboardRepeatRate(const TTimeIntervalMicroSeconds32 &aInitialTime, const TTimeIntervalMicroSeconds32 &aTime)
sl@0: 	{
sl@0: 	iInitialRepeatSet=aInitialTime;
sl@0: 	iRepeatSet=aTime;
sl@0: 	iMinGap=TTimeIntervalMicroSeconds32(100000000);	// Any very big number will do
sl@0: 	iMaxGap=TTimeIntervalMicroSeconds32(0);
sl@0: 	iTotalGap=TTimeIntervalMicroSeconds32(0);
sl@0: 	SetState(EStateWaitingForKeyDown);
sl@0: 	Client()->iWs.Flush();
sl@0: 	}
sl@0: 
sl@0: //
sl@0: 
sl@0: TKRepeatTest::TKRepeatTest() : CTestBase(_L("KRepeat"))
sl@0: 	{}
sl@0: 
sl@0: TKRepeatTest::~TKRepeatTest()
sl@0: 	{
sl@0: 	CTWin::Delete(iWin);
sl@0: 	Client()->iWs.SetKeyboardRepeatRate(iOldInitialTime, iOldTime);
sl@0: 	}
sl@0: 
sl@0: void TKRepeatTest::ConstructL()
sl@0: 	{
sl@0: 	iWin=new(ELeave) CRKWindow(this);
sl@0: 	TSize screenSize=Client()->iGroup->Size();
sl@0: 	iWin->SetUpL(TPoint(5,5),TSize(screenSize.iWidth/2,screenSize.iHeight-10),Client()->iGroup,*Client()->iGc);
sl@0: 	Client()->iGroup->SetCurrentWindow(iWin);
sl@0: 	Client()->iWs.GetKeyboardRepeatRate(iOldInitialTime, iOldTime);
sl@0: 	}
sl@0: 
sl@0: TInt TKRepeatTest::CheckReportL()
sl@0: 	{
sl@0: 	if (iWin->CheckResults())
sl@0: 		{
sl@0: 		CTDialog *dialog=new(ELeave) CTDialog();
sl@0: 		dialog->SetTitle(_L("Keyboard repeat innacuracies"));
sl@0: 		dialog->SetLine1(iWin->Report());
sl@0: 		dialog->SetNumButtons(2);
sl@0: 		dialog->SetButtonText(0,_L("Okay"));
sl@0: 		dialog->SetButtonText(1,_L("Retest"));
sl@0: 		dialog->SetButtonText(2,_L("Fail"));
sl@0: 		dialog->ConstructLD(*Client()->iGroup,*Client()->iGc);
sl@0: 		switch(dialog->Display())
sl@0: 			{
sl@0: 			case 0:
sl@0: 				break;
sl@0: 			case 1:
sl@0: 				return(ETrue);	// Redo test
sl@0: 			case 2:
sl@0: 				TestL(EFalse);
sl@0: 				break;
sl@0: 			}
sl@0: 		}
sl@0: 	return(EFalse);
sl@0: 	}
sl@0: 
sl@0: void TKRepeatTest::TestKeyboardRepeatRateL(const TTimeIntervalMicroSeconds32 &aInitialTime, const TTimeIntervalMicroSeconds32 &aTime)
sl@0: 	{
sl@0: 	do
sl@0: 		{
sl@0: 		Client()->iWs.SetKeyboardRepeatRate(aInitialTime, aTime);
sl@0: 		iWin->SetKeyboardRepeatRate(aInitialTime, aTime);
sl@0: 		CActiveScheduler::Start();
sl@0: 		if (iAbort)
sl@0: 			AbortL();
sl@0: 		} while(CheckReportL());
sl@0: 	}
sl@0: 
sl@0: TestState TKRepeatTest::DoTestL()
sl@0: 	{
sl@0: 	switch(iState)
sl@0: 		{
sl@0: 		case 0:
sl@0: 			LogSubTest(_L("Keyboard Repeat"),1);
sl@0: 			TestKeyboardRepeatRateL(TTimeIntervalMicroSeconds32(1000000), TTimeIntervalMicroSeconds32(500000));
sl@0: 			LogSubTest(_L("Keyboard Repeat"),2);
sl@0: 			TestKeyboardRepeatRateL(TTimeIntervalMicroSeconds32(200000), TTimeIntervalMicroSeconds32(100000));
sl@0: 			LogSubTest(_L("Keyboard Repeat"),3);
sl@0: 			TestKeyboardRepeatRateL(TTimeIntervalMicroSeconds32(0), TTimeIntervalMicroSeconds32(100000));
sl@0: 			LogSubTest(_L("Keyboard Repeat"),4);
sl@0: 			TestKeyboardRepeatRateL(TTimeIntervalMicroSeconds32(100000), TTimeIntervalMicroSeconds32(100000));
sl@0: 			iState++;
sl@0: 			break;
sl@0: 		default:
sl@0: 			return(EFinished);
sl@0: 		}
sl@0: 	return(ENext);
sl@0: 	}
sl@0: