Wiley.Symbian.OS.C.plus.plus.for.Mobile.Phones.Aug.2007 (779890), страница 78
Текст из файла (страница 78)
Thepositions of the control’s components are adjusted accordingly, andPositionChanged() is called.• PositionChanged() responds to changes in the position of acontrol and is called whenever the application calls SetPosition()on the control. It has an empty default implementation.15.4Handling Key and Pointer EventsWhether an application needs to handle both types of event depends inpart on the target phone’s UI.
One of the design considerations for theS60 UI is that it should support one-handed operation. In consequence,S60 phones do not have touch-sensitive screens, which require holdingthe phone in one hand and the stylus in the other, so applications writtenspecifically for this UI do not need to handle pointer events.Applications running on pointer-based phone UIs, such as UIQ, generally have to handle both types of event. Such phones generally havesome keys, and also use front-end processors (FEPs) associated with, say,handwriting recognition, or a virtual (on-screen) keyboard, to generatekey events.Whether you choose to handle one or both types of event may alsodepend on the nature of your application. In general, if there are nospecific reasons to the contrary, handling both types of event will make iteasier to convert your application to run on a phone that uses a differentUI. Conforming to the general interaction style of an existing phone isgenerally a good idea.The two types of event have some fundamental differences.
A pointerevent occurs at a specific position on the screen, which usually corresponds to one particular application’s window and, more precisely, oneparticular control associated with that window. A key event has no suchintrinsic connection to a particular control: it is the internal logic of anapplication that determines this connection, and it is often the case thatdifferent types of key event are processed by different controls within theapplication.This fundamental difference is reflected in the way that Symbian OShandles the two types of event.Key EventsKey events are system events that usually originate from the keyboarddriver. The keyboard driver passes such events to the window serverwhich, in turn, offers them to one or more of the foreground application’scontrols by a mechanism that is described later in this section.
Key eventsHANDLING KEY AND POINTER EVENTS433from other sources (such as a FEP) may follow a different route, but arereceived and handled by a control in exactly the same way as those thatoriginate from the keyboard driver.In UIQ, the primary method of text input is the front-end processor.UIQ provides two FEPs: handwriting recognition and an on-screenvirtual keyboard. (Other FEPs may be written by third parties.) BothFEPs receive pointer events and translate them into key events, whichare passed to the application.
Whether the key event is generated bya FEP or a physical keyboard shouldn’t make any difference to yourapplication. The FEP architecture was designed so that applicationsdon’t need to be FEP-aware.In principle, all Symbian OS applications are expected to respond tokey events.Representation of key eventsA key event is represented by an instance of TKeyEvent and a key-eventtype, which may be EEventKeyDown, EEventKey or EEventKeyUp.Every time a key is pressed, all three key-event types are generated.Unless your application is particularly interested in detecting when a keyis pressed or released, you can safely ignore key events of types otherthan EEventKey.The TKeyEvent class has four data members.• iCode contains the key’s character code, and is usually of mostsignificance to an application.• iModifiers contains the state of any modifier keys, such as Controlor Shift, as defined in the TEventModifier class.• iRepeats contains the number of auto-repeat events, 0 signifyingan event without repeats.
It is normal to ignore this value.• iScanCode contains the scan code of the key that caused the event.Standard scan codes are defined in TStdScanCode. In general, thisvalue is useful only to game applications for which the position of thekey on the keyboard is more important than the character it represents.The legal values for iCode, iScanCode, and iModifiers aredefined in e32keys.h. UIQ defines some additional key codes inquartzkeys.h, to represent the events generated by the two or fourdirection keys on the keypad, and the Confirm key.Values from the TKeyCode enumeration are used to interpretiCode. The values are <0x20 for non-printing Unicode characters,434CONTROLS0x20 – 0xf7ff for printing Unicode characters, and >=0xf800 for theusual function, arrow, menu, etc. keys found on PC keyboards.
AlthoughSymbian OS phones may have no keyboard, many of these key eventsmay still be generated using a FEP.It is very rare for scan codes to be of interest. The scan codes aredefined by the historical evolution of IBM PC keyboards since 1981: theyoriginally represented the physical position of a key on the 81-key IBMPC keyboard, and have evolved since then to support new keyboards andpreserve compatibility with older ones. Since keyboards and keypads usedon Symbian OS phones are rather different, scan codes have limited value.Distributing key eventsThe control stack is used to pass key events to an application’s controls.To register its interest in processing key events, a control must beadded to the control stack by means of a call to the AddToStackL()function of the application UI class.
A control should also overridethe OfferKeyEventL() method and provide its own key-handlingbehavior.All key events that may potentially be handled by controls, whetherthey are generated from a real key press or from a FEP, are processedby the control stack’s OfferKeyL() function. This calls the OfferKeyEventL() function of each object on the control stack until either:• all the controls have been offered the key event and have indicated,by returning EKeyWasNotConsumed, that they cannot process theevent• a control can process the key event, and indicates that it has done soby returning the value EKeyWasConsumed.It follows that a control’s implementation of OfferKeyEventL()must ensure that it returns EKeyWasNotConsumed if it does not doanything in response to a key event, otherwise other controls or dialogsmay be prevented from receiving the key event.
The default action ofCCoeControl’s OfferKeyEventL() function is just to return EKeyWasNotConsumed.Processing key eventsA compound control may process and consume keys and/or may offerkey events to its component controls. A typical pattern is for the containercontrol to process cursor key events, using them to navigate between itscomponent controls. Other key events may be passed to one or other ofthe components.The Noughts and Crosses application demonstrates the typical responseto key events. It doesn’t have to check whether it should have been offeredHANDLING KEY AND POINTER EVENTS435the key event: the framework will only offer such an event if the controlis supposed to have it.The application doesn’t have to consume all key events that it isoffered: the view’s OfferKeyEventL() function takes no action forevents other than EEventKey and consumes only the up, down, left andright cursor key events when they can successfully be used to navigatebetween the tiles.TKeyResponse COandXAppView::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType){TKeyResponse keyResponse = EKeyWasNotConsumed;if (aType!=EEventKey){return keyResponse;}TInt index = IdOfFocusControl();switch (aKeyEvent.iCode){case EKeyLeftArrow: // check not in first columnif (index % KTilesPerRow){MoveFocusTo(index-1);keyResponse = EKeyWasConsumed;}break;case EKeyRightArrow: // check not in last columnif ((index % KTilesPerRow) < KTilesPerRow - 1){MoveFocusTo(index+1);keyResponse = EKeyWasConsumed;}break;case EKeyUpArrow: // check not on top rowif (index >= KTilesPerRow){MoveFocusTo(index-KTilesPerRow);keyResponse = EKeyWasConsumed;}break;case EKeyDownArrow: // check not in bottom rowif (index < KNumberOfTiles - KTilesPerRow){MoveFocusTo(index+KTilesPerRow);keyResponse = EKeyWasConsumed;}break;default:keyResponse = ComponentControl(index)->OfferKeyEventL(aKeyEvent, aType);break;}return keyResponse;}The view finds the current tile (the one which has the focus) with acall to IdOfControlWithFocus().436CONTROLSTInt COandXAppView::IdOfControlWithFocus(){TInt ret = -1;for (TInt i=0; i<CountComponentControls(); i++){if (ComponentControl(i)->IsFocused()){ret = i;break;}}__ASSERT_ALWAYS(ret>=0, Panic(EOandXNoCurrentTile));return ret;}If the requested move is allowed – for example, an EKeyUp event isallowed only if the current tile is not in the top row – the required changein the tile index is determined and focus is transferred to the new currenttile by calling SetFocus().If the key event is not a cursor key, the view just passes it to the currenttile by calling its OfferKeyEventL().TKeyResponse COandXTile::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType){if (aType!=EEventKey){return EKeyWasNotConsumed;}TKeyResponse keyResponse;switch (aKeyEvent.iCode){case EKeyOK:TryHitL();keyResponse = EKeyWasConsumed;break;default:keyResponse = EKeyWasNotConsumed;break;}return keyResponse;}The tile is only interested in the key event with key code EKeyOK,corresponding to an ‘enter’ press on an S60 phone’s joystick control.
Thecall to TryHitL() does nothing if the current tile already contains anought or a cross, otherwise it sets the tile to contain a nought or a cross,depending on whose turn it is.The above code usefully demonstrates the three main ways in which akey event may be handled:• ignore it, if it is a key that is either not recognized or not needed atthat timeHANDLING KEY AND POINTER EVENTS437• handle it directly in the control• use it to generate another event or command (such as TryHitL())that may be processed elsewhere.Key events are only offered to controls that have been added to thecontrol stack. If such a control is a compound control, it must explicitlyoffer the event to any of its component controls that may be capable ofprocessing the event.Input capabilitiesIn general, a control that supplies its own OfferKeyEventL() shouldalso provide a matching implementation of InputCapabilities().FEPs call this function, via the application UI and the control framework,to determine what classes of key event are appropriate to send to thecurrently focused control.
In the case of a compound control, the FEPreceives an or ed combination of the input capabilities of the controland all focused component controls. In consequence, it is not alwaysnecessary for a container control to override CCoeControl’s defaultimplementation (which returns TCoeInputCapabilities::ENone).In the Noughts and Crosses example, only the COandXTile class overrides this function:TCoeInputCapabilities COandXTile::InputCapabilities() const{return TCoeInputCapabilities::ENavigation;}This information is supplied to the FEP to help it to optimize itsperformance.