Does Global Shortcuts exist ?



  • Hi,

    Qxt provided a Global Shortcut class, making shortcuts available even if the app had not the focus : http://libqxt.bitbucket.org/doc/tip/qxtglobalshortcut.html
    Sadly, it's no more maintened.

    Does Qt propose an alternate solution ?

    Thanks in advance.



  • I think this class could do the job : http://doc.qt.io/qt-5/qabstractnativeeventfilter.html
    But it's a low level approach, something like QCoreApplication::registerGlobalShortcut(QKeysequence*, &slot) would have been more convenient.


  • Moderators

    Qt doesn't expose cross-platform way to do that AFAIK. I haven't actually tested but I don't think an app that doesn't have keyboard focus receives any native events, at least on Windows.

    You would have to first ask for it explicitly by registering a hotkey using native api (e.g. RegisterHotKey and then you could check for the WM_HOTKEY message in the installed native event filter.



  • Thanks you for your answer. It's apreciated, because I can't get the thing working.
    I first tried that, and it works :

    #include <QCoreApplication>
    #include "windows.h"
    #include <QDebug>
    
    int main(int argc, char *argv[])
    {
        if (RegisterHotKey(NULL, 1, MOD_ALT | 0x4000, 0x42))  //0x42 is 'b'
        {
            qDebug() << "Hotkey 'ALT+b' registered, using MOD_NOREPEAT flag";
        }
    
        MSG msg = {0};
        while (GetMessage(&msg, NULL, 0, 0) != 0)
        {
            if (msg.message == WM_HOTKEY)
            {
                qDebug() << "WM_HOTKEY received";
            }
        }
    
        return 0;
    }
    

    Basically, it's a copy of the example of Microsoft.
    Now I try to use the QCoreApplication::setNativeEventFilter method : just a QCoreApplication, and a derived class with one method rewritten :

    #include <QAbstractNativeEventFilter>
    #include <QCoreApplication>
    #include <QDebug>
    #include "windows.h"
    
    class NativeEventFilter: public QAbstractNativeEventFilter
    {
        public:
            bool nativeEventFilter(const QByteArray& eventType, void* message, long*)
            {
                if (eventType == "windows_dispatcher_MSG")
                {
                    MSG* msg = static_cast<MSG*>(message);
                    qDebug() << QString("Message: %1").arg(msg->message);
    
                    if (msg->message == WM_HOTKEY)
                    {
                        qDebug() << QString("Event WM_HOTKEY received");
                        return true;
                    }
                }
                return false;
            }
    };
    
    int main(int argc, char *argv[])
    {
        if (RegisterHotKey(NULL, 1, MOD_ALT | 0x4000, 0x42))  //0x42 is 'b'
        {
            qDebug() << "Hotkey 'ALT+b' registered, using MOD_NOREPEAT flag";
        }
    
        QCoreApplication app(argc, argv);
        NativeEventFilter* nef = new NativeEventFilter;
        app.installNativeEventFilter(nef);
        return app.exec();
    }
    

    I can't see an WM_HOTKEY event anymore...

    Any tip to get something like that working would be greatly apreciated. Perhaps I am totally on the wrong way ?


  • Moderators

    Despite of what the docs seem to suggest a hotkey message comes with the eventType set to "windows_generic_MSG" and not "windows_dispatcher_MSG".

    Since any type of Windows message is a MSG struct pointer and that code won't compile on any other platform anyway there's little point to checking that type I think. Something like this works ok:

    bool nativeEventFilter(const QByteArray&, void* message, long*) {
    #ifdef Q_OS_WIN
        MSG* msg = static_cast<MSG*>(message);
        if(msg->message == WM_HOTKEY)
            qDebug() << "WM_HOTKEY !";
    #endif
        return false;
    }
    

    Btw. I don't see any info on MSDN about what happens to the registered hotkey when your process finishes, so just to be on the safe side you might want to call UnregisterHotKey after you're done with it. Also don't forget to change the second param (the id) of the RegisterHotKeyif you're gonna use several different hotkeys.



  • Many, many thanks, you're right, and I have got it work now !

    https://github.com/Folcogh/FMetro/blob/master/NativeEventFilter.hpp
    See this class : https://github.com/Folcogh/FMetro/blob/master/NativeEventFilter.cpp
    (like you said, I should add a call to UnregisterHotKey in the dtor)

    I have removed the type check, and I have read the sources of Qxt : http://libqxt.bitbucket.org/doc/

    The documentation says something about returning 'true' after reading the event, but Qxt doen't act like that.
    So the Qt's documentation seems rather wrong about global hotkeys.

    Also don't forget to change the second param (the id) of the RegisterHotKeyif you're gonna use several different hotkeys.

    Qxt uses the key code to identify the keys, it's a nice idea.

    Now I have to work learn how Windows maps the keyboard, and how Qt does it, to allow me to translate a Windows key into a Qt key.

    Many thanks again, it was a must-have feature to my program. :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.