CGEventPost - 模拟键盘事件时可能出现的错误?

时间:2010-01-05 18:18:40

标签: macos quartz-graphics

我有一个非常简单的代码块,用于模拟键盘事件。下面的简单例子应该输入“Cz” - 换档键下降,c键下降,c上升,换档上升。然后z键向下和向上。

有时订单会变得混乱。当我创建一个定时器来每秒调用这个例程时,输出应该是CzCzCzCz ....但这是我得到的:

CZcZCZCzczCzczCzczCZCZCzCz

我会再次运行它:

CzCzCzCzCZCzCZCzCZCzCZCzCZCzCzCz

不同。同样错了。

代码:

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);

在如何实现shift键的keydown和keyup方面,我是否缺少一些东西?我认为这可能是一个错误 - 我会在哪里举报?

6 个答案:

答案 0 :(得分:23)

我找到了一种可靠的方法来发布修改后的键盘事件 - 它不遵循Apple的文档中的示例(这不起作用),但似乎有意义,最重要的是,WORKS。

您需要在按键上设置修饰符标志,而不是发送'shift键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-flag,但不确定这是否正确)。

event2 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, false);
CGEventSetFlags(event2, kCGEventFlagMaskShift);
CGEventPost(kCGSessionEventTap, event2);

最后(并且奇怪地)你需要发送班次键的'key up'事件:

  e5 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)56, false);
CGEventPost(kCGSessionEventTap, e5);

完成后,请不要忘记发布活动。

我希望这对某人有用 - 我花了很长时间才能让它发挥作用。

答案 1 :(得分:10)

最简洁的方法是将当前修饰符标记与所需修饰符的标志进行按位OR运算,例如:

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);

答案 2 :(得分:3)

我最近遇到了类似的问题。而不是传递NULL作为CGEventCreateKeyboardEvent的第一个参数,创建一个这样的事件源:

CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);

并在创建和发布活动时使用它。 CF完成后再发布它。

答案 3 :(得分:2)

this guy's bug的任何关系?

答案 4 :(得分:2)

与此处引用其他解决方案的其他注释一样,在使用带有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);

答案 5 :(得分:0)

可靠的解决方法:

+(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"];