Trolltech | Documentation | Qt Quarterly | « Data Sharing with Class | Fun, Fast and Flexible Qt Script »

Early Easter Eggs
Qt has a very flexible and powerful event system. In this article, we will use it to hide an Easter egg in an application -- too late for this year's Easter, but early enough for next year.

An object can monitor another object's events by calling QObject::installEventFilter():

    targetObj->installEventFilter( monitorObj );

After the call, all events destined for the target object first pass through the monitor object's eventFilter() virtual function. And if the target object is qApp, the events for all objects in the application pass through the monitor's eventFilter() function.

This technique can be used to implement an EasterEgg class that helps you hide Easter eggs in your application. For example, as long as the EasterEgg object constructed below exists, the doSomething() slot of myWin is called when the user types the magic word 'TEKEHTOPA':

    EasterEgg egg1( "TEKEHTOPA", myWin, SLOT(doSomething()) );

We will present the code for EasterEgg step by step, starting with the class definition.

    class EasterEgg : public QObject
    {
	Q_OBJECT
    public:
	EasterEgg( const char *magicWord, QObject *target, const char *slot );

	virtual bool eventFilter( QObject *obj, QEvent *event );

    signals:
	void found();

    private:
	QCString magic;
	int j;
    };

The EasterEgg class inherits QObject and reimplements QObject::eventFilter(). The private data member magic holds the magic word, and j holds how far the user got into typing it. For example, if magic is 'TEKEHTOPA' and the user has typed 'TEKE' so far, then j equals 4. The found() signal is emitted when the user has typed the entire magic word.

    EasterEgg::EasterEgg( const char *magicWord, 
                          QObject *target, const char *slot )
	: magic( magicWord ), j( 0 )
    {
	qApp->installEventFilter( this );
	connect( this, SIGNAL(found()), target, slot );
    }

The constructor initializes the private data members, installs the EasterEgg object as a monitor for the application's events, and connects found() to the slot passed as parameter.

    bool EasterEgg::eventFilter( QObject *obj, QEvent *event )
    {
	if ( event->type() == QEvent::KeyPress ) {
	    QKeyEvent *keyEvent = (QKeyEvent *) event;
	    int key = keyEvent->key();
	    if ( magic[j] == key ) {
		j++;
		if ( j == magic.length() ) {
		    emit found();
		    j = 0;
		}
	    } else {
		int right = j;
		while ( j > 0 ) {
		    if ( magic[j - 1] == key &&
			magic.left(j - 1) == magic.mid(right - j + 1, j - 1) )
			break;
		    j--;
		}
	    }
	}
	return FALSE;
    }

The reimplementation of QObject::eventFilter() updates j according to which key is pressed. If the key is the expected one, j is incremented by one; otherwise, j is decremented. The found() signal is emitted when the magic word has been typed, and j is then reset to 0. At the end of the function, we return FALSE, indicating that the event should be propagated to its target object.

The code that decrements j (the 'else' branch of the 'if' above) is tricky. It's tempting to reset j to 0, but that would sometimes be wrong. For example, if the user typed 'TEKT', j should be 1, not 0, since the last T can be the first T of 'TEKEHTOPA'. If the magic word is 'OOP', j equals 2 when the user has typed 'OO' and should remain 2 when a third 'O' is typed.

The beauty of this approach is that it doesn't require a QApplication subclass and it allows multiple Easter eggs, with distinct magic words, simultaneously. Its main limitation is that it only understands key presses, but there's nothing fundamentally different with other types of event.

Easter eggs are one of the most charming traditions of computer science, along with video game cheats. The EasterEgg class can be used for both. If you want to find out more about Easter Eggs, including the 'Spy Hunter' style game in Microsoft Excel 2000, see the Easter Eggs Archive at www.eeggs.com.

If you want to find out more about event filters, read the documentation for QApplication::notify() as well as Events and Filters.


This document is licensed under the Creative Commons Attribution-Share Alike 2.5 license.

Copyright © 2002 Trolltech. Trademarks Fun, Fast and Flexible Qt Script »