mirror of
https://github.com/jimeh/dotfiles.git
synced 2026-02-19 13:46:41 +00:00
Add PushToTalk Spoon to Hammerspoon config
This commit is contained in:
147
hammerspoon/Spoons/PushToTalk.spoon/init.lua
Normal file
147
hammerspoon/Spoons/PushToTalk.spoon/init.lua
Normal file
@@ -0,0 +1,147 @@
|
||||
--- === PushToTalk ===
|
||||
---
|
||||
--- Implements push-to-talk and push-to-mute functionality with `fn` key.
|
||||
--- I implemented this after reading Gitlab remote handbook https://about.gitlab.com/handbook/communication/ about Shush utility.
|
||||
---
|
||||
--- My workflow:
|
||||
---
|
||||
--- When Zoom starts, PushToTalk automatically changes mic state from `default`
|
||||
--- to `push-to-talk`, so I need to press `fn` key to unmute myself and speak.
|
||||
--- If I need to actively chat in group meeting or it's one-on-one meeting,
|
||||
--- I'm switching to `push-to-mute` state, so mic will be unmute by default and `fn` key mutes it.
|
||||
---
|
||||
--- PushToTalk has menubar with colorful icons so you can easily see current mic state.
|
||||
---
|
||||
--- Sample config: `spoon.SpoonInstall:andUse("PushToTalk", {start = true, config = { app_switcher = { ['zoom.us'] = 'push-to-talk' }}})`
|
||||
--- and separate keybinding to toggle states with lambda function `function() spoon.PushToTalk.toggleStates({'push-to-talk', 'release-to-talk'}) end`
|
||||
---
|
||||
--- Check out my config: https://github.com/skrypka/hammerspoon_config/blob/master/init.lua
|
||||
|
||||
local obj = {}
|
||||
obj.__index = obj
|
||||
|
||||
-- Metadata
|
||||
obj.name = "PushToTalk"
|
||||
obj.version = "0.1"
|
||||
obj.author = "Roman Khomenko <roman.dowakin@gmail.com>"
|
||||
obj.homepage = "https://github.com/Hammerspoon/Spoons"
|
||||
obj.license = "MIT - https://opensource.org/licenses/MIT"
|
||||
|
||||
obj.defaultState = 'unmute'
|
||||
|
||||
obj.state = obj.defaultState
|
||||
obj.pushed = false
|
||||
--- PushToTalk.app_switcher
|
||||
--- Variable
|
||||
--- Takes mapping from application name to mic state.
|
||||
--- For example this `{ ['zoom.us'] = 'push-to-talk' }` will switch mic to `push-to-talk` state when Zoom app starts.
|
||||
obj.app_switcher = {}
|
||||
|
||||
local function showState()
|
||||
local device = hs.audiodevice.defaultInputDevice()
|
||||
local muted = false
|
||||
if obj.state == 'unmute' then
|
||||
obj.menubar:setIcon(hs.spoons.resourcePath("speak.pdf"))
|
||||
elseif obj.state == 'mute' then
|
||||
obj.menubar:setIcon(hs.spoons.resourcePath("muted.pdf"))
|
||||
muted = true
|
||||
elseif obj.state == 'push-to-talk' then
|
||||
if obj.pushed then
|
||||
obj.menubar:setIcon(hs.spoons.resourcePath("record.pdf"), false)
|
||||
else
|
||||
obj.menubar:setIcon(hs.spoons.resourcePath("unrecord.pdf"))
|
||||
muted = true
|
||||
end
|
||||
elseif obj.state == 'release-to-talk' then
|
||||
if obj.pushed then
|
||||
obj.menubar:setIcon(hs.spoons.resourcePath("unrecord.pdf"))
|
||||
muted = true
|
||||
else
|
||||
obj.menubar:setIcon(hs.spoons.resourcePath("record.pdf"), false)
|
||||
end
|
||||
end
|
||||
|
||||
device:setMuted(muted)
|
||||
end
|
||||
|
||||
function obj.setState(s)
|
||||
obj.state = s
|
||||
showState()
|
||||
end
|
||||
|
||||
obj.menutable = {
|
||||
{ title = "UnMuted", fn = function() obj.setState('unmute') end },
|
||||
{ title = "Muted", fn = function() obj.setState('mute') end },
|
||||
{ title = "Push-to-talk (fn)", fn = function() obj.setState('push-to-talk') end },
|
||||
{ title = "Release-to-talk (fn)", fn = function() obj.setState('release-to-talk') end },
|
||||
}
|
||||
|
||||
local function appWatcher(appName, eventType, appObject)
|
||||
local new_app_state = obj.app_switcher[appName];
|
||||
if (new_app_state) then
|
||||
if (eventType == hs.application.watcher.launching) then
|
||||
obj.setState(new_app_state)
|
||||
elseif (eventType == hs.application.watcher.terminated) then
|
||||
obj.setState(obj.defaultState)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function eventTapWatcher(event)
|
||||
device = hs.audiodevice.defaultInputDevice()
|
||||
if event:getFlags()['fn'] then
|
||||
obj.pushed = true
|
||||
else
|
||||
obj.pushed = false
|
||||
end
|
||||
showState()
|
||||
end
|
||||
|
||||
--- PushToTalk:init()
|
||||
--- Method
|
||||
--- Initial setup. It's empty currently
|
||||
function obj:init()
|
||||
end
|
||||
|
||||
--- PushToTalk:init()
|
||||
--- Method
|
||||
--- Starts menu and key watcher
|
||||
function obj:start()
|
||||
self:stop()
|
||||
obj.appWatcher = hs.application.watcher.new(appWatcher)
|
||||
obj.appWatcher:start()
|
||||
|
||||
obj.eventTapWatcher = hs.eventtap.new({hs.eventtap.event.types.flagsChanged}, eventTapWatcher)
|
||||
obj.eventTapWatcher:start()
|
||||
|
||||
obj.menubar = hs.menubar.new()
|
||||
obj.menubar:setMenu(obj.menutable)
|
||||
obj.setState(obj.state)
|
||||
end
|
||||
|
||||
--- PushToTalk:stop()
|
||||
--- Method
|
||||
--- Stops PushToTalk
|
||||
function obj:stop()
|
||||
if obj.appWatcher then obj.appWatcher:stop() end
|
||||
if obj.eventTapWatcher then obj.eventTapWatcher:stop() end
|
||||
if obj.menubar then obj.menubar:delete() end
|
||||
end
|
||||
|
||||
--- PushToTalk:toggleStates()
|
||||
--- Method
|
||||
--- Cycle states in order
|
||||
---
|
||||
--- Parameters:
|
||||
--- * states - A array of states to toggle. For example: `{'push-to-talk', 'release-to-talk'}`
|
||||
function obj:toggleStates(states)
|
||||
new_state = states[1]
|
||||
for i, v in pairs(states) do
|
||||
if v == obj.state then
|
||||
new_state = states[(i % #states) + 1]
|
||||
end
|
||||
end
|
||||
obj.setState(new_state)
|
||||
end
|
||||
|
||||
return obj
|
||||
Reference in New Issue
Block a user