Symbian源码分析(转)

Symbian源码分析:拷贝8位描述符到16位的方法

 

如果直接用Copy函数的话,16位描述符的长度会被设为8位的长度,如果是ASCII码的话没有问题,中文的话就会乱码,看看Copy函数的源代码:
EXPORT_C void TDes16::Copy(const TDesC8 &aDes)
        {
        TInt len=aDes.Length();
        SetLength(len);
        const TUint8 *pS=aDes.Ptr();
        const TUint8 *pE=pS+len;
        TUint16 *pT=WPtr();
        while (pS<pE)
                *pT++=(*pS++);
        }
可以看到,16位描述符长度被设为和8位描述符一样,pT一次跳16位,即2个字节,而pS一次跳8位,以保证对其。
如果是中文的话,应该直接取TDesC8的指针,转为TUint16*拷贝:
TBuf<0x50> des;
des.Copy((TUint16*)des8.Ptr(), des8.Length() >> 1);
这里用到的是Copy的重载函数:
EXPORT_C void TDes16::Copy(const TUint16 *aBuf,TInt aLength)
        {
        __CHECK_ALIGNMENT(aBuf,ETDes16CopyBufLength);
        SetLength(aLength);
    memCopy(WPtr(),aBuf,aLength);
        }

 

Symbian之源码分析之EikEnv.cpp

这篇着重讲下里面CEikonEnv相关的几句:

CEikonEnv* env = new CEikonEnv;

TRAP(error, env->ConstructAppFromCommandLineL(aApplicationFactory, *commandLine));

env->Execute();

env->DestroyEnvironment();

一、创建CEikonEnv实例

CEikonEnv的默认构造函数实现为空,但是其基类CCoeEnv的构造函数做了些事情:

CCoeEnv::CCoeEnv() : CActive(EActivePriorityWsEvents)

{

TInt error=KErrNone;

//conenv已经存在时抛cone 2异常

__ASSERT_ALWAYS(!TheCoe(),Panic(ECoePanicEnvironmentAlreadyExists));

//设置当前conenv

if (error==KErrNone)

error=SetTheCoe(this);

//初始化清理栈,注意用的是New()而不是NewL()

iCleanup=CTrapCleanup::New();

if ((iCleanup==NULL) && (error==KErrNone))

error=KErrNoMemory;

//不能在这里抛异常,否则iCleanup对象所分配的内存将永远无法收回。

//所以在这里需要一个标记,在CCoeEnv::ConstructL里会处理。

if (error!=KErrNone)

{

iExtra=REINTERPRET_CAST(CCoeEnvExtra*, error);

iEnvFlags|=EExtraPointerIsErrorCode;

}

}

二、创建应用程序

这部分代码比较多,本篇先说到调用CEikonEnv::ConstructL()为止。

CEikonEnv::ConstructAppFromCommandLineL(const TApaApplicationFactory& aApplicationFactory,const CApaCommandLine& aCommandLine)

{

// Construct iEikEnvExtra here so that the app language can be stored in it

if (!iEikEnvExtra)

iEikEnvExtra = CEikEnvExtra::NewL(*this);

//连接AppArc server

RApaLsSession apparcServer;

CleanupClosePushL(apparcServer);

TInt err = apparcServer.Connect();

//保存程序Language到iEikEnvExtra->iAppLanguage及baflutils里

StoreAppLanguageL(apparcServer);

//设置默认screen

if (aCommandLine.IsDefaultScreenSet()) //如果命令行参数有设置过

第1页 第2页 第3页 第4页 第5页

这篇着重讲下里面CEikonEnv相关的几句:

CEikonEnv* env = new CEikonEnv;

TRAP(error, env->ConstructAppFromCommandLineL(aApplicationFactory, *commandLine));

env->Execute();

env->DestroyEnvironment();

一、创建CEikonEnv实例

CEikonEnv的默认构造函数实现为空,但是其基类CCoeEnv的构造函数做了些事情:

CCoeEnv::CCoeEnv() : CActive(EActivePriorityWsEvents)

{

TInt error=KErrNone;

//conenv已经存在时抛cone 2异常

__ASSERT_ALWAYS(!TheCoe(),Panic(ECoePanicEnvironmentAlreadyExists));

//设置当前conenv

if (error==KErrNone)

error=SetTheCoe(this);

//初始化清理栈,注意用的是New()而不是NewL()

iCleanup=CTrapCleanup::New();

if ((iCleanup==NULL) && (error==KErrNone))

error=KErrNoMemory;

//不能在这里抛异常,否则iCleanup对象所分配的内存将永远无法收回。

//所以在这里需要一个标记,在CCoeEnv::ConstructL里会处理。

if (error!=KErrNone)

{

iExtra=REINTERPRET_CAST(CCoeEnvExtra*, error);

iEnvFlags|=EExtraPointerIsErrorCode;

}

}

二、创建应用程序

这部分代码比较多,本篇先说到调用CEikonEnv::ConstructL()为止。

CEikonEnv::ConstructAppFromCommandLineL(const TApaApplicationFactory& aApplicationFactory,const CApaCommandLine& aCommandLine)

{

// Construct iEikEnvExtra here so that the app language can be stored in it

if (!iEikEnvExtra)

iEikEnvExtra = CEikEnvExtra::NewL(*this);

//连接AppArc server

RApaLsSession apparcServer;

CleanupClosePushL(apparcServer);

TInt err = apparcServer.Connect();

//保存程序Language到iEikEnvExtra->iAppLanguage及baflutils里

StoreAppLanguageL(apparcServer);

//设置默认screen

if (aCommandLine.IsDefaultScreenSet()) //如果命令行参数有设置过

第1页 第2页 第3页 第4页 第5页

接上页

iEikEnvExtra->iDefaultScreenNumber = aCommandLine.DefaultScreen();

else

{ //否则用apparc保存的默认screen

if (!err)

err = apparcServer.GetDefaultScreenNumber(iEikEnvExtra->iDefaultScreenNumber, RProcess().Type()[2]);

if (err)

iEikEnvExtra->iDefaultScreenNumber = 0;

}

//关闭AppArc server session

CleanupStack::PopAndDestroy(&apparcServer);

//创建应用程序环境,调用CEikonEnv::ConstructL()

const TBool startAppInForeground = (command!=EApaCommandBackground && command!=EApaCommandBackgroundAndWithoutViews);

ConstructL(startAppInForeground, aCommandLine.ParentWindowGroupID());

……

}

CEikEnv::ConstructL()

{

//调用基类ConstructL()

CCoeEnv::ConstructL()

//一系列初始化

……

//似乎加载dll库的地方在这里

LoadLibrariesL();

}

CCoeEnv::ConstructL()

{

//创建iExtra

iExtra=new(ELeave) CCoeEnvExtra;

iExtra->ConstructL();

//创建ActiveScheduler

CreateActiveSchedulerL();

CActiveScheduler::Add(this);

//一系列初始化sessions、screen、gc、font等等

ConnectToFileServerL();

ConnectToWindowServerL();

InitScreenL( aDefaultScreenNumber); // Modified May 04 support for Multiple Screens.

InitRootWindowL(aInitialFocusState, aWindowGroupID);

InitSystemFontsL();

InitSystemGcL();

……

//等待WSERV的事件

iWsSession.EventReady(&iStatus);

SetActive();

//当RunL被调用时,会先调用iAppUi->MonitorWsEvent(event)

//在AppUi中设置过Moniotr的可以在MonitorWsEvent中处理所有的event

//再调用iAppUi->HandleWsEventL(event,window)

//CCoeAppUi::HandleWsEventL会根据TWsEvent分发事件给CCoeControl

第1页 第2页 第3页 第4页 第5页

接上页

//同时等待下一个WSERV事件

}

网上关于symbian源码分析的文章非常少,而本人对于symbian的一些底层机制也不是非常的清晰,所以难免出错,欢迎大家在回复中指出。

继续跟踪CEikonEnv::ConstructAppFromCommandLineL的代码:

CEikonEnv::ConstructAppFromCommandLineL()

{

……

//创建程序进程

iProcess = CEikProcess::NewL(iFsSession, aCommandLine.ParentProcessId());

//是否作为一个服务器启动程序?

const TUint serverDifferentiator = aCommandLine.ServerRequired();

if (serverDifferentiator)

iEikonEnvFlags.Set(EStartedAsServerApp);

//是否将程序放到后台运行

if (!startAppInForeground)

{

iRootWin.SetOrdinalPosition(-1000);

iRootWin.EnableReceiptOfFocus(ETrue);

if (RProcess().Priority() <= EPriorityForeground)

RThread().SetProcessPriority(EPriorityBackground);

}

//在AddNewDocumentL里面会先创建Application,再创建Document

//http://developer.symbian.org/oss/FCL/interim/sf-test/platform/smoketest/file/c108117318cb/localisation/apparchitecture/apparc/APPARC.CPP

CEikDocument& doc = *static_cast(iProcess->AddNewDocumentL(aApplicationFactory));

iProcess->SetMainDocument(&doc);

//在这里创建AppUi

doc.PrepareToEditL(); // creates AppUi

CEikAppUi& appUi = *EikAppUi();

//初始化ViewManager

const TBool runAppWithoutViews = (command==EApaCommandRunWithoutViews || command==EApaCommandBackgroundAndWithoutViews);

if (!runAppWithoutViews)

appUi.CheckInitializeViewsL(appUi.Application()->AppDllUid());

//创建CEikStartUpViewActivator

if (startAppInForeground && command!=EApaCommandViewActivate )

iEikEnvExtra->iViewActivator = CEikStartUpViewActivator::NewL(appUi, *this, iEikEnvExtra->iViewActivator);

第1页 第2页 第3页 第4页 第5页

接上页

SetAppReady();

//创建结束

}

void CEikDocument::PrepareToEditL()

{

//CYourDocument类需要重载CreateAppUiL函数并创建AppUi。

iAppUi=CreateAppUiL();

iAppUi->SetDocument(this);

iAppUi->SetEmbeddedDocInfo(NULL,NULL);

//CYourAppUi会重载ConstructL函数

//必须首先调用CEikAppUi::BaseConstructL()

iAppUi->ConstructL();

}

void CEikAppUi::BaseConstructL(TInt aAppUiFlags)

{

//第一次设置AppUi时返回的值为NULL

iContainerAppUi = static_cast(iCoeEnv->SetAppUi(this));

//这里会创建控件栈CCoeControlStack

//以及创建CCoeViewManager

CCoeAppUi::ConstructL(iContainerAppUi);

//初始化DebugKeys以及AlertWin

if (!iContainerAppUi)

iEikonEnv->ControlStackReadyL();

//加载资源文件,EIK_APP_INFO资源里定义的东东应该是在这里被加载的

if (!(aAppUiFlags&(ENoAppResourceFile|ENonStandardResourceFile)))

ReadAppInfoResourceL();

else if (!(aAppUiFlags&ENoScreenFurniture))

CreateResourceIndependentFurnitureL();

iCoeEnv->AddMessageObserverL(*this);

iEikonEnv->PostAppUiInitializeL();

iCoeEnv->RootWin().EnableScreenChangeEvents();

}

这样初始化的过程就结束了,里面还有一堆东西没有看懂,不过重要的几个步骤上面都在了。

三、运行应用程序

env->Execute()调用的是CCoeEnv::Execute():

void CCoeEnv::Execute()

{

iEnvFlags|=ESchedulerIsRunning;

//运行活动调度器,里面是个While循环

//直到程序退出才会返回

TRAPD(exitCondition,CActiveScheduler::Start());

//看是否正常退出或者是Leave导致的退出

__ASSERT_ALWAYS((exitCondition==KLeaveExit) || (exitCondition==KErrNone), Panic(ECoePanicLeaveWithoutTrap));

第1页 第2页 第3页 第4页 第5页

接上页

//会调用iAppUi的PrepareToExit(),可以进行一些预处理

PrepareToExit();

}

四、销毁应用程序

env->DestroyEnvironment()主要是对一些之前所产生分配的内存的释放,会调用底层的 CCoeEnv::DestroyEnvironmentStatic()和CCoeEnv::DestroyEnvironmentEnd(),最后 delete CEikonEnv对象本身。

本文固定链接:http://www.wangth.com/?p=181

第1页 第2页 第3页 第4页 第5页

Symbian之源码分析之EikStart.cpp

 

开源了那么久,今天终于决定去看看那近2G的代码了。我们先看看启动一个程序到初始化UI类完成系统都做了些什么。

首先说下Eikon、Uikon、Avkon、Qikon的概念。在Symbian OS v5里UI框架叫做Eikon,虽然它被设计成支持8位build和16位build,但事实上它只支持8位build。到了OS v5.1,Eikon开始支持16位build,为了体现这个改变,将Eikon更名为Uikon。这之后基于Uikon层之上衍生出了S60平台的应用程序框架”Avkon”(OS v6.0)以及UIQ平台的应用程序框架”Qikon”(OS v7.0)。

Uikon采用CEik、Avkon采用CAkn、UIQ采用CQik作为类名的前缀。

相关wiki:

http://wiki.forum.nokia.com/index.php/Uikon-Eikon-Avkon-Qikon

接下来进入主题,我们依旧以HelloWorld工程为例,看它的第一个文件HelloWorld.cpp:

#include

#include "HelloWorldApplication.h"

LOCAL_C CApaApplication* NewApplication()

{

return new CHelloWorldApplication;

}

GLDEF_C TInt E32Main()

{

return EikStart::RunApplication( NewApplication );

}

当一个程序启动时,都会调用E32Main()函数。NewApplication函数创建并返回一个CApaApplication实例,LOCAL_C即static的宏定义。RunApplication接收的参数是TApaApplicationFactory,其中有这么段定义:

class TApaApplicationFactory

{

public:

typedef CApaApplication* (*TFunction)();

};

所以这里传进去的是NewApplication函数的地址,工厂函数Factory的命名由此而来。EikStart::RunApplication()函数的关键代码如下:

EikStart::RunApplication(TApaApplicationFactory aApplicationFactory)

{

//创建命令行对象并获取程序启动命令行参数

CApaCommandLine* commandLine = NULL;

TInt error = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);

//更改进程名

//注意{}的妙用,这样TFileName就不会一直存在于栈上面,节省了512字节的空间。Symbian默认的栈空间大小为8KB,最大可为64KB。

{

第1页 第2页

开源了那么久,今天终于决定去看看那近2G的代码了。我们先看看启动一个程序到初始化UI类完成系统都做了些什么。

首先说下Eikon、Uikon、Avkon、Qikon的概念。在Symbian OS v5里UI框架叫做Eikon,虽然它被设计成支持8位build和16位build,但事实上它只支持8位build。到了OS v5.1,Eikon开始支持16位build,为了体现这个改变,将Eikon更名为Uikon。这之后基于Uikon层之上衍生出了S60平台的应用程序框架”Avkon”(OS v6.0)以及UIQ平台的应用程序框架”Qikon”(OS v7.0)。

Uikon采用CEik、Avkon采用CAkn、UIQ采用CQik作为类名的前缀。

相关wiki:

http://wiki.forum.nokia.com/index.php/Uikon-Eikon-Avkon-Qikon

接下来进入主题,我们依旧以HelloWorld工程为例,看它的第一个文件HelloWorld.cpp:

#include

#include "HelloWorldApplication.h"

LOCAL_C CApaApplication* NewApplication()

{

return new CHelloWorldApplication;

}

GLDEF_C TInt E32Main()

{

return EikStart::RunApplication( NewApplication );

}

当一个程序启动时,都会调用E32Main()函数。NewApplication函数创建并返回一个CApaApplication实例,LOCAL_C即static的宏定义。RunApplication接收的参数是TApaApplicationFactory,其中有这么段定义:

class TApaApplicationFactory

{

public:

typedef CApaApplication* (*TFunction)();

};

所以这里传进去的是NewApplication函数的地址,工厂函数Factory的命名由此而来。EikStart::RunApplication()函数的关键代码如下:

EikStart::RunApplication(TApaApplicationFactory aApplicationFactory)

{

//创建命令行对象并获取程序启动命令行参数

CApaCommandLine* commandLine = NULL;

TInt error = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);

//更改进程名

//注意{}的妙用,这样TFileName就不会一直存在于栈上面,节省了512字节的空间。Symbian默认的栈空间大小为8KB,最大可为64KB。

{

第1页 第2页

接上页

TFileName executableFileName = RProcess().FileName();

error = User::RenameThread(TParsePtrC(executableFileName).Name());

}

//创建CEikonEnv对象并通过命令行参数创建应用程序

CEikonEnv* env = new CEikonEnv;

TRAP(error, env->ConstructAppFromCommandLineL(aApplicationFactory, *commandLine));

//执行应用程序,里面有个While循环,直到程序退出时才返回

env->Execute();

//销毁env环境

env->DestroyEnvironment();

}

以上代码来自http://developer.symbian.org/xref/oss/xref/MCL/sf/mw/classicui/commonuisupport/uikon/coresrc/EIKSTART.CPP

classicui打包下载:http://developer.symbian.org/oss/MCL/sf/mw/classicui/archive/tip.zip

原创文章,转载请注明出处:Cherubine

本文固定链接:http://www.wangth.com/?p=175

第1页 第2页

 

Symbian之定时器

之前说活动对象的时候用了定时器的例子,是用的RTimer + CActive的组合。Symbian中还有三种定时器,分别是CTimer, CPeriodic, CHeartBeat。

一、CTimer

CTimer继承自CActive,封装了对RTimer的使用。需继承CTimer来使用,且不需要实现DoCancel()函数。

二、CPeriodic

CPeriodic是CTimer的子类,需要实现一个回调函数Loop(),Start()的时候将Loop作为参数传进去,之后就会周期性的调用Loop()函数。

三、CHeartBeat

CHeartBeat也是CTimer的子类,比CPeriodic更为精确。一般配合MBeating使用,设置枚举变量TTimerLockSpec为心跳间隔时间,每次心跳都会调用Beat()函数,而当与系统时间不同步时则会调用Synchronize()。

上面三种定时器的代码可参考下面的链接:

http://blog.csdn.net/coderwu/archive/2009/04/21/4097746.aspx

http://blog.csdn.net/sharetop/archive/2008/03/15/2185652.aspx

原创文章,转载请注明出处:Cherubine

本文固定链接:http://www.wangth.com/?p=164

 

Symbian SMS编码之PDU 发送短信篇

首先来了解下发送方的短信PDU格式:

一、SCA

见接收篇

二、PDUType

bit7: RP,见接收篇

bit6: UDHI,见接收篇

bit5: SRR(Status Report Request) ,请求状态报告

0 ? 不需要报告

1 ? 需要报告

bit4、3: VPF(Validity Period Format)有效期格式

00 ? VP 段没有提供(长度为 0 )

01 ? 保留

10 ? VP 段以整型形式提供(相对的)

11 ? VP 段以8位组的一半(semi-octet)形式提供(绝对的)

bit2: RD拒绝复本(Reject Duplicate),

0 ? 通知 短消息服务中心(SMSC)接受一个SMS-SUBMIT,即使该消息是先前已提交过的,并还存在于SMSC中未发送出去。MS重复的条件是:消息参考(MR)、接收方地址(DA)及发送方地址(OA)相同

1 ? 通知 SMSC 拒绝一个重复的 SMS

bit1、0: MTI,见接收篇

三、MR(Message Reference)信息参考

设为00即可

四、DA(Destination Adress)接收方手机号码的地址

DA格式与OA格式是一样的,详见接收篇。

五、PID

见接收篇

六、DCS

见接收篇

七、VP(Validity Period)短信的有效时间

分相对和绝对两种情况,具体可以参考:

http://borland.mblogger.cn/shuixin13/posts/10087.aspx#VP

八、UDL

见接收篇

九、UD

见接收篇

了解了发送方格式后我写了这样一个程序:

连接串口后需要设置发送格式为PDU

在PDU mode下,发送的命令为:

AT+CMGS=

length为PDU串长度

接着需要sleep半秒钟,否则写入数据过快会导致ERROR

然后将SCA地址+PDU串的字符串写入串口,最后的x1A是,是将短信发出去的符号

返回结果:

+CMGS: 67

OK

67表示发送成功的第67条消息。

测试手机收到内容为“Test”的短信,说明发送成功。

Symbian函数(HandleListBoxEventL\OfferKeyEventL\HandleKeyEventL\HandleControlE

Symbian函数(HandleListBoxEventLOfferKeyEventLHandleKeyEventLHandleControlEventL)

一.HandleListBoxEventL(CEikListBox* aListBox, TListBoxEvent aListBoxEvent)

其实就是使用了Observer模式,其中ListBox的父控件是Observer。

假设iListBox的父控件为CMyContainer

1. CMyContainer要实现MEikListBoxObserver接口

2. iListBox构造完成后要调用

iListBox->SetListBoxObserver(this);

3. 当在iListBox中选中某个Item时,iListBox就会通过MEikListBoxObserver接口通知父控件。可以这样 处理这个通知:

void CMyContainer::HandleListBoxEventL(CEikListBox* /*aListBox*/,TListBoxEvent aEventType )

{

if (( aEventType == MEikListBoxObserver::EEventEnterKeyPressed)||

( aEventType== MEikListBoxObserver::EEventItemClicked ))

{

// 如果当前选中的是第二项

if(iListBox->CurrentItemIndex()==2)

{

// 则调用其它函数,或者

// 1. 切换到其它视图(如果你的视图继承自CAknView),或者

AppUi()->ActivateLocalViewL(TUid::Uid(ETheViewID));

// 2. 切换到其它视图(如果你的视图继承自CCoeControl)

// AppUi()->HandleCommandL(ECmdSwithToOtherView)

// 自己要AppUi类的HandleCommandL()中处理ECmdSwithToOtherView命令完成切换

}

}

}

二.virtual TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);

这个函数专门用于处理键盘事件,如果对程序的交互和运行需要通过键盘控制,那么视图类就应该去实现这个方法。如果类实现这个方法,特别需要注意的是,若对象没有对键盘事件作出响应那么应该返回EKeyWasNotConsumed ,反之,若对象对该键盘事件做出了响应那么就要返回EKeyWasConsumed。当键盘事件发生时,控制框架调用每一个在控件栈中对象的 OfferKeyEventL()函数,直到他们中其中的一个可以处理这个键盘事件并返回EKeyWasConsumed。

参数:

const TKeyEvent& aKeyEvent :键盘事件。TKeyEvent 类描述了键盘事件的细节,他包括四个属性,分别是iCode, iModifiers, iRepeats, iScanCode

第1页 第2页 第3页

Symbian函数(HandleListBoxEventLOfferKeyEventLHandleKeyEventLHandleControlEventL)

一.HandleListBoxEventL(CEikListBox* aListBox, TListBoxEvent aListBoxEvent)

其实就是使用了Observer模式,其中ListBox的父控件是Observer。

假设iListBox的父控件为CMyContainer

1. CMyContainer要实现MEikListBoxObserver接口

2. iListBox构造完成后要调用

iListBox->SetListBoxObserver(this);

3. 当在iListBox中选中某个Item时,iListBox就会通过MEikListBoxObserver接口通知父控件。可以这样 处理这个通知:

void CMyContainer::HandleListBoxEventL(CEikListBox* /*aListBox*/,TListBoxEvent aEventType )

{

if (( aEventType == MEikListBoxObserver::EEventEnterKeyPressed)||

( aEventType== MEikListBoxObserver::EEventItemClicked ))

{

// 如果当前选中的是第二项

if(iListBox->CurrentItemIndex()==2)

{

// 则调用其它函数,或者

// 1. 切换到其它视图(如果你的视图继承自CAknView),或者

AppUi()->ActivateLocalViewL(TUid::Uid(ETheViewID));

// 2. 切换到其它视图(如果你的视图继承自CCoeControl)

// AppUi()->HandleCommandL(ECmdSwithToOtherView)

// 自己要AppUi类的HandleCommandL()中处理ECmdSwithToOtherView命令完成切换

}

}

}

二.virtual TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);

这个函数专门用于处理键盘事件,如果对程序的交互和运行需要通过键盘控制,那么视图类就应该去实现这个方法。如果类实现这个方法,特别需要注意的是,若对象没有对键盘事件作出响应那么应该返回EKeyWasNotConsumed ,反之,若对象对该键盘事件做出了响应那么就要返回EKeyWasConsumed。当键盘事件发生时,控制框架调用每一个在控件栈中对象的 OfferKeyEventL()函数,直到他们中其中的一个可以处理这个键盘事件并返回EKeyWasConsumed。

参数:

const TKeyEvent& aKeyEvent :键盘事件。TKeyEvent 类描述了键盘事件的细节,他包括四个属性,分别是iCode, iModifiers, iRepeats, iScanCode

第1页 第2页 第3页

接上页

。当处理一个TKeyEvent的时候,TStdScanCode型的iScanCode通常被TKeyCode型的iCode取代。

TEventCode aType :键盘事件类型,包括:EEventKey, EEventKeyUp or EEventKeyDown

返回值指明对象是否处理了这个键盘事件。

任意一个键盘的按键事件都将导致三个独立的事件:EEventKeyDown, EEventKey和EEventKeyUp,事实上他们触发的顺序也是这个样子的。为可以获得可以被OfferKeyEventL()函数处理的键盘事件,应用程序必须调用CCoeAppUi::AddToStackL()方法,把控件压入到栈中。这只是对控件起作用,而不是组成控件的控件组件。复合控件如果有需要的话也可以把键盘事件传递给他们的组件控件,但是组件控件本身并不可以在控制栈上。

如果一个类覆盖了 CCoeControl::OfferKeyEventL() 方法那么他同时也要覆盖InputCapabilities() 虚函数,返回一个TCoeInputCapabilities 对象,这个对象的属性符合OfferKeyEventL()函数的行为。通常没有必要在内部调用InputCapabilities() 方法,而这个方法也一般被UI控制框架调用。

三、 virtual void HandleKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);

HandleKeyEventL一般用在AppUi中,Container中一般是使用OfferKeyEventL。HandleKeyEventL处理按键和所有来自OfferKeyEventL返回的OfferKeyEventL没有定义的按键事件。

对于symbian操作系统上按键事件的捕获,既可以通过UI中的HandleKeyEventL也可以通过view中的OfferKeyEventL,这两个函数都是通过重载基类中的相应函数来实现的。使用这两个函数的主要区别在于使用OfferKeyEventL前需把对应的view压入控件栈(AddToStackL),否则捕获不到该控件对应的按键输入,而HandleKeyEventL 则不需要压入控件栈,可以处理全局按键事件。这两个函数根据实际情况分别使用,当多个view时最好用OfferKeyEventL,这样便于控制,可在各个view中分别对按键输入做不同的相应。另外,如果同时定义了这两个函数,关于他们的执行顺序,有按键事件时其先被传递到控件栈中的OfferKeyEventL,如果OfferKeyEventL返回EKeyWasConsumed(被消耗),则不再传到HandleKeyEventL中,否则传递到HandleKeyEventL在做处理。

当用户按下一个键后,keyboard hardware就会生成一个中断,由keyboard driver捕捉,之后分解出这次按键事件的key code,然后driver将它发送到系统端的一个线程——被称为window server,而window server又会把它发向在window

第1页 第2页 第3页

接上页

group中拥有焦点的那个应用程序中,这个步骤是使用一个control environment(CONE)来完成的,它是window server和user interface library之间的一个API函数。

从api函数中可以看出这个处理过程当windows server发送一个按键的事件便调用AppUI中的HandleWsEventL(),HandleWsEventL()方法首先调用CCoeControl::OfferKeyEventL()如果OfferKeyEvent()返回EKeyWasNotConsumed则继续调用AppUI中的HandleKeyEventL()。如果OffKeyEventL()处理了事件则返回EKeyWasConsumed。

如果想直接调用AppUI中的HandleKeyEventL()可以通过set ECoeStackFlagRefusesAllKeys 来省去调用OfferKeyEventL()。

每次按键都会产生3个事件类型1 EEventKeyDown,2 EEventKeyUp,3 EEventKeyDown;可以从OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)中的aType中得到事件类型。aKeyEvent是一个struct可以得到按键的更多属性,eg:iCode指名按了哪个键(键名在e32keys.h中)iRepeats可以判断是重复按键还是长按键。如果想改变系统的按键重复率可以通过RWsSession 的SetKeyboardRepeatRate方法来设置。

S60手机默认情况下是不能接受连续按键的且只有先按下的键可以被接受(也就是按键阻塞,电源键和编辑键默认为非按键阻塞)。可以通过s60提供的CAKnAppUI中的SetKeyBlockMode()方法来取消按键阻塞。

四、void HandleControlEventL (CCoeControl* aControl,TCoeEvent aEventType)

纯虚方法HandleControlEventL()来接收和处理按钮事件。

void CBasic_M1000AppView::HandleControlEventL(CCoeControl* aControl,TCoeEvent aEventType)

{ //First check the control the event is coming from

if ( aControl == iSendButton)

{

_LIT(KTEXT,"Click");

switch (aEventType)

{

case EEventPointer:

iLabel->SetTextL(KTEXT);

iLabel->DrawDeferred();

break;

default:

break;

}

}

}

第1页 第2页 第3页

 

symbian 第五版 如何使用拖拽事件

Symbian(Drag Event)第五版如何捕获拖拽事件

大家如果有第五版的项目的话,肯定会遇到要处理触屏事件的.

第五版的触屏事件的处理系统提供了此函数:

void HandlePointerEventL(const TPointerEvent& aPointerEvent);

我们只需要重载此函数即可以得到相应的事件类型

EButton1Down,

EButton1Up,

EDrag//拖拽事件

void CDrag***View::HandlePointerEventL(const TPointerEvent& aPointerEvent)

{

CCoeControl::HandlePointerEventL(aPointerEvent);

switch( aPointerEvent.iType )

{

case TPointerEvent::EDrag:

{

}

break;

}

}

如果只这样的话.系统是没有办法捕获到拖拽事件的

我们还需要在ConstructL中打开拖拽事件

EnableDragEvents();

posted @ 2011-01-14 09:51  冰岛  阅读(2454)  评论(0编辑  收藏  举报