03 October, 2013

Пишем Objective-C код прямо в Qt проекте, не выходя из Qt Creator

На примере обработчика глобальных горячих клавиш MacOSX

Иногда бывают случаи, когда необходимо добавить в программу платформо-зависимый код, и, если в Linux и Windows все стандартные заголовки являются C/C++ заголовками, то в среде MacOSX это Objective-C заголовки, и если их просто подключить в проект, вы получите тысячи и тысячи ошибок сборки, поэтому для MacOSX необходима возможность писать часть кода на Objective-C,  и такая возможность есть.

Разбирать будем на примере перехвата глобального сочетания горячих клавиш с помощью платформозависимого метода
bool QApplication::macEventFilter(EventHandlerCallRef caller, EventRef event).
Если переопределить этот виртуальный метод, вы будете получать вообще все event'ы от  опереционной системы в него, соответственно нам необходимо отфильтровать то, что нас интересует и отдать управление дальше в ином случае, чтобы проигнорировать событие данный метод просто должен вернуть false. Но для того, чтобы проверить событие event, нам необходимо сконвертировать его в NSEvent * - класс из MacOSX API.

Итак, первое что нужно сделать, это объявить в каком-нибудь заголовочном файле функцию нашего обработчика (скорее всего это будет заголовок вашего класса наследника от QApplication):
#ifdef Q_WS_MAC
bool eventHandler(EventRef e);
#endif
Далее мы создаем файл с телом этой функции и расширением .mm, назовем его mac_helper.mm:
#include <QtDebug>
#ifdef QT_MAC_USE_COCOA
#import <Cocoa/Cocoa.h>
bool eventHandler(EventRef e)
{
   NSEvent *event = reinterpret_cast<NSEvent *>(e);
   Q_ASSERT(event);
   if ([event type] == NSKeyDown) {
       if ([event modifierFlags] & NSShiftKeyMask) {
           if ([event keyCode] == 0x44) {
               qDebug() << "Hello key event!";
               return true;
           }
       }
   }
   return false;
}
#endif
В этом файле мы видим тело нашей функции написанное уже на Objective-C, хотя, как вы можете заметить, мы смело используем обычный qDebug(), и это будет работать.

Осталось только вызвать наш обработчик из QApplication:
#ifdef Q_WS_MAC
bool RMS_Keyboards_Application::macEventFilter(EventHandlerCallRef, EventRef e)
{
    return eventHandler(e);
}
#endif
И не забыть добавить .mm файл в проект, это делается таким образом:
mac {
     OBJECTIVE_SOURCES += mac_helper.mm
}
Кстати, для заголовков на Objective-C тоже есть директива, она, как не трудно догадаться называется: OBJECTIVE_HEADERS.

На этом все.

1 comment:

  1. День добрый и с Новым Годом!
    У меня так и не получилось подружить Qt с objective-C... :(
    >#ifdef QT_MAC_USE_COCOA
    - данный флаг у меня выключен, включить надобно где-то в настройках проекта? Где именно? Или пересобрать Qt (какие флаги надо будет установить при сборке)?
    >#import
    - сорри, не нашёл данной библиотечки на своём маке... Не подскажете, где её искать? Или это связано с ответом на вопрос выше?

    Буду премного благодарен за Ваши ответы или разъяснения

    ReplyDelete