Tracking HipChat Activity with AppleScript

The Problem

Chat tools are great for being able to work remotely, at least until you get bombarded by one chat after another. I've often wondered if I could come up with a way to track who my chats are with and how much time was spent chatting with each person. My initial attempts involved trying to connect the HipChat API, but I would get rate-limited before I even got through the full set of contacts, much less the rooms themselves. And as far as I could tell, I had to cycle through all public and/or subscribed rooms and not just the rooms that I subscribed to.

(You might be familiar with RescueTime doing similar for webpages, but it doesn't appear to do that for HipChat or Microsoft Teams as far as I've been able to tell.)

A Simpler Algorithm

What if I could just log periodically when I'm chatting with a specific person or on a specific topic? I started playing with the Accessibility Inspector to try and figure out if I could get a specific path to the name display so that I could track who I was chatting with/what room I was in.

Name in HipChat
Name display in HipChat

I could an incredibly long tree down to the name display, so I went directly into Script Editor with some AppleScript to dump the UI elements of HipChat (commented out below), but found that the display was too generic... so I switched to grabbing the entire contents:

For HipChat, the above produces a long list of element hierarchies, but static text is mentioned in the hierarchy (I used somebody else's name because your own name appears in more windows in the view, but there may be multiple hierarchies that display the name you're looking for):

static text "Thomas Powell" of group 1 of group 13 of group 4 of UI element 1 of scroll area 1 of group 1 of group 1 of group 1 of group 1 of window "HipChat" of application process "HipChat" of application "System Events",

So I would remove the last bit of the hierarchies, and ask for the "name of" or "value of" the remainder of the hierarchy.

name of UI element of group 2 of group 1 of group 3 of UI element 1 of scroll area 1 of group 1 of group 1 of group 1 of group 1 of window "HipChat" of application process "HipChat" of application "System Events"

Ultimately, "name of" was the key to getting the display value I was looking for, but the chat rooms had a slightly different hierarchy, and both required trial and error to find the correct hierarchy. Ultimately, the value I was looking for was in a list within the "name of" the UI element at the bottom of the hierarchy, so I continued the inspection in Script Editor until I got to the correct value.

Solution:

(Disclaimer: I am barely able to write AppleScript that parses, much less AppleScript that looks good.)

I ended up creating an application the allows me to select a log file for output. Then I created a giant loop that checks if HipChat (or Microsoft Teams or RubyMine) or the front applications and then logs a usage with name or project in a log file + timestamp separated by a semicolon. (I used Ruby to generate the statistics based on this... sorry.)

I don't wait for any period if none of the applications I'm looking for are currently in front. If one of them is, I delay 15 seconds.

Observations:

HipChat had *by far* the hardest hierarchy to find the name / chat room info in. For RubyMine, the file path and file name are in the window title and the git project are in one of the static texts near the top level. Microsoft Teams was similarly friendly in that the title of the window reflected the context it was being used in.

Future plans:

Hammerspoon looks a little more promising for doing anything more complex and/or DRYing this up, but there's something to be said for being able to quickly hack your way to the data you want vs. actually having to plan things out.

Applescript to periodically raise unsent Outlook replies to the foreground

I've had a particular problem starting replies in Outlook for Mac and then losing track of them or forgetting about them.

This script is a fairly naive attempt at having such replies raised to the foreground. It doesn't distinguish between a reply you're reading and one you're writing. It also won't notice email that you're composing that *doesn't* have a 'Re:' as the start of the title. I imagine there's a window property that I can look for to select those, I just didn't want to go there yet.

The script also unintelligently repeats every 60 seconds, which I figure is better than leaving an email unsent for 2 hours.

I'm publishing updates to my "applefritters" project on GitHub if you want to keep up with further improvements to this script.

repeat
	tell application "System Events"
		tell process "Microsoft Outlook"
			repeat with aWindow in (get every window)
				set aName to get the name of aWindow
				set initialName to ((characters 1 through 3 of aName) as string)
				if (initialName = "Re:") then
					tell application "Microsoft Outlook"
						activate
					end tell
					activate aWindow
					set frontmost to true
					perform action "AXRaise" of aWindow
					exit repeat -- only activate one window
				end if
			end repeat
		end tell
	end tell
	delay 60
end repeat

Applescripts to Mute or Unmute Lync

In preparation for hooking up Lync muting and unmuting to separate hotkeys, I wanted to make sure that my scripts no longer toggled the mute button, but only muted or unmuted.

For that to work, I needed to retrieve the current state of the checkbox.

set theCheckbox to checkbox 5 of splitter group 1 of aWindow
tell theCheckbox
  set checkboxStatus to value of theCheckbox as boolean
  if checkboxStatus is true then click theCheckbox
end tell

In this case, I store off the checkbox into a variable theCheckbox and then later the checkbox status into a variable, allowing me to unset the checkbox if it is true.

This results in the following script for unmuting:

tell application "Microsoft Lync"
	activate
end tell
tell application "System Events"
	tell process "Microsoft Lync"
		repeat with aWindow in (get every window)
			set aName to get the name of aWindow
			set initialName to ((characters 1 through 12 of aName) as string)
			if (initialName = "Conversation") then
				activate aWindow
				set theCheckbox to checkbox 5 of splitter group 1 of aWindow
				tell theCheckbox
					set checkboxStatus to value of theCheckbox as boolean
					if checkboxStatus is true then click theCheckbox
				end tell
			end if
		end repeat
	end tell
end tell

And for muting:

tell application "Microsoft Lync"
	activate
end tell
tell application "System Events"
	tell process "Microsoft Lync"
		repeat with aWindow in (get every window)
			set aName to get the name of aWindow
			set initialName to ((characters 1 through 12 of aName) as string)
			if (initialName = "Conversation") then
				activate aWindow
				set theCheckbox to checkbox 5 of splitter group 1 of aWindow
				tell theCheckbox
					set checkboxStatus to value of theCheckbox as boolean
					if checkboxStatus is false then click theCheckbox
				end tell
			end if
		end repeat
	end tell
end tell

These scripts (and hopefully, others soon) are available on GitHub

Toggling the mute button in Microsoft Lync for Mac via Applescript

Through liberal use of the dictionary for Microsoft Lync, the Accessibility Inspector, and a few web links, I've come up with this script which toggles the mute button in Lync for Mac.

tell application "Microsoft Lync"
  activate
end tell
tell application "System Events"
  tell process "Microsoft Lync"
    repeat with aWindow in (get every window)
      set aName to get the name of aWindow
      set initialName to ((characters 1 through 12 of aName) as string)
      if (initialName = "Conversation") then
        activate aWindow
        click checkbox 5 of splitter group 1 of aWindow
      end if
    end repeat
  end tell
end tell

I still want to hook it up to a hotkey, and ideally, have a different hotkey for mute and unmute, but that will have to be left for another session. I will hopefully update this post with more details as I figure out how to explain them.