Странное поведение при публикации CGEvent в PSN - PullRequest
4 голосов
/ 13 мая 2010

РЕДАКТИРОВАТЬ - не получаю много информации об этом, так что это тощий. Я публикую события клавиатуры в 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 ]

2 голосов
/ 25 мая 2010

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

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

Например, во втором бите кода вы создаете 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, вызывать функции в различных сценариях, передавать переменные, возвращать значения и т. Д.

1 голос
/ 09 ноября 2010

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

CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);

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

...