Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Register Global Hotkey under Qt and Mac OS X

Tags:

c++

macos

cocoa

qt

Having read through various posts and threads that lead me nowhere I need your help.

I do have a Qt Application for Mac OS X that at some point of use will be in the background and not active. When this is the case I want to add a global hotkey so that the user can easily turn certain features on or off by clicking pre-defined hotkeys. The following isn't working while the app is in the background and not focused.

QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_F12), parent);
shortcut->setContext(Qt::ApplicationShortcut);

So far I found Qxt which happens to be outdated for Qt 5.5. Then there is DDHotkey which requires a certain compiler which we can not use for various reasons. Lastly, I found the solution of adding a global AppleScript which registers an event, again, not what I am looking for.

tell application "System Events" to tell process "myApp"
    click menu item "myButton" of menu 1 of menu bar item "Menu" of menu bar 1
end tell

Is there a way to use objective-c or cocoa to accomplish exactly what I am looking for? Please lead me in the right direction if I may have missed something.

Thanks in advance!


To those who seek a more Qt way, check the following repository: https://github.com/ddqd/qxtglobalshortcut5

It makes use of the outdated qxt library but gets it working again. The person tested it until Qt 5.4, we use it successfully under Qt 5.5.

like image 719
Philipp Meissner Avatar asked Nov 30 '15 16:11

Philipp Meissner


1 Answers

This might be what you're looking for https://github.com/jaz303/JFHotkeyManager

You could also look at this example from Apple, using the RegisterEventHotKey API call which I think will point you in the right direction. https://developer.apple.com/library/prerelease/mac/samplecode/FunkyOverlayWindow/Listings/FunkyOverlayWindow_OverlayWindow_m.html#//apple_ref/doc/uid/DTS10000391-FunkyOverlayWindow_OverlayWindow_m-DontLinkElementID_8

Or you could try this code

#import <Carbon/Carbon.h>

EventHandlerUPP hotKeyFunction;

pascal OSStatus hotKeyHandler(EventHandlerCallRef nextHandler,EventRef theEvent, void *userData)
{    
    Notify *obj =  userData;
    [obj foo];    
    return noErr;
}

@implementation Notify

- (id)init
{
    self = [super init];
    if (self) {
        //handler
        hotKeyFunction = NewEventHandlerUPP(hotKeyHandler);
        EventTypeSpec eventType;
        eventType.eventClass = kEventClassKeyboard;
        eventType.eventKind = kEventHotKeyReleased;
        InstallApplicationEventHandler(hotKeyFunction,1,&eventType,self,NULL);
        //hotkey
        UInt32 keyCode = 80; //F19    
        EventHotKeyRef theRef = NULL;
        EventHotKeyID keyID;
        keyID.signature = 'FOO '; //arbitrary string
        keyID.id = 1;
        RegisterEventHotKey(keyCode,0,keyID,GetApplicationEventTarget(),0,&theRef);

    }        
    return self;
}

- (void)foo
{

}

@end

And the header

#include "notify.mm"
@interface Notify
 - (id)init;
 - (void)foo;
@end

Simply this is just a object with a method and a constructor, in objective-c this is called init, or initialize, and variants. Calling it should be straight forward with "new".

E.x

#include "notify.h"
int main(){
  Notify* object = new Notify();
}

However, some basic understanding of Objective-C is needed. It's mostly syntax differences in my opinion. But I'm no Objective-C expert myself. Anyway, there is a lot of ways to solve it, this might not be the best idea. You can also call Objective-C code from inside of a C++ class of yours. Take a look at the links bellow for a great example of how that's done.

https://el-tramo.be/blog/mixing-cocoa-and-qt/

https://github.com/remko/mixing-cocoa-and-qt/

http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++

like image 86
Meeh Avatar answered Sep 23 '22 17:09

Meeh