📄 iomain.cpp
字号:
// IOMAIN.CPP
//
// Copyright (c) 1997-2002 Symbian Ltd. All rights reserved.
#include <oplr.h>
#include "iodef.h"
#include "iodev.h"
#include "oplutil.h"
#include <coemain.h>
#if !defined(__S80_DP2_0__)
#include <eikkeys.h>
#endif
#include <apgtask.h>
#include "clckupdt.h"
#include <fepbase.h>
#include <e32def.h>
#if defined(__UIQ__)
#include <quartzkeys.h>
#endif
#if defined(__SERIES60__)
#include <aknappui.h>
#include <coecntrl.h>
#endif
_LIT(KLitC, "C");
_LIT(KLitO, "O");
_LIT(KLitF, "F");
_LIT(KLitX, "X");
_LIT(KLitS, "S");
_LIT(KLitR, "R");
_LIT(KLitU, "U");
_LIT(KOplIOSystem,"Opl IO system");
const TInt KShelfLifeOfUnhandledUserEvents=10*1000000; // 10 seconds
const TInt KMaxNestedDialogDepth=16; // Max number of nested dialogs that the runtime can handle.
enum
{
EOplEventUnknown = 0x1400
};
class TSingleEventSource : public MEventSource
{
public:
inline TSingleEventSource(TRequestStatus& aRequestStatus, TInt aPriority) :iRequestStatus(aRequestStatus), iPriority(aPriority) {}
private:
// from MEventSource
virtual void CancelRequest();
virtual TRequestStatus& RequestStatus();
virtual TInt Priority() const;
private:
TRequestStatus& iRequestStatus;
TInt iPriority;
};
void TSingleEventSource::CancelRequest()
// This function should never get called as objects of this class should
// only ever be the *only* event source being waited on (aUserEventsRequired must be
// EUserEventsNone, aArrayOfAdditionalEventSources must only contain this object)
{
#ifdef _DEBUG
User::Panic(KOplIOSystem,6);
#endif
}
TRequestStatus& TSingleEventSource::RequestStatus()
{
return iRequestStatus;
}
TInt TSingleEventSource::Priority() const
{
return iPriority;
}
//
// Class TTimerEventSource
//
class TTimerEventSource : public MEventSource
{
public:
inline TTimerEventSource(RTimer& aActiveTimer, TRequestStatus& aRequestStatus, TInt aPriority) :iActiveTimer(aActiveTimer), iRequestStatus(aRequestStatus), iPriority(aPriority) {}
private:
// from MEventSource
virtual void CancelRequest();
virtual TRequestStatus& RequestStatus();
virtual TInt Priority() const;
private:
RTimer& iActiveTimer;
TRequestStatus& iRequestStatus;
TInt iPriority;
};
void TTimerEventSource::CancelRequest()
{
iActiveTimer.Cancel();
}
TRequestStatus& TTimerEventSource::RequestStatus()
{
return iRequestStatus;
}
TInt TTimerEventSource::Priority() const
{
return iPriority;
}
//
// Class CEventQueue
//
class CEventQueue : public CBase, public CCoeFep::MKeyEventQueue
{
public:
static CEventQueue* NewL();
virtual ~CEventQueue();
inline TBool IsNotEmpty() const {return (iQueue.Count()>iNumberOfEventsInBackupRegion);}
inline TBool BackupIsEmpty() const {return (iNumberOfEventsInBackupRegion==0);}
inline void PeekNextEvent(TWsEvent& aEvent) const {aEvent=iQueue[iNumberOfEventsInBackupRegion];}
inline void ConsumeNextEvent() {RemoveEventAdjustingNumberOfExpiringEvents(iNumberOfEventsInBackupRegion);}
inline void PutNextEventInBackup() {++iNumberOfEventsInBackupRegion;}
void RestoreAllEventsFromBackup();
void PurgeAllNonKeyEvents();
void PrepareToStartActiveScheduler();
void NotifyActiveSchedulerStopped();
TInt AppendEvent(const TWsEvent& aEvent);
// from CCoeFep::MKeyEventQueue
virtual void AppendKeyEventL(const TKeyEvent& aKeyEvent);
private:
class CTimeOutTimer : private CTimer
{
public:
static CTimeOutTimer* NewL(CEventQueue& aEventQueue);
void Activate();
void Deactivate();
private:
CTimeOutTimer(CEventQueue& aEventQueue);
virtual void RunL();
private:
CEventQueue& iEventQueue;
};
friend class CTimeOutTimer;
private:
CEventQueue();
void ConstructL();
void RemoveEventAdjustingNumberOfExpiringEvents(TInt aIndex);
void PurgeAllExpiringEvents();
private:
RArray<TWsEvent> iQueue;
CTimeOutTimer* iTimeOutTimer;
TInt iNumberOfEventsInBackupRegion;
TInt iNumberOfExpiringEvents;
};
CEventQueue* CEventQueue::NewL()
{
CEventQueue* eventQueue=new(ELeave) CEventQueue;
CleanupStack::PushL(eventQueue);
eventQueue->ConstructL();
CleanupStack::Pop(); // eventQueue
return eventQueue;
}
CEventQueue::~CEventQueue()
{
iQueue.Close();
delete iTimeOutTimer;
}
void CEventQueue::RestoreAllEventsFromBackup()
{
CWsEventHandler::Signal(iNumberOfEventsInBackupRegion);
iNumberOfEventsInBackupRegion=0;
}
void CEventQueue::PurgeAllNonKeyEvents()
{
__ASSERT_DEBUG(BackupIsEmpty(), User::Panic(KOplIOSystem, 24));
for (TInt i=iQueue.Count()-1; i>=0; --i)
{
if (iQueue[i].Type()!=EEventKey)
{
RemoveEventAdjustingNumberOfExpiringEvents(i);
User::WaitForAnyRequest(); // returns straightaway as we're consuming the signal
// associated with the event that has just been taken
// out of iQueue
}
}
}
void CEventQueue::PrepareToStartActiveScheduler()
{
// Empty the queue and stop the timer for purging old unhandled events
iNumberOfExpiringEvents=iQueue.Count();
PurgeAllExpiringEvents();
iTimeOutTimer->Deactivate();
}
void CEventQueue::NotifyActiveSchedulerStopped()
{
iTimeOutTimer->Activate();
}
TInt CEventQueue::AppendEvent(const TWsEvent& aEvent)
{
const TInt error=iQueue.Append(aEvent);
if (error==KErrNone)
{
CWsEventHandler::Signal(1);
}
return error;
}
void CEventQueue::AppendKeyEventL(const TKeyEvent& aKeyEvent)
{
TWsEvent event;
event.SetType(EEventKey);
event.SetHandle(NULL);
event.SetTimeNow();
*event.Key()=aKeyEvent;
User::LeaveIfError(AppendEvent(event));
}
CEventQueue::CEventQueue()
:iQueue(10),
iNumberOfEventsInBackupRegion(0),
iNumberOfExpiringEvents(0)
{
}
void CEventQueue::ConstructL()
{
iTimeOutTimer=CTimeOutTimer::NewL(*this);
iTimeOutTimer->Activate();
}
void CEventQueue::RemoveEventAdjustingNumberOfExpiringEvents(TInt aIndex)
{
iQueue.Remove(aIndex);
if (aIndex<iNumberOfExpiringEvents)
{
--iNumberOfExpiringEvents;
}
}
void CEventQueue::PurgeAllExpiringEvents()
{
for (TInt i=iNumberOfExpiringEvents-1; i>=0; --i)
{
iQueue.Remove(i);
if (i>=iNumberOfEventsInBackupRegion)
{
User::WaitForAnyRequest(); // returns straightaway as we're consuming the signal
// associated with the event that has just been taken
// out of iQueue
}
}
iNumberOfExpiringEvents=iQueue.Count();
}
//
// Class CEventQueue::CTimeOutTimer
//
CEventQueue::CTimeOutTimer* CEventQueue::CTimeOutTimer::NewL(CEventQueue& aEventQueue)
{
CTimeOutTimer* timeOutTimer=new(ELeave) CTimeOutTimer(aEventQueue);
CleanupStack::PushL(timeOutTimer);
timeOutTimer->ConstructL();
CleanupStack::Pop(); // timeOutTimer
return timeOutTimer;
}
void CEventQueue::CTimeOutTimer::Activate()
{
After(TTimeIntervalMicroSeconds32(KShelfLifeOfUnhandledUserEvents));
}
void CEventQueue::CTimeOutTimer::Deactivate()
{
Cancel();
}
CEventQueue::CTimeOutTimer::CTimeOutTimer(CEventQueue& aEventQueue)
:CTimer(EActivePriorityDefault),
iEventQueue(aEventQueue)
{
CActiveScheduler::Add(this);
}
void CEventQueue::CTimeOutTimer::RunL()
{
iEventQueue.PurgeAllExpiringEvents();
Activate();
}
//
// Class CSignalBuffer
//
// This is a *very* non-standard active-derived class - it's used to temporarily
// buffer any signals from OPL asynchonous requests that complete whilst
// we're executing CActiveScheduler::Start (e.g. when displaying a dialog)
class CSignalBuffer : public CActive
{
public:
static CSignalBuffer* NewL();
virtual ~CSignalBuffer();
void StartBufferingAnyUnhandledSignals();
void StopBufferingAndReplaceAnyBufferedSignals();
private:
CSignalBuffer();
virtual void DoCancel();
virtual void RunL();
private:
TInt iNumberOfBufferedSignals;
};
CSignalBuffer* CSignalBuffer::NewL()
{
return new(ELeave) CSignalBuffer;
}
CSignalBuffer::~CSignalBuffer()
{
Cancel();
CWsEventHandler::Signal(iNumberOfBufferedSignals);
}
void CSignalBuffer::StartBufferingAnyUnhandledSignals()
{
SetActive();
}
void CSignalBuffer::StopBufferingAndReplaceAnyBufferedSignals()
{
// Stop buffering
__ASSERT_ALWAYS(IsActive(), User::Panic(KOplIOSystem, 11));
Cancel();
// Restore any buffered signals
CWsEventHandler::Signal(iNumberOfBufferedSignals);
iNumberOfBufferedSignals=0;
}
CSignalBuffer::CSignalBuffer()
:CActive(KMinTInt),
iNumberOfBufferedSignals(0)
{
iStatus=KErrNone;
CActiveScheduler::Add(this);
}
void CSignalBuffer::DoCancel()
{
CWsEventHandler::Signal(1); // Generate a signal for Cancel to consume to pretend that we're
// a normal CActive-derived class (objects of this class actually
// have *no* signal associated with them, even when IsActive(),
// hence the need for this signal here)
}
void CSignalBuffer::RunL()
{
++iNumberOfBufferedSignals;
SetActive();
}
//
// Class TArrayOfAdditionalEventSources
//
class TArrayOfAdditionalEventSources
{
public:
TArrayOfAdditionalEventSources(const TArray<MEventSource*>& aArrayOfAdditionalEventSources);
inline TBool AtLeastOneHasCompletedAndBeenConsumed() const {return (iBitArrayOfCompletedAdditionalEventSourcesConsumed!=0);}
const MEventSource* CompletedAdditionalEventSourceWithHighestPriority() const;
void MarkAsConsumed(const MEventSource* aEventSource); // to be passed what has been returned
// by CompletedAdditionalEventSourceWithHighestPriority
void CancelAll();
private:
inline TBool HasNotBeenConsumed(TInt aIndex) const {return ((iBitArrayOfCompletedAdditionalEventSourcesConsumed&(1<<aIndex))==0);}
inline void MarkAsConsumed(TInt aIndex) {__ASSERT_DEBUG((iArrayOfAdditionalEventSources[aIndex]->RequestStatus()!=KRequestPending) && HasNotBeenConsumed(aIndex), User::Panic(KOplIOSystem, 5)); iBitArrayOfCompletedAdditionalEventSourcesConsumed|=(1<<aIndex);}
private:
const TArray<MEventSource*>& iArrayOfAdditionalEventSources;
TUint iBitArrayOfCompletedAdditionalEventSourcesConsumed;
};
TArrayOfAdditionalEventSources::TArrayOfAdditionalEventSources(const TArray<MEventSource*>& aArrayOfAdditionalEventSources)
:iArrayOfAdditionalEventSources(aArrayOfAdditionalEventSources),
iBitArrayOfCompletedAdditionalEventSourcesConsumed(0)
{
__ASSERT_DEBUG(aArrayOfAdditionalEventSources.Count()<=(TInt)sizeof(TUint)*8, User::Panic(KOplIOSystem, 8));
}
const MEventSource* TArrayOfAdditionalEventSources::CompletedAdditionalEventSourceWithHighestPriority() const
{
const MEventSource* completedAdditionalEventSourceWithHighestPriority=NULL;
for (TInt i=iArrayOfAdditionalEventSources.Count()-1; i>=0; --i)
{
MEventSource& eventSource=*iArrayOfAdditionalEventSources[i];
if ((eventSource.RequestStatus()!=KRequestPending) && HasNotBeenConsumed(i))
{
if ((completedAdditionalEventSourceWithHighestPriority==NULL) || (eventSource.Priority()>completedAdditionalEventSourceWithHighestPriority->Priority()))
{
completedAdditionalEventSourceWithHighestPriority=&eventSource;
}
}
}
return completedAdditionalEventSourceWithHighestPriority;
}
void TArrayOfAdditionalEventSources::MarkAsConsumed(const MEventSource* aEventSource)
{
for (TInt i=iArrayOfAdditionalEventSources.Count()-1; ; --i)
{
__ASSERT_ALWAYS(i>=0, User::Panic(KOplIOSystem, 4));
if (iArrayOfAdditionalEventSources[i]==aEventSource)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -