4

有一个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 )
        }
}

测试用例:

  • 让我们说运行TextEdit.appNotes.app
  • ps axu | grep -E 'MacOS/(TextEdit|Notes)'- 示例中记下他们的 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
  • 记住PID:87756 83077
  • 从终端运行swift skey.swift 87756 83077
  • 两个应用程序窗口(TextEdit 和 Notes)中出现“1”,即使它们在后台(终端在活动应用程序中)。
  • 所以,脚本按预期工作!

问题

  • 编译脚本swiftc skey.swift
  • 使用相同的参数运行编译后的二进制文件,例如./skey 87756 83077
  • 只有第一个 PID 获得“1”(在这种情况下,仅在注释中)

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

  • swift skey.swift 87756 83077
  • 或者./skey 87756 83077

编辑

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

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

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

4

0 回答 0