Some of my macros rely on the ability to get selected text.
Currently, I'm using BetterTouchTool to accomplish this. Here is an example for an Applescrilt I wrote:
-- Get the selected text from BetterTouchTool
tell application "BetterTouchTool"
set selectedText to get_selection
end tell
-- Check if we got something
if selectedText is not "" then
set wrappedText to "(" & selectedText & ")"
-- Type the wrapped text, replacing the selection
tell application "System Events"
keystroke wrappedText
end tell
end if
I prefer using a method to get selected text instead of copying it to my clipboard, as I want to avoid cluttering my clipboard.
I’m wondering if there are any other ways to get selected text without relying on additional software like BetterTouchTool. ?
I'm trying to create a script or macro that can work for anyone on a Mac, without requiring extra tools.
However, for some unknown reason, the previous clipboard entries didn’t seem to be removed. I'm using the Alfred clipboard manager, in case that matters.
Perhaps I made an error in the order of the actions or something similar.
Would you mind sharing a screenshot of a macro setup that achieves this?
Alfred’s clipboard history is independent of Keyboard Maestro’s clipboard history. These are separate implementations of the same idea and the data is not shared.
This is true. I don't know of a way to programmatically remove the most recent item from Alfred's clipboard history viewer, other than a string of keystrokes:
That said, the Delete Past Clipboard action does solve the issue in practical terms; the only issue is that Alfred's history won't reflect the actual system clipboard.
Or it's that BTT is using a private method to get the selection, and Peter has decided he'd prefer not to do that. I don't know, of course, but that's one possible explanation. (The danger of using private methods is that they can change at any time, without any notice to developers. And if you're selling apps to people, that's a Bad Thing™.)
This isn't perfect, but it's pretty good. I modified the original to speed it up and handle Safari. It covers most of my needs reliably:
use sys : application "System Events"
-- Use the following delay to choose an application window
-- and highlight some text. Then ensure that the window remains
-- in focus until the script terminates.
set P to the first process whose frontmost is true
-- To handle Safari
if name of P is "Safari" then
tell application "Safari" to return (do JavaScript "(''+getSelection())" in document 1)
end if
set _W to a reference to the first window of P
set _U to a reference to ¬
(UI elements of P whose ¬
name of attributes contains "AXSelectedText" and ¬
value of attribute "AXSelectedText" is not "" and ¬
class of value of attribute "AXSelectedText" is not class)
tell sys to if (count _U) ≠ 0 then ¬
return the value of ¬
attribute "AXSelectedText" of ¬
_U's contents's first item
set _U to a reference to UI elements of _W
tell sys to repeat while (_U exists)
tell (a reference to ¬
(_U whose ¬
name of attributes contains "AXSelectedText" and ¬
value of attribute "AXSelectedText" is not "" and ¬
class of value of attribute "AXSelectedText" is not class)) ¬
to if (count) ≠ 0 then return the value of ¬
attribute "AXSelectedText" of its contents's first item
set _U to a reference to (UI elements of _U)
end repeat
--"No selection found."
""
I typically use it in an Execute AppleScript action set to save results to a variable.
Another possibility to get selected text might be a 'Quick Action' service created in Automator.app that will save the selected text to a Keyboard Maestro variable. A Keyboard Maestro Macro can trigger this service and then use the variable for further action. As setting and getting the variable shows a slight delay we must instruct the Keyboard Maestro Macro to set the variable to empty, then to trigger the service, and then to wait until the variable is not empty any longer. In the example the Automator service is named: "KMGetText" and the variable is named: "TextSelection". In theory, this should allow to get any selected text that services can get without using the clipboard.
How about copying the System Clipboard to a temporary one before running your method, then saving what you've retrieved to a variable or another clipboard, then copying the temporary clipboard back to the System Clipboard? It's not elegant but it's simple to follow.
Sometimes you may not want to use the clipboard, for example, if you use external clipboard history managers or have clipboard triggers you wish to avoid activating.
Automator services that act on selected text are only active if text is selected. Thus, the macro will spit out an error message that it cannot find the service if no text has been selected. You will get a different result with shortcuts, they still run without selected text. In that case add a line to the applescript before the tell block to catch that case, maybe:
if input is {} then set input to "Please select some text"
You might also want to set the 'time out' for the 'Pause Until Condition' to a lower value in the macro, 99 h are a tad long.
You will get a different result with shortcuts, they still run without selected text
Good point! I will be sure to add that.
You might also want to set the 'time out' for the 'Pause Until Condition' to a lower value in the macro, 99 h are a tad long.
Beat you to it...but I'm not sure how much I need this action other than as a precaution. Also, I've disabled the action to set the variable to empty as I'm not experiencing any issues (yet ).