Introduction

The BlackBerry platform support library, BPS, provides an API for system events. In Qt, BPS events are integrated into Qt’s event loop, i.e. Qt receives and consumes BPS events. One example in which Qt consumes a BPS event is the NAVIGATOR_EXIT event – when receiving that event, Qt will trigger quitting the application. See Handling BPS events [developer.blackberry.com] article for more details.

Receiving BPS events

Since BPS events are integrated into Qt’s event loop, how is it possible as a user to still receive BPS events? An application should never call bps_get_event() [developer.blackberry.com] itself, as that would ‘steal’ the events from Qt, and Qt would miss out on important events like the above mentioned NAVIGATOR_EXIT.

Instead, Qt offers to install native event filters. Once a native event filter is installed, Qt will forward all BPS events to that native event filter. So the solution for receiving BPS events is to install a native event filter and process the BPS events in the event filter function.

The following example shows how to install native event filters to process a NAVIGATOR_SWIPE_DOWN event. The Qt4 and the Qt5 versions are a bit different, therefore the two code examples.

Native event filters are installed on a per-thread basis, as each thread in Qt has its own event dispatcher. Each thread only receives the native events requested in that thread. If your code that installs the native event filter is running in multiple threads, this needs to be considered, especially in Qt4 version, in which the previous event filter pointer then needs to be stored on a per-thread basis, and not as a global variable.

Note that this wiki page is about native events only, e.g. BPS events on the BlackBerry platform. Receiving normal QEvents is an entirely unrelated matter, see the documentation of QCoreApplication::notify() [qt-project.org] for details about that.

Qt4 Example

First, install the native event filter. Note that the previous event filter needs to be remembered, as the native event filters form a chain – one event filter always needs to pass on the native event to the previous filter in the chain, otherwise the event gets lost!

  1. static QAbstractEventDispatcher::EventFilter s_previousEventFilter = 0;
  2. s_previousEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(s_eventFilter);

Afterwards, make sure BPS delivers navigator events to the current thread. For certain types of events, like navigator and virtual keyboard events, Qt will already have requested the events, but I can’t hurt to request them twice:

  1. navigator_request_events();

Other event types, such as mmrenderer events, are not automatically requested by Qt, there you have to call the appropriate foo_request_events() function yourself.
Note that it is not necessary to call bps_initialize() yourself, Qt already does that for you. But again, it doesn’t hurt either.
Lastly, let’s have a look at the event filter function:

  1. static bool s_eventFilter(void *message)
  2. {
  3.     bps_event_t * const event = static_cast<bps_event_t *>(message);
  4.  
  5.     if (event && bps_event_get_domain(event) == navigator_get_domain()) {
  6.         const int id = bps_event_get_code(event);
  7.         if (id == NAVIGATOR_SWIPE_DOWN)
  8.           qDebug() << "The user swiped down!";
  9.     }
  10.  
  11.     if (s_previousEventFilter)
  12.         return s_previousEventFilter(message);
  13.     else
  14.         return false;
  15. }

Note that in Qt4, native event filters should never be removed once installed, as that will easily break the chain. Instead of removing a native event filter, simply don’t do any event processing in it anymore, apart from passing the event on to the previous element in the chain.

Qt5 Example

The API for native event filters in Qt5 has been improved, the brittle event filter chaining is no longer exposed.

Instead of an event filter function like in Qt4, there is an event filter object:

  1. class MyEventFilter : public QAbstractNativeEventFilter
  2. {
  3.   bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE
  4.   {
  5.     Q_UNUSED(eventType);
  6.     Q_UNUSED(result);
  7.  
  8.     bps_event_t * const event = static_cast<bps_event_t *>(message);
  9.     if (event && bps_event_get_domain(event) == navigator_get_domain()) {
  10.         const int id = bps_event_get_code(event);
  11.         if (id == NAVIGATOR_SWIPE_DOWN)
  12.           qDebug() << "The user swiped down!";
  13.     }
  14.  
  15.     return false; // Do not filter out the event
  16.   }
  17. };

Installing the event filter is easy:

  1. MyEventFilter *filter = ...;
  2. QCoreApplication::eventDispatcher()->installNativeEventFilter(filter);

Afterwards, make sure BPS delivers navigator events to the current thread. For certain types of events, like navigator and virtual keyboard events, Qt will already have requested the events, but I can’t hurt to request them twice:

  1. navigator_request_events();

Other event types, such as mmrenderer events, are not automatically requested by Qt, there you have to call the appropriate foo_request_events() function yourself.
Note that it is not necessary to call bps_initialize() yourself, Qt already does that for you. But again, it doesn’t hurt either.

In Qt5, native event filters can easily be removed again by calling QAbstractEventDispatcher::removeNativeEventFilter().

Categories: