Using Frontmost Application?

@dabee,

I would create Automator Quick Action (service), which receives: Text, from application: Any. Then I would assign system-wide shortcut in the System Preferences to this service.

When executing compiled script, current application (and frontmost) is editor. When executing script saved as application, current application (and frontmost) is script app. So, if you still prefer the usual script (or script app), then you should hide the current application to get other front process.


set thisAppName to name of current application

tell application "System Events"
	set visible of process thisAppName to false
	set frontApp to name of first application process whose frontmost is true
end tell

NOTE: all keystrokes goes to front window (of frontmost process) telling only to System Events.app. So, telling some other app to keystroke doesn’t make any sense.

To test my suggestion, I created text in the TextEdit.app, then selected one piece of this text. Following script successfully replaces the selected piece of text with “Hello”:


set thisAppName to name of current application

tell application "System Events"
	set visible of process thisAppName to false
	set frontApp to name of first application process whose frontmost is true
	keystroke "Hello"
end tell

The keystrokes are about taking focus in the front app, then copying and pasting of modified text. I’ve used keystrokes (like copy and paste) in other apps all the time.

I’m not trying to replace it with static text. I need Ruby to modify the text accordingly. This doesn’t bring in that at all. I have no need to replace text with “Hello”.

As I said in the original post. I’m trying to modify the text that’s selected.

Plugable-ud-ultc4k-triple-4k-Port.jpg => Plugable ud ultc4k triple 4k Ports.jpg

I don’t force you to send “Hello”. This is just an example, isn’t it obvious to you? You can send another keystroke, and somewhere in the middle of the actual script, Ruby has to modify the contents of the clipboard. My script simply demonstrates how to work with the right front process.

The copy and paste you use all time in other apps is commands of this other apps. And the keystroke command belongs only to System Events.app

The issue with your approach is that you said to make something in Automator. THIS is what takes Ruby out of the equation. An Automator Quick Action in Launchbar means the script itself is run. As standalone. So there is no governing script that integrates Ruby at all. A master governing Ruby script can implement AppleScript through the syntax that I posted.

I see what you did by shoving the (either Launchbar or Automator Quick Action) focus aside, leaving the second-in-line app (the editor) having focus. Unfortunately this didn’t do the trick either. The problem is that this isn’t about visibility. You’re still living in an AppleScript world with that instruction. All this should be able to run in the background, as Launchbar disappears after you select an Action. This is why I’m choosing Ruby to use AppleScripts to bounce around, as the master controller. You know that AppleScript can instruct an application to accomplish something without having it visible or active.

Here is the script and the error:

require 'clipboard'
def osascript(script) = system 'osascript', *script.split(/\n/).map { |line| ['-e', line] }.flatten

# mys=<<-TEXT
# tell application "System Events" to keystroke "c" using command down
# TEXT

mys=<<-TEXT
set thisAppName to name of current application
tell application "System Events"
   set visible of process thisAppName to false
   set the clipboard to the name of first application process whose frontmost is true
end tell
TEXT
osascript(mys)

r = ''
text = Clipboard.paste
text.strip.split("\n").each do |i|
  begin
    stuff = i.strip.split(/\s*:\s*/)
    r += stuff.first.strip.rjust(find_largest_key(text)+5) + " : " + stuff[1].strip + "\n"
  rescue
    r += i
  end
end

Clipboard.copy(r)

mys=<<-TEXT
tell application "System Events" to keystroke "v" using command down
TEXT
osascript(mys)

[format]
RF spacecase (com.viaduct.LaunchBar.action.RFspacecase): Script Error: </Users/rich/.rbenv/shims/ruby /Users/rich/Library/Application Support/LaunchBar/Actions/RF spacecase.lbaction/Contents/Scripts/default.rb>
58:62: execution error: Can’t make selection of application “” into type text. (-1700)
[/format]

I think at this point, I simply need to get that app into the clipboard and reduce the rest of the functionality, to keep this simple.

[format]require ‘clipboard’
def osascript(script) = system ‘osascript’, *script.split(/\n/).map { |line| [‘-e’, line] }.flatten
r = ‘’

mys=<<-TEXT
tell application “System Events” to set the clipboard to name of first application process whose frontmost is true
TEXT
osascript(mys)

origapp = Clipboard.paste
r += “origapp: #{ origapp }\n”

mys = “tell application "#{ origapp }" to set the clipboard to (selection as text)”
r += “mys: #{ mys }\n”
osascript(mys)

Clipboard.copy(r)

mys=<<-TEXT
tell application “BBEdit” to activate
tell application “System Events” to keystroke “v” using command down
TEXT
osascript(mys)[/format]

Unfortunately, I don’t understand anything about Ruby.

The only thing I can say is that the description of the error tells you not to try to use the reserved word text (which is the name of the class, otherwise the name of the type) as a variable.

The error should be here:

text = Clipboard.paste

Ya I’ve tried different things in that area. The issue is that I still can’t get the frontmost app, outside of any text manipulation.

I think here you need to send the keystroke to the target process:

Something like

set myProcess to first application process whose frontmost is true
set the clipboard to the name of myProccess

--<SNIP>--

tell application "System Events"  to tell myProcess to keystroke "v" using command down

Ya I thought as much. Problem is, myProcess is never defined. It won’t capture what I consider “my current app”.

The first part of what I posted defines myProcess.

As I understand it your current app is behind LaunchBar when executed. When you set the visible of LaunchBar to false, that makes your current app frontmost. Next, set the variable myProcess to that process and then direct your UI commands to that process within System Events.

Or am I missing something?

Yes. It doesn’t work.

OK, I can’t help with any of your Ruby stuff, so I’ve commented that all out, and this is just the appleScript stuff.

What I think is happening is that because your appleScripts segments are not part of the same script they are not sharing variables, so the variable myProcess, defined in the first appleScript segment is not defined in the second.

But, there’s a conflict in your script. When you do a command-c you’re setting the same clipboard that the “set the clipboard to” command does, so that overwrites the value the script copies with command-c.

The solution is to define myProcess again. This should work because that app should still be frontmost.

I tried this with a few different apps (including BBEdit) and it worked (but without the Ruby stuff)

 
--require 'clipboard'
--def osascript(script) = system 'osascript', *script.split(/\n/).map { |line| ['-e', line] }.flatten
--
--# mys=<<-TEXT
----# tell application "System Events" to keystroke "c" using command down--<<This line  conflicts with the clipboard command, and there's no need to have this script segment at all
--# TEXT
--
--mys=<<-TEXT
set thisAppName to name of current application
tell application "System Events"
	set visible of process thisAppName to false
	set myProcess to first application process whose frontmost is true
	--set processName to (the name of myProcess)
	tell myProcess
		keystroke "c" using command down
	end tell
	log (the clipboard)
	
end tell
--set the clipboard to processName--<<This line  conflicts with the keystroke command and there's no need for it now either. 
log (the clipboard) 

--TEXT
--osascript(mys)
--
--r = ''
--text = Clipboard.paste
--text.strip.split("\n").each do |i|
--  begin
--    stuff = i.strip.split(/\s*:\s*/)
--    r += stuff.first.strip.rjust(find_largest_key(text)+5) + " : " + stuff[1].strip + "\n"
--  rescue
--    r += i
--  end
--end
--
--Clipboard.copy(r)
--
--mys=<<-TEXT
tell application "System Events"
	log (the clipboard)
	set myProcess to first application process whose frontmost is true
	tell myProcess
		keystroke "v" using command down
	end tell
end tell

–osascript(mys)

If this doesn’t work you’ll need to find a way to move variables from AppleScript to Ruby and from Ruby to AppleScript.

Hope that helps.

Excellent. THIS works.

Not sure what log (the clipboard) means. Any chance you can elaborate on that quickly?

Here’s the final script:

[format]require ‘clipboard’
def osascript(script) = system ‘osascript’, *script.split(/\n/).map { |line| [‘-e’, line] }.flatten

mys=<<-TEXT
set thisAppName to name of current application
tell application “System Events”
set visible of process thisAppName to false
set myProcess to first application process whose frontmost is true
tell myProcess
keystroke “c” using command down
end tell
end tell
TEXT
osascript(mys)

Clipboard.copy(Clipboard.paste.gsub(‘-’, ’ '))

mys=<<-TEXT
tell application “System Events”
set myProcess to first application process whose frontmost is true
tell myProcess
keystroke “v” using command down
end tell
end tell
TEXT
osascript(mys)[/format]

As I see it, the correct solution is using my suggestion of process visibility. Let me remind you that @daBee answered me literally the following:

“I see what you did by shoving the (either Launchbar or Automator Quick Action) focus aside, leaving the second-in-line app (the editor) having focus. Unfortunately this didn’t do the trick either. The problem is that this isn’t about visibility.”

Also, I remind you that the keystroke commands belong to the System Events application itself. Therefore, processes do not need to be told.

mys=<<-TEXT
tell application “System Events” to keystroke “v” using command down
TEXT
osascript(mys)

The same with keystroke “c”

mys=<<-TEXT
set thisAppName to name of current application
tell application “System Events”
set visible of process thisAppName to false
set myProcess to first application process whose frontmost is true
keystroke “c” using command down
end tell
TEXT
osascript(mys)

Well, then visibility would have told me that the current focus on activating the LaunchBar script, would be something as frontmost application, which didn’t occur. It returned nil result. Automator further shields any interaction. Automator I would only use for direct applications, however packaged.

In any case, I’m happy it works now, which is the goal. Having to push aside an empty focus, is an AS issue. Other implementations using LaunchBar, is straight forward. Managing operations in specific applications is predictable.

Glad it worked.

If you’re editing AppleScripts in Script Editor or Script Debugger the log command shows you the value of whatever your are logging at that moment during execution of your script.

It’s ignored at runtime.

Speaking of automator, I believe you could use automator to build a service that would do the same thing, via a menu item. (Once that service is built and saved Automator would be out of the picture)

All the Apple documentations I’ve seen and all the expert tools (ScriptDebugger; UI Browser) all address UI commands to the process within System Events that own the UI elements.

It wasn’t long ago where someone was posting UI scripts that required delays without sending the commands to the process inside SE, and did not require delays once that was corrected.

OK, log X isn’t what I can use.

Automator is the last thing I would use. I live in another language and Launchbar allows that. It also allows the AS and Automator options, but they have been quite convoluted for…decades.

The errors/results that I see are in the Console, and even with successful results, Launchbar successes are…not presenting as I would expect.

Cheers.

Hey thanks for the insight/conversation. New stuff for an application (Launchbar) that isn’t clear.

I’m no fan of Automator, but I believe it’s the easiest way to install an AppleScript (and thereby a shell script or ruby script) as a service. Once it’s installed you don’t have to bother with Automator.

The keystroke command does not exist for applications. So I can assure you that it should be directed to System Events.

And the fact that someone once accidentally succeeded with delays is explained in a completely different way. Namely, the fact that AppleScript is famous for its “fool-proof” because it automatically redirects many erroneous commands to the right application. Of course, fixing a user error slows down the script, which creates some unpredictable delay, giving the impression of a “working” script.

In fact, the script itself should control the delay. Every time after opening a new window, menu or dialog. Using automated delay like this:

repeat until window 1 of process theProcess exists
delay 0.1
end repeat

Then you can send the keystroke to System Events, and it keystrokes to this new window.

I didn’t want to be clever here and continue the topic, but I always want users not to get lost in their work. Of course, this is my personal opinion: understanding how everything works is important for writing durable and stable scripts.

Best practice:

 
tell application "Safari" to activate
tell application "System Events"
    tell process "Safari"
        -- Perform user interface scripting tasks
    end tell
end tell

From Apple:

Mac Automation Scripting Guide: Automating the User Interface

https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/AutomatetheUserInterface.html#//apple_ref/doc/uid/TP40016239-CH69-SW1

User interface scripting terminology is found in the Processes Suite of the System Events scripting dictionary. This suite includes terminology for interacting with most types of user interface elements, including windows, buttons, checkboxes, menus, radio buttons, text fields, and more. In System Events, the process class represents a running app. Listing 37-1 shows how to target an app using this class.

Listing 37-1
AppleScript: Targeting an app for user interface scripting

 
tell application "System Events"
    tell process "Safari"
        -- Perform user interface scripting tasks
    end tell
end tell