资料来自互联网
当用户按下一个键后,keyboard hardware就会生成一个中断,由keyboard driver捕捉,之后分解出这次按键事件的key code,然后driver将它发送到系统端的一个线程——被称为window server,而window server又会把它发向在window 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()方法来取消按键阻塞。
‘
iScanCode 和 iCode:
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了,人家就是这么定义的 -.-!!!
下面让我们看看两个完整的按键事件的实例:
a:
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 *********************************
了解了按键的处理流程之后,就可以在按键事件处理过程中的任何阶段拦截按键了。
见文:后台运行程序捕获按键
也可以在底层拦截按键,通过这种方式拦截按键之后,其它的任何按键处理都不会得到按键事件。可以通过S60Ex/Animation来测试。
见:
使用动画DLL捕获按键事件
内容如下:
动画DLL定义了一组多态DLL框架,用来处理动画。但是它也可以用来获得底层window server事件。
本文提供了一个方法,通过使用动画DLL捕捉底层事件。显示动画的示例在S60示例代码中有,但是未包含底层事件的处理。
所有的这些底层事件都可以通过MEventHandler::OfferRawEvent()接收和处理。这个方法需要在CAnim派生类中完成。函数将返回EFalse,此外
后台程序或前台程序需要使用RWindowGroup::CaptureKey()捕捉按键事件。
TBool CImage::OfferRawEvent( const TRawEvent& aRawEvent )
{
// To capture Zero key press
if(aRawEvent.Type()==TRawEvent::EKeyDown && aRawEvent.ScanCode()=='0')
{
// Event handling code
}
return EFalse;
}
当事件处理程序打开时,这些事件将送到MEventHandler::OfferRawEvent()方法中。可以通过调用 MAnimGeneralFunctions::GetRawEvents
(ETrue)函数完成。一个对象的类MAnimGeneralFunctions()没有生成。这个类由window server完成,并提供了通过CAnim::iFunctions指针访问所
有CAnim派生类的应用方法。因此为了接收到底层事件,需要增加下列代码到CAnim派生类的ConstructL()方法
void CImage::ConstructL( TAny* /*aArgs*/, TBool /*aHasFocus*/ )
{
iFunctions->GetRawEvents(ETrue);
}