Qt Webkit and Javascript magnetic stripe example

Published on March 1, 2011

Archived Notice

This article has been archived and may contain broken links, photos and out-of-date information. If you have any questions, please Contact Us.

At Boundary Devices, we're relative newcomers to the world of Qt, but we were somewhat surprised to learn about Nokia's decision to favor Windows CE instead of MeeGo for future smart phone designs. It's hard for us to say what the right direction may be for the cell-phone marketplace; nevertheless, we're very impressed with the code quality of Qt and the power of Qt Webkit. We've been looking at it with an eye toward how it may be used to integrate hardware like barcode scanners, RFID readers, and magnetic stripe readers. In this post, we'll show how we used the Qt Webkit Bridge to allow Ryan's magstripe driver to deliver events and data directly to a browser.

What events does it handle?

As described in Ryan's earlier post, we've connected a Neuron insertion-style reader to the GPIO ports of the Nitrogen i.MX51 board. These readers are commonly used in casino player-tracking applications to determine when a customer is present and playing a particular slot machine so their loyalty account will be credited with their play. This reader has two switches, front and rear, that allow an application to detect when a card has been inserted and whether it's still present. So, in addition to the information encoded on the magnetic stripe, we have events for each of the switches going open and closed. In the mag_decode driver, all events are delivered in text lines from /dev/magstripe. Switch transitions are indicated by lower and UPPER-case letters F and R for the front and rear switches respectively. Any line containing more than a single letter is data from the magnetic stripe itself.
  • F - Front switch open
  • f - Front switch closed
  • R - Rear switch open
  • r - Rear switch closed
  • data - Magstripe data

How are they handled?

We deliver the events up to Javascript in the form of two callbacks, switchChange() and swipe():
      magstripe.switchChange.connect(function(s){
           console.log("switchChange: "+s);
      });
      magstripe.swipe.connect(function(s){
           console.log("swipe: "+s);
      });
Note that the magstripe global is the object defined by the Webkit bridge. We'll describe the C++ code in detail below. In Qt parlance, the switchChange() and swipe() handlers above are slots connected up to the signals generated by C++. There are other ways to approach this integration. You could use a keyboard wedge and have your app keep track of key-down and key-up events, but you'd need a lot of state and you'd have to be careful about the input focus. You'd also be stuck wondering whether a card is present during initialization. That last problem is dealt with by the next two Javascript interfaces, getMagstripe() and getSwitchState():
      var swstate = magstripe.switchState ;
      console.log( "switch state: "+swstate+"n");
      var ms = magstripe.magstripe ;
      console.log("mag stripe: "+ms);
These two methods of the magstripe allow your web pages to query the state of the mag stripe reader at initialization time. If you were going the keyboard-wedge route, you'd need to pass that state between pages yourself.

How do I get my app to read these events?

As we mentioned before, the key to this whole scheme is the Qt Webkit Bridge. This technology builds upon the solid footing of Qt, allowing QObjects to be exposed to Qt Webkit through the QWebFrame::addToJavaScriptWindowObject() method. This method allows you fine-grained control over what is exposed to the web environment, and includes support for data access and signal delivery. The Qt docs do a great job of describing the Webkit bridge, so we won't delve too far into the details. Instead, we'll describe the primary interfaces we used to implement the magstripe object. The sources for this are available for download. The following is a slightly stripped version of the declaration of class magstripe_t.
class magstripe_t : public QObject {
	Q_OBJECT
public:
	Q_PROPERTY(QString magstripe READ getMagstripe);
	QString getMagstripe(void);
	Q_PROPERTY(QString switchState READ getSwitchState);
	QString getSwitchState(void);
	Q_INVOKABLE void clear();
signals:
	void switchChange(QString);
	void swipe(QString);
private slots:
	void readData(int fd);
	...
};
Things to note about this declaration:
  • magstripe_t is a QObject. This is requirement #1.
  • magstripe_t makes two properties available through the Q_PROPERTY macro. This is really all that's necessary to provide the magstripe and switchState interfaces. Also note that these properties are implemented using getter methods getMagstripe and getSwitchState.
  • magstripe_t exposes a clear() method that is callable from Javascript through the Q_INVOKABLE macro. I forgot to mention this before.
  • magstripe_t can emit two signals: switchChange and swipe. Handlers for these aren't even implemented in C++, as they're designed to be handled in web pages.
  • magstripe_t contains a single slot: readData(). The implementation of this module makes use of something called QSocketNotifier which allows a file descriptor (to /dev/magstripe in this case) to be polled by the main event loop. When data is available to be read from the file descriptor, the main loop generates a signal which is handled by the readData slot. If you read the implementation of this method in magstripe.cpp, you'll see that the code simply parses lines coming from /dev/magstripe and emits either the switchChanged() or swipe() signals.

Watch it in action

Now for the requisite video of this in action. The screen layout uses the really nice JQuery Mobile library and uses two images to display the state of each of the front and rear switches. It also contains a static text field displaying the last magstripe read and a list box with the history (so you can see changes with each event). I hope this blog post is helpful to others exploring the Qt framework and Qt Webkit. Using these helpful tools, you can simply and directly define which events and interfaces you want to expose from native code into a browser. The Trolltech (Nokia) folks have done some amazing work making all of this so straightforward and they deserve a lot of kudos.