Setting the front most window using accessibility API
Asked Answered
S

3

6

I want to set a certain window, from an external app (for example textedit), to be front most.

I can successfully get a reference to the app itself using GetFrontProcess, and check whether it is front most. If it is not, I can use setFrontProcess to make it focussed.

I can then use the the accessibility API to examine all the windows under that application. I am checking that a certain window exists, and if so I compare it against the front most window of the application:

//get the front window of textEditApp and store it in 'currentFrontWindow'
    AXUIElementCopyAttributeValue(textEditApp, kAXFocusedWindowAttribute, (CFTypeRef *)&currentFrontWindow);

If the window I am interested in is not frontmost, I need to set it so. I thought that I could use AXUIElement Set AttributeValue to do this but I am not getting any success. Below is how I have tried to do it.

//set the front window of textEditApp to be desiredFrontWindow
AXUIElementSetAttributeValue(textEditApp, kAXFocusedUIElementAttribute, desiredFrontWindow);

I have checked that the window exists, and the application is 'switched to' successfully. But why doesn't this line of code bring the specified window to the front?

Thanks.

Spanos answered 22/1, 2010 at 1:14 Comment(0)
C
8

But why doesn't this line of code bring the specified window to the front?

Because you tried to set a read-only attribute.

In order to make a window frontmost, you need to set the appropriate property of the window. The same goes for an application: To make an application frontmost, you need to set the appropriate property of the application.

The Cocoa/Mac OS X name for the frontmost window is “the main window”. (See, for example, NSApplication's and NSWindow's methods relating to that concept.) Accessibility uses the same name, so to make a single window frontmost, set the value of its kAXMainAttribute to kCFBooleanTrue.

The way to make the application frontmost is similar: Set the value of its kAXFrontmostAttribute to kCFBooleanTrue. You'll need to do both of these to both set the frontmost window of the application and make the application active.

As far as I can tell, there is no way to bring only a single window of an application frontmost and give it session focus.

Confessional answered 22/1, 2010 at 4:44 Comment(1)
Thanks (once again) Peter - this works a charm. As for the application, I've been using setFrontProcess rather than kAXFrontMostAttribute - is this a bad idea? Having navigated my way through the application and window, there is a certain AXUIElementRef I am interested in bring to the front (ie giving it keyboard focus). I can bury down through the layers of elements to get a reference to it, but how do i set it in focus? Is there an equivalent of kAXMainAttribute for elements? Maybe I should post (yet) another Q.Spanos
S
8

I was able to accomplish this in an app I worked on by bringing the application to the front, then bringing a single window to the front.

First bringing the app to the front:

let currentPid = NSRunningApplication.currentApplication().processIdentifier
if let pid = (the pid of the app in question) where pid != currentPid {
  NSRunningApplication(processIdentifier: pid)?.activateWithOptions(.ActivateIgnoringOtherApps)
}

Then sending the window to the front:

let window = (window AXUIElement)
AXUIElementSetAttributeValue(window, NSAccessibilityMainAttribute, true)
Selfcentered answered 26/10, 2015 at 2:32 Comment(1)
I think that in modern day swift this would look like AXUIElementSetAttributeValue(window, kAXMainWindowAttribute as CFString, true as CFTypeRef)Adelaideadelaja
I
1

I recently discovered that, if you don't mind some Carbon, you can use SetFrontProcessWithOptions to bring a window to the front and give it focus if you pass kSetFrontProcessFrontWindowOnly as the second argument.

Imbrue answered 22/7, 2011 at 2:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.