Sunday, May 9, 2021

#1 2021-05-04 09:39:21 am

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

Special Character Insert Script

Mac computers have various methods by which the user can insert special characters; these include keyboard shortcuts, the character viewer, and text replacement. Most users need nothing more.

I find the character viewer a bit difficult to use, and I have trouble remembering keyboard shortcuts and text-replacement characters for infrequently-used characters. So, I wrote the script included below.

To test this script, simply open and run it in Script Editor. Adding a new character to the script requires its decimal ID, which can easily be found online, and the site I use (because it's easily searched) is linked below. There is no requirement as to the name of the special character. This script should work with any application that has an Edit > Paste menu item.

https://kellykjones.tripod.com/webtools … table.html

Applescript:

use framework "Foundation"
use scripting additions

on main()
   set characterData to {{"dash - em", 8212}, {"dash - en", 8211}, {"divide", 247}, {"double angle - left", 171}, {"double angle - right", 187}, {"double quote - left", 8220}, {"double quote - right", 8221}, {"ellipsis", 8230}, {"not equal to", 8800}, {"plus or minus", 177}, {"single quote - left", 8216}, {"single quote - right", 8217}, {"space - nonbreaking", 160}}
   
   set characterData to sortTheList(characterData) -- this can be removed if sorting is not desired
   set characterSettingPlist to "com.peavine.CharacterInsert"
   set dialogDefault to item 1 of readPlist(characterSettingPlist, "")
   
   set characterDescriptions to {}
   repeat with aList in characterData
       set end of characterDescriptions to item 1 of aList
   end repeat
   
   set theCharacters to (choose from list characterDescriptions default items dialogDefault with prompt "Select one or more characters to insert" with title "Character Insert" with multiple selections allowed)
   if theCharacters = false then error number -128
   
   set theIDs to {}
   repeat with i from 1 to (count theCharacters)
       repeat with j from 1 to (count characterData)
           if item i of theCharacters = item 1 of item j of characterData then
               set end of theIDs to item 2 of item j of characterData
               exit repeat
           end if
       end repeat
   end repeat
   
   set the clipboard to character id theIDs
   
   tell application "System Events"
       set appName to (name of first process whose frontmost is true)
       tell process appName
           set frontmost to true
           click menu item "Paste" of menu "Edit" of menu bar 1
       end tell
   end tell
   
   writePlist(characterSettingPlist, {theCharacters})
end main

on sortTheList(theList)
   repeat with i from (count theList) to 2 by -1
       repeat with j from 1 to i - 1
           if item 1 of item j of theList > item 1 of item (j + 1) of theList then
               set {item j of theList, item (j + 1) of theList} to {item (j + 1) of theList, item j of theList}
           end if
       end repeat
   end repeat
   return theList
end sortTheList

on readPlist(thePlist, theDefault)
   set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:thePlist
   theDefaults's registerDefaults:{theKey:theDefault}
   return theKey of theDefaults as list
end readPlist

on writePlist(thePlist, theList)
   set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:thePlist
   set theKey of theDefaults to theList
end writePlist

main()

Last edited by peavine (2021-05-04 10:14:00 am)


2018 Mac mini - macOS Catalina

Offline

 

#2 2021-05-04 05:45:45 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6627

Re: Special Character Insert Script

One thing to keep in mind is that some characters can have more than one ID. And you can probably simplify things a bit by using a record rather than list of lists.

So something like:

Applescript:

set characterData to {|dash - em|:{8212}, |dash - en|:{8211}} -- etc
set characterData to current application's NSDictionary's dictionaryWithDictionary:characterData
set characterDescriptions to characterData's allKeys() as list

set theCharacters to (choose from list characterDescriptions with prompt "Select one or more characters to insert" with title "Character Insert" with multiple selections allowed)
if theCharacters = false then error number -128

set theIDs to {}
set theValues to (characterData's objectsForKeys:theCharacters notFoundMarker:{}) as list
repeat with aValue in theValues
   set theIDs to theIDs & aValue
end repeat

I'm not quite sure why you're bothering with defaults, given the list doesn't change.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#3 2021-05-04 06:24:48 pm

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

Re: Special Character Insert Script

Shane Stanley wrote:

I'm not quite sure why you're bothering with defaults, given the list doesn't change.



Thanks Shane, I'll rewrite my script as you suggest. The script will be much cleaner without the clumsy repeat loop and sort handler, and this will be a good learning experience, as I've never used NSDictionary before.

As far as the default setting, its purpose is to remember the character or characters selected in the dialog from one running of the script to the next. Thus, for example, if I insert left and right double quotes once in a document, there is a reasonable probability that I will insert them again in that document. So, just for me, this is a desirable feature, and I don't know what this has to do with the list not changing. sad

Last edited by peavine (2021-05-04 07:05:42 pm)


2018 Mac mini - macOS Catalina

Offline

 

#4 2021-05-04 07:08:58 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6627

Re: Special Character Insert Script

peavine wrote:

I don't know what this has to do with the list not changing.



Nothing -- I scanned the code in too much haste.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#5 2021-05-04 07:41:22 pm

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

Re: Special Character Insert Script

This revised version of my script is based in part on the suggestion made by Shane in post 2 above. This revision eliminates two repeat loops and a slow sort handler, and streamlines the plist handlers.

Applescript:

-- Revised 2021.05.06

use framework "Foundation"
use scripting additions

on main()
   set characterData to {|dash - em|:8212, |dash - en|:8211, |division sign|:247, |double angle - left|:171, |double angle - right|:187, |double quote - left|:8220, |double quote - right|:8221, |ellipsis symbol|:8230, |not equal to|:8800, |plus or minus|:177, |single quote - left|:8216, |single quote - right|:8217, |space - nonbreaking|:160}
   
   set characterData to current application's NSDictionary's dictionaryWithDictionary:characterData
   set characterDescriptions to (characterData's allKeys()'s sortedArrayUsingSelector:"caseInsensitiveCompare:") as list
   
   set plistPath to POSIX path of ((path to preferences as text) & "CharacterInsert.plist")
   
   set dialogDefault to readPlist(plistPath)
   set theCharacters to (choose from list characterDescriptions with prompt "Select one or more characters to insert" default items dialogDefault with title "Character Insert" with multiple selections allowed)
   if theCharacters = false then error number -128
   
   set theIDs to (characterData's objectsForKeys:theCharacters notFoundMarker:{}) as list
   set the clipboard to character id theIDs
   
   tell application "System Events"
       set appName to (name of first process whose frontmost is true)
       tell process appName
           set frontmost to true
           click menu item "Paste" of menu "Edit" of menu bar 1
       end tell
   end tell
   
   writePlist(plistPath, theCharacters)
end main

on readPlist(thePath)
   set theArray to current application's NSArray's arrayWithContentsOfFile:thePath
   return theArray as list
end readPlist

on writePlist(thePath, theList)
   set theArray to current application's NSArray's arrayWithArray:theList
   theArray's writeToFile:thePath atomically:true
end writePlist

main()

Last edited by peavine (2021-05-06 02:54:14 pm)


2018 Mac mini - macOS Catalina

Offline

 

#6 2021-05-04 10:31:14 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6627

Re: Special Character Insert Script

Here's a version without using a dictionary either, using Cocoa to provide the names of the characters. It does no sorting, relying on your entry order.

Applescript:

use AppleScript version "2.5" -- 10.11 or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

set theChars to current application's NSString's stringWithString:"–—“”‘’≠±…" -- edit to suit

set characterSettingPlist to "com.peavine.CharacterInsert"
set dialogDefault to item 1 of readPlist(characterSettingPlist, "")
-- convert string to list of char names
set theNames to theChars's stringByApplyingTransform:(current application's NSStringTransformToUnicodeName) |reverse|:false
set theNames to theNames's substringWithRange:{3, (theNames's |length|()) - 4}
set theNames to theNames's lowercaseString()
set theList to (theNames's componentsSeparatedByString:"}\\n{") as list

set theCharacters to (choose from list theList with prompt "Select one or more characters to insert" with title "Character Insert" default items dialogDefault with multiple selections allowed)
if theCharacters = false then error number -128

writePlist(characterSettingPlist, {theCharacters})
-- convert names back to string
set theNames to (current application's NSArray's arrayWithArray:theCharacters)'s componentsJoinedByString:"}\\N{"
set theNames to current application's NSString's stringWithFormat_("\\N{%@}", theNames)
set theNames to theNames's uppercaseString()
set theString to theNames's stringByApplyingTransform:(current application's NSStringTransformToUnicodeName) |reverse|:true
-- put on clipboard
set thePasteboard to current application's NSPasteboard's generalPasteboard()
thePasteboard's clearContents()
thePasteboard's writeObjects:{theString}

on readPlist(thePlist, theDefault)
   set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:thePlist
   theDefaults's registerDefaults:{theKey:theDefault}
   return theKey of theDefaults as list
end readPlist

on writePlist(thePlist, theList)
   set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:thePlist
   set theKey of theDefaults to theList
end writePlist

Last edited by Shane Stanley (2021-05-05 01:27:42 am)


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#7 2021-05-04 11:30:01 pm

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

Re: Special Character Insert Script

Works great Shane. smile

A few comments:

* The words, use AppleScript, needs to be added to the beginning of the script.

* The list of character names in the dialog contains a "}" after the last entry. This is eliminated by removing the space at the end of theChars string.

* The script places the character on the clipboard but does not insert it in the active document. If a user desires that, they can simply simply copy over the section from my script beginning with: tell application "System Events". I assume there's not a better way to do this.

* Adding new characters to theChars string is drop-dead simple--simply place the cursor in the string where the character should be inserted; open Character Viewer; and double click on the desired character. There are a few characters that cannot be added in this manner--such as a nonbreaking space--but a copy and paste will do that.

Last edited by peavine (2021-05-04 11:55:05 pm)


2018 Mac mini - macOS Catalina

Offline

 

#8 2021-05-05 01:26:57 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6627

Re: Special Character Insert Script

peavine wrote:

* The list of character names in the dialog contains a "}" after the last entry. This is eliminated by removing the space at the end of theChars string.



That "space" was actually a no-break space, but it looks like the forum software converted it to a standard space. I'll edit it out.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)