8

If my understanding is correct, there are two types of content that can be copied to the Mac global (systemwide) clipboard:

  • text

or

  • file

Even though they are two different, discrete data types, they share the very same clipboard. For example, if you have an image file on your clipboard, and then you copy a text sentence, the sentence will overwrite the image file, and vice versa. Please correct me if I am wrong.

My question is, how can I determine if the clipboard does not contain text, using AppleScript?

The context of my question is an AppleScript .scpt file that speaks the selected text in the System Voice at a specified volume. The selected text is copied to the clipboard, and then the text is spoken via the say command. The script is triggered by keystroke via FastScripts.app.

Every so often, I am given an error dialog that states, "Error Number: -1728." This error occurs when, instead of text being highlighted, I have highlighted or selected an actual file. Mac's Speech function cannot speak a file; Speech can only verbalize text.

So, I would like to create an if...then statement in my script to catch this error. Ideally, I would then like to convert the file to text, if possible in the way that TextEdit does.

bmike
  • 235,889
rubik's sphere
  • 5,610
  • 13
  • 56
  • 109

1 Answers1

5

If the Clipboard contains a file object, then clipboard info will contain, e.g., «class furl» (a file URL), along with many other classes.

The follow example code will check for the presence of «class furl» in the clipboard info:

if ((clipboard info) as string) contains "«class furl»" then
    say "the clipboard contains a file named " & (the clipboard as string)
else
    say "the clipboard does not contain a file"
end if

Update:

As I mentioned in one of my comments, there are other ways to code this, and this approach will return either an empty list or a list containing one list, which should be faster instead of the 14 that the first example returns if it contains a file. If the Clipboard does not contain a file, then the list returned is empty and it errors out, setting cbFile to false, and if not empty, setting it to true, which then is tested against in the following example.

try
    (item 1 of (clipboard info for «class furl»))
    set cbFile to true
on error
    set cbFile to false
end try
if cbFile then
    say "the clipboard contains a file named " & (the clipboard as string)
else
    say "the clipboard does not contain a file"
end if

By the way, I ran the purge command in Terminal in between testing these two examples and it felt like the second example is a bit faster, however YMMV.

user3439894
  • 58,676
  • Do you also know how to get just the filename (not the full path) as text, of a file that's on the clipboard? If the if condition is met: if ((clipboard info) as string) contains "«class furl»" then I would like my script to say the filename of the clipboard file. – rubik's sphere Apr 27 '17 at 06:38
  • Let me know if you think that the question in my above comment warrants a dedicated post. – rubik's sphere Apr 27 '17 at 06:39
  • @rubik's sphere, I've updated the answer to handle the condition set in your comment. By the way, if you want the fully qualified pathname you'll need to use Cocoa-AppleScript and NSPasteboard, which I'm not up on as regular AppleScript. – user3439894 Apr 27 '17 at 11:30
  • Another narrow question would be best, @rubik'ssphere . Linking the two here in comments would be nice as well. I'll edit the question you posted here down to make it clearer the topic here. – bmike Apr 27 '17 at 11:30
  • To the down-voter, please explain a legitimate reason for it, does this not answer the question asked? Do you have a better answer instead of an unwarranted down-vote!? – user3439894 Apr 27 '17 at 13:29
  • @user3439894 Your solution works nicely. But I notice that there is a short delay before the script speaks, "The clipboard contains a file named filename." Is there anything that I can do to shorten or eliminate this delay? – rubik's sphere Apr 27 '17 at 21:52
  • @rubik's sphere, How long of a delay?... When I run this example code in Script Editor, as is, I really do not notice a delay. Are you noticing a delay with this example code in Script Editor, as is, or have you taken this example and reworked it to fit your needs in the larger script and that's were you notice a delay? If the former, there's more then one way to write this code and I've tested different codings but really don't notice a delay on my system. If the latter, then without seeing the code to test against, there's really nothing I can say, (code pun intended). – user3439894 Apr 28 '17 at 01:50
  • @user3439894 When I run your code in Script Editor.app, verbatim, there is a 1 second delay before "The clipboard contains a file named..." is spoken, but "The clipboard does not contain a file" is immediately spoken. This is true no matter the type or location of the file that is on the clipboard. Do you not experience the delay on your system? This is obviously not a big delay, but it is long enough for me to notice the delay every time. Would it be possible for me to test the other coding method(s)? – rubik's sphere Apr 28 '17 at 02:45
  • @rubik's sphere, Now that I know you're comparing a diff between the two states, that's to be expected as there is more processing taking place when it evaluates to true. If false, the return of clipboard info can contain as few as 4 classes and if true, can contain many more, e.g. 14, classes. All of which have to be enumerated and some of those may take longer to enumerate then others, which further adds to the expected delay. So that alone starts the delay diff. Also if true, the Clipboard is queried for the filename as a string, thus adding more to the delay diff. Does that make sense? – user3439894 Apr 28 '17 at 03:27
  • @rubik's sphere, I updated the answer adding another example for you to test to see if it's any faster. – user3439894 Apr 28 '17 at 04:51
  • @user3439894 Yes, that makes sense. Thanks for the detailed explanation. I'm still surprised that such a powerful & advanced machine cannot perform this relatively simple task instantly. I suppose that some inefficient code on Apple's part is to blame. I have found that your alternate method is not faster than the original method, as far as I can tell. The new method still has a 1 second delay. I am unable to accurately measure the runtime down to the millisecond. Thank you for all of your help. – rubik's sphere Apr 28 '17 at 11:52
  • @rubik's sphere, FWIW Saving both versions of code as .scpt with modding the false branch, so say would say the exact same thing as the true branch, done so for best comparison, and running with osascript as an argument of time, there was a difference between the 2 versions. I closed/opened Terminal and used the purge command in between each run and when all was said an done ver1 had a 0.719s diff between the T/F branch and ver2 had a 0.363s diff between the T/F branch in comparison with a 0.356s diff between each version. While ver2 was technically faster the differential is negligible. – user3439894 Apr 28 '17 at 16:52
  • @user3439894 Interesting analysis. In that case, I will go with the alternate method. – rubik's sphere Apr 28 '17 at 19:24