4

I have an Automator Service that is comprised of a single "Run AppleScript" action. The AppleScript basically consists of a series of dialogs.

In the middle of the script, the script relies on keystroking ⌘ command + C in order to get the selected rich text into the script as the clipboard. This copy command must fall in the middle of the script, as the user might want to paste the real clipboard into the initial dialog.

AppleScript dialogs in Services are by default pinned on top of all windows; you cannot change this.

AppleScript is only able to keystroke ⌘ command + C when the underlying app is in focus, which makes sense, considering that it is the underlying app -- not the script dialog -- that contains the selected text.

So, I'll put my question inelegantly: Is there a way to make the top part of the window immediately behind the Service dialog gray and thus make the top bar of the Service dialog white, while still not moving the script dialog out of view?

I cannot go by the title of the window or the app of the window, because these variables will vary. The constant is that the window that I want to bring into focus will always be immediately behind the Service dialog.

The following is an example of what I'm talking about:

-- Back up original clipboard contents:
set savedClipboard to the clipboard

set optionList to {"Uppercase case"}
set dialogBoxChoice to choose from list optionList with title "Change case of selection" with prompt "Choose a letter case:"

-- Copy selected text to clipboard:
tell application "System Events" to keystroke "c" using {command down}
delay 1 -- Without this, the clipboard may have stale data.
set theSelectedText to the clipboard

-- Makes the selected text all uppercase:
-- From: http://apple.stackexchange.com/a/171196/184907
set theModifiedSelectedText to (do shell script ("echo " & theSelectedText & " | tr a-z A-Z;"))

display dialog theModifiedSelectedText

-- Overwrite the old selection with the desired text:
set the clipboard to theModifiedSelectedText
tell application "System Events" to keystroke "v" using {command down}
delay 1 -- Without this delay, may restore clipboard before pasting.

-- Restore clipboard:
set the clipboard to savedClipboard

If you put the above code in a keyboard-shortcut-triggered Service, you will see that the script will fail to tell application "System Events" to keystroke "c" using {command down}; thus, theSelectedText will be identical to the savedClipboard every time.

  • I can see what you're trying to do... but what are you actually trying to achieve? You appear to be offering choices where none are needed, bringing up dialogs that will interrupt a simple 'replace selected text' routine & leaving yourself with a modal that you don't know whether or not the user wants to use or be behind. – Tetsujin Feb 14 '17 at 9:41
  • Essentially, you don't want to be 'telling system events' anything you can tell the script itself. Use tell me – Tetsujin Feb 14 '17 at 10:49
  • @Tetsujin Regarding your first comment, the code I included above was just an example; it is not the actual code of the script. The code in question is lengthy and I did not want this post to get derailed by that code in particular. I instead wanted a generalized answer to the question in the title. I included only enough code to demonstrate the issue and nothing more. So, that's why it has a choose from list of only one item, which is obviously nonsensical. Anyway, your solution completely solves my issue. Thanks! – rubik's sphere Feb 16 '17 at 9:13
2

This will do what I think you're looking for. I removed the 'choice of one' from the beginning as it didn't seem relevant to the workflow.

I'm using an activeApp variable to call the app forwards after the dialogs. If you use System Events to call forwards it will not restore the frontmost window.

By using tell me instead of tell application "System Events" except where necessary, you can avoid the complication of the modal dialog stealing focus & not returning to your frontmost window afterwards.

Adding & quoted form of to the shellscript will work in more cases. Some apps will error without it, including Automator itself.

The Automator service receives no input from any application
I've left in a lot of debug, in the form of dialogs, to observe the progress.

on run {input, parameters}
    tell me
        tell application "System Events" to set activeApp to name of first application process whose frontmost is true
        -- Back up original clipboard contents:
        set savedClipboard to the clipboard
        display dialog ("Original clip - " & (the clipboard))
        activate application activeApp
        tell application "System Events" to keystroke "c" using command down
        delay 1
        display dialog ("Copied clip - " & (the clipboard))
        set theSelectedText to the clipboard
        set theModifiedSelectedText to do shell script "echo " & quoted form of theSelectedText & " | tr a-z A-Z;"
        display dialog {"Modified clip - " & theModifiedSelectedText}
        activate application activeApp
        set the clipboard to theModifiedSelectedText
        delay 1
        tell application "System Events" to keystroke "v" using {command down}
        -- Restore clipboard:
        delay 1
        set the clipboard to savedClipboard
        display dialog ("Restored clip - " & (the clipboard))
    end tell
    set input to {}
    return input
end run

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .