November 23, 2020

Teams Shortcuts: Smart Reply

In this post I highlight a feature implemented in the Teams Shortcuts PowerTool.
This is about how to reply to a chat thread in Microsoft Teams quoting the selected previous thread in a nice quote block with mention to the quoted thread author and a link to the quoted conversation - all this within the stroke of a hotkey. I call this feature "smart reply".

Teaser animated image:
Microsoft Teams Smart Reply with mention and link to conversation


Status quo

There is a feature only in the Teams mobile app, where if you swipe a conversation it will reply to it with quoting of the swiped thread.
This feature isn't implemented in the Client Desktop application yet. 
This is a much voted uservoice: Reply to specific message in chat on desktop app



Also the mobile feature does not mention the previous author nor provides a link to jump back to the original conversation. Moreover, you can not select a part to be quoted: only the whole thread is inserted in the blockquote.

If you want to reply with quote manually, this is the way to go:
  • Select the part of the thread to quote
  • Ctrl+C to copy to the clipboard
  • Click on the reply area (or press the hotkey Alt+Shift+R
  • Type > to open the blockquote (alternatively, use the quote button in the compose toolbar)
  •  paste (Ctrl+V) the text to quote. 
  • Shift+Enter (twice) to exit the blockquote.
You can see in this video the current situation including manual way of doing on desktop version.

Screencast - Teams Shortcuts Smart Reply

Usage

  • In a conversation thread, select the text you want to quote.
  • Hit the hotkey Alt+R (alternatively, open the Teams Shortcuts menu with Win+T and select "Smart Reply")
Hint: you can use Shift+Up to select a full thread.

(It is pretty smart:) In case you are quoting a thread you are the author of, it won't mention yourself but put as header before the blockquote: "I wrote:"

For the tool to work even without Active Directory connection, your Email, Display Name are stored in the registry.
If you want to refresh this registry entry, you can do so via the System Tray Icon context menu->Settings->Update Personal information.

The feature/hotkey also works in a non channel-based chat i.e. 1-1 or group chat. In this case it will redirect to the new conversation box. So you only need to remember the hotkey Alt+R instead of native Alt+Shift+R or Alt+Shift+C hotkeys. (unified hotkey)

In case you don't have selected anything, it will just create a new conversation without quote.

N.B: You can configure in the Settings if you want the mentions to be personalized by the first name.

Also if the Mention is not auto-validated properly you might need to tune in the PowerTools.ini file the parameter TeamsMentionDelay = 1300 (ms) by default.

Implementation Notes

The core function is implemented in ahk/Lib/Teams.ahk->Teams_SmartReply function
Code extract follows below:

; -------------------------------------------------------------------------------------------------------------------
Teams_SmartReply(doReply:=True){
If GetKeyState("Ctrl") {
    Run, "https://tdalon.blogspot.com/2020/11/teams-shortcuts-smart-reply.html"
    return
}

savedClipboard := ClipboardAll
sSelectionHtml := GetSelection("Html",False)

If (sSelectionHtml="") { ; no selection -> default reply
    Send !+r ; Alt+Shift+r
    Clipboard := savedClipboard
    return
}

If InStr(sSelectionHtml,"data-tid=""messageBodyContent""") { ; Full thread selection e.g. Shift+Up
    ; Remove Edited block

    sSelectionHtml := StrReplace(sSelectionHtml,"<div>Edited</div>","")

    ; Get Quoted Html
    ;sPat = Us)<dd><div>.*<div data-tid="messageBodyContainer">(.*)</div></div></dd>
    sPat = sU)<div data-tid="messageBodyContent"><div>\n?<div>\n?<div>(.*)</div>\n?</div>\n?</div> ; with line breaks
    If RegExMatch(sSelectionHtml,sPat,sMatch)
        sQuoteBodyHtml := sMatch1 
    Else { ; fallback
        sQuoteBodyHtml := GetSelection("text",False) ; removes formatting
    }
    
    sHtmlThread := sSelectionHtml

} Else { ; partial thread selection

    sQuoteBodyHtml := GetSelection("text",False) ; removes formatting
    If (!sQuoteBodyHtml) {
        MsgBox Selection empty!
        Clipboard := savedClipboard
        return
    }

    SendInput +{Up} ; Shift + Up Arrow: select all thread
    Sleep 200
    SendInput ^a
    sHtmlThread := GetSelection("html",False)
}
; Extract Teams Link

; Full thread selection to get link and author
; &lt;https://teams.microsoft.com/l/message/19:b4371b8d10234ac9b4e0095ace0aae8e@thread.skype/1600430385590?tenantId=8d4b558f-7b2e-40ba-ad1f-e04d79e6265a&amp;amp;groupId=56bc81d8-db27-487c-8e4f-8d5ea9058663&amp;amp;parentMessageId=1600430385590&amp;amp;teamName=GUIDEs&amp;amp;channelName=Best Work Hacks&amp;amp;createdTime=1600430385590&gt;</div></div><!--EndFragment-->

; Get thread author and conversation title from parent thread
; <span>Dalon, Thierry</span><div>Quick Share link to Teams</div><div data-tid="messageBodyContainer">
sPat = U)<span>([^>]*)</span><div>(.*)</div><div data-tid="messageBodyContainer">
If (RegExMatch(sHtmlThread,sPat,sMatch)) {
    sAuthor := sMatch1
    sTitle := sMatch2
} Else { ; Sub-thread
; <span>Schmidt, Thomas</span><div data-tid="messageBodyContainer">
    sPat = U)<span>([^/]*)</span><div data-tid="messageBodyContainer">
    If (RegExMatch(sHtmlThread,sPat,sMatch)) {
        sAuthor := sMatch1
    }
}

If (sAuthor = "") { ; something went wrong
; TODO error handling
    MsgBox Something went wrong! Please retry.
    Clipboard := savedClipboard
    return
}

; Get thread link
sPat := "U)<div>&lt;https://teams\.microsoft\.com/(.*;createdTime=.*)&gt;</div>.*</div><!--EndFragment-->"
If (RegExMatch(sHtmlThread,sPat,sMatch)) {
    sMsgLink = https://teams.microsoft.com/%sMatch1%
    sMsgLink := StrReplace(sMsgLink,"&amp;amp;","&")
}

If (doReply = True) { ; hotkey is buggy - will reply to original/ quoted thread-> need to click on reply manually in case of quote from another thread
    If (sMsgLink = "") ; group chat
        Send !+c ; Alt+Shift+c
    Else
        Send !+r ; Alt+Shift+r
    Sleep 800
} Else { ; ask for continue
    Answ := ButtonBox("Paste conversation quote","Activate the place where to paste the quoted conversation and hit Continue`nor select Create New...","Continue|Create New...")
    If (Answ="Button_Cancel") {
        ; Restore Clipboard
        Clipboard := savedClipboard
        Return
    }
}

If (People_IsMe(sAuthor)) 
    sAuthor = I 

TeamsReplyWithMention := False
If WinActive("ahk_exe Teams.exe") { ; SendMention
    ; Mention Author
    If (sAuthor <> "I") {
        TeamsReplyWithMention := True
        SendInput > ; markdown for quote block
        Sleep 200  
        Teams_SendMention(sAuthor)
        sAuthor =
    }
}

If (sMsgLink = "") ; group chat
    sQuoteTitleHtml = %sAuthor% wrote:
Else
    sQuoteTitleHtml = <a href="%sMsgLink%">%sAuthor%&nbsp;wrote</a>:    

If (TeamsReplyWithMention = True)
    sQuoteHtml = %sQuoteTitleHtml%<br>%sQuoteBodyHtml%
Else
    sQuoteHtml = <blockquote>%sQuoteTitleHtml%<br>%sQuoteBodyHtml%</blockquote>


WinClip.SetHTML(sQuoteHtml)
WinClip.Paste() ; seems asynchronuous
Sleep 500

; Escape Block quote in Teams: twice Shift+Enter
If WinActive("ahk_exe Teams.exe") {
    ;SendInput {Delete} ; remove empty div to avoid breaking quote block in two
    SendInput +{Enter} 
    SendInput +{Enter}
}

; Restore Clipboard
Clipboard := savedClipboard

} ; eofun

See also

Uservoice: Reply to specific message in chat on desktop app

No comments:

Post a Comment