Non-Scrivener Specific AppleScript Question

ed
edmo
Posts: 47
Joined: Wed Oct 25, 2006 6:06 pm
Location: Vancouver, BC, CAN

Wed Aug 26, 2009 5:45 pm Post

Hi All - hoping the bright minds here in the Scrivenerati might be able to help me with an appleScript problem that's been driving me around the bend. My objective is to transfer the contents of the clipboard to another app - say the notes field of a new THL task or Mori document. The catch is that I want the clipboard contents to remain unaltered. I want graphics, fonts, colours, links, columns, etc. all preserved.

The other catch is that I don't want to have to use system events and keystrokes to navigate into the app and its document and paste the clipboard in. It seems to me that there has to be another way - i.e. using something like ""tell App X to make new entry with properties {title:entryTitle, notes:the clipboard}"" but specifying, somehow, that the clipboard and its properties in their entirety are to populate the note, rather than just the clipboard's rearranged text.

Am I drunk or does someone know of a way to do this? Or both? Thanks for any help.

User avatar
Jaysen
Posts: 6309
Joined: Mon Dec 17, 2007 4:00 am
Platform: Mac + Windows
Location: East-Be-Jesus-Nowhere SC, USA

Wed Aug 26, 2009 10:59 pm Post

in script editor look in the library, section StandardAdditions. The clipboard is in there.

You can add your app to the library and it should expose any apple scriptable (exposed by software) functions/objects. You'll need to look there on how to create the new doc.

A rough guess would be

Code: Select all

tell application x
  activate
  set myDoc to create document with properties of the clipboard
end tell

I highly suspect this is NOT what you want, but the idea is there. Provide a few more specifics and I am sure someone will offer a better solution.
Jaysen

I have a wife and 2 kids that I can only attribute to a wiggle, a giggle, and the realization that she was out of my league so I might as well be happy with her as a friend. 26 years marriage later, I can't imagine life without her. -Me 10/7/09

ImageImage

ed
edmo
Posts: 47
Joined: Wed Oct 25, 2006 6:06 pm
Location: Vancouver, BC, CAN

Thu Aug 27, 2009 10:14 pm Post

Hi Jaysen - thanks very much for the reply and the assistance. I did go into the Script Editor app and opened the Dictionary (I'm assuming that's what you meant by 'library'). After having looked at the clipboard-related material in Standard Additions - and yet again all over the interwebs - I must say that I'm still stumped. (Disclaimer, I'm an appleScript novice.)

Using TextEdit as an example, I want to put the contents of the clipboard - unaltered - into a new TextEdit document (without using System Events and keystrokes). The following script achieves most of this, but alters the clipboard contents - it essentially pastes and matches style, rather than just pastes.

tell application "TextEdit"
activate
set myDoc to make new document
tell myDoc
make new paragraph at end with data (the clipboard)
end tell
end tell

I don't know if it has to do with classes or properties or clipboard info or what-have-you, but it seems to me there must be a way to achieve my desired ends here.

Again, all in Scrivener-land, any help would be much appreciated.

User avatar
Jaysen
Posts: 6309
Joined: Mon Dec 17, 2007 4:00 am
Platform: Mac + Windows
Location: East-Be-Jesus-Nowhere SC, USA

Fri Aug 28, 2009 1:20 am Post

Not sure that is possible. I think the default (meaning not using the low level api) for the clipboard is plain text.

That said, if you can stomach a little system event, the following works for me 100%

Code: Select all

tell application "TextEdit"
   activate
   set myDoc to document 1
   tell application "System Events"
      key code 9 using {command down}
   end tell
end tell

Change text edit to app of choice.
Jaysen

I have a wife and 2 kids that I can only attribute to a wiggle, a giggle, and the realization that she was out of my league so I might as well be happy with her as a friend. 26 years marriage later, I can't imagine life without her. -Me 10/7/09

ImageImage

ed
edmo
Posts: 47
Joined: Wed Oct 25, 2006 6:06 pm
Location: Vancouver, BC, CAN

Fri Aug 28, 2009 4:14 am Post

Thanks again for your response, Jaysen. The reason I don't want to use system events and keystrokes/keycodes if at all possible is that I want to send the clipboard contents to other apps in the background. For instance I might want to send the clipboard contents to the notes field in a Mori document, or the notes field in a The Hit List task, in the background. My understanding is that the system events method you've posted below will only work in the acitvated/frontmost app.

As you have alluded, I may be completely out of luck here, but I figured that if there's a way to do what I'm looking for, yourself or some of the other folks on this forum would be likelier than the average bear to know of it.

User avatar
Jaysen
Posts: 6309
Joined: Mon Dec 17, 2007 4:00 am
Platform: Mac + Windows
Location: East-Be-Jesus-Nowhere SC, USA

Fri Aug 28, 2009 12:35 pm Post

True, but you can apple script who gets to be the frontmost when you are done. Dirty, but tested to work:

Code: Select all

global myFrontApp

tell application "System Events"
   set myFrontApp to name of the first process whose frontmost is true
end tell

tell application "TextEdit"
   activate
   set myDoc to document 1
   tell application "System Events"
      key code 9 using {command down}
   end tell
end tell

tell application myFrontApp
   activate
end tell

Don't like the last activate there, but I am not an applescript guy.

Maybe you can have your cake and eat it too?
Jaysen

I have a wife and 2 kids that I can only attribute to a wiggle, a giggle, and the realization that she was out of my league so I might as well be happy with her as a friend. 26 years marriage later, I can't imagine life without her. -Me 10/7/09

ImageImage

ed
edmo
Posts: 47
Joined: Wed Oct 25, 2006 6:06 pm
Location: Vancouver, BC, CAN

Fri Aug 28, 2009 6:37 pm Post

Jaysen, that's a great way to keep track of and get back to your initial app, so thanks, I hadn't thought of that. I do have a workflow that activates the target app, then uses system events to keystroke cmd-v and then to keystroke cmd-tab to switch back to the original app (similar to what you've proposed here). More and more it is appearing that I can't do what I was hoping, which was to do all of this quickly, quietly, and elegantly in the background.

For instance, again using TextEdit as an example, almost everything I want to achieve can be delivered with a single line of appleScript...
***tell application "TextEdit" to tell document "Target Document" to make new paragraph at end with data (the clipboard)***
Clean, quick, quiet, no app switching, no system events, no keystrokes - easy-peasy, lemon-squeezy.

Unfortunately, the one requirement that it does not meet - for me - is that it alters the clipboard contents, reducing them to text only, and unformatted at that. I assumed - it appears incorrectly - that there would be an easy way to let appleScript know to leave the clipboard contents alone. i.e ***make new paragraph at end with data (the clipboard, just as it's content frickin' appeared a moment ago whenst I copied it, for crissakes)***. Between the two of us, however, it looks like this is not a possibility.

If anyone else has an unexplored idea for me, please do chime in, otherwise I'll assume that I'm beaten.

Thanks again.

fl
flow
Posts: 66
Joined: Tue Jul 24, 2007 12:16 am

Sun Sep 06, 2009 9:13 am Post

Code: Select all

try
   set rtf_data to the clipboard as «class RTF »

   set leFiche to "volume:Users:username:Desktop:clipboard contents.rtf"
   set file_ID to open for access leFiche with write permission
   write rtf_data to file_ID
   close access file_ID
on error errMsg number errNum
   if errMsg = "Can't make some data into the expected type." then
      display dialog "The clipboard does not contain rich text"
      error number -128
   else
      display dialog "Houston, we have a problem." & return & errNum & return & errMsg
   end if
end try

User avatar
gr
Posts: 2273
Joined: Wed Feb 14, 2007 3:57 am
Platform: Mac + iOS
Location: Florida

Sun Sep 06, 2009 2:27 pm Post

It is possible that your clipboard does not contain the information that you think it does. For example, if you are copying some text and pictures from a Word document, it is quite possible that your Clipboard contains only unicode text and not the pictures.

So, when working on this and trying to get the rich stuff out, you need to make sure that some rich stuff is actually on the clipboard.

In Script Editor:

Code: Select all

set k to the clipboard
return class of k


If you run this with the Event Log active, you can see a representation of what is on the clipboard (be prepared for a wait if you have picture data on there, as you will get a numerical dump of the pic data), and the Result tab will show you the class of the clipboard contents.

Examples: A copy from Preview of a picture yields a clipboard of class Record containing one record whose type is picture and whose value is the pic data. A copy from Word of some text with an embedded picture yields a clipboard of class Unicode Text. The contents in this case include only the text with a gap where the picture should be.

User avatar
gr
Posts: 2273
Joined: Wed Feb 14, 2007 3:57 am
Platform: Mac + iOS
Location: Florida

Sun Sep 06, 2009 3:50 pm Post

The real challenge in what you are trying to do is that the clipboard can contain basically anything. So, when a Paste operation is called for in a given application, that app has some real work to do to figure out what to do with what is on the clipboard. This process is not likely made Applescript accessible by the app. What you are typically given is something lower down--like how to insert some content of a known and appropriate type into a content area.

--Greg

P.S. I am finding TextEdit a problematic test case. Pasting mixed text and graphics from Word does not work under any circumstances. Pasting a picture copied out of Preview works, but the Applescript dictionary of TextEdit is very spotty. Documents contain a (rich) text object. Text objects contain paragraphs, but paragraphs lack a contents property. So, it seems that about all you can do is directly set the text of a document--but this gives you no obvious way to insert a picture object (or record containing on) like you get from Preview.

fl
flow
Posts: 66
Joined: Tue Jul 24, 2007 12:16 am

Sun Sep 06, 2009 9:19 pm Post

From "AppleScript: The Comprehensive Guide to Scripting and Automation on Mac OS X" by Hanaan Rosenthal (a book I recommend highly), page 446:

Understanding How the Mac Clipboard Works

The Mac clipboard is a clever piece of software; it's simple to use but surprisingly sophisticated beneath the surface.

When a user copies some data from an application, the clipboard has no idea what kind of application the user is going to paste that data into next. To provide as much flexibility as possible when copying and pasting between applications, the clipboard doesn't just get the data in the native format used by that application; it gets it in as many different formats as the application can provide. This gives the clipboard a sort of "backup plan" when pasting the data into other applications. Less sophisticated formats may not contain as much of the original data as the native format, but they are likely to be understood by a greater number of applications--and something is better than nothing.

For example, when you copy text from a rich-text document in TextEdit, the Mac clipboard obtains this text in as many formats as it can, from the basic (string) to the richest (RTF).

It does this so that when you paste this text into another application, the receiving application can pick whichever format is best for it. For example, Microsoft Word can understand RTF data, so it will ask the clipboard for this because RTF contains not only character data but also lots of valuable style information that Word can put to good use. An application such as Terminal would take the UTF 8–encoded character data, since that’s the richest format it can understand and use. An elderly, Carbon-based, plain-text editor that doesn’t support Unicode text would make do with the basic string data.

Finding Out What’s on the Clipboard

The clipboard info command returns some information about the contents of the clipboard, as shown in the following example:

Code: Select all

set the clipboard to "Paste me!"
clipboard info
--> {{string, 9}}

The result shows that the clipboard contains a string of 9 bytes. Next, here’s an example of the clipboard information after copying text from TextEdit:

Code: Select all

clipboard info
--> {{Unicode text, 1142}, {scrap styles, 62}, {string, 571}, ➥
{uniform styles, 564}, {«class ut16», 1144}, {«class utf8», 575}, ➥
{«class RTF», 914}}

The result is a list containing all the formats TextEdit used to place the same data on the clipboard. It shows that the basic character information is available in any of four formats: string and three Unicode encodings (Unicode text, «class ut16», and «class utf8»). Also, some separate style information is available (scrap stylesand uniform styles) for applications that know how to combine this with one of the previous character-only formats. Finally, the data is available in RTF («class RTF»), which combines both character and style information in a single format.

User avatar
AmberV
Posts: 24669
Joined: Sun Jun 18, 2006 4:30 am
Platform: Mac + Linux
Location: Ourense, Galiza
Contact:

Sun Sep 06, 2009 11:18 pm Post

I've moved this to the Developers & Code section as it isn't really relevant to Scrivener technical support.
.:.
Ioa Petra'ka
“Whole sight, or all the rest is desolation.” —John Fowles

ed
edmo
Posts: 47
Joined: Wed Oct 25, 2006 6:06 pm
Location: Vancouver, BC, CAN

Tue Sep 08, 2009 7:54 pm Post

@flow and @gr: Thanks very much to both of you for your help. The class stuff is something that I had been looking at before, but I had been missing a couple of crucial pieces of information that I now have, thanks to you . The first had to do with those chevron-y/arrow-y symbols bracketing the "class RTF", and the second had to do with only being able to write the rtf data to a closed file, rather than being able to append it to an open document.

Anyhoo, @flow's script definitely accomplishes what I'd requested in my original post, but now, if I may be so bold, I have two additional questions I'm hoping someone could help me with:

1. How do I make those symbols surrounding "class RTF"?

2. Once I've got the rtf clipboard contents into my TextEdit document, how do I change the font/font family to Helvetica without losing the typeface attributes?

For example...
tell application "TextEdit"
tell document 1
set font to "Helvetica"
end tell
end tell

This script - against my wishes - strips all bold and oblique attributes, converting everything to Helvetica regular typeface. Even, for instance, if the document's contents are already in Helvetica (which I tried as a test case). Sizes, colours and links are all preserved, but bold and oblique typefaces are not. Any ideas for me?

fl
flow
Posts: 66
Joined: Tue Jul 24, 2007 12:16 am

Wed Sep 09, 2009 2:40 am Post

@edmo

1. It's actually «class RTF », with a space between the 'F' and the right pointing double angle quotation. (Script Editor will want that space.) Option-\ for the left pointing double angle quotation and option-shift-\ for the right one.

2. I wasn't able to delve into this question deeply. I did paste some rich text into TextEdit, then changed the font using your script and ran into the same problem. Then I used "get properties of paragraph 1" and got the following as the result:

Code: Select all

{size:14.0, color:{65535, 0, 0}, font:"Calibri-BoldItalic", class:text}
The bold and italic attributes are considered part of the font (at least for TextEdit). Helvetica, Helvetica-Bold, Helvetica-Italic, and Helvetica-BoldItalic are four different fonts. Didn't come up with an easy solution right off the bat. I'll look into it more when I have more time and report back.

User avatar
gr
Posts: 2273
Joined: Wed Feb 14, 2007 3:57 am
Platform: Mac + iOS
Location: Florida

Wed Sep 09, 2009 1:01 pm Post

TextEdit recognizes 'attribute run' objects within a document. An attribute run is a run of text with all the same styling. Seems like you might accomplish what you want by looping through all the attribute runs in the document and changing the italic ones to Helv-italic and the bold ones to Helv-bold, the bold-italic ones to Helv-bolditalic, and the rest to Helvetica.

--Greg

P.S. It will be worth it to you to find some sites dedicated to Applescript and look for relevant scripts to download and examine. Someone out there has spent time figuring out how to do tricks with TextEdit, for example, and seeing how they did what they did is probably your quickest route to getting where you are going. (You will no doubt find some helpful forums there, too!)