Gamepad

What's New in Qt 5.7.0: Qt Gamepad

By Jeff Tranter

Qt Gamepad is a Qt module that supports the use of gamepad hardware. Gamepad is the term used to refer to input devices with buttons, directional controls (which may be digital joypads or analog joysticks), and sometimes keys for keyboard input. Used on video game consoles, they are also available for personal computers. (They typically connect using a USB interface.)

The Qt Gamepad module is new in Qt 5.7.0 and provides both QML and C++ interfaces. It is considered a tech preview release in Qt 5.7.0, which means that the APIs are still subject to change in the future.

The module supports Linux, Windows, macOS/iOS and Android platforms, as well as any other platform that supports the Simple DirectMedia Layer (SDL) library.

It can read button and axis input events from game controllers, as well as keyboard events.

C++ Classes

The Qt Gamepad module defines three classes: QGamepad, QGamepadManager, and QGamepadKeyNavigation. Note that for Qt 5.7.0, only the QGamepad class is documented in Qt Assistant (1).

QGamepad represents a gamepad controller device attached to the system. QGamepadManager provides a higher level interface for querying the attached gamepads and events related to all of the devices. The QGamepadKeyNavigation class provides support for keyboard events triggered by gamepads. All three classes derive from QObject and provide signals, slots, and properties.

There are five Qt Gamepad programming examples included with the Qt 5.7.0 source that can be helpful for understanding how the C++ APIs work. We'll explore a programming example in this blog.

Here are screen shots of two of the example programs:

demo1.png


demo2.png

QML Types

Qt Gamepad also provides a QML interface to gamepads, though the QML types are not documented as of Qt 5.7.0. The components provided when you import the module QtGamepad 1.0 are QGamepad, QGamepadKeyNavigation, QGamepadManager, and QGamepadMouseItem. The first three are analogous to the corresponding C++ types and provide similar methods.

The quickGamepad example, included with the Qt 5.7.0 source, illustrates how to use the Qt Gamepad module from QML.

An Example

Here is a short C++ example application. It was loosely based on the simple example included in the Qt source code, but with a few changes. Unlike the original example, I selected the QGamepadManager class to illustrate its usage.

The program displays information about any attached gamepad, and then outputs events from the first device. Here is source code for the main portion of the code. You can download the complete compilable example from the ICS ftp site (2).

#include "gamepadmonitor.h"
#include <QObject>
#include <QDebug>
#include <QGamepad>
#include <QGamepadManager>

GamepadMonitor::GamepadMonitor(QObject *parent)
    : QObject(parent)
{
    qDebug() << "QGamePadManager Demo\n";

    auto gamepads = QGamepadManager::instance()->connectedGamepads();
    qDebug() << "Number of gamepads:" << gamepads.size();

    for (auto i : gamepads) {
        QGamepad *gamepad = new QGamepad(i);
        qDebug() << "Gamepad:" << i;
        qDebug() << "  device id:   " << gamepad->deviceId();
        qDebug() << "  name:        " << gamepad->name();
        qDebug() << "  is connected?" << gamepad->isConnected();
    }

    qDebug() << "\nMonitoring for events...\n";

    connect(QGamepadManager::instance(), &QGamepadManager::connectedGamepadsChanged, this,
        []() { qDebug() << "connected gamepads changed:"; });
    connect(QGamepadManager::instance(), &QGamepadManager::gamepadConnected, this,
        [](int deviceId) { qDebug() << "gamepad connected:" << deviceId; });
    connect(QGamepadManager::instance(), &QGamepadManager::gamepadDisconnected, this,
        [](int deviceId) { qDebug() << "gamepad disconnected:" << deviceId; });
    connect(QGamepadManager::instance(), &QGamepadManager::gamepadButtonPressEvent, this,
        [](int deviceId, QGamepadManager::GamepadButton button, double value) { qDebug() << "button press event:" << deviceId << button << value; });
    connect(QGamepadManager::instance(), &QGamepadManager::gamepadButtonReleaseEvent, this,
        [](int deviceId, QGamepadManager::GamepadButton button) { qDebug() << "button release event:" << deviceId << button; });
    connect(QGamepadManager::instance(), &QGamepadManager::gamepadAxisEvent, this,
        [](int deviceId, QGamepadManager::GamepadAxis axis, double value) { qDebug() << "axis event:" << deviceId << axis << value; });
    connect(QGamepadManager::instance(), &QGamepadManager::buttonConfigured, this,
        [](int deviceId, QGamepadManager::GamepadButton button) { qDebug() << "button configured:" << deviceId << button; });
    connect(QGamepadManager::instance(), &QGamepadManager::axisConfigured, this,
        [](int deviceId, QGamepadManager::GamepadAxis axis) { qDebug() << "axis configured:" << deviceId << axis; });
    connect(QGamepadManager::instance(), &QGamepadManager::configurationCanceled, this,
        [](int deviceId) { qDebug() << "configuration canceled:" << deviceId; });
}

QGamepadManager is a singleton, and provides a method to return a list of the identifiers for all the connected gamepads. When given an identifier, you can create a gamepad object, as we did in the for loop above.

The QGamepadManager instance emits signals when events occur from any gamepad. This includes button and axis events, as well as gamepad devices being connected or disconnected. Note my use of C++11 Lambda functions to avoid having to create slots for each signal.

wingman_0.jpg

In order to experiment with the Qt Gamepad module, I used an old Logitech Wingman Attack 2 USB joystick that I had on hand.

Technically this is a joystick, rather than a gamepad. However, this is not an issue because on the Linux platform kernel drivers for USB joysticks use the same evdev input event interface as other input devices, including gamepads, mice, keyboards and touchscreens.

I tested it on an Ubuntu Linux desktop system. Supported USB devices should be detected and load the appropriate Linux kernel driver. On my system, the output of dmesg indicated that a suitable device was found and a driver loaded:

 

 

usb 3-2.1: New USB device found, idVendor=046d, idProduct=c20d
usb 3-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 3-2.1: Product: WingMan Attack 2
usb 3-2.1: Manufacturer: Logitech
usb 3-2.1: ep 0x81 - rounding interval to 64 microframes, ep desc says 80 microframes
input: Logitech WingMan Attack 2 as /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2.1/3-2.1:1.0/input/input30
hid-generic 0003:046D:C20D.000C: input,hidraw3: USB HID v1.10 Joystick [Logitech WingMan Attack 2] on usb-0000:00:14.0-2.1/input0

 

Running the sample application produced the following output:

QGamePadManager Demo

Number of gamepads: 1
Gamepad: 49677
  device id:    49677
  name:         ""
  is connected? true

Monitoring for events...

button press event: 49677 6 0.94902
axis event: 49677 0 1
button release event: 49677 6
axis event: 49677 1 -0.858824
button press event: 49677 6 1
axis event: 49677 0 -0.529412
axis event: 49677 1 -0.905882
axis event: 49677 1 -0.898039
axis event: 49677 1 -0.921569
button press event: 49677 6 0.972549
button press event: 49677 6 0.0901961
button press event: 49677 6 0.0588235
button release event: 49677 6
button release event: 49677 6

On the Windows platform, which uses the XInput API, the Wingman 2 was detected as a joystick -- but not as a gamepad. As a result, the example Qt gamepad programs did not report any devices connected. I also tried the SDL backend on Linux and it did not detect the Wingman 2 as a gamepad.

With a suitable gamepad device, the program example above should work on other platforms where the Qt Gamepad module is supported, assuming it is included as part of your Qt build.

Summary

A number of commercial and open source games have been written using Qt. With the new Qt Gamepad module, it will now be easier for game developers to support input from gamepads in a portable manner. I hope this will encourage more game developers to consider using Qt.

In Qt 5.7.0, the module is still a technical preview. I look forward to seeing the APIs finalized and better documented in future Qt releases.

References

  1. Qt Gamepad, Qt Documentation Snapshot, last accessed 1 Aug 2016, https://doc-snapshots.qt.io/qt5-dev/qtgamepad-index.html
  2. Source Code for Example Application, last accessed 1 Aug 2016, ftp://ftp.ics.com/pub/pickup/gamepadexample.zip