I've used Nokia Series 60 AppWizard 1.9 with VC++ and created a Dialog-based application with support for view architecture. The problem is that no matter what I do, the left and right cursor keys (aka joystick) does not change views, as it should (or shouldn't?).
Anyway, how can I process messages and where (in application source) to switch views (View1<->View2) using the Left<->Right combination. Example source would be fine (use the appwizard to get the stub code).
Before I try to answer your question, I have the impression that it would help first to clarify what code wizard actually generates.
Application UI creates a CEikDialog-derived dialog and displays it in its 2nd phase constructor.
Dialog based with view support
Application UI creates two (could have been any other number) CAknView-derived views and activates first one in its 2nd phase constructor. Each view maintains its own CEikDialog-derived dialog.
Even though it's not absolutely necessary to implement it like that, each view's dialog gets created every time view is activated by application UI (via view's DoActivateL) and destroyed every time view is deactivated (again by application UI calling view's DoDeactivate). Switching between views is handled in application UI's HandleKeyEventL method.
Almost identical to 'Dialog based': the only difference is that application UI creates and displays CCoeControl-derived control instead of a CEikDialog-derived dialog. CCoeControl-derived control in turn creates and displays two labels.
Eikon control with view support
Almost identical to 'Dialog based with view support': the only difference is that views create CCoeControl-derived controls instead of CEikDialog-derived dialogs.
'View support' samples turned out slightly more complicated by the fact that wizard also generates the code which creates and uses tabs in the navigator pane as a way to switch between views.
Normally one would consider using tabs to switch between multiple views, of course; it's just that they don't have to be used together. The samples could equally work without tabs (and without any other modification in the code).
Getting back to your question, the answer is: since the application UI is the main place for handling keyboard events (HandleKeyEventL) and menu commands (HandleCommandL), you would probably do it there (or at least in this particular case). And since you have generated your application using wizard (without modifying anything?), the application should work correctly.
Sometimes it happens that the lost of focus causes emulator to not response to mouse clicks on cursor buttons. Typical case is when program continues to execute after being stopped in the debugger. Clear all breakpoints and see if the program responds as it should.
klisa, thanks for answering my question, your explanations do help a lot.
Forgot to mention that this behaviour is not only in the emulator evident, but to the device itself; you're right, the application is losing focus after the dialog has been initialized and handling has passed to it's view (via the AddViewL call). Compiling the code without the AddViewL statement does work (switching views), but it generates errors (panics?) during runtime.
Any idea what's wrong with the code generated by appwizard? Have you actually tried to compile and use this code, to see what happens?
I just tested wizard-generated code, and you are right: it doesn't work.
What's more important is that we have a completely different issue here; it has nothing to do with the focus.
The problem is in a thing called control stack. Control stack does what MFC message maps do in Windows (OK, OK, not quite but still): delegates (here only keyboard) events accross controls registered on the stack.
Each control on the stack gets a chance to process keyboard events, according to its priority. Since we don't set priority anywhere in the example, all controls get equal, default priority.
Since all the controls on the stack have the same priority, in that case their order of placing on the stack determines who is going to get keyboard focus first.
Typically, the priority list looks something like this: debug keys first, then the active dialog (if there is one), then hotkeys in menubars, and finally the view. If none of them processes it, application UI gets it in HandleKeyEventL.
This is exactly the case with this example. View has been added to the control stack in the application UI, and then on top of it
its dialog has been added. It means views' dialog gets the chance to process keyboard events first.
Processing keyboard events means having virtual methiod OfferKeyEventL overriden in the dialog.
None of the two dialogs in the example has it, meaning that the base class CEikDialog::OfferKeyEventL implementation does some processing of key events.
If someone had asked me, I would have said that CEikDialog::OfferKeyEventL probably doesn't consume arrow key events, returning EKeyWasNotConsumed to indicate that next control on the control stack should get a chance to process it.
As I said, in case that no controls on the stack process keyboard event, it ultimately ends up in application UI's HandleKeyEventL (where we expect it), switching the tabs.
But that's not happening.
It's because dialog's base class OfferKeyEventL implementation apparently does consume the keyboard event, so application UI never gets a chance to process it.
Quickest 'solution' is, of course, to implement OfferKeyEventL in both of your dialogs, returning EKeyWasNotConsumed. This will bypass base class implementation and application UI will eventually get the key.
(In so called reality, proper OfferKeyEventL implementation would probably have to be more careful when bypassing base class implementation.)
Your suggestion was correct, the AppUi() class does get the KeyEvents now correctly and tab switching works.
It is a shame however that such an important feature of SymbianOS (the control stack) does not get proper documentation - I was only able to find some paragraphs explaining vaguely it's purpose, but no code examples :( Nokia/Symbian should provide more examples on this and FIX the AppWizard so that it produces correct source.