将 CGEvent 发布到 PSN 时出现奇怪的行为

发布于 2024-09-01 01:04:00 字数 1859 浏览 6 评论 0 原文

编辑 - 没有得到太多的意见,所以这里是瘦的。我正在将键盘事件发布到 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); 

EDIT - not getting much input on this so here's the skinny. I'm posting keyboard events to a PSN. I then switch to another window, post some more events (this time tat session level) and switch back to the first window. When I start posting to the PSN again, nothing happens. Until I move the mouse or scroll wheel. Why would this be the case and how can I work around it (if not fix it)?

ORIGINAL -
If I set up a loop that posts some keyboard events to a PSN, I find that it works fine except for when first launched. The event only seems to post when i do something with the mouse manually - even just moving it slightly. Here's the details, if they help.

An external application has a list box of text lines, which I am reading by posting copy commands (and checking the pasteboard). Unfortunately this is my only way to get this text.

Sometimes, the application pulls focus away from the list, which I can detect. When this happens, the most reliable way to return focus is by sending a mouse event to click on a text field directly above the list, then send a 'tab' keyboard event to shift the focus onto the list.

So at launch, the loop runs fine, scrolling down the list and copying the text. When focus is shifted away, its is detected fine, and the events are sent to move focus back to the list. But nothing seems to happen. The loop continues detecting that focus has changed, but the events only work once I move the mouse. Or even just use the scroll wheel. Strange.

Once this has happened the first time, it works fine - each time focus moves, the PSN events switch it back without me having to do anything at all.

Here's the code that runs in the loop - verified as working:

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

And here's where I switch focus, also working (except when first required):

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

又怨 2024-09-08 01:04:00

嘿,我知道这不是你想听到的,但是 applescript 对于这种事情效果更好 - 通过发布复制命令来读取文本字段,通过将单击事件发送到附近的项目然后发送选项卡事件来设置焦点 - 它确实不是最好的方法来做到这一点。

模拟事件的问题在于生成事件并不是故事的全部。仅当目标应用程序正确解释它们时,它们才会成为“事件”。你知道目标应用程序是否是可可应用程序吗?

例如,在第二段代码中,您创建了 4 个事件。目标应用程序需要运行其事件处理循环(您对此没有太多控制权),并检查排队的事件。如果这样做,它会发现同时有鼠标按下、鼠标抬起、按键按下、按键抬起。您希望它将这些同时发生的事件解释为鼠标单击,然后是按键……但谁说它会呢?

您可以通过添加刷新事件队列的组合来实现此目的,让目标应用运行它的运行循环,加入一些在模拟事件之间暂停,并摆弄事件时间戳 - 但它可能不会那么可靠。

在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

cocoa应用程序中,您可以将字符串作为Applescript执行,您可以在不同脚本中调用函数,传递变量,返回值等。

Hey, i know it's not what you want to hear but applescript works much better for this kind of thing - reading textfields by posting copy commands, setting focused by sending click events to nearby items then sending tab events - it really isn't the best way to do it.

The problem with simulating events is that generating them isn't the whole story. They only become 'Events' if the target app interprets them correctly. Do you know if the target app is even a cocoa app?

For example, in your second bit of code you create 4 events. The target app needs to run it's event processing loop, which you don't have much control over, and check for queued events. If it did this it would find a simultaneous mouse down, mouse up, key down, key up. You want it to interpret these simultaenious events as a mouse click and THEN a keypress.. but who is to say it will?

You may be able to get this to work by adding into the mix a combination of flushing event queues, getting the target app to run it's runloop, throw in some pauses between the simulated events, and fiddling with event timestamps - but it probably won't be that reliable.

In Applescript you could get the text of row 3 of a table in another app by

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

From a cocoa App you can execute a String as an Applescript, you can call functions in different scripts, pass variables, return values, etc.

忆离笙 2024-09-08 01:04:00

不要使用 null CGEventSourceRef 创建事件,而是尝试以这种方式创建输入源:

CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);

基于此 邮件列表消息,这似乎是使用 CGEventCreateXXXEvent 成功发布事件的秘诀。 Google 搜索显示,很多开发人员都遇到了这方面的问题,但这是我发现的一篇成功的文章,并且正确的 CGEventSourceRef(而不是 NULL)似乎是此示例与我的所有其他示例中的一个区别已经找到了。它解决了我发布键盘事件的问题。

Instead of creating the event with a null CGEventSourceRef try creating an input source this way:

CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);

Based on this mailing list message, this seems to be the secret for success in posting events with CGEventCreateXXXEvent. A Google search shows that lots of devs are having problems with this, but this is the one success post I've found, and a proper CGEventSourceRef (instead of NULL) seems to be the one difference in this example vs. all the others I've found. It solved my problems with posting keyboard events.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文