Scythe Studio website employs cookies to improve your user experience (Read more)

How to track keyboard usage on Windows with Qt in 2020

There are many use cases when the frequency of user input needs to be tracked. The simple example is a time-tracking app (like Chronos) with a feature of tracking user activity based on keyboard usage. This way employer can be sure that employees are productive. At first sight, the problem seems to have a simple solution – in case of C++ class just implement eventFilter method, or when dealing with QML simply create a handler for signal Keys.onPressed.

The solution seems to work fine, but under one crucial condition – app window maintain focused. When a user switches to another app or minimises Qt app, tracking of keyboard won’t be occurring, even though the Qt app is still running.

How to track keyboard usage in the background using Qt and QML on Windows, then? We will show you the solution for Windows which has this feature. Let’s break it into pieces to make sure that you will know how it is working from inside out.


The libraries

On the beginning, you should create a C++ class that will take care of tracking keyboard. As the solution needs to be accessible from QML level, the C++ class need to inherit from QObject. Initially, your class should look like this:

#include <QObject>

class KeyboardMonitor : public QObject
    explicit KeyboardMonitor(QObject *parent = nullptr);


To make background keyboard tracking possible you will need to include winuser header to your project. This library is part of Win32 API, so no additional library linking is needed. You can read more about it in the documentation. However, to make this library work you need also to add windows header.

#include <QObject>
#include <windows.h>
#include <winuser.h>

class KeyboardMonitor : public QObject
    explicit KeyboardMonitor(QObject *parent = nullptr);



Checking keys state

Now you have all the necessary components to begin tracking. First of all, you need to check the state of keys, to know if they’re pressed or not. GetAsyncKeyState function will be most suitable for this. How does this function work? The best answer can be found in the documentation:

If the function succeeds, the return value (SHORT type) specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState. However, you should not rely on this last behavior.

The function takes the virtual-key code as a parameter, to determine which key to check. The virtual-key codes range from 1 to 254. As quoted above to determine if the key was pressed, you need to verify if the most significant bit is set. To do so, you can use bitwise AND operation (more about it here) with the value of key state returned by GetAsyncKeyState and expected value. As the returned value is a SHORT type it has a length of 16-bits. The decimal value of short with only most significant bit set is 32 768 which equals to 0x100000 in the hexadecimal positional system.

The first step will be to count the number of keys pressed by the user. The simplest way is to just loop through all the keys and check if the value of their state has the most significant bit set. If the bit is set, the number of pressed keys is incremented. You can store it in some variable like numberOfActions. The function (trackActions sounds like a good name) should look similar to this:

void KeyboardMonitor::trackActions() {
    for (int i = 1; i < 255; ++i) {
        if(GetAsyncKeyState(i) & 0x100000) {



Right now, you can count the number of user key presses, but the function needs to be called manually. If you just put it in the infinite loop the whole app could just freeze due to GUI thread being blocked (if you are not implementing any kind of multi-threading). Do not worry – there is an uncomplicated solution that fits perfectly into the Qt philosophy.

All you need to do is to create an instance of QTimer object (call it _timer for instance) and connect the timeout signal to trackActions function which you just created. This way, every time the timer triggers, trackActions is called. The connection can be created inside class constructor by adding just a single line:

connect(_timer, &QTimer::timeout, this, &KeyboardMonitor::trackActions);

Now you should set the timer interval. This will indicate how often the keys states would be checked. According to research done by Kevin Killourhy and Roy Maxion (more information about it here), the statistical average time of a single key-press is about 100 ms. We will stick to this interval. What is left to start a timer. At this point class constructor should look much like this:

KeyboardMonitor::KeyboardMonitor(QObject *parent) : QObject(parent)
  , _numberOfActions(0)
  , _timer(new QTimer(this)) //timer object initialization
    //Connecting timer to function that handles keboard tracking
    connect(_timer, &QTimer::timeout, this, &KeyboardMonitor::trackActions);


Usage statistics

Key presses counting is not the most elegant way to present user activity. What if the app counts a lot of activity short after launching, and after that, no input would be recorded? The result will look normal, due to the lack of reference to the time when the keys were pressed.

The solution is to create a variable that will store the count of key presses occurred only in a single second – the history of values can be stored any other dynamic data structure. For now, let’s only create a variable to store that value. If you want to see how to implement vector containing history check Scythe-Studio Github page.

APS looks like a good name for a new member variable. This acronym stands for Actions Per Second. While defining variable try to use Q_PROPERTY macro – it will help us a lot when trying to expose this variable to QML later. Simply create a property macro and use refactor option in the context menu to auto-generate setter, getter and signal.

Using Qt Creator refactor option

As we want to update APS value after each second, we will need to wait for several timer iterations to pass before the update. In this case, 1 second passes after 10 of 100-millisecond intervals. The same effect could be achieved by using an additional timer with iteration set to 1 sec, although there is a catch. As every timer works on a separate thread some synchronisation mechanism (like mutex) would be needed. We want to keep code as simple as possible, so we will stick to determining time passing with an iterator.

Now all you need to do inside trackActions function is to add increment instruction for iterator and add APS variable update when the iterator reaches a value of 9 (since counting from 0):

void KeyboardMonitor::trackActions() {
    for (int i = 1; i < 255; ++i) {
        // The bitwise and selects the function behavior
        if(GetAsyncKeyState(i) & 0x100000) {
            //If the button is pressed number of action is increased

    if(_secIterator == 9) {
        _secIterator = 0;
        _numberOfActions = 0;


Exposing to QML

At this point, you have a fully functional monitor that can be accessed from C++. In case you want to show the result of tracking in QML GUI, you need to make accessing monitor class from the QML level possible. Thanks to previous additions this will be pretty easy.

In the first step, you need to create an instance of a monitor in main.cpp file. After that, you should provide context for the engine to make monitor accessible from QML. This can be done using setContextProperty function, that needs QQmlContext header to be included.

KeyboardMonitor* keyboardMonitor = new KeyboardMonitor();

QQmlApplicationEngine engine;

//First parameter is name of object that you will use to access it from QML, second is a pointer to it
engine.rootContext()->setContextProperty("keyboardMonitor", keyboardMonitor);

Now you can access monitor object in any QML file inside your project. Thanks to the Q_PROPERTY macro used before, all the variables decorated with it can be accessed like standard QML properties, including property binding, and using signals like onValueChanged.

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

ApplicationWindow {
  visible: true
  width: 640
  height: 480
  title: qsTr("Hello World")

  Page {
    id: mainPage
    anchors.fill: parent

    Text {
      id: apsLabel

      anchors {
        horizontalCenter: parent.horizontalCenter
        bottomMargin: 40

      font.pointSize: 30
      text: qsTr("APS")

    Text {
      id: apsValue
      anchors.centerIn: parent

      font.pointSize: 60
      text: keyboardMonitor.aps

Now you can see how the app works:

Learn more

If you are still hungry for knowledge you can find the whole project and source code with some extra features on Scythe-Studio Github page. Don’t forget to like Scythe-Studio Facebook page to get notifications about new posts!




Scythe-Studio does not bear responsibility for inappropriate or malicious use of presented solutions and code. The whole content of the post has fully educational purpose.

Latest posts

Company employees self-development main image
Company employees self-development

 Anyone who works in the IT industry knows how important self-development is. Improving our competence helps us to find better […]

24 Jun 2021
QML 3D: First impressions main image
QML 3D: First impressions

If we think about it for a minute, it is impossible to imagine an app without a UI. We need […]

26 May 2021
Top 10 Cross-platform apps ideas 2021 main image
Top 10 Cross-platform apps ideas 2021

When developing an application you want it to be as enjoyable for clients as it’s possible, so you take much […]

15 Apr 2021
How tu customise installer behaviour with Qt Installer Framework main image
How tu customise installer behaviour with Qt Installer Framework

In previous posts of this series, we briefly touched on the topic of scripting, while describing how to add custom […]

30 Mar 2021
How to use NFC in Qt/Qml application? main image
How to use NFC in Qt/Qml application?

Have you ever wondered how to use NFC in Qt/Qml application? This blog post will give you a complex overview […]

09 Mar 2021
How to generate barcode in Qt/QML application main image
How to generate barcode in Qt/QML application

Nowadays, everywhere we look, no matter if it’s a real-life shop or web page, we can see these little, simple and useful, […]

24 Feb 2021
Low technology stack with Qt: Saved money main image
Low technology stack with Qt: Saved money

When creating a new software, you want the quality to be the highest, while keeping the costs low and delivery […]

08 Feb 2021
How to customize installer UI with Qt Installer Framework main image
How to customize installer UI with Qt Installer Framework

In the previous post you learned the basics of the app deployment process and installer generation. However Qt Installer Framework […]

12 Jan 2021
Deploying app and generating offline installers for Windows Qt Installer Framework tutorial main image
Deploying app and generating offline installers for Windows Qt Installer Framework tutorial

Development is not an only part of product delivering – deployment and maintenance are both equally important parts of the […]

25 Nov 2020
How to interface Qt with Android Java code main image
How to interface Qt with Android Java code

Software development is demanding and often requires us to use languages or solutions that are not part of our main […]

18 Nov 2020