0

If I open multiple windows/tabs of a browser, and I want to distinguish between them so that I can control those windows individually from my application, what is the approach? If I send command programmatically to a process with PID id it will send that command to the most recently active window but I want to send command to all the window of that process. If I query for PID of running process with CGWindowListOption I get owner PIDs of running processes. let windowsListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0))

I need to know and use something that will trigger multiple window/process at the same time. Is there a different PID of different window of the same process? For example: Chrome tab 1 has a pid, tab 2 will have another pid. How to find those PIDs instead of the owner PID only?

So how can I find out different process id or similar attribute of a process with multiple window with same owner PID?

Rifat
  • 1,700
  • 3
  • 20
  • 51
  • 1
    What do you mean by "control" and "trigger" in these cases? Move them? Close them? Change what space they're on? Chrome tabs aren't windows, so it's not clear what you mean by your example. In most cases you interact with other apps through AppleEvents (i.e. AppleScript), not Quartz Window Services. In Quartz, the identifier for a Window is its WindowNumber. Windows don't have PIDs (that's a process ID, not a window ID). – Rob Napier Oct 16 '20 at 16:45
  • @RobNapier Thank you for a response. I am sending key input events to a process via `pid_t`. Now I can send the event and it works until I make another window(new tab on new window of chrome/any browser) of that process. Sending event via `pid_t` will send that event to the most recently active window. But I want to send that event to that previous window. This is the problem, how can I send the event to that window? All I can see is getting process ids, but I need to target that window specifically. How to capture that window info? – Rifat Oct 17 '20 at 06:14
  • 1
    Keyboard events are sent to processes, not to windows. Processes are responsible for dispatching events internally (for a Cocoa app, this is done via the responder chain, but for non-Cocoa apps, it may have its own system). This is a duplicate of https://stackoverflow.com/questions/21878987/mac-send-key-event-to-background-window The answer there is correct, but it wasn't accepted, so I can't dupe there. As noted there, the usual solution is AppleScript, not keyboard events. – Rob Napier Oct 17 '20 at 15:46
  • If your target application doesn't support the needed AppleScript hooks, you can send arbitrary key events in AppleScript by sending them to System Events. For one simple example, see https://stackoverflow.com/questions/6584357/why-applescript-always-send-keystrokes-with-command-down You can use AppleScript to target specific windows if the target app can support that. But windows do not have a PID. – Rob Napier Oct 17 '20 at 15:49
  • @RobNapier That answer in that question does not answer what I want and probably same for what that question require as well. That answer does not target multiple windows of same ownerID or with same process name, that ansewer just sends event to a process with `CGEVENT.PostToPSN`. Moreover I can not see this function with similar parameters in swift. Swift suggestion only shows ` CGEvent.postToPSN(self: CGEventt)` only. – Rifat Oct 18 '20 at 00:40
  • The second linked question solution activates a window then sends key command with apple script. As your first linked question mentions, activating window in between is noticeable. Maybe there is no way to send events to specific/all window of a application but theres some application that does it. – Rifat Oct 18 '20 at 00:55
  • You do not send CGEvents to windows. You send them to processes. Applications then dispatch them to windows. Generally when you want to control a specific window in an app, you send it AppleEvents (i.e. AppleScript). But these are generally not "receive a key-down for the 'b' key." They're generally commands like "close window" or "open file". You can send key-down events using System Events, but again, these do not generally target specific windows. In Cocoa particularly, windows are not a thing that receives keyboard events themselves. What specific thing are you trying to do with this? – Rob Napier Oct 18 '20 at 16:11
  • You mentioned specifically tabs in Chrome. Chrome has a fairly standard AppleScript interface, and you can enumerate its tabs and send it commands (including executing arbitrary JavaScript in a specific tab). I would generally recommend this approach over trying to send keyboard events. – Rob Napier Oct 18 '20 at 16:13
  • I need something that will enumerate over tabs. Lets say TextEdit instead of chrome, if we open two TextEdit window, how to select the window that was not selected recently programatically? ____ Now what I'm trying to do this week is to make a software that will send key events to all the window visible to user with permissions off course. All things working (`CGEvent.SendTOPID`). I can not get it to work if a software has two window open. I can get app reference and call withoptions: ActivateAllWIndows or activateIgnoringOtherApps. But no option I see for a way to activate background window. – Rifat Oct 18 '20 at 16:41
  • Correct; that's not something you would do by sending key events. AppleScript will do exactly what you're describing (and is designed precisely for this problem). – Rob Napier Oct 18 '20 at 16:46
  • Ok. Will you please point me to some apple script code snippet that will activate a background window? EG: `tell application "TextEdit" activate background window / window number X end tell` – Rifat Oct 18 '20 at 16:49
  • I thought you didn't want to activate the window. Activating the window will bring it to the front and steal focus from the user. Is that what you're trying to do? – Rob Napier Oct 18 '20 at 16:52
  • I do not see any other option to dispatch key events to all open windows of app like TextEdit. Maybe I can add more code to activate my software after it dispatches key events. – Rifat Oct 18 '20 at 16:54
  • What key event are you trying to send? – Rob Napier Oct 18 '20 at 16:56
  • I can send any virtual key of type UInt16, the keyEvents that are generated on keyPress. Lets say 0x31 for space or anything similar. https://stackoverflow.com/questions/47116132/send-keyevent-to-a-target-window-via-process-id – Rifat Oct 18 '20 at 16:58
  • I'm sorry; I don't know how to help you here. What you've literally asking for is not possible. That's the final answer. You cannot do it. But, I strongly suspect that your real goal is very possible and even straight-forward. If you will tell me your actual goal, I believe I can help. But the answer to the question you've given is: you can't. – Rob Napier Oct 18 '20 at 17:01
  • I told you my goal. Dispatching key event to multiple window / all window visible onscreen. Everythings working except if a software has more than one window it gets the event to one widnow only. So I'm trying to activate or reactivate other inactive window to achieve this goal. Thats all. – Rifat Oct 18 '20 at 17:16
  • If theres no way to activate window from background, I will just abandon the project. – Rifat Oct 18 '20 at 17:39

1 Answers1

1

This activates each window in TextEdit and sends a space keystroke.

activate application "TextEdit"

tell application "System Events"
    tell application process "TextEdit"
        repeat with theWindow in windows
            perform action "AXRaise" of theWindow
            keystroke " "
        end repeat
    end tell
end tell

But to note how this would work without pressing keys, the following appends "A" to all the currently open documents without bringing anything to the foreground or interfering with the user's input.

tell application "TextEdit"
    repeat with theDocument in documents
        set text of theDocument to (text of theDocument) & "A"
    end repeat
end tell

Whenever possible, you want things like this rather than sending keystrokes.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610