Here’s a better script, based in large part on the script by @koenigyvan (Yvan):
property ptyScriptName : "Toggle Show/Hide of Emoji Window"
property ptyScriptVer : "3.1"
property ptyScriptDate : "2017-11-07"
property ptyScriptAuthor : "JMichaelTX" -- based on script by Yvan Koenig
# While this script is based largely on scripts by others, all errors are mine.
(*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PURPOSE:
• Quickly Show/Hide the Emoji & Symbols Window
that should work in any macOS language
REQUIRED:
1. macOS 10.11.6+ (may work on earlier versions, but I have not tested any other versions)
2. Mac Applications
• System Preferences > Keyboard must be set to:
"Show Keyboard, Emoji, & Symbol Viewers in menu bar"
REF: This script is based largely on:
1. Yvan KOENIG, 2017-11-07, Show Emoji & Symbols GUI access -- ASUL
http://lists.apple.com/archives/applescript-users/2017/Nov/msg00079.html
2. Aviral Bansal, 2016-04-02, Speed up AppleScript UI scripting? - Stack Overflow
https://stackoverflow.com//a/36370637/915019
3. Thomas Floeren, 2017-11-07, Suggestion on ASUL to Use “killall System Events”
http://lists.apple.com/archives/applescript-users/2017/Nov/msg00083.html
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*)
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation" -- don't really need this
use scripting additions
property LF : linefeed
property isKMErunning : false -- is Keyboard Maestro Engine running?
property groupName : "Favorites" -- Emoji Folder to be selected
tell application "System Events" to set isKMErunning to (exists process "Keyboard Maestro Engine")
--- Get the localized version of "Emoji" ---
set theSource to (path to library folder from system domain as text) & "Frameworks:Carbon.framework:Versions:A:Frameworks:HIToolbox.framework:"
set EmojiAndSymbols_loc to localized string "Emoji & Symbols" from table "Menus" in bundle (theSource as «class furl»)
--- TODO: Get Localized Version of "Favorites" ---
set favFolderName to "Favorites" -- folder on Emoji Window (not used in this version)
#?# set favFolderName to localized string favFolderName from ??? -- anyone know?
##TODO: Add code to select Favorites folder ##
-----------------------------------------------
--- PART 1. Show the Emoji Viewer Menu Items
-----------------------------------------------
tell application "System Events" to tell process "SystemUIServer"
set emojiViewerMenu to first item of ¬
(menu bar items of menu bar 1 ¬
whose value of attribute "AXDescription" = "text input")
tell emojiViewerMenu
--- Must Use "ignoring" and then "killall" to avoid ~5 sec Delay ---
ignoring application responses
perform action "AXPress" # Reveal the menu items
end ignoring
end tell -- emojiViewerMenu
end tell -- System Events -> "SystemUIServer"
-----------------------------------------------------------------
--- Finish the Process to Avoid Delay from Menu Press ---
-----------------------------------------------------------------
do shell script "killall System\\ Events"
delay 0.1
--------------------------------------------------------------------
--- PART 2. Click on the Emoji Item to Show/Hide the Emoji Window
--------------------------------------------------------------------
(*
NOW, Click on the Emoji Menu Item ---
• This will toggle the display of the emoji window
• The menu item always contains "Emoji"
• But starts with "Show" when the window is not visible
• Starts with "Hide" when the window is visible
*)
tell application "System Events" to tell process "SystemUIServer" to tell emojiViewerMenu
tell menu 1
try
set toggleEmojiMenuItem to first menu item whose name contains EmojiAndSymbols_loc
set emojiStatus to first word of (get name of toggleEmojiMenuItem)
click toggleEmojiMenuItem
set scriptResults to "OK" & LF & "Emoji & Symbols Window Status: " & emojiStatus
on error
key code 53 # Escape to hide the menu
set errMsg to "The Emoji Viewer has NOT been enabled in System Preferences > Keyboard."
set msgTitleStr to ptyScriptName
display notification errMsg with title ptyScriptName sound name "Basso.aiff"
set emojiStatus to "None"
set scriptResults to "ERROR" & LF & errMsg
end try
end tell # menu 1
end tell
---------------------------------------------------------------
--- PART 3. Move Emoji Window & Select Favorites ---
---------------------------------------------------------------
if (emojiStatus = "Show") then
my moveEmojWin()
my selectFavEmoji()
end if
return scriptResults
--------------------------------------------------------------------------
--~~~~~~~~~~~~~~~~~~~~~~~~~~~ END OF MAIN SCRIPT ~~~~~~~~~~~~~~~~~~~~~~~~
--------------------------------------------------------------------------
on moveEmojWin()
--- MOVE WINDOW ---
--- Get Mouse Pos if KM is running, else Get Center of Frontmost Window ---
set {mouseX, mouseY} to my getMousePos()
--- Pause Until Window is Open ---
set {elapTime, successBool} to my pauseUntilWin("Characters", "CharacterPalette", 2)
tell application "System Events"
tell process "CharacterPalette"
--- MOVE WINDOW BELOW MOUSE ---
tell window 1 to set position to {mouseX + 10, mouseY + 20}
end tell
end tell
end moveEmojWin
on selectFavEmoji()
tell application "System Events"
tell process "CharacterPalette"
--- GET GROUP LIST ---
set groupList to name of first UI element of rows of table 1 of scroll area 1 of splitter group 1 of splitter group 1 of window 1 -- "Characters"
set groupIndex to my getIndex(groupName, groupList)
if (groupIndex ≠ 0) then
--- SELECT USER REQUESTED GROUP ---
select row groupIndex of table 1 of scroll area 1 of splitter group 1 of splitter group 1 of window 1 -- "Characters"
else
--- GROUP NAME NOT FOUND ---
set msgStr to "Emoji/Character Group NOT Found: " & groupName
set msgTitleStr to ptyScriptName
display notification msgStr with title msgTitleStr sound name "Basso.aiff"
end if
end tell -- process "CharacterPalette"
end tell -- "System Events"
end selectFavEmoji
on pauseUntilWin(pWinTitle, pProcessName, pMaxTimeSec)
(*
Usage Note: It is best to test for existance of the literal process BEFORE
calling this handler. For example:
if (exists process "CharacterPalette") then
*)
local startTime, elapTime, errMsg
set LF to linefeed
set successBool to true
set startTime to current application's NSDate's |date|()
tell application "System Events"
repeat until window pWinTitle of process pProcessName exists
set elapTime to -(startTime's timeIntervalSinceNow())
if (elapTime > pMaxTimeSec) then
set successBool to false
set errMsg to "Max Time of " & pMaxTimeSec & " sec exceeded waiting for:" & LF & ¬
"Window: " & pWinTitle & LF & "Process: " & pProcessName
--log errMsg
display notification errMsg
exit repeat
end if
delay 0.1
end repeat
end tell
set elapTime to (-(round ((startTime's timeIntervalSinceNow()) * 100)) / 100.0)
return {elapTime, successBool}
end pauseUntilWin
on getMousePos()
local mousePosStr, mouseX, mouseY
if isKMErunning then
tell application "Keyboard Maestro Engine" to set mousePosStr to process tokens "%CurrentMouse%"
set {mouseX, mouseY} to my splitStrToList(mousePosStr, ",")
else
--- NEED ALTERNATE METHOD TO GET MOUSE POS ---
-- For Now, Use Center of Frontmost Window --
set {mouseX, mouseY} to my getWinCenter()
end if
return {mouseX, mouseY}
end getMousePos
on getWinCenter()
local posWin, sizeWin, centerWin, nameProcess
tell application "System Events"
set frontProcess to first process whose frontmost is true
set nameProcess to name of frontProcess
tell frontProcess
set oWin to front window
set posWin to position of oWin
set sizeWin to size of oWin
end tell
end tell
set centerWin to {(item 1 of posWin) + ((item 1 of sizeWin) / 2), (item 2 of posWin) + ((item 2 of sizeWin) / 2)}
return centerWin
end getWinCenter
on splitStrToList(pString, pDelim)
set textDelimSave to AppleScript's text item delimiters
set AppleScript's text item delimiters to pDelim
set newList to text items of pString
set AppleScript's text item delimiters to textDelimSave
return newList
end splitStrToList
on joinListToStr(pList, pDelim)
set textDelimSave to AppleScript's text item delimiters
set AppleScript's text item delimiters to pDelim
set newString to pList as string
set AppleScript's text item delimiters to textDelimSave
return newString
end joinListToStr
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on getIndex(pItem, pList) -- @List @Index
(* VER: 2.0 2017-08-02
---------------------------------------------------------------------------------
PURPOSE: Get the Index (Item #) of a Item within a List
PARAMETERS:
• pItem ║ any ║ Item to Find. Can be text, numeric, date, or list
• pList ║ text ║ List to be searched.
RETURNS: integer ║ Index number (0 if NOT found)
AUTHOR: JMichaelTX
—————————————————————————————————————————————————————————————————————————————————
*)
local idx, i
set idx to 0
set lenList to length of pList
set pItem to contents of pItem
repeat with i from 1 to lenList
if (pItem = (contents of item i of pList)) then
set idx to i
exit repeat
end if
end repeat
return idx
end getIndex
--~~~~~~~~~~~~~~~ END OF handler getIndex ~~~~~~~~~~~~~~~~~~~~~~~~~