Странное поведение при публикации CGEvent в PSN

РЕДАКТИРОВАТЬ - не получая много информации по этому вопросу, так что это тощий. Я публикую события клавиатуры в PSN. Затем я переключаюсь в другое окно, публикую еще несколько событий (на этот раз на уровне сеанса) и переключаюсь на первое окно. Когда я снова начинаю отправлять сообщения в PSN, ничего не происходит. Пока я не двигаю мышь или колесо прокрутки. Почему это так и как я могу обойти это (если не исправить)?

ОРИГИНАЛ. Если я настрою цикл, который отправляет некоторые события клавиатуры в PSN, я обнаружу, что он работает нормально, за исключением первого запуска. Событие появляется, когда я что-то делаю с помощью мыши вручную - даже слегка перемещая его. Вот подробности, если они помогут.

Внешнее приложение имеет список текстовых строк, который я читаю, публикуя команды копирования (и проверяя монтажную область). К сожалению, это мой единственный способ получить этот текст.

Иногда приложение отводит фокус от списка, который я могу обнаружить. Когда это происходит, самый надежный способ вернуть фокус - отправить событие мыши, чтобы щелкнуть текстовое поле непосредственно над списком, а затем отправить событие клавиатуры "Tab", чтобы переместить фокус на список.

Таким образом, при запуске цикл работает нормально, прокручивая список вниз и копируя текст. Когда фокус смещен, он обнаруживается нормально, и события отправляются, чтобы переместить фокус обратно в список. Но, похоже, ничего не случилось. Цикл продолжает обнаруживать, что фокус изменился, но события работают, только когда я перемещаю мышь. Или даже просто используйте колесо прокрутки. Странный.

Как только это произошло в первый раз, все работает нормально - каждый раз, когда фокус перемещается, события PSN переключают его обратно, и мне вообще ничего не нужно делать.

Вот код, который выполняется в цикле - проверен как работающий:

    //copy to pasteboard - CMD-V
e3 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)8, true);
CGEventSetFlags(e3, kCGEventFlagMaskCommand);
CGEventPostToPSN(&psn, e3);
CFRelease(e3);
e4 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)8, false);
CGEventPostToPSN(&psn, e4);
CFRelease(e4);

//move cursor down
e1 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)125, true);
CGEventPostToPSN(&psn, e1);
CFRelease(e1);
e2 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)125, false);
CGEventPostToPSN(&psn, e2);
CFRelease(e2);

И вот где я переключаю фокус, также работающий (кроме случаев, когда это требуется):

    //click in text input box - point is derived earlier
e6 = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, point, 0);
CGEventPostToPSN(&psn, e6);
CFRelease(e6);
e7 = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, point, 0);
CGEventPostToPSN(&psn, e7);
CFRelease(e7);

//press tab key to move to chat log table
CGEventRef e = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)48, true);
//CGEventPost(kCGSessionEventTap, e);
CGEventPostToPSN(&psn, e);
CFRelease(e);
CGEventRef e11 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)48, false);
CGEventPostToPSN(&psn, e11);
CFRelease(e11); 

2 ответа

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

Проблема с имитацией событий заключается в том, что их генерация - это не вся история. Они становятся "Событиями", только если целевое приложение правильно их интерпретирует. Вы знаете, является ли целевое приложение даже приложением какао?

Например, в вашем втором бите кода вы создаете 4 события. Целевое приложение должно запустить цикл обработки событий, который вы не можете контролировать, и проверить наличие событий в очереди. Если бы он сделал это, он бы обнаружил одновременную мышь вниз, мышь вверх, ключ вниз, ключ вверх. Вы хотите, чтобы эти одновременные события интерпретировались как щелчок мыши, а затем нажатие клавиши... но кто это скажет?

Вы можете добиться того, чтобы это работало, добавив в микс комбинацию очистки очередей событий, получения целевого приложения для запуска runloop, добавления некоторых пауз между смоделированными событиями и работы с метками времени событий - но, вероятно, это победило ' быть надежным.

В Applescript вы можете получить текст строки 3 таблицы в другом приложении,

tell application "System Events"
  tell process targetAppName
    set frontmost to true
    tell window named windowTitle
      tell table 1
        set value of attribute "AXFocused" to true
        set txtField to first text field of row 3
        return value of txtField
      end tell
    end tell
  end tell
end tell

Из приложения какао вы можете выполнять String как Applescript, вызывать функции в разных сценариях, передавать переменные, возвращать значения и т. Д.

Вместо создания события с нулевым CGEventSourceRef попробуйте создать источник ввода следующим образом:

CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);

Основываясь на этом сообщении списка рассылки, похоже, это секрет успеха при публикации событий с CGEventCreateXXXEvent. Поиск Google показывает, что у многих разработчиков возникают проблемы с этим, но это единственный пост, который я нашел, и правильный CGEventSourceRef (вместо NULL), похоже, является единственным отличием в этом примере по сравнению со всеми другими, которые я нашел. Это решило мои проблемы с публикацией событий клавиатуры.

Другие вопросы по тегам