首页 > 解决方案 > 如何正确地将按键发送到 BG 应用程序,而 swift 脚本和编译的 swiftc 二进制文件之间没有区别

问题描述

有一个swift名为的小脚本skey.swift,即使它们不处于活动状态(例如它们在后台),也会通过它们的PID(进程 ID)将按键发送到进程中。

import Foundation
if CommandLine.argc < 2 {
        print("Error", CommandLine.arguments[0], " No arguments are passed.")
        exit(1)
}

let src = CGEventSource(stateID: CGEventSourceStateID.hidSystemState)

let key_d = CGEvent(keyboardEventSource: src, virtualKey: 0x12, keyDown: true)  // key "1" press
let key_u = CGEvent(keyboardEventSource: src, virtualKey: 0x12, keyDown: false) // key "1" release

for i in 1 ..< Int(CommandLine.argc) {
        if let pid = pid_t(CommandLine.arguments[i]) {
                print("arg:", pid)
                key_d?.postToPid( pid )
                key_u?.postToPid( pid )
        }
}

测试用例:

me              87756   3,3  0,3  4716112  97228   ??  S    11:54     0:28.01 /Applications/Notes.app/Contents/MacOS/Notes
me              83077   0,0  0,1  4609916  49312   ??  S     8:00     0:04.58 /Applications/TextEdit.app/Contents/MacOS/TextEdit

问题

为什么运行脚本之间有这样的区别:

编辑

刚刚 在这个源代码中找到了 一个评论

// Maybe this is a dumb way to solve this, but let's sleep for just a moment so they events don’t arrive out of order.

所以,开始尝试usleep自己。50µs 无济于事,但使用2x1000µs HELPED,最后编译和解释版本的工作方式完全相同。

所以,这行得通

for i in 1 ..< Int(CommandLine.argc) {
        if let pid = pid_t(CommandLine.arguments[i]) {
                print("arg:", pid)
                key_d?.postToPid( pid )
                usleep(1000)
                key_u?.postToPid( pid )
                usleep(1000)
        }
}

但是,作为谈论“愚蠢方式”的评论 -很高兴知道正确的方式,因为代码应该在任何 macOS 中工作......

编辑 2

根据@willeke的评论,我尝试了以下

for i in 1 ..< Int(CommandLine.argc) {
        if let pid = pid_t(CommandLine.arguments[i]) {
                print("arg:", pid)
                key_d?.postToPid( pid )
                key_u?.postToPid( pid )
        }
}
sleep(1) // give enough time to send events before exit

它按预期工作。看来事件发送过程一定存在,否则他的所有事件都被丢弃。

标签: swiftmacosswift-compiler

解决方案


推荐阅读