×
Namespaces

Variants
Actions

How to read key-input in console applications

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata
Article
Created: giaperrucci (07 Jun 2007)
Last edited: hamishwillee (26 Jul 2012)

This code-snippet show how you can get user input in your console applications – this can be very handy for e.g. implementing a small menu and for simple testing purposes.

We’ll be using the following three functions from the CConsoleBase class:

  • void Read(TRequestStatus) - issues an asynchronous request, waiting for the user to press a key.
  • TKeyCode KeyCode() – return the TKeyCode corresponding to the key pressed.
  • void ReadCancel() – cancels a pending Read request.

As you can see the Read(TRequestStatus) function is an asynchronous function to utilize it probably we need to wrap it in an active object.

The following code snippet shows you how this could implemented in a CKeyInput class (note, error handling and such are not implemented).

KeyInput.h

#ifndef KEYINPUT_H
#define KEYINPUT_H
 
#include <e32base.h>
#include <e32keys.h>
 
 
class MKeyInputObserver
{
public:
virtual TBool ProcessKeyPress(TKeyCode aKey) = 0;
};
 
// Forward declaration
class CConsoleBase;
 
class CKeyInput : public CActive
{
public:
static CKeyInput* NewL(CConsoleBase *aBase, MKeyInputObserver *aObserver);
static CKeyInput* NewLC(CConsoleBase *aBase, MKeyInputObserver *aObserver);
 
void GetKeyPress();
void Stop();
~CKeyInput();
 
private:
void ConstructL();
CKeyInput(CConsoleBase *aBase, MKeyInputObserver *aObserver);
 
private: // From CActive
void RunL();
void DoCancel();
TInt RunError(TInt aError);
 
 
private:
CConsoleBase *iBase;
MKeyInputObserver *iObserver;
 
};
 
 
#endif

As you can see we’re using the observer pattern to propagate incoming key-presses back to an observer of the type MKeyInputObserver, the observer will have to implement the MKeyInputObserver::ProcessKeyPress() function. The observer will also be determining whether the CKeyInput active object should continue reading key input. If the observer returns ETrue from the ProcessKeyPress function the CKeyInput class will continue and issue another read request, if the observer returns EFalse this signals the CKeyInput class that no more input should be read. To see how this is implemented let’s take a look at the CKeyInput class declaration:

KeyInput.cpp

#include "KeyInput.h"
#include <e32cons.h> // Console
 
CKeyInput* CKeyInput::NewL(CConsoleBase *aBase, MKeyInputObserver *aObserver)
{
CKeyInput *self = CKeyInput::NewLC(aBase, aObserver);
CleanupStack::Pop(self);
return self;
}
 
CKeyInput* CKeyInput::NewLC(CConsoleBase *aBase, MKeyInputObserver *aObserver)
{
CKeyInput *self = new (ELeave) CKeyInput(aBase, aObserver);
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
 
void CKeyInput::GetKeyPress()
{
iBase->Read(iStatus);
SetActive();
}
 
CKeyInput::~CKeyInput()
{
Cancel();
}
 
void CKeyInput::ConstructL()
{
}
 
CKeyInput::CKeyInput(CConsoleBase *aBase, MKeyInputObserver *aObserver) :
CActive(EPriorityStandard), iBase(aBase), iObserver(aObserver)
{
CActiveScheduler::Add(this);
}
 
void CKeyInput::RunL()
{
User::LeaveIfError(iStatus.Int());
 
TKeyCode keyCode = iBase->KeyCode();
TBool cont = iObserver->ProcessKeyPress(keyCode);
 
if((int)ETrue == cont)
{
iBase->Read(iStatus);
SetActive();
}
 
}
 
void CKeyInput::DoCancel()
{
iBase->ReadCancel();
}
 
TInt CKeyInput::RunError(TInt aError)
{
// Implement error handling
return KErrNone;
}

Now we’ve done all the groundwork all that’s left is to take advantage of our band new key-input reader class. For a simple example we first need at class working as an observer of our CKeyInput class e.g.


class CConsoleAS : public CBase, public MKeyInputObserver
{
public:
static CConsoleAS* NewLC();
static CConsoleAS* NewL();
~CConsoleAS();
void PrintMenu();
 
 
private:
CConsoleAS();
void ConstructL();
 
private: // From MKeyInputObserver
TBool ProcessKeyPress(TKeyCode aKey);
 
};
 
CConsoleAS* CConsoleAS::NewLC()
{
CConsoleAS *self = new (ELeave) CConsoleAS;
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
 
 
CConsoleAS* CConsoleAS::NewL()
{
CConsoleAS *self = CConsoleAS::NewLC();
CleanupStack::Pop(self);
return self;
}
 
 
CConsoleAS::~CConsoleAS()
{
 
}
 
 
CConsoleAS::CConsoleAS()
{
}
 
 
void CConsoleAS::ConstructL()
{
 
}
 
 
TBool CConsoleAS::ProcessKeyPress(TKeyCode aKey)
{
_LIT(KPrint, "%d");
console->Printf(KPrint, aKey);
if(aKey < 92)
{
// consume
return ETrue;
}
 
switch(aKey)
{
case 92: // 1
{
CActiveScheduler::Stop();
return EFalse;
}
case 97: // 2
{
console->Printf(_L("Hello world!"));
return ETrue;
}
case 100: // 3
{
console->Printf(_L("Why oh why, world?"));
return ETrue;
}
default:
{
_LIT(KUnknown, "Err unkown command\n");
console->Printf(KUnknown);
PrintMenu();
return ETrue;
}
}
}
 
 
void CConsoleAS::PrintMenu()
{
_LIT(KExit, "(1) Exit\n");
console->Printf(KExit);
_LIT(KStartServer, "(2) Start server\n");
console->Printf(KStartServer);
_LIT(KStartClient, "(3) Start client\n");
console->Printf(KStartClient);
}


This class could be used in a simple console application, such as the ones created by the Application Wizards in the following way:

LOCAL_C void MainL()
{
 
CConsoleAS *driver = CConsoleAS::NewLC();
driver->PrintMenu();
CKeyInput *keyInput = CKeyInput::NewLC(console, driver);
keyInput->GetKeyPress();
CActiveScheduler::Start();
 
CleanupStack::PopAndDestroy(2); // CConsoleAS, CKeyInput
 
}


Related Links:

This page was last modified on 26 July 2012, at 03:10.
53 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×