Recording, saving, loading and replaying of Qt input events could come in handy in numerous situations. For example, in automatic GUI testing or when implementing a macro system (like the one in Microsoft Office or Adobe Photoshop), in interactive help systems, demos of all sorts etc.
Input events in Qt are nicely grouped by inheritance of QInputEvent class and there are just 6 classes describing specific events, namely QContextMenuEvent, QKeyEvent, QMouseEvent, QTabletEvent, QTouchEvent and QWheelEvent. All of them are pretty straightforward to serialize, deserialize and clone. Combined with Qt’s ability to install a global event filter (using qApp) it made implementing QIERAP (Qt Input Events Recorder And Player 😉 ) demo possible.
So… today, I give you QInputEventRecorder class, BSD-licensed as always. It facilitates four functions: recording of input events, storing them in binary files (created using QDataStream), loading them back and replaying them with given speed factor. QInputEventRecorder captures events targeted at specified widget and all of its children. It assumes that all widgets have names. In case they don’t you can use QInputEventRecorder::nameAllWidgets(QWidget*) static method which gives unique names to all unnamed children of the specified widget. This method could be further enhanced to generate names in a more reproducible manner, to preserve validity of recordings after GUI modifications, particularly after reordering or insertion of new elements. This is one of the items on my hobby TODO list 😉 In general, event designates are remembered not only by their name but also by their relation to other widgets, e.g. if we have widget_2 which is a child of widget_1 (which has no parent) it’s going to be recorded as widget_1/widget_2, while widget_1 will be recorded simply as widget_1. As an extra precaution, class name of the target widget is also stored, which might be good or bad depending on if you plan to eventually swap classes of some widgets on your form.
I guess that’s pretty much all there is to it, you will learn rest of the story from code itself. I’m also attaching a Win32 binary and a sample recording so that everyone can see it in action 🙂
And this is what you should see when the demo stops running: