Simulating and intercepting key events

Simulating key events

Simulating key events is done by calling CCoeFep ’s member function SimulateKeyEventsL(); this sends to the application a key event for each of the items in the array passed to it. There are two overloads of SimulateKeyEventsL(): in the first and most commonly used overload, only the character codes of the key events are specified; in the second overload, modifier keys can also be specified for each key event to be simulated. The header file epoc32\include\E32KEYS.H defines the various modifiers possible. The FEP author needs to derive from CCoeFep::MModifiedCharacter in order to use the second overload of SimulateKeyEventsL(), implementing all three of its pure virtual functions. The ModifierMask() function returns the modifiers whose value the FEP wishes to specify; the values for the modifiers are returned by the ModifierValues() function. ModifierValues() should not return values for any modifiers that are not also returned by ModifierMask().

For example, supposing a FEP wishes to send a key event to an application with the func modifier on and the shift modifier off. In this case the ModifierMask() function would return EModifierFunc|EModifierShift and the ModifierValues() function would return EModifierFunc. The resulting key event received by the application would then have the EModifierFunc modifier on and the EModifierShift modifier off (even if the shift key is being pressed down). All the other modifiers in the key event, since they were not returned in the ModifierMask() function, will reflect the current state of the keyboard.

Intercepting key events

In order for a FEP to intercept key events before they reach the application beneath them, the FEP control must be added to the control stack at a high priority. This is done by using the following code in the control’s construction routine:

STATIC_CAST(CCoeAppUi*, iCoeEnv->AppUi())->AddToStackL(this, ECoeStackPriorityFep, ECoeStackFlagRefusesFocus|ECoeStackFlagSharable);

and the following code in its destructor:

STATIC_CAST(CCoeAppUi*, iCoeEnv->AppUi())->RemoveFromStack(this);

Passing the flag ECoeStackFlagSharable to AddToStackL() ensures that if an embedded object is edited from an application, for instance an embedded drawing is edited inside a word processor document, the FEP’s control will also be put onto the child application’s control stack when the child application is started. More importantly, the ECoeStackFlagRefusesFocus flag should be passed to AddToStackL() because FEPs in general should not “steal” focus from the target underneath them. For the same reason, SetNonFocusing() (a member function of CCoeControl) should be called in the control’s construction routine to prevent mouse or pen events from giving it focus. On some occasions it may be legitimate for the FEP to take the focus, for instance if the FEP has a floating window and it is temporarily in a mode where the user can move this window around the screen by using the arrow keys. In this case, the FEP’s control can take the focus by calling:

CCoeAppUi& appUi=*STATIC_CAST(CCoeAppUi*, iCoeEnv->AppUi());
appUi.UpdateStackedControlFlags(this, 0, ECoeStackFlagRefusesFocus);
appUi.HandleStackChanged();

The following code causes the FEP’s control to revert to normal operation by losing focus:

CCoeAppUi& appUi=*STATIC_CAST(CCoeAppUi*, iCoeEnv->AppUi());
appUi.UpdateStackedControlFlags(this, ECoeStackFlagRefusesFocus, ECoeStackFlagRefusesFocus);
appUi.HandleStackChanged();

Adding the FEP’s control to the control stack at priority ECoeStackPriorityFep means that it gets first refusal of all key events. The UI framework offers key events to the FEP control by calling its OfferKeyEventL() virtual function (although key events for a FEP over an OPL application follow a different route, described below). The signature of this virtual function, which is first declared in CCoeControl, is:

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

The first thing that should be done at the start of OfferKeyEventL() is to call either of the two macros below, both of which are defined in epoc32\include\FEPBASE.H:

#define FEP_START_KEY_EVENT_HANDLER_L(aFep, aKeyEvent, aEventCode)
#define FEP_START_KEY_EVENT_HANDLER_NO_DOWN_UP_FILTER_L(aFep, aKeyEvent, aEventCode)

The aFep parameter must be a CCoeFep object. Note that it should not be a pointer to a CCoeFep. The aKeyEvent and the aEventCode parameters should be respectively the TKeyEvent and the TEventCode parameters of the OfferKeyEventL() function itself. The OfferKeyEventL() function should only be returned from by calling either of the following two macros (these are also defined in epoc32\include\FEPBASE.H):

#define FEP_END_KEY_EVENT_HANDLER_L(aFep, aKeyEvent, aKeyResponse)
#define FEP_END_KEY_EVENT_HANDLER_NO_DOWN_UP_FILTER_L(aFep, aKeyEvent, aEventCode, aKeyResponse)

Both of these two macros contain a return statement, so the return C++ keyword should not occur in the OfferKeyEventL() function at all. Note that the macro used at the start of the OfferKeyEventL() function should match the macro used to return from it; in other words, both should be of the no-down-up-filter type or neither should be. The no-down-up-filter variants should be used if the FEP wishes to handle EEventKeyDown or EEventKeyUp events. This is likely to be rare, however; most FEPs are probably only interested in EEventKey events, in which case FEP_START_KEY_EVENT_HANDLER_L and FEP_END_KEY_EVENT_HANDLER_L should be used. These variants filter out EEventKeyDown and EEventKeyUp events so that the FEP only receives EEventKey events.

The first three parameters of the FEP_END_KEY_EVENT_HANDLER_ XXX macros are the same as for the FEP_START_KEY_EVENT_HANDLER_ XXX macros. The fourth parameter should be a TKeyResponse value (an enum defined in epoc32\include\COEDEF.H). Specifying EKeyWasNotConsumed as this fourth parameter allows that key event to 'fall through' to the application, whereas specifying EKeyWasConsumed prevents the application from receiving that event. A good rule of thumb for a FEP that takes key events as its input is to intercept as few key events as possible when not inside a FEP transaction, but once inside a transaction to block all key events from getting through to the application. A transaction may be defined as the composition and abandoning/committing of a piece of text ('committing' means sending it on to the application). For a Japanese FEP, that piece of text may be an entire sentence, whereas for a Chinese FEP it may be just one or two characters.

For a FEP running over an OPL application, the OfferKeyEventL() virtual function declared in CCoeFep will get called. This is a completely independent function from CCoeControl ’s virtual function of the same name, and it has a different signature which is as follows:

void OfferKeyEventL(TEventResponse& aEventResponse, const TKeyEvent& aKeyEvent, TEventCode aEventCode);

This virtual function should be implemented in exactly the same way as CCoeControl ’s OfferKeyEventL(), the meaning of the aKeyEvent and aEventCode parameters being the same as for CCoeControl ’s OfferKeyEventL(). The aEventResponse parameter should be set by the function overriding CCoeFep::OfferKeyEventL() to either CCoeFep::EEventWasNotConsumed or CCoeFep::EEventWasConsumed, and this must be done before any function that can leave is called.