Получение координат мыши на Мохаве - PullRequest
0 голосов
/ 04 января 2019

У меня есть очень простое приложение для командной строки, которое захватывает координаты мыши при следующем щелчке мыши.

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>

CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
    CGFloat displayScale = 1.0f;
    if ([[NSScreen mainScreen] respondsToSelector:@selector(backingScaleFactor)])
    {
        displayScale = [NSScreen mainScreen].backingScaleFactor;
    }

    CGPoint loc = CGEventGetLocation(event);
    CFRelease(event);
    printf("%dx%d\n", (int)roundf(loc.x * displayScale), (int)roundf(loc.y * displayScale) );
    exit(0);
    return event;
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        CFMachPortRef eventTap;
        CGEventMask eventMask;
        CFRunLoopSourceRef runLoopSource;
        eventMask = 1 << kCGEventLeftMouseDown;
        eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap,
                                    1, eventMask, myCGEventCallback, @"mydata");

        runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
        CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource,
                           kCFRunLoopCommonModes);
        CGEventTapEnable(eventTap, true);
        CFRunLoopRun();
    }
    return 0;
}

Я создаю его с помощью cmake со следующим файлом:

cmake_minimum_required(VERSION 3.0.0)


project (location)

set(CMAKE_C_FLAGS "-arch x86_64 -mmacosx-version-min=10.12 -std=gnu11 -fobjc-arc -fmodules")

Это все работало нормально до обновления до Мохаве.

Небольшое возмущение показывает, что это связано с последним набором обновлений безопасности и некоторыми подсказками (за исключением того, что CGEventTapCreate() не возвращает ноль) о настройках некоторых значений в Info.plist, чтобы разрешить приложению использовать API доступности. Но я изо всех сил пытаюсь понять, где его поместить, так как у меня есть только один файл .m с кодом.

Редактировать

  • Это необходимо для запуска от имени пользователя без прав root (политика компании)
  • если единственный способ заставить его запрашивать разрешение, его можно расширить до приложения с графическим интерфейсом пользователя с минимальным пользовательским интерфейсом

Это приложение просто для захвата верхнего левого угла области экрана для передачи во второе приложение, которое передает эту область экрана на второе устройство. Код для стримера является общим для Win / Linux / MacOS, поэтому мы стараемся держать коллекцию координат экрана совершенно отдельной

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Я обнаружил, что документация CGEventTap устарела, начиная с Мохаве. Запуск от имени root использовался для обхода определенных прав, но в Мохаве это было ужесточено. Как вы заметили, один странный побочный эффект заключается в том, что root все еще может получить порт mach для крана; это просто, что никакие события не могут быть прочитаны от этого. Если вы попробуете ваше приложение без запуска от имени пользователя root, вы должны получить ожидаемое всплывающее окно с запросом разрешения.

Если вы не получаете всплывающее окно или вам нужно работать от имени пользователя root для других целей, вы можете вручную добавить свое приложение в базу данных доверенных TCC с помощью SystemPreferences -> Security & Privacy -> Privacy -> Accessibility

устанавливает некоторые значения в Info.plist, чтобы приложение могло использовать API специальных возможностей

Я полагаю, вы имеете в виду добавление прав (которые также являются списком). Право, которое позволяет приложению использовать Accessibility API, является правом com.apple.private.tcc.allow (со значением kTCCServiceAccessibility). Как вы можете догадаться по названию, оно разрешено только в двоичных файлах, подписанных Apple.

Вы можете добавить эти права в свое собственное приложение, если отключите Системную защиту целостности (SIP) и загрузите ядро ​​с параметром amfi_get_out_of_my_way=1, но я бы не стал его рекомендовать (и, конечно, ваши клиенты не захотят к). С отключенным SIP вы можете вручную добавить запись в базу данных TCC для предоставления привилегий, но все равно не будете ее рекомендовать.

Возможная альтернатива

Вы можете использовать монитор событий:

NSEventMask mask = (NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask);
mouseEventMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask: mask
                     handler:^(NSEvent *event){
                         // get the current coordinates with this
                         NSPoint coords = [NSEvent mouseLocation];
                         // event cooordinates would be event.absoluteX and event.absoluteY
                         ... do stuff
                     }];

В документации упоминается:

События, связанные с ключами, могут отслеживаться только в том случае, если доступность включена или если ваше приложение доверено для доступа со специальным доступом (см. AXIsProcessTrusted).

Но я не думаю, что это относится к событиям мыши.

0 голосов
/ 05 января 2019

Как вы и предполагаете, касания событий не будут работать в Мохаве, если у вас нет доступа к ним. Из документации :

Сигналы событий получают события «вверх» и «вниз», если одно из следующего условие истинно: текущий процесс выполняется от имени пользователя root. Доступ для вспомогательных устройств включен. В OS X v10.4 вы можете включить эта функция с помощью системных настроек, панель универсального доступа, Вид клавиатуры.

Приложение с графическим интерфейсом предложит пользователю включить доступность в первый раз, когда это необходимо, но похоже, что приложение CLI этого не делает (что имеет смысл).

Нет способа включить это программно или через скрипт; пользователь должен сделать это самостоятельно.

Запуск инструмента как root должен работать - можете ли вы применить это?

В противном случае вы можете направить пользователя в нужное место в Системных настройках:

tell application "System Preferences"
    reveal anchor "Privacy_Accessibility" of pane id "com.apple.preference.security"
    activate
end tell

Это возможно при использовании Углерод , если ваше приложение не помещено в "песочницу".

Наконец, быстрый тест показывает, что это возможно, по крайней мере, с использованием IOHID. Я бесстыдно позаимствовал класс KeyboardWatcher из этого ответа . Затем изменил тип устройства:

[self watchDevicesOfType:kHIDUsage_GD_Keyboard];

в

[self watchDevicesOfType:kHIDUsage_GD_Mouse];

Наконец, мой обратный вызов выглядит так:

static void Handle_DeviceEventCallback (void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef value)
{
    IOHIDElementRef element = IOHIDValueGetElement(value);
    IOHIDElementType elemType = IOHIDElementGetType(element);

    if (elemType == kIOHIDElementTypeInput_Button)
    {
        int elementValue = (int) IOHIDValueGetIntegerValue(value);
        // 1 == down 0 == up
        if (elementValue == 1)
        {
            CGEventRef ourEvent = CGEventCreate(NULL);
            CGPoint point = CGEventGetLocation(ourEvent);
            printf("Mouse Position: %.2f, y = %.2f \n", (float) point.x, (float) point.y);
        }
    }
}

Это действительно быстрая хакерская работа, но она демонстрирует, что это возможно, и, надеюсь, вы сможете усовершенствовать ее для своих нужд.

...