How to Get the Position of a Keyboard Maestro User Prompt Window?

I'm using the code that was talked about in the thread Prompt for User Input > Window Position. Specifically:

image

I'd like to do this only if the prompt is NOT on the front screen. The problem is, I can't figure out how to get the position of the prompt.

%FrontWindowPosition% doesn't seem to return the value. I think I somehow need to tell KM I want the position of the front window of the Keyboard Maestro Engine.

Anyone got any ideas? Thanks.

@ccstone - this sounds like something you might know how to do in AS, if not any other way? :crossed_fingers:

Hey Dan,

There's no way I know of to do this with Keyboard Maestro native actions.

The AppleScript is simple enough:

tell application "System Events"
   tell application process "Keyboard Maestro Engine"
      tell front window
         set frontWinSize to its size
         set frontWinPos to its position
      end tell
   end tell
end tell

You have to remember though that AppleScript thinks of multiple screens as one big Desktop.

Run this to see what I mean:

desktopBounds()

--------------------------------------------------------
--ยป HANDLERS
--------------------------------------------------------
on desktopBounds()
   tell application "Finder"
      set _bnds to bounds of window of desktop
      return _bnds
   end tell
end desktopBounds
--------------------------------------------------------

AppleScriptObjC can get the number of screens and various information about them, but as far as I know it cannot position windows itself. You have to translate that information as necessary and then use either a scriptable app itself or System Events to actually move the windows.

Since you have to work with AppleScript anyway, you might as well stay in AppleScript for this bit:

# Move the front Keyboard Maestro Engine Window
tell application "System Events"
   tell application process "Keyboard Maestro Engine"
      tell front window
         set {position, size} to {{95, 23}, {516, 368}}
      end tell
   end tell
end tell

Here's how to get screen-information with AppleScriptObjC:

--------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2021/09/18 14:21
# dMod: 2021/09/18 14:21 
# Appl: AppleScriptObjC
# Task: Get Information for All Connected Screens.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @ASObjC, @Connected, @Screens, @Information
# Test: macOS 10.14.6 (Mojave) or later is required.
--------------------------------------------------------
use AppleScript version "2.6" -- Mojave (10.14) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
--------------------------------------------------------

set allScreensInfoList to {}

set theScreens to current application's NSScreen's screens()

repeat with theScreen in theScreens
   
   set theScreenInfo to theScreen's deviceDescription() as record
   
   tell theScreen
      set screenInfo to its visibleFrame()
   end tell
   
   set theScreenInfo to theScreenInfo & {|visibleFrame|:screenInfo}
   
   set end of allScreensInfoList to theScreenInfo
   
end repeat

return allScreensInfoList

--------------------------------------------------------

-Chris

2 Likes

Thanks, Chris. I knew about the "one big screen" thing - that's the way Windows works too (or at least, it did when I was developing for it).

Before you replied, I messed around and came up with this:

tell application "System Events"
	tell application process "Keyboard Maestro Engine"
		get position of window "Keyboard Maestro User Input"
	end tell
end tell

I had to use the window name, because it would sometimes return a palette's position.

It turns out that when I use this code, there's enough of a delay that the prompt window becomes visible on the other screen before it gets moved, which is kind of annoying. But I may be able to live with it. We'll see.

Thanks again.

That's probably at least in part because Keyboard Maestro is slow to run AppleScripts.

Script files run a bit faster than text scripts.

You could also emplace your user-prompt within the AppleScript as XML to run with do-script, so the run-time overhead doesn't cause extra latency.

I usually run AppleScripted stuff from FastScripts for extra speed, and when I do that I put any Keyboard Maestro actions in the script if possible.

-Chris

@peternlewis

Hey Peter,

This is the AppleScript properties record of a Prompt-with-List action window.

As you can see the names, descriptions, and subrole don't do a good job describing it:

{
   minimum value:missing value, 
   orientation:missing value, 
   position:{
      470, 
      82
   }, 
   class:window, 
   accessibility description:missing value, 
   role description:"window", 
   focused:false, 
   title:"Window", 
   size:{
      500, 
      430
   }, 
   help:missing value, 
   entire contents:{}, 
   enabled:missing value, 
   maximum value:missing value, 
   role:"AXWindow", 
   value:missing value, 
   subrole:"AXUnknown", 
   selected:missing value, 
   name:"Window", 
   description:"window"
}

If possible for Keyboard Maestro 10 would you make sure the accessibility information properly describes the various Window/UI objects Keyboard Maestro uses?

TIA.

-Chris

1 Like

I will take a look. I should be able to ensure the window title is more appropriate.

I doubt I can reasonably affect the subrole, and even if I could, what would be a more useful value.

The accessibility description doesn't mean much either in this case, it would have no more information than the title.

2 Likes

Does this, in general, imply ducking in and out of AppleScript is a poor performance choice?

I'm tending to slim down the Keyboard Maestro wrapper and try to substitute AppleScript wherever I can. ("Wherever I can" is more a statement about my AppleScript knowledge than anything.)

Hey Martin,

Yes, but that's a relative thing.

In general we're talking around one to three tenths of a second of overhead, and I haven't tested on Apple Silicon.

But yes โ€“ many separate Execute an AppleScript actions will add up overhead.

For some processes that will make little difference to the outcome, but for others the user may feel the delay and be frustrated depending upon what their expectations are.

-Chris

1 Like

Perhaps, but I think you might.

Here's an AppleScript Choose-From-List Dialog Properties Record:

{
   minimum value:missing value, 
   orientation:missing value, 
   position:{
      550, 
      163
   }, 
   class:window, 
   accessibility description:missing value, 
   role description:"dialog", 
   focused:false, 
   title:"TEST WINDOW PROPERTIES", 
   size:{
      340, 
      319
   }, 
   help:missing value, 
   entire contents:{}, 
   enabled:missing value, 
   maximum value:missing value, 
   role:"AXWindow", 
   value:missing value, 
   subrole:"AXDialog", 
   selected:missing value, 
   name:"TEST WINDOW PROPERTIES", 
   description:"dialog"
}

As you can see the subrole is AXDialog, and that would seem a more appropriate subrole for Keyboard Maestro's dialogs if it can be changed.

-Chris

These style of windows are not dialogs, so no, that does not seem a more appropriate subrole to me.

I have adjusted the various windows to have appropriate window titles.

5 Likes

I thought the Prompt With List window would be the same as the Prompt for User Input window, but it isn't.

{
   minimum value:missing value, 
   orientation:missing value, 
   position:{
      458, 
      178
   }, 
   class:window, 
   accessibility description:missing value, 
   role description:"system floating window", 
   focused:false, 
   title:"Keyboard Maestro User Input", 
   size:{
      537, 
      171
   }, 
   help:missing value, 
   entire contents:{}, 
   enabled:missing value, 
   maximum value:missing value, 
   role:"AXWindow", 
   value:missing value, 
   subrole:"AXSystemFloatingWindow", 
   selected:missing value, 
   name:"Keyboard Maestro User Input", 
   description:"system floating window"
}

As you can see the subrole is different than the prompt-with-list window.

Prompt for User Input:

subrole:"AXSystemFloatingWindow",

Prompt with List:

subrole:"AXUnknown",

-Chris

Yes. The window looks different and behaves differently, so it is a different role.