Draw a text overlay at the cursor (like a tooltip?)

My goal is to see a message whenever I copy something to the clipboard, since I often fat finger things. "Display text briefly" is alright, but it appears all the way on the top left corner of the screen. I want something to appear right on the cursor, since that's where my eyes will be at that moment.
I've tried finding solutions but they all involve windows, and I don't want to have to click to dismiss anything. I just want a brief visual confirmation that yes, I copied the text.

Any suggestions?

Wouldn't just a distinctive system sound be enough to confirm the copy for you @dougyd?

Copy

If you do not need the text, then you can use the Mouse Effect action.

Keyboard Maestro 8.2.4 “Highlight Location” Action

Highlight Location.kmactions (609 B)

2 Likes

If you really want, I can get an actual tooltip to appear with any message you want to display. However, like a tooltip, there’s would be a second or so delay from the time the signal is sent to when the tooltip appears.

Yeah an actual tooltip would be perfect! How would you do that?

I usually have my computer muted (at work) so that wouldn't work for me. Thanks for the suggestion though!

Hmm that looks really promising! Is there a way to get the position of the text cursor instead of the mouse?

Unfortunately there is no general way to tell the screen location of the current insertion point. You may be able to do it using accessibility or AppleScript in some cases, but not in general.

Apologies, I spoke too soon. I wrote an AppleScriptObjC script that can create an NSWindow instance, i.e. create a window. I made the window invisible and had it fill the screen, then attached a tooltip to it, which displays when the mouse hovers over the window. And since the window fills the screen, it is always hovering over the window, and so the tooltip appears (after the default delay I mentioned previously). Then, after 5 seconds, my script closes the window and destroys the instance.

The script runs fine in Script Editor and does what I'd expect.

However, having just tested it in Keyboard Maestro, it doesn't work. My guess is that, since Keyboard Maestro executes AppleScripts using osascript, an NSWindow instance can't be created outwith an environment that, itself, isn't attached to the GUI. Of course, I may be wrong and there may be another reason why it's not working, but either way, I'm sorry to get your hopes up.

1 Like

Usually that is resolved by surrounding the code with a tell application to give it an application context to create the window in.

That was one of my first thoughts, and I wrapped it inside a tell application "Finder" block without much effect. I've popped my code in the drop-down if you have time to glance over it and see anything obvious.

AppleScript
use framework "Appkit"
use scripting additions

property this : a reference to current application
property NSBackingStoreBuffered : a reference to NSBackingStoreBuffered of this
property NSBorderlessWindowMask : a reference to NSBorderlessWindowMask of this
property NSColor : a reference to NSColor of this
property NSScreen : a reference to NSScreen of this
property NSWindow : a reference to NSWindow of this

script _NSWindow
	script tooltip
		property input : a reference to system attribute "KMVAR_Input"
	end script
	
	to make
		tell (NSWindow's alloc()'s ¬
			initWithContentRect:(NSScreen's ¬
				screens()'s item 1's frame()) ¬
				styleMask:NSBorderlessWindowMask ¬
				backing:NSBackingStoreBuffered ¬
				defer:true)
			
			setOpaque_(yes)
			setAlphaValue_(1.0)
			setBackgroundColor_(NSColor's systemPinkColor())
			
			setReleasedWhenClosed_(yes)
			setExcludedFromWindowsMenu_(yes)
			
			set t to "👍🏼"
			tell input of tooltip to if "" ≠ it ¬
				then set t to its contents
			
			contentView()'s setToolTip:t
			
			orderFrontRegardless()
			delay 5
			|close|()
		end tell
	end make
end script

tell application "System Events"
	make _NSWindow
end tell

Your script worked for me in High Sierra. The window appeared (solid pink) and the tooltip appeared.

Oddly the tooltip does not go away until you click.

Changing the setOpaque_ to not and the setAlphaValue_ to 0 results in no window appearing and the tooltip appearing.

Just to clarify, do you mean that it worked whilst being executed within a KM Execute AppleScript action ?

Sorry, no I was just using AppleScript.

Hmm, you probably have to find some way for some to tell some foreground app to run the script.

Hey CJK,

I have a question about your code that is totally unrelated to KM, but I am not sure where I should pose that question at? Here? Stack Overflow ApplescriptObjC form?

Please let me know!

Thanks

If it is about the code shown above, feel free to ask it here.

As Peter already said, you are welcome to ask it here, regardless of whether or not I may be able to help personally, as there are many talented scripters on this forum, and each brings their own applied skillset and unique approach to their solutions.

I saw you found a working solution on Stack Overflow, and it's from red_menace, who knows his stuff. Having read over it, it sounds like you initially were able to create the NSWindow object; and you believe you created an NSTextView object; but the problem was in getting content into the NSTextView, and then into the NSWindow. Assuming my grasp of the issue is accurate, my one query over red_menace's answer would be his assertion (hypothesis) that the issue arises from one or more methods lacking a target. All of the (AppleScriptObjC) methods in the visible code snippets are targeted at the NSWindow instance and there's no ambiguity here (in fact, the odd-man-out is the AppleScript delay command, which is also targeting the NSWindow instance despite being a scripting additions command, but thankfully AppleScript deals with ambiguous use of its own terminology pretty intelligently).

Ultimately, the problem was entirely one of attaching the NSTextView object to the NSWindow, which he showed you how to do.

To clarify the use of the its keyword—whilst certainly not wrong nor harmful and arguably clearer to a human reader—it is entirely superfluous in the original form of the script. However, when red_menace opted for a different syntax to set AppleScriptObjC property values directly, it became necessary: property values must be qualified with its; conversely, the original script calls the properties' setter methods, which don't require qualification of their target.
Both approaches are equally valid, so you can decide what you personally prefer.

For comparison, I've included a working version of the script written using the syntax of the original, which partly serves to demonstrate that targeting was never an issue, and partly because I feel a sense of responsibility to do so given the original script came from me.

AppleScriptObjC NSWindow + NSTextView
use framework "Foundation"
use scripting additions

property this : a reference to the current application
property nil : a reference to missing value
property _1 : a reference to reference

property NSColor : a reference to NSColor of this
property NSTextView : a reference to NSTextView of this
property NSWindow : a reference to NSWindow of this

property NSBackingStoreBuffered : a reference to 2
property NSBorderlessWindowMask : a reference to 0


# Create an NSTextView instance
tell NSTextView's alloc()
	initWithFrame_({{20, 20}, {600, 440}})
	setString_("this is a test")
	
	set TextView to it
end tell

# Create an NSWindow instance
tell (NSWindow's alloc()'s initWithContentRect:{¬
	{200, 600}, {640, 480}} ¬
	styleMask:NSBorderlessWindowMask ¬
	backing:NSBackingStoreBuffered ¬
	defer:yes)
	
	setOpaque_(yes)
	setAlphaValue_(0.5)
	setBackgroundColor_(NSColor's grayColor())
	setReleasedWhenClosed_(yes)
	setExcludedFromWindowsMenu_(yes)
	
	contentView()'s addSubview:TextView
	
	orderFrontRegardless()
	delay 5
	|close|()
end tell