6

Goal

I want to have a AppleScript that let's me get the ID or something similar of the selected Messages.app conversation/chat, and then later have a AppleScript which can open the correct Messages conversation/chat corresponding to this ID.

  • Get ID/reference to currently selected Messages.app chat
  • Open a particular Messages.app chat based on a ID/reference

What I have tried so far

With Mail.app I can do the following:

tell application "Mail" set selectedMessages to selection set theMessage to item 1 of selectedMessages set messageid to message id of theMessage -- Make URL (must use URL-encoded values for "<" and ">") set urlText to "message://" & "%3c" & messageid & "%3e" return urlText end tell

But with Messages.app, there is to selection object.


Tried to get the content of the clipboard to see if there is any ID's or something of value which can be used, but it looks like the clipboard access is not as powerful as it is through cocoa programming (where you can get a lot of meta data and alternative clipboard content).


Double click on a conversation so that it opens with it's own window. Tried to get the ID of this window, and then open it later. Didn't work.

Cœur
  • 37,241
  • 25
  • 195
  • 267
eivindml
  • 2,197
  • 7
  • 36
  • 68
  • Could you expound a bit more on what you want? Are you talking about two separate scripts, because as written it reads like it. Also, what do you mean by "and then later have a AppleScript which can open the correct Messages conversation/chat" in what context is "open" referring to? I'm asking because, 1. IMO what you're asking for is not totally clear. 2. I do know of a way to store an identifier of what's selected in the list in the main Messages windows and get back to that, but without clarification I don't want to waste time writing something of nothing. – user3439894 Sep 06 '17 at 22:49
  • It should be one script. The bullet points are the steps required. I want to extract some sort of id from the selected message, which then will let me run a script with this ID, that opens the same message thread again. – eivindml Sep 07 '17 at 09:19
  • Messsage.app opens showing one window, where on the left side you can select from all your conversations. Any given selection on the left side of this window shows the name of the buddy, the date or time of the last message and the message or part thereof. So just to be clear, are you wanting to select one of these conversations on the left side of this window and store info about that selection and then the next time you run the script, that previously targeted selection will have focus regardless of what presently has focus prior to running the script again? If not then what is it you want!? – user3439894 Sep 07 '17 at 15:08
  • Also, how do you intend to run the script, by the Script menu, 3rd-party tool, as an app or how/what? Also, I wanted to start the comment prior to tho one with, "By default Messages opens showing one window..." but didn't have room. I know it can open with more then on window showing but only one main Messages window and it that window I'm referring to in my previous comment, not a window of an individual conversation. – user3439894 Sep 07 '17 at 15:12
  • It's going in to be executed from a Cocoa app, but that's not the point. As long as this can be executed from Scrip Editor for instance, I can figure out the rest. To clearify what I want: 1. I with my mouse open Messages.app and select/open a conversation I want a reference to. 2. I execute a Apple Script from Scrip Editor which grabs something that can work as a unique reference back to this conversation. – eivindml Sep 07 '17 at 15:14
  • It's the first part that's difficult. The next step would be to have a script which can use this unique reference to open the spesific conversation message in Messages.app. This script can be with a hardcoded "ID". Then I have everything I need, and I can piece it together. – eivindml Sep 07 '17 at 15:21
  • All I have is a working UI scripting solution however, since you're going to run this from a Cocoa app it's probably a waste time posting. – user3439894 Sep 07 '17 at 15:58
  • @user3439894 I would love to see it anyways. :) – eivindml Sep 08 '17 at 08:26

1 Answers1

1

To use this AppleScript script, as a script (.scpt) or an application (.app), you need to first select the target conversation in the list of conversations in Messages.app that you want it to always return to thereafter, and initially run this twice. This then sets property theSelectedRow : 0 to property theSelectedRow : i where the value of i will be the row number of the conversation in the list of conversations that was selected when initially run twice. The script also sets property thisName : "" to a value that is the name contained within the description of UI element 1 of row i. Between the value of these two properties, the script will always set focus back to the selected target conversation in subsequent runs, providing it still exists, even as its row number changes. If the selected target conversation no longer exists, the user is notified.

Read the comments throughout the script so as to have an understanding of what the code is doing.

AppleScript code:

--  # These two properties are used to hold information about the target 
--  # conversation in order to always set focus to it when the script runs
--  # after the initial runs. Initially, the script must be run twice to have 
--  # the selected target conversation be returned to on subsequent runs.
--  # 
--  # Note: This is also true anytime the script is modified or compiled, in
--  # Script Editor, as that resets the value of a property to its original value.

property thisRowNumber : 0
property thisName : ""


--  # See if the shift modifier key was pressed. This allows 
--  # setting the focus to a different target conversation.
--  # Note: Unlike when the script is modified or compiled from within
--  # Script Editor, when invoking this, the change is immediate when
--  # done after the initial runs to have the values of the properties set.

if my shiftKeyWasDown() then set thisRowNumber to 0


--  ### Main ###

tell application "Messages"
    if running then
        my selectTargetConversation()
        if minimized of window "Messages" is true then
            set minimized of window "Messages" to false
        end if
    else
        activate
        delay 2 -- # Allow time for Messages.app to open, adjust as/if necessary.
        my selectTargetConversation()
    end if
    activate
end tell


--  ### Handlers ###


--  # Detects if the shift modifier key was pressed.

on shiftKeyWasDown()
    if (do shell script "/usr/bin/python -c 'import Cocoa; print Cocoa.NSEvent.modifierFlags() & Cocoa.NSShiftKeyMask '") > 1 then
        return true
    else
        return false
    end if
end shiftKeyWasDown


--  # The 'getNameFromDescription' handler extracts the name portion of the 'description'
--  # within the 'UI element' of the 'row' of the target conversation. Example 'description':
--  # "Conversation with: Johnny Appleseed. Last activity: 6:10 PM. Last message: Look at all these trees!. "
--  # This is called from within a 'repeat' loop within the 'selectTargetConversation' handler:
--  # 'set thisName to my getNameFromDescription(description of UI element 1 of row i)'
--  # The 'thisName' property, in this example, would get set to: "Johnny Appleseed"

on getNameFromDescription(theText)
    set TID to AppleScript's text item delimiters
    set AppleScript's text item delimiters to {": "}
    set theText to text item 2 of theText
    set AppleScript's text item delimiters to {". "}
    set theText to text item 1 of theText
    set AppleScript's text item delimiters to TID
    return theText
end getNameFromDescription


--  # This handler provides all the logic necessary to ensure the 'Messages' window
--  # is available to set/reset focus back to the target conversation with each run,
--  # providing the target conversation still exists and sets focus to the target if it does.

on selectTargetConversation()

    tell application "System Events"

        --  # Make sure the 'Messages' window is available.
        --  # 
        --  # This branch of the 'if' block handles when Messages.app
        --  # is open, but without any windows showing.

        if (count of windows of application process "Messages") is equal to 0 then

            click UI element "Messages" of list 1 of application process "Dock"
            delay 0.25

        else
            --  # A least one window is open, make sure it's the 'Messages' window.

            --  # Set a flag to test against.

            set theMessagesWindowIsNotOpen to true

            set theWindowList to every window of application process "Messages"
            repeat with thisWindow in theWindowList
                if name of thisWindow is equal to "Messages" then
                    set theMessagesWindowIsNotOpen to false
                    exit repeat
                end if
            end repeat

            --  # If the value of 'theMessagesWindowIsNotOpen' is still 'true', 
            --  # then the 'Messages' window was not open, so open it.

            if theMessagesWindowIsNotOpen then
                tell application "Messages" to activate
                delay 0.25
                keystroke "0" using {command down}
            end if

        end if

        --  # When 'thisRowNumber is equal to 0' it's either the first time the script has run or it has been reset.
        --  # Get the 'row' number of the selected target conversation and set its value to 'thisRowNumber'.
        --  # Get the name within the 'description' of the 'UI element' of the selected 'row' and set it to 'thisName'.
        --  # Between the value of these two properties, the script will always set focus back to the selected target
        --  # conversation, providing it still exists. If the selected target conversation no longer exists, notify user.

        tell table 1 of scroll area 1 of splitter group 1 of window "Messages" of application process "Messages"

            if thisRowNumber is equal to 0 then

                repeat with i from 1 to (count rows)
                    if selected of row i is equal to true then
                        set thisRowNumber to i
                        set thisName to my getNameFromDescription(description of UI element 1 of row i)
                        exit repeat
                    end if
                end repeat

            else
                --  # Make sure the 'row' number, 'thisRowNumber', and the name within 'description of UI element' 
                --  # matches the value of the 'thisName' property, and if so, then set focus to it.

                if description of UI element 1 of row thisRowNumber contains thisName then

                    set selected of row thisRowNumber to true

                else
                    --  # The values no longer match. Ascertain the new 'row' number for 'thisRowNumber' that 
                    --  # contains the value of 'thisName', while verifying the target conversation still exists, and 
                    --  # reset focus back to the original selected target conversation, if it still exists.

                    --  # Set a flag to test against.

                    set theConversationNoLongerExists to true

                    repeat with i from 1 to (count rows)
                        if description of UI element 1 of row i contains thisName then
                            set thisRowNumber to i
                            set selected of row i to true
                            set theConversationNoLongerExists to false
                            exit repeat
                        end if
                    end repeat

                    --  # If the value of 'theConversationNoLongerExists' is still 'true',
                    --  #  then the conversation no longer exists, notify the user.

                    if theConversationNoLongerExists then
                        tell current application
                            display dialog "The target conversation has been deleted since the target was last set. Reset to a new target by selecting a conversation and then press the shift key down when running this script." buttons {"OK"} default button 1 with title "Target Conversation Reset Needed"
                        end tell
                    end if

                end if
            end if
        end tell
    end tell

end selectTargetConversation

Note: This was written and tested under OS X 10.8.5, however, I believe it will work as is under later versions of OS X/macOS and Messages.app, even with the current macOS 10.13 beta.

Additionally, the script employs minimal error handling and is absent of any try statements and on error handlers. Although aside from the value from the delay commands, that can be adjusted as/if needed, it should run fine without additional error handling. As always, the user can add/remove and or adjust the code as/if needed or wanted.

user3439894
  • 7,266
  • 3
  • 17
  • 28
  • @cavalcade, This was written and worked as tested under OS X 10.8.5 and was only posted because the OP asked to see it (see the comments under the OP). I am not in a position to test under macOS 10.14.5 at the present time. Sorry I cannot help other then to say you'll need to troubleshoot it as your would any other code written for a different version then the one you're using. – user3439894 May 28 '19 at 17:36
  • All good my man. Thanks for posting. Would be nice if Apple exposed Messages named groups functionality via scripting. Unfortunately they do not AFAICT – cavalcade May 28 '19 at 23:54
  • @cavalcade, Thanks for Sloth in [See what process is using a file in Mac OS X](https://stackoverflow.com/questions/8317177/see-what-process-is-using-a-file-in-mac-os-x/20438848#20438848) +1. – user3439894 May 29 '19 at 00:14