Alternative Methods for Retrieving Selected Text on Mac

Hey everyone,

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.

Have a great day

You can always delete the past clipboard. There's a dedicated action for this.

Yes, I initially tried this method.

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?

You just need to set it to delete past clipboard 0.

I have this action saved as a favourite:

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.

That's exactly my issue.

Anyway, the script attached above, which relies on BTT, gets selected text action works great.

Interesting why there is no such action in KM. I guess this could be a potential feature request, since this is quite useful in my opinion

Thanks for your answer

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™.)

-rob.

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.

4 Likes

Brilliant! I'd had a go at scripting it this morning and got nowhere. Thanks for sharing!

1 Like

That’s great! Thank you

1 Like

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.


2 Likes

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.

Nice! I'm liking this method the most...using the shortcuts app though :wink:

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.

1 Like

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 :crossed_fingers:).