[ZZ]Symbian的按键事件

【1】Symbian 按键事件的捕获

对于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 group中拥有焦点的那个应用程序中,这个步骤是使用一个control environment(CONE)来完成的,它是window serveruser interface library之间的一个API函数。

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

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

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

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

【2】Symbian 按键事件的处理

const TKeyEvent& aKeyEvent -- 记录了按键的具体信息:

iCode:键盘码
iScanCode:扫描码

iModifier:修饰键

iRepeats:是个标记,告诉你产生的这个按键事件是你重复按键还是长按一个键时周期产生的按键事件。

TKeyEvent还是要看下e32keys.h头文件(epoc32\include),定义都在里面。

TEventCode aType -- 记录键盘事件类型:

EEventKeyDown:接收按键按下时的信息。
EEventKey:在按键按下后,到按键松开前,周期性的收集信息.键盘连击率,RWsSession::SetKeyboardRepeatRate方法设置时间间隔)。
EEventKeyUp:收集按键释放信息。

    而每次按键时,都会依次产生上面三个按键事件(其实也不完全是这样,后面会说到),根据不同的应用需求做处理,在很多基本的应用时,我们不太关心键按下或松开的时刻,而只关心我们按的是什么键,比如在对话框里输入一些,我们只关心按的是a还是b,而合适按下a或b对我们来说并不重要,那么我们在OfferKeyEventL()或HandleKeyEventL()中,只需对(aType == EEvenKey)时做处理。而另外一种情况,比如游戏,一个键的按下或释放的时刻就显得很重要了,这时需要对(aType == EEvenKeyDown)或(aType == EEvenKeyUp)时进行处理,比如我们可以在(aType == EEvenKeyDown)时移动一个物体,在(aType == EvenKeyUp)时停止移动。

    好了,大概的把这些简单的说完了,下面就开始我们的重头戏--aKeyEvent。aKeyEvent记录了我们按键的详细信息,我们先从最简单的两个iRepeats和iModifier开始。

    iRepeats。w32std.h里是这样定义iRepeats的:TInt iRepeats;
    说的很清楚了,你按键时不是先产生个aTyep=EEvenKeyDown的事件嘛,紧接着产生aType=EEvenKey的事件,如果你按下那个键(比如a)的时间足够长(也不需要太长),超过了系统默认时间间隔(如果你没有用RWsSession::SetKeyboardRepeatRate()设置的时间间隔)的话,那么经历那个系统默认时间间隔后,会再次产生aTyep=EEvenKey的事件,而这两次aTyep=EEvenKey事件的唯一区别就是前一个的aKeyEvent.iRepeats=0,而之后的aKeyEvent.iRepeats=1。所以aTyep=EEvenKey(且aKeyEvent.iRepeats=1)的事件每隔一定时间间隔就会自动产生,直到你松开按键。而后产生aTyep=
EEvenKeyUp事件。
    iModifier。w32std.h里是这样定义iModifier的:TUint iModifiers;

    那么我们再看看TEventModifier的定义(e32keys.h中)。

enum TEventModifier
    {
    EModifierAutorepeatable=0x00000001,
    EModifierKeypad=0x00000002,        
    EModifierLeftAlt=0x00000004,       
    EModifierRightAlt=0x00000008,      
    EModifierAlt=0x00000010,           
    EModifierLeftCtrl=0x00000020,      
    EModifierRightCtrl=0x00000040,     
    EModifierCtrl=0x00000080,          
    EModifierLeftShift=0x00000100,     
    EModifierRightShift=0x00000200,    
    EModifierShift=0x00000400,         
    EModifierLeftFunc=0x00000800,      
    EModifierRightFunc=0x00001000,     
    EModifierFunc=0x00002000,          
    EModifierCapsLock=0x00004000,      
    EModifierNumLock=0x00008000,       
    EModifierScrollLock=0x00010000,    
    EModifierKeyUp=0x00020000,         
    EModifierSpecial=0x00040000,       
    EModifierDoubleClick=0x00080000,   
    EModifierPureKeycode=0x00100000,   
    EModifierKeyboardExtend=0x00200000,
    EModifierCancelRotation=0x00000000,
    EModifierRotateBy90=0x00400000, 
    EModifierRotateBy180=0x00800000,
    EModifierRotateBy270=0x01000000,
    EModifierPointer3DButton1=0x02000000,
    EModifierPointer3DButton2=0x04000000,
    EModifierPointer3DButton3=0x08000000,
    EAllModifiers=0x0fffffff           
    };

    定义虽然有点多,但是很容易看出,iModifier就是指Shift、Alt、Ctrl等这种修饰键有没有被按下。想想也很容易理解,我们单独按一个a和shift^a(产生的是A,大写)结果是不一样的,总得有个参数标记一下,这个参数就是iModifier了。另外,从定义中不知道你发现没,他们都是单字节位定义的,比如:
EModifierAutorepeatable=0x00000001           对应的二进制是  0001
EModifierKeypad=0x00000002                   对应的二进制是  0010 
EModifierLeftAlt=0x00000004                  对应的二进制是  0100

    这样做是因为有时候我们可能按下不只一个的修饰键,比如两个(shift + alt),而把这样同时两个或者更多修饰键被按下的情况一一枚举出来是不科学和不实用的,使用这种单字节位定义的好处就是我们在判断某个修饰键有没有被按下时,只需要按位与(&)一下就行了,比如,如果没有其他修饰键,一般按a时产生的iModifer是3(对应的二进制是0011),那么:
if (aKeyEvent.iModifier & EModifierAutorepeatable)和

if (aKeyEvent.iModifier & EModifierKeypad)时都为真,而

if (aKeyEvent.iModifier & EModifierLeftAlt)就为假,
    这样我们在处理按键事件时就能方便的判断出来那些修饰键被按下了。另外需要注意的就是,我测试时发现按下修饰键时只产生EEvenKeyDown和EEvenKeyUp事件,而无EEvenKey。

【3】Symbian 按键事件的处理2

    iCode是每次完整的按键事件对应的一个唯一键盘码,所谓完整的按键事件就是EEvenKeyDown、EEvenKeyUp及EEvenKey这三个事件,iCode在EEvenKeyDown和EEvenKeyUp中均为0,只有在EEvenKey中才对应相应的键盘码,这在SDK中有说:The character code generated for an EEventKey, or 0 for a down or up event.Key codes for special keys are defined in TKeyCode.

    可见,在EEvenKeyDown和EEvenKeyUp中我们无法根据iCode进行相应处理,因为所有按键的iCode都是0,我们只能根据iScanCode来判断按下的键位并处理。那么什么是iScanCode呢?

    iScanCode在SDK中是这样描述的:The scan code of the key that caused the event.

    怎么样,迷糊了吧,我们按下a这个键,不就是"a"这个键cause the event,而且The character code generated for the EEventKey也是a啊,iScancode和iCode的区别在哪呢?别忘了,可能还有修饰键呢,如果我们只按下a,那么iScancode = 0x41和iCode = 0x61(对应ASCII中小写的a),而如果我们按下shift + a,那么iScancode = 0x41和iCode = 0x41(对应ASCII中大写的A)。至于为啥小写a的iScancode为啥是0x41而不是0x61那就得问symbian了,人家就是这么定义的。

下面让我们看看两个完整的按键事件的实例:

184.190 --->code :0
184.190 --->scan code :41
184.190 --->iModifiers :0
184.190 --->iRepeats :0
EEvenKeyDown:a
184.190 *********************************
184.190 --->code :61
184.190 --->scan code :41
184.190 --->iModifiers :1
184.190 --->iRepeats :0
EEvenKey :a
184.190 *********************************
184.320 --->code :0
184.320 --->scan code :41
184.320 --->iModifiers :0
184.320 --->iRepeats :0
EEvenKeyUp:a
184.320 *********************************
shift + a (实际上是左shift):
233.020 --->code :0
233.020 --->scan code :12
233.020 --->iModifiers :500
233.020 --->iRepeats :0
233.020 leftshift was pressed
EEvenKeyDown:shift
233.020 *********************************
233.210 --->code :0
233.215 --->scan code :41
233.215 --->iModifiers :500
233.215 --->iRepeats :0
233.215 leftshift was pressed
EEvenKeyDown:a
233.215 *********************************
233.215 --->code :41
233.215 --->scan code :41
233.215 --->iModifiers :501
233.215 --->iRepeats :0
233.215 leftshift was pressed
EEvenKey:shift + a
233.215 *********************************
233.340 --->code :0
233.340 --->scan code :41
233.340 --->iModifiers :500
233.340 --->iRepeats :0
233.340 leftshift was pressed
EEvenKeyUp:a
233.345 *********************************
233.680 --->code :0
233.680 --->scan code :12
233.680 --->iModifiers :0
233.680 --->iRepeats :0
EEvenKeyUp:shift

233.680 *********************************

原文出处:http://blog.sina.com.cn/s/articlelist_1594757942_1_2.html

 

转载于:https://www.cnblogs.com/wk23415/archive/2011/07/08/2100777.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值