CGEventPost - возможная ошибка при имитации событий клавиатуры?
У меня очень простой кусок кода, который предназначен для имитации событий клавиатуры. В простом примере ниже следует ввести "Cz" - клавиша смены идет вниз, клавиша c спускается, c появляется и сдвигается вверх. Затем клавиша z переходит вниз и вверх.
Кажется, что иногда порядок путается. Когда я создаю таймер для вызова этой процедуры каждую секунду, вывод должен быть CzCzCzCz.... Но вот что я получаю:
CZcZCZCzczCzczCzczCZCZCzCz
Я запустил его еще раз:
CzCzCzCzCZCzCZCzCZCzCZCzCZCzCzCz
Different. И одинаково неправильно.
Код:
e1 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)56, true);
CGEventPost(kCGSessionEventTap, e1);
CFRelease(e1);
e2 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)8, true);
CGEventPost(kCGSessionEventTap, e2);
CFRelease(e2);
e3 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)8, false);
CGEventPost(kCGSessionEventTap, e3);
CFRelease(e3);
e4 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)56, false);
CGEventPost(kCGSessionEventTap, e4);
CFRelease(e4);
e7 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, true);
CGEventPost(kCGSessionEventTap, e7);
CFRelease(e7);
e8 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, false);
CGEventPost(kCGSessionEventTap, e8);
CFRelease(e8);
Есть ли что-то, что мне не хватает в том, как реализовать keydown и keyup для клавиши shift? Я думаю, что это может быть ошибка - где я могу сообщить об этом?
Ответы
Ответ 1
Я нашел надежный способ опубликовать измененные события клавиатуры - он не следует примеру в документации Apple (что не работает), но, похоже, имеет смысл, а главное, WORKS.
Вместо того, чтобы отправлять сообщения "shift key down" и "shift key up" (как указано в документах), вам нужно установить флаг модификатора при нажатии клавиши. Здесь, как выводить прописную букву Z.
CGEventRef event1, event2;
event1 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, true);//'z' keydown event
CGEventSetFlags(event1, kCGEventFlagMaskShift);//set shift key down for above event
CGEventPost(kCGSessionEventTap, event1);//post event
Затем я освобождаю ключ "z" для полноты (также устанавливаю флаг shift, хотя не уверен, что это правильно).
event2 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, false);
CGEventSetFlags(event2, kCGEventFlagMaskShift);
CGEventPost(kCGSessionEventTap, event2);
Наконец (и причудливо) вам нужно отправить событие "key up" для клавиши shift:
e5 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)56, false);
CGEventPost(kCGSessionEventTap, e5);
Не забудьте освободить свои события, как только вы закончите с ними.
Я надеюсь, что это полезно кому-то - мне потребовалось много времени, чтобы заставить это работать.
Ответ 2
Самый чистый способ для этого - побитовое ИЛИ - текущие флаги модификатора с флагом желаемого модификатора (-ов), например:
CGEventFlags flags = kCGEventFlagMaskShift;
CGEventRef ev;
CGEventSourceRef source = CGEventSourceCreate (kCGEventSourceStateCombinedSessionState);
//press down
ev = CGEventCreateKeyboardEvent (source, keyCode, true);
CGEventSetFlags(ev,flags | CGEventGetFlags(ev)); //combine flags
CGEventPost(kCGHIDEventTap,ev);
CFRelease(ev);
//press up
ev = CGEventCreateKeyboardEvent (source, keyCode, false);
CGEventSetFlags(ev,flags | CGEventGetFlags(ev)); //combine flags
CGEventPost(kCGHIDEventTap,ev);
CFRelease(ev);
CFRelease(source);
Ответ 3
Любое отношение к ошибка этого парня?
Ответ 4
Недавно у меня была аналогичная проблема. Вместо передачи NULL в качестве первого аргумента CGEventCreateKeyboardEvent создайте источник события, например:
CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
и использовать его во время создания и публикации событий. CFRelease это, когда вы закончите с ним.
Ответ 5
Как и другой комментарий, относящийся к другим решениям здесь, после использования прописных букв с помощью маски Shift последовательный вызов приведет к тому, что любой другой предполагаемый несмещенный символ будет преобразован в сдвинутые символы. Я решил, что вызов CGEventCreateKeyboardEvent каким-то образом сохраняет предыдущие маски, поэтому я целенаправленно очищаю маску модификатора:
CGEventRef event1, event2;
CGEventSourceRef source = CGEventSourceCreate (kCGEventSourceStateCombinedSessionState);
CGEventFlags flags;
event1 = CGEventCreateKeyboardEvent (source, keyCode, true);
if (upper)
flags = kCGEventFlagMaskShift | CGEventGetFlags(event1);
else
flags = ~kCGEventFlagMaskShift & CGEventGetFlags(event1);
CGEventSetFlags(event1, flags);
CGEventPost(kCGHIDEventTap,event1);
event2 = CGEventCreateKeyboardEvent (source, keyCode, false);
if (upper)
flags = kCGEventFlagMaskShift | CGEventGetFlags(event2);
else
flags = ~kCGEventFlagMaskShift & CGEventGetFlags(event2);
CGEventSetFlags(event2, flags);
CGEventPost(kCGHIDEventTap,event2);
CFRelease(event1);
CFRelease(event2);
CFRelease(source);
Ответ 6
надежное обходное решение:
+(void)runScript:(NSString*)scriptText
{
NSDictionary *error = nil;
NSAppleEventDescriptor *appleEventDescriptor;
NSAppleScript *appleScript;
appleScript = [[NSAppleScript alloc] initWithSource:scriptText];
appleEventDescriptor = [appleScript executeAndReturnError:&error];
}
[self runScript:@"tell application \"System Events\" to key code "c" using shift down"];
[self runScript:@"tell application \"System Events\" to key code "z"];