Overview
It sends Cmd+Shift+M, then confirms the toggle actually registered by reading Teams' "Mute mic"/"Unmute mic" accessibility button label before and after -- a real success/failure signal instead of a timeout guess -- and shows the resulting state (or the failure) in an on-screen alert.
The accessibility-tree button lookup (findButton in ui.lua) is adapted from
_teamsFindButtonByLabel in
RobvH/teams-mac-hotkeys.
The Teams local API client (api.lua) follows the protocol handling of
asp55/MSTeams.spoon2 (MIT, (c) 2026 asp55).
Download: https://github.com/hugoh/TeamsControl.spoon/releases/latest
Variables
Bundle identifier of the Microsoft Teams app (default: "com.microsoft.teams2").
Seconds to wait for Teams to come to the front for the click fallback before giving up (default: 5).
Seconds between accessibility re-checks after sending the mute keystroke (default: 0.05).
How many times to re-check the button label -- after the keystroke, and again after the click fallback -- before declaring the toggle failed (default: 10).
Show a menu bar indicator during Teams calls: the macOS mic glyph when unmuted, the slashed mic when muted, nothing otherwise. Clicking it toggles mute (default: true).
Use Teams' local third-party API (a websocket on localhost) when it is available: mute toggles then need no keystroke or focus change. Falls back to the keystroke/click path whenever the API is off, not paired, or doesn't answer (default: true).
Port of Teams' local API (default: 8124).
Seconds between attempts to reach Teams' local API while it is unavailable (default: 30).
Seconds to wait for Teams to confirm a mute toggle sent through its API before falling back to the keystroke (default: 0.5).
How many times to retry reaching Teams' local API for one running instance of Teams before giving up until Teams restarts. A successful connection resets the count (default: 3).
Methods
Sets one or more of TeamsControl's variables from a table. Call it before start().
Parameters
opts- a table with any of the variable names documented on this page as keys
Returns
- The TeamsControl object, for method chaining
Toggles the Teams meeting microphone by sending Cmd+Shift+M to Teams without bringing it forward. If that doesn't register, Teams is activated, its mute button clicked, and focus returned to the app you were in. Re-entrant calls while a toggle is already in flight are ignored.
Parameters
done- an optional function called once when the toggle has settled (or the call was ignored), so callers can drive a busy indicator
Returns
- The TeamsControl object, for method chaining
Binds hotkeys for TeamsControl.
Parameters
mapping- a table with atoggleMutekey mapped to a{ {modifiers}, key }spec
Returns
- The TeamsControl object, for method chaining
Called automatically by hs.loadSpoon(). Logs the loaded version.
Returns
- The TeamsControl object, for method chaining
Watches for Teams running. While it does, starts the menu bar indicator, if showMenubar is
set, and connects to Teams' local API, if useApi is set.
Returns
- The TeamsControl object, for method chaining
Unbinds any hotkeys bound via bindHotkeys, stops the menu bar indicator and disconnects from the Teams API.
Returns
- The TeamsControl object, for method chaining