Michael Lotz <mmlr@xxxxxxxx> wrote: > > For B_KEY_DOWN, BWindow will first handle this message in > > DispatchMessage to intercept TAB, SHIFT+TAB, OPTION+TAB, etc > > keystrokes > > to that it would advance to the next focus item/group. It is after > > that > > check that it calls fFocus->KeyDown(); Same goes for the menu and > > DefaultButton. > You have your BWindow which has a BView attached where you track > B_KEY_DOWNs > with the KeyDown hook function. This works well for almost all cases. > But if you > want to write a Terminal application, you will need to get those > B_TAB keys too. Actually, this is not correct; the basic idea is, but the B_TAB key is (like all other keys) supposed to get through to a normal KeyDown(). The view itself is responsible to trigger the navigation (as stippi correctly remembered) - AFAICT the window only handles the control group navigation. IOW our implementation seems to be wrong - but please check before you trust me :-) [...] > later should go to the filter function, plus those who would normally > be dispatched by > BWindow like the B_TAB. Again, that's not correct. BWindow dispatches key events in DispatchMessage() and makes sure that all command keys are filtered out, etc. B_TAB comes definitely through. > Look at MiniView.cpp in src/tests/apps/miniterminal for the > implementation. This way it > works under R5 as it should and we get the following if we hit > debugger from the filter > function: > > w>MiniTerminal:sc > frame retaddr > fd039c18 8000608e MiniView::MessageFilter(BMessage *, BHandler **, > BMessageFilter *) + > 0000002e > fd039c58 ec199012 BLooper::apply_filters(BList *, BMessage *, > BHandler *) + 000000e2 > fd039c88 ec19a8ab BLooper::top_level_filter(BMessage *, BHandler * > ) + 00000087 > fd039cac ec25307e BWindow::task_looper(void) + 000003a2 > fd039d28 ec19ae46 BLooper::_task0_(void *) + 00000036 > fd039d3c ec06c50d thread_start + 00000039 > w>MiniTerminal: > > This tells us, the BWindow::task_looper got the message, called > apply_filters and found > the filter we added to our BView and called it's function. Note that this only applies if the target handler is known at this point. If all handlers are asked subsequently, the message filter must still be applied, which is not yet done (I recently added a comment about this to BHandler::MessageReceived()). > Without my change, we do pretty much the same thing, we would get > into the > task_looper and would call apply_filters. BUT we would not catch the > filter that > was added to our BView, because we would only check the filters that > were > applied to the BWindow itself and not to the view that will later > receive the > B_KEY_DOWN event. A looper knows about its handlers as a windows knows its views - there is nothing special here; a looper must apply the filters for the handlers, the window itself shouldn't care. > If we bdb the MiniTerminal from where we will find that the > BWindow::task_looper calls > BWindow::determine_target somewhere before applying the filters. What > I guess from this > now is: The BWindow finds out whether itself or the focus view will > be the target for this > event and then calls apply_filters for the actual target and not > itself. Why should that behaviour be different for a BWindow (compared to a BLooper)? > For any B_KEY_DOWN or B_KEY_UP event aswell as B_UNMAPPED_KEY_DOWN, > B_UNMAPPED_KEY_UP, > B_MODIFIERS_CHANGED and B_MOUSE_WHEEL_CHANGED the focus view will be > the actual target, so > this is what determine_target returns. > > This does not break the path of the message to dispatch. Even if we > change the target, the > BWindow will get the message to dispatch, but only if we did not > filter it out by our > BMessageFilter: > > if (handler) // the determine_target one -> our MiniView > { > // Do filtering > handler = top_level_filter(fLastMessage, handler); > // filtering is applied to the BMessageFilters of MiniView > > // if we skip the message from within the filter, handler will > be NULL. > // if we don't change the handler to something else from within > our > // filter funcation, the looper of the handler will be the > looper of > // the BWindow we are in -> this one. > if (handler && handler->Looper() == this) > { > // so we get here normally and can handle B_TAB from > // BWindow for TAB navigation. > DispatchMessage(fLastMessage, handler); > } A filter can redirect a message to another looper? And if that's the case, it should probably not be eaten like done here. > We must find out what the target will be first, only then we can call > the correct filters. > I hope this clears it up a bit. That part is correct, but for loopers too. Bye, Axel.