Saturday, December 3, 2022

#1 2022-10-01 01:51:24 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1517

Scripting the macOS Stickies app

There's only two threads on MacScripter's regarding the Stickies app, and they are both dated. So, I thought I would provide a few script suggestions. Please note that:

* The Stickies app is not scriptable and, as a result, everything has to be done with System Events.
* I intentionally omitted any error correction, which the user can add when required.
* A new Stickie note can be created from a selection in an app with the Shift-Command-Y keyboard shortcut.

Applescript:


-- Position and resize frontmost note
tell application "System Events" to tell process "Stickies"
   set frontmost to true
   set position of window 1 to {50, 50}
   set size of window 1 to {450, 300}
end tell

-- Position and resize every note to one location
tell application "System Events" to tell process "Stickies"
   set frontmost to true
   set position of every window to {50, 50}
   set size of every window to {450, 300}
end tell

-- Resize and cascade notes
set {x, y} to {50, 50} -- initial position of notes
set {w, h} to {450, 300} -- initial size of notes
set windowOverlap to 40

tell application "System Events" to tell process "Stickies"
   set frontmost to true
   set windowCount to (count windows)
   repeat with i from windowCount to 1 by -1 -- from old to new
       -- repeat with i from 1 to windowCount -- from new to old
       set position of window i to {x, y}
       set size of window i to {w, h}
       set {x, y} to {x + windowOverlap, y + windowOverlap}
   end repeat
end tell

-- Resize and tile notes (revised 2022.10.10)
set {w, h} to {450, 300} -- user set size of notes
set wB to 10 -- user set buffer between notes
set {x1, y1, x2, y2} to {0, 25, 1920, 1080} -- user set usable screen bounds
set windowsPerRow to ((x2 - x1) - wB) div (w + wB) -- do not change

tell application "System Events" to tell process "Stickies"
   set frontmost to true
   set xOriginal to x1
   repeat with i from 1 to (count windows)
       set position of window i to {x1 + wB, y1 + wB}
       set size of window i to {w, h}
       if i mod windowsPerRow = 0 then
           set x1 to xOriginal
           set y1 to y1 + h + wB
       else
           set x1 to x1 + w + wB
       end if
   end repeat
end tell

-- Backup notes to text file on desktop (revised 2022.10.18)
set homeFolder to (path to home folder as text)
set stickieFolder to homeFolder & "Library:Containers:com.apple.Stickies:Data:Library:Stickies:"
set targetFile to homeFolder & "Desktop:" & "Stickie Notes.txt"

tell application "Finder"
   set stickieFiles to (files in folder stickieFolder whose name extension is "rtfd")
   set stickieFiles to sort stickieFiles by creation date
end tell

set text item delimiters to "/"
repeat with aFile in stickieFiles
   set aPosixFile to POSIX path of (aFile as alias)
   set aNote to do shell script "textutil -stdout -convert txt " & quoted form of aPosixFile
   set contents of aFile to "---" & linefeed & text item -2 of aPosixFile & linefeed & "---" & linefeed & linefeed & aNote & linefeed & linefeed
end repeat
set text item delimiters to ""
set stickieFiles to stickieFiles as text

set openedFile to (open for access file targetFile with write permission)
try
   set eof openedFile to 0
   write stickieFiles to openedFile as «class utf8»
   close access openedFile
on error errMsg number errNbr
   close access openedFile
end try

-- Trim whitespace, create new note, and paste clipboard
use framework "Foundation"
use scripting additions

trimClipboardText()
createNote()

on trimClipboardText()
   set thePattern to "(?m)^\\h+|\\h+$" -- user can edit to change characters removed
   set theString to the clipboard -- user can edit for desired class type
   set theString to current application's NSMutableString's stringWithString:theString
   (theString's replaceOccurrencesOfString:thePattern withString:"" options:1024 range:{0, theString's |length|()})
   set the clipboard to (theString as text)
end trimClipboardText

on createNote()
   tell application "Stickies" to activate
   tell application "System Events" to tell process "Stickies"
       repeat until menu "File" of menu bar 1 exists
           delay 0.02
       end repeat
       click menu item "New Note" of menu "File" of menu bar 1
       repeat until menu "Edit" of menu bar 1 exists
           delay 0.02
       end repeat
       click menu item "Paste" of menu "Edit" of menu bar 1
   end tell
end createNote

Last edited by peavine (2022-10-18 07:19:35 am)


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#2 2022-10-02 11:56:29 pm

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 2589

Re: Scripting the macOS Stickies app

Cool script, @peavine,

You can put automated delays instead of hard-coded delay 0.2:

Applescript:


repeat until menu "File" of menu bar 1 exists
delay 0.02
end repeat

repeat until menu "Edit" of menu bar 1 exists
delay 0.02
end repeat


Model: MacBook Pro
OS X: Catalina 10.15.7
Web Browser: Safari 15.6.1
Ram: 4 GB

Offline

 

#3 2022-10-04 01:23:16 am

Fredrik71
Member
Registered: 2019-10-23
Posts: 1090

Re: Scripting the macOS Stickies app

@peavine
Did you know that you could type and select any text in TextEdit and use keyboard shortcut shift + command + y to make sticky available for the selected text. In other words I believe its possible to do this with any selected text not specified to TextEdit.

So instead of using GUI scripting you could use NSServices (keyboard shortcuts)

Next you could decide the position x, y of the stickers, at least you do not need GUI Scripting.

Something like this maybe.

Applescript:

set targetText to (the clipboard) as text
if targetText is "" then return display dialog "No plain-text find in clipboard..."

tell application "TextEdit"
   make new document with properties {text:targetText}
   activate
end tell

-- select all text, use make sticker service
tell application "System Events"
   keystroke "a" using {command down}
   keystroke "y" using {shift down, command down}
end tell

delay 0.5

tell application "TextEdit" to close front document

Last edited by Fredrik71 (2022-10-04 02:13:07 am)


Node-RED makes it easy to automate IoT

Offline

 

#4 2022-10-04 02:11:27 pm

Fredrik71
Member
Registered: 2019-10-23
Posts: 1090

Re: Scripting the macOS Stickies app

Sometimes its not clipboard, variable as string we want... but something else.
This script demonstrate its possible to use keyboard shortcuts to get selection inside a AppleScript
that store a string as variable. And we like to transfer this string to app that is not scriptable.

Most macOS app have keyboard shortcuts and sometimes its powerful to explore them with script.

Applescript:

set a to "abc"

its textStringToStickies(a)

on textStringToStickies(theString)
   tell application "TextEdit"
       make new document with properties {text:theString}
       activate
   end tell
   tell application "System Events"
       keystroke "a" using {command down}
       keystroke "y" using {shift down, command down}
   end tell
   delay 0.2
   tell application "TextEdit" to close front document
end textStringToStickies

Last edited by Fredrik71 (2022-10-04 02:14:58 pm)


Node-RED makes it easy to automate IoT

Offline

 

#5 2022-10-06 09:40:15 am

estockly
Member
Registered: 2009-01-03
Posts: 158

Re: Scripting the macOS Stickies app

I like this script. What characters are these:

Applescript:

   set thePattern to "(?m)^\\h+|\\h+$"

Offline

 

#6 2022-10-06 02:31:33 pm

Fredrik71
Member
Registered: 2019-10-23
Posts: 1090

Re: Scripting the macOS Stickies app

The weakness to use GUI scripting and only access the menu is that not all people use the same localized string. And other may use index to access menu bar items but could brake when the software developer change or update the application.

Most times I do not think Apple or developers change keyboard shortcuts that is standard.

So you function could look like this, it did work on my machine.

Ps. And you do not need repeat loops for keyboard shortcuts

Applescript:

on createNote()
   tell application "Stickies" to activate
   
   tell application "System Events"
       if application "Stickies" is frontmost then
           -- make new document
           keystroke "n" using {command down}
           -- paste from clipboard to front document
           keystroke "v" using {command down}
       end if
   end tell
end createNote

Last edited by Fredrik71 (2022-10-06 02:35:14 pm)


Node-RED makes it easy to automate IoT

Offline

 

#7 2022-10-06 06:22:13 pm

estockly
Member
Registered: 2009-01-03
Posts: 158

Re: Scripting the macOS Stickies app

peavine wrote:

Thanks Ed for trying my script. Those are "horizontal whitespace characters" which normally means spaces and tabs. The pattern can be changed to remove just about any characters or character classes that are desired.



Have you seen this handler from KniazidisR?

MacScripter / Automated Rutines, lesson 1. Working with Text.

Applescript:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

trimWhiteSpaceAroundString("     How now brown cow.    ")

on trimWhiteSpaceAroundString(thisString)
   set cocoaString to ¬
       current application's NSString's stringWithString:thisString
   set whiteSpaceCharacters to ¬
       current application's NSCharacterSet's whitespaceAndNewlineCharacterSet()
   set cocoaString to cocoaString's stringByTrimmingCharactersInSet:whiteSpaceCharacters
   return cocoaString as text
end trimWhiteSpaceAroundString



If you just want spaces and tabs removed you could substitute this:         

Applescript:

   set whiteSpaceCharacters to ¬
current application's NSCharacterSet's whitespaceCharacterSet()

Offline

 

#8 2022-10-06 09:27:15 pm

estockly
Member
Registered: 2009-01-03
Posts: 158

Re: Scripting the macOS Stickies app

Got it, thanks

Offline

 

#9 2022-10-08 09:51:57 pm

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 2589

Re: Scripting the macOS Stickies app

peavine wrote:
estockly wrote:

Have you seen this handler from KniazidisR?



Ed. KniazidisR's handler only removes whitespace from the beginning and end of a string. My handler removes whitespace from the beginning and end of every paragraph in the string. Also, even if KniazidisR's handler is modified to work the same as mine, it is significantly slower in my testing.


Since using shell commands or AsObjC takes time to bootstrap, I usually use the more efficient plain-AppleScript handler for none very large text. Stickies - just the case when the text should not be large.:

Applescript:


on trimClipboardText()
   set theText to the clipboard as text
   -- removes Trailing and Leading Spaces and Tabs in the Clipboard text
   script o
       property aList : missing value
   end script
   set {ATID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {" ", tab}}
   set o's aList to theText's text items
   repeat with anItm in (get o's aList)
       if contents of anItm is "" then set contents of anItm to missing value
   end repeat
   set the clipboard to o's aList's text as text
   set AppleScript's text item delimiters to ATID
end trimClipboardText

set the clipboard to " This is test        text with spaces and tabs "
trimClipboardText()
set trimmedText to the clipboard --> "This is test text with spaces and tabs"

.
Here is a very basic handler (variation of the handler above) without involving the clipboard:

Applescript:


on removeTrailingAndLeadingSpacesAndTabs_ATID(theText)
   script o
       property aList : missing value
   end script
   set {ATID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {" ", tab}}
   set o's aList to theText's text items
   repeat with anItm in (get o's aList)
       if contents of anItm is "" then set contents of anItm to missing value
   end repeat
   set theText to o's aList's text as text
   set AppleScript's text item delimiters to ATID
   return theText
end removeTrailingAndLeadingSpacesAndTabs_ATID

.
Three do shell script solutions I know at the  moment:

Applescript:


on removeTrailingAndLeadingSpacesAndTabs_sed(theText)
   do shell script "echo " & quoted form of theText & " | sed -E 's/[[:space:]]+/ /g ; s/^[[:space:]]|[[:space:]]$//g'"
end removeTrailingAndLeadingSpacesAndTabs_sed


on removeTrailingAndLeadingSpacesAndTabs_xargs(theText)
   do shell script "echo " & quoted form of theText & " | xargs"
end removeTrailingAndLeadingSpacesAndTabs_xargs


on removeTrailingAndLeadingSpacesAndTabs_tr(theText)
   do shell script "echo " & theText & " | tr -s ' ' | sed -E 's/^ | $//g'"
end removeTrailingAndLeadingSpacesAndTabs_tr

.
AsObjC solution (one more):

Applescript:


use framework "Foundation"
use scripting additions

on removeTrailingAndLeadingSpacesAndTabs_AsObjC(theText)
   set theString to current application's NSString's stringWithString:theText
   set stringLength to theString's |length|()
   set theString to theString's stringByReplacingOccurrencesOfString:" +" withString:" " options:(current application's NSRegularExpressionSearch) range:{location:0, |length|:stringLength}
   set theWhiteSet to current application's NSCharacterSet's whitespaceCharacterSet()
   return (theString's stringByTrimmingCharactersInSet:theWhiteSet) as text
end removeTrailingAndLeadingSpacesAndTabs_AsObjC

Last edited by KniazidisR (2022-10-08 10:37:22 pm)


Model: MacBook Pro
OS X: Catalina 10.15.7
Web Browser: Safari 15.6.1
Ram: 4 GB

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)