Перемещение окна и изменяет размеры API в OS X

One Image может исправить эту проблему.

Для More

27
задан Le Dude 5 March 2009 в 10:12
поделиться

2 ответа

Используйте Доступность API. Используя этот API можно соединиться с процессом, получить список окон (на самом деле массив), получить положения и размеры каждого окна и также изменить свойства окна, если Вам нравится.

Однако приложение может только использовать этот API, если пользователь включил доступ для вспомогательных устройств в его предпочтениях (Система Prefs-> Универсальный Доступ), в этом случае все приложения могут использовать этот API, или если Ваше приложение является доверяемым вспомогательным приложением (когда этому доверяют, это может использовать API, даже если эта опция не проверяется). Доступность, которую сам API предлагает необходимым функциям для подавания заявки, доверяла - в основном необходимо стать корнем (использование служб безопасности для запроса корневых полномочий пользователя) и затем отметить процесс, как доверяется. После того как Ваше приложение было отмечено доверяемое, оно должно быть перезапущено, поскольку доверяемое состояние только проверяется на запуске и не может измениться, в то время как приложение работает. Доверительное состояние является постоянным, если пользователь не перемещает приложение где-то в другом месте или хеш двоичных изменений приложения (например, после обновления). Если пользователю включили вспомогательные устройства в его prefs, все приложения рассматривают, как будто им доверяли. Обычно Ваше приложение проверяло бы, включена ли эта опция, если это, пойдите и сделайте свой материал. В противном случае это проверило бы, доверяют ли этому уже, если это, снова просто сделайте свой материал. Если не пытаются сделать себя, доверял, и затем перезапустите приложение, если пользователь не отклонил корневую авторизацию. API предлагает все необходимые функции для проверки всего этого.

Там существуйте закрытые функции, чтобы сделать то же использование менеджера окон Mac OS, но единственное преимущество, которое купило бы Вас, состоит в том, что Вы не должны быть доверяемым приложением Доступности (который является одной операцией времени на первом запуске в большинстве случаев). Недостатки - то, что этот API может изменить любое время (он уже изменился в прошлом), это все не документировано, и функции только известны посредством инженерного анализа. Доступность однако общедоступна, она документируется, и она не имеет, изменяются очень, так как первая версия OS X, которая представила ее (некоторые новые функции были добавлены в 10,4 и снова в 10,5, но не много еще, изменилась).

Вот пример кода. Это будет ожидать 5 секунд, таким образом, можно будет переключиться на другое окно, прежде чем это сделает что угодно еще (иначе, это будет всегда работать с окном терминала, довольно скучным для тестирования). Затем это получит переднюю сторону большая часть процесса, передняя сторона большая часть окна этого процесса, распечатает, это - положение и размер, и наконец переместите его на 25 пикселей направо. Вы компилируете его на командной строке как этот (предположение, что это называют test.c),

gcc -framework Carbon -o test test.c

Обратите внимание на то, что я не выполняю проверки ошибок в коде для простоты (существуют различные места, которые могли заставить программу отказывать, если что-то идет, неправильные и определенные вещи могут/могут, идут не так, как надо). Вот код:

/* Carbon includes everything necessary for Accessibilty API */
#include <Carbon/Carbon.h>

static bool amIAuthorized ()
{
    if (AXAPIEnabled() != 0) {
        /* Yehaa, all apps are authorized */
        return true;
    }
    /* Bummer, it's not activated, maybe we are trusted */
    if (AXIsProcessTrusted() != 0) {
        /* Good news, we are already trusted */
        return true;
    }
    /* Crap, we are not trusted...
     * correct behavior would now be to become a root process using
     * authorization services and then call AXMakeProcessTrusted() to make
     * ourselves trusted, then restart... I'll skip this here for
     * simplicity.
     */
    return false;
}


static AXUIElementRef getFrontMostApp ()
{
    pid_t pid;
    ProcessSerialNumber psn;

    GetFrontProcess(&psn);
    GetProcessPID(&psn, &pid);
    return AXUIElementCreateApplication(pid);
}


int main (
    int argc,
    char ** argv
) {
    int i;
    AXValueRef temp;
    CGSize windowSize;
    CGPoint windowPosition;
    CFStringRef windowTitle;
    AXUIElementRef frontMostApp;
    AXUIElementRef frontMostWindow;

    if (!amIAuthorized()) {
        printf("Can't use accessibility API!\n");
        return 1;
    }

    /* Give the user 5 seconds to switch to another window, otherwise
     * only the terminal window will be used
     */
    for (i = 0; i < 5; i++) {
        sleep(1);
        printf("%d", i + 1);
        if (i < 4) {
            printf("...");
            fflush(stdout);
        } else {
            printf("\n");
        }
    }

    /* Here we go. Find out which process is front-most */
    frontMostApp = getFrontMostApp();

    /* Get the front most window. We could also get an array of all windows
     * of this process and ask each window if it is front most, but that is
     * quite inefficient if we only need the front most window.
     */
    AXUIElementCopyAttributeValue(
        frontMostApp, kAXFocusedWindowAttribute, (CFTypeRef *)&frontMostWindow
    );

    /* Get the title of the window */
    AXUIElementCopyAttributeValue(
        frontMostWindow, kAXTitleAttribute, (CFTypeRef *)&windowTitle
    );

    /* Get the window size and position */
    AXUIElementCopyAttributeValue(
        frontMostWindow, kAXSizeAttribute, (CFTypeRef *)&temp
    );
    AXValueGetValue(temp, kAXValueCGSizeType, &windowSize);
    CFRelease(temp);

    AXUIElementCopyAttributeValue(
        frontMostWindow, kAXPositionAttribute, (CFTypeRef *)&temp
    );
    AXValueGetValue(temp, kAXValueCGPointType, &windowPosition);
    CFRelease(temp);

    /* Print everything */
    printf("\n");
    CFShow(windowTitle);
    printf(
        "Window is at (%f, %f) and has dimension of (%f, %f)\n",
        windowPosition.x,
        windowPosition.y,
        windowSize.width,
        windowSize.height
    );

    /* Move the window to the right by 25 pixels */
    windowPosition.x += 25;
    temp = AXValueCreate(kAXValueCGPointType, &windowPosition);
    AXUIElementSetAttributeValue(frontMostWindow, kAXPositionAttribute, temp);
    CFRelease(temp);

    /* Clean up */
    CFRelease(frontMostWindow);
    CFRelease(frontMostApp);
    return 0;
}

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

Вместо "kAXFocusedWindowAttribute" Вы используете "kAXWindowsAttribute" для функции AXUIElementCopyAttributeValue. Результатом не является затем никакой AXUIElementRef, но CFArray элементов AXUIElementRef, один для каждого окна этого приложения.

47
ответ дан Mecki 28 November 2019 в 05:10
поделиться

Я соглашаюсь, что Доступность является наилучшим путем вперед. Но если Вы захотите быстрый-и-грязный, то AppleScript будет работать также.

2
ответ дан vasi 14 October 2019 в 13:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: