Way to close the special character viewer/pop-up?

It kills me to have to move the mouse to close this thing:

Is there any way to close it cleanly/reliably?

Thanks!

Try this:

[test] Close Characters Palette.kmmacros (2.1 KB)

2 Likes

Thanks, Tom. Any way to turn this into a toggle show/hide?

@Tom will probably have a better way, but this seems to work:

2017-09-04 19:26 CT

I have enhanced my original Macro, and published in the Macro Library.
See:

###MACRO: @UI Toggle Show/Hide Emoji & Symbols (CharacterPalette) Window

Thanks for the great ideas and code, all! :smiley:

@ajg23 and @Tom:

MACRO: @UI Toggle Show/Hide Emoji & Symbols (CharacterPalette) Window

Hey JM, since you were asking for "a better way", here is my take :wink: I do not think it is better than the macro you posted in the meantime, it's just a slim all-in-one AppleScript solution:

tell application "System Events"
    tell process "CharacterPalette"
        tell window "Characters"
            try
                click button 2 -- Faster in this case
                --click (first button whose description is "close button")
            on error
                my launchCharacters()
            end try
        end tell
    end tell
end tell

on launchCharacters()
    tell application "System Events"
        tell (first process whose frontmost is true)
            tell menu "Edit" of menu bar 1
                click menu item "Emoji & Symbols"
            end tell
        end tell
    end tell
end launchCharacters

Toggle Characters Palette.kmmacros (2.4 KB)

It makes use of the de facto already present check for an existing window (the try block, line 4).

Obviously it doesn't include any of the advanced "Show Window, Position, & Select Group" things from your macro.

1 Like

Thanks, Tom. I do like your solution better. :+1:
I think I will incorporate it into my macro.


EDIT: 2017-09-05  6:03 PM CT

@Tom, I tested your script and it works great, and is very fast.
However, from a pure logic perspective, I moved your `try` statement up to the top.

```applescript
tell application "System Events"
  try -- below process and/or window may not exist    #@JMichaelTX
    
    tell process "CharacterPalette"
      tell window "Characters"
        click button 2 -- Faster in this case
        --click (first button whose description is "close button")
      end tell
    end tell
    
  on error
    my launchCharacters()
  end try
end tell

on launchCharacters()
  tell application "System Events"
    tell (first process whose frontmost is true)
      tell menu "Edit" of menu bar 1
        click menu item "Emoji & Symbols"
      end tell
    end tell
  end tell
end launchCharacters

```

I understand what you mean. But, I think, in this case the logic may not be as it appears at first glance:

Try this:

  1. Copy each variant of the script to a Script Debugger window.
  2. Set both scripts to Debug mode.
  3. Make sure no Character palette is open.
  4. Now step (⌘Y) through my script variant, the one with the "smaller" try block.
  5. Close the Character palette again and now step (⌘Y) through the script variant with the "extended" try block (the variant you have posted).

Logic suggests that the script with the small try block should throw an error at the click button line while the script with the extended try block should throw the error already at the tell process "CharacterPalette" line, since there is no such process running.

But, if you have stepped through both scripts, you will notice that both are throwing the error at the click button line, no matter where the try block actually starts.

My explanation for this:

The description of the target object consists of the two containers (tell process "CharacterPalette" and tell window "Characters") and the object itself (button 2).

So, it seems that AppleScript does nothing until the object description is completed, that is, until the actual call of the final object (click button 2) takes place.

This would explain that the error is – in both cases – caught at the click button line even if none of the containers (process "CharacterPalette" and window "Characters") actually exists.

So it doesn't seem to matter if we include the containers in the try block, and my rule of thumb is to include as little code as possible in a try block. [1]

That being said, I don't see any real-world difference in execution time, or any other drawbacks of including the containers in the try block. [2]

Sorry for the longish write-up, but I find this interesting, and until now I wasn't fully aware of the exact error "location" in case of missing object containers. So, thanks for posting that variant!


[1]: Well this is my rule of thumb. I'm not saying that it is correct :wink:

[2]: When running the scripts in Script Debugger I noticed something interesting: If SD's "Result" window is open and set to "Best", then the script with the extended try block makes SD display the whole list of found elements, while the script with the minimal try block doesn't generate any elements listing at all. But I think this is a SD thing and without importance outside of SD.

Tom, great discussion. I enjoyed it, and it provoked my thinking. Thanks.

To follow-up on your points, I wrote this test script:


set locStr to "TBD"
set testStr to "none" -- "Process" OR "Window"

set AppleScript's text item delimiters to ","

tell application "System Events"
  try -- below process and/or window may not exist    #@JMichaelTX
    set locStr to "Before Process"
    tell process "CharacterPalette"
      set locStr to "AFTER Process, Before Window"
      
      if (testStr = "Process") then
        log ("visible: " & visible as text)
        log ("background only: " & background only as text)
        log ("frontmost: " & frontmost as text)
      end if
      
      tell window "Characters"
        set locStr to "AFTER Window"
        if (testStr = "Window") then
          log ("position: " & position as text)
        end if
      end tell
    end tell
    
    set locStr to "NO ERRORS: " & locStr
  on error
    set locStr to "ERROR at " & locStr
    
    display dialog locStr giving up after 2
    
  end try
end tell

return locStr

## NO ERRORS if testStr = "none" ##
-->AFTER Window

My conclusions:

  1. telling a process or window that does not exist will NOT produce an error unless you have a command directed to that entity.
  2. You can use other commands, like set a variable to text
  3. I still think my logic is better to put the try BEFORE the tell process command.
  • I believe it is technically correct.
  • It is where it needs to be if I ever wanted to add commands to the process.

It was interesting to play with.
BTW, the reason for all the log commands is because I wanted to run this in Script Editor, to eliminate any possible issue with SD triggering Apple Events in its Results panel.

@Tom, you may be interested in this topic I just posted in the SD Forum:
What is Best Method: try/catch OR Test for Existence?

Heck, I completely forgot about the SD forum. Haven’t opened it for weeks or even months…

The question you posted there (try vs if…then) is also interesting.

I think Jonas’ idea, to replace "Emoji & Symbols" with menu item -1 is a good one. I think it is indeed always the last menu item of the Edit menu.

OK, that's good to know. I think I'll use that as the default, maybe with a try/on error that uses the menu item name.