mirror of
https://github.com/jimeh/dotfiles.git
synced 2026-02-19 06:26:39 +00:00
Add PushToTalk Spoon to Hammerspoon config
This commit is contained in:
@@ -70,3 +70,4 @@ endef
|
||||
$(eval $(call dep-file,inspect.lua,"https://github.com/kikito/inspect.lua/raw/v3.1.0/inspect.lua"))
|
||||
$(eval $(call dep-spoon,RoundedCorners,"https://github.com/Hammerspoon/Spoons/raw/master/Spoons/RoundedCorners.spoon.zip"))
|
||||
$(eval $(call dep-spoon,HeadphoneAutoPause,"https://github.com/Hammerspoon/Spoons/raw/master/Spoons/HeadphoneAutoPause.spoon.zip"))
|
||||
$(eval $(call dep-spoon,PushToTalk,"https://github.com/Hammerspoon/Spoons/raw/master/Spoons/PushToTalk.spoon.zip"))
|
||||
|
||||
100
hammerspoon/Spoons/PushToTalk.spoon/docs.json
Normal file
100
hammerspoon/Spoons/PushToTalk.spoon/docs.json
Normal file
@@ -0,0 +1,100 @@
|
||||
[
|
||||
{
|
||||
"Command": [],
|
||||
"Constant": [],
|
||||
"Constructor": [],
|
||||
"Deprecated": [],
|
||||
"Field": [],
|
||||
"Function": [],
|
||||
"Method": [
|
||||
{
|
||||
"def": "PushToTalk:init()",
|
||||
"desc": "Starts menu and key watcher",
|
||||
"doc": "Starts menu and key watcher",
|
||||
"name": "init",
|
||||
"signature": "PushToTalk:init()",
|
||||
"stripped_doc": "",
|
||||
"type": "Method"
|
||||
},
|
||||
{
|
||||
"def": "PushToTalk:stop()",
|
||||
"desc": "Stops PushToTalk",
|
||||
"doc": "Stops PushToTalk",
|
||||
"name": "stop",
|
||||
"signature": "PushToTalk:stop()",
|
||||
"stripped_doc": "",
|
||||
"type": "Method"
|
||||
},
|
||||
{
|
||||
"def": "PushToTalk:toggleStates()",
|
||||
"desc": "Cycle states in order",
|
||||
"doc": "Cycle states in order\n\nParameters:\n * states - A array of states to toggle. For example: `{'push-to-talk', 'release-to-talk'}`",
|
||||
"name": "toggleStates",
|
||||
"parameters": [
|
||||
" * states - A array of states to toggle. For example: `{'push-to-talk', 'release-to-talk'}`"
|
||||
],
|
||||
"signature": "PushToTalk:toggleStates()",
|
||||
"stripped_doc": "",
|
||||
"type": "Method"
|
||||
}
|
||||
],
|
||||
"Variable": [
|
||||
{
|
||||
"def": "PushToTalk.app_switcher",
|
||||
"desc": "Takes mapping from application name to mic state.",
|
||||
"doc": "Takes mapping from application name to mic state.\nFor example this `{ ['zoom.us'] = 'push-to-talk' }` will switch mic to `push-to-talk` state when Zoom app starts.",
|
||||
"name": "app_switcher",
|
||||
"signature": "PushToTalk.app_switcher",
|
||||
"stripped_doc": "For example this `{ ['zoom.us'] = 'push-to-talk' }` will switch mic to `push-to-talk` state when Zoom app starts.",
|
||||
"type": "Variable"
|
||||
}
|
||||
],
|
||||
"desc": "Implements push-to-talk and push-to-mute functionality with `fn` key.",
|
||||
"doc": "Implements push-to-talk and push-to-mute functionality with `fn` key.\nI implemented this after reading Gitlab remote handbook https://about.gitlab.com/handbook/communication/ about Shush utility.\n\nMy workflow:\n\nWhen Zoom starts, PushToTalk automatically changes mic state from `default`\nto `push-to-talk`, so I need to press `fn` key to unmute myself and speak.\nIf I need to actively chat in group meeting or it's one-on-one meeting,\nI'm switching to `push-to-mute` state, so mic will be unmute by default and `fn` key mutes it.\n\nPushToTalk has menubar with colorful icons so you can easily see current mic state.\n\nSample config: `spoon.SpoonInstall:andUse(\"PushToTalk\", {start = true, config = { app_switcher = { ['zoom.us'] = 'push-to-talk' }}})`\nand separate keybinding to toggle states with lambda function `function() spoon.PushToTalk.toggleStates({'push-to-talk', 'release-to-talk'}) end`\n\nCheck out my config: https://github.com/skrypka/hammerspoon_config/blob/master/init.lua",
|
||||
"items": [
|
||||
{
|
||||
"def": "PushToTalk.app_switcher",
|
||||
"desc": "Takes mapping from application name to mic state.",
|
||||
"doc": "Takes mapping from application name to mic state.\nFor example this `{ ['zoom.us'] = 'push-to-talk' }` will switch mic to `push-to-talk` state when Zoom app starts.",
|
||||
"name": "app_switcher",
|
||||
"signature": "PushToTalk.app_switcher",
|
||||
"stripped_doc": "For example this `{ ['zoom.us'] = 'push-to-talk' }` will switch mic to `push-to-talk` state when Zoom app starts.",
|
||||
"type": "Variable"
|
||||
},
|
||||
{
|
||||
"def": "PushToTalk:init()",
|
||||
"desc": "Starts menu and key watcher",
|
||||
"doc": "Starts menu and key watcher",
|
||||
"name": "init",
|
||||
"signature": "PushToTalk:init()",
|
||||
"stripped_doc": "",
|
||||
"type": "Method"
|
||||
},
|
||||
{
|
||||
"def": "PushToTalk:stop()",
|
||||
"desc": "Stops PushToTalk",
|
||||
"doc": "Stops PushToTalk",
|
||||
"name": "stop",
|
||||
"signature": "PushToTalk:stop()",
|
||||
"stripped_doc": "",
|
||||
"type": "Method"
|
||||
},
|
||||
{
|
||||
"def": "PushToTalk:toggleStates()",
|
||||
"desc": "Cycle states in order",
|
||||
"doc": "Cycle states in order\n\nParameters:\n * states - A array of states to toggle. For example: `{'push-to-talk', 'release-to-talk'}`",
|
||||
"name": "toggleStates",
|
||||
"parameters": [
|
||||
" * states - A array of states to toggle. For example: `{'push-to-talk', 'release-to-talk'}`"
|
||||
],
|
||||
"signature": "PushToTalk:toggleStates()",
|
||||
"stripped_doc": "",
|
||||
"type": "Method"
|
||||
}
|
||||
],
|
||||
"name": "PushToTalk",
|
||||
"stripped_doc": "I implemented this after reading Gitlab remote handbook https://about.gitlab.com/handbook/communication/ about Shush utility.\n\nMy workflow:\n\nWhen Zoom starts, PushToTalk automatically changes mic state from `default`\nto `push-to-talk`, so I need to press `fn` key to unmute myself and speak.\nIf I need to actively chat in group meeting or it's one-on-one meeting,\nI'm switching to `push-to-mute` state, so mic will be unmute by default and `fn` key mutes it.\n\nPushToTalk has menubar with colorful icons so you can easily see current mic state.\n\nSample config: `spoon.SpoonInstall:andUse(\"PushToTalk\", {start = true, config = { app_switcher = { ['zoom.us'] = 'push-to-talk' }}})`\nand separate keybinding to toggle states with lambda function `function() spoon.PushToTalk.toggleStates({'push-to-talk', 'release-to-talk'}) end`\n\nCheck out my config: https://github.com/skrypka/hammerspoon_config/blob/master/init.lua",
|
||||
"submodules": [],
|
||||
"type": "Module"
|
||||
}
|
||||
]
|
||||
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
|
||||
BIN
hammerspoon/Spoons/PushToTalk.spoon/muted.pdf
Normal file
BIN
hammerspoon/Spoons/PushToTalk.spoon/muted.pdf
Normal file
Binary file not shown.
BIN
hammerspoon/Spoons/PushToTalk.spoon/record.pdf
Normal file
BIN
hammerspoon/Spoons/PushToTalk.spoon/record.pdf
Normal file
Binary file not shown.
68
hammerspoon/Spoons/PushToTalk.spoon/speak.pdf
Normal file
68
hammerspoon/Spoons/PushToTalk.spoon/speak.pdf
Normal file
@@ -0,0 +1,68 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD>
|
||||
3 0 obj
|
||||
<< /Length 4 0 R
|
||||
/Filter /FlateDecode
|
||||
>>
|
||||
stream
|
||||
x<EFBFBD>]<5D>In<49>0E<><<3C>N<EFBFBD><4E><EFBFBD><EFBFBD><EFBFBD>=Ba <20>"]<5D><>?P<>$<24><>0 <20>gq<67><71><EFBFBD>9<><39><EFBFBD><EFBFBD>><3E>r<EFBFBD><72>e<>VS<56>>(}'ǎ4j<34><6A>*<2A>\<5C>v0<76><17><>Tz<54><7A>,+t شz<D8B4>((<28>yZ@<40><><11><>m<EFBFBD><17>f<EFBFBD><66>t<EFBFBD>ex<65><78>E<EFBFBD><45><EFBFBD><EFBFBD><12>'C<>k9o<39><6F><EFBFBD><EFBFBD>:<3A>aӶ<03><>6<EFBFBD><36><EFBFBD><EFBFBD><0C>8s;<3B>ҩ<0B><>H<11>kדO<D793>uw<75>C+<2B>FT<46>{\CIeV<65>6x<36><78>zsm،@<40><><<3C><>j<EFBFBD>̭<EFBFBD><CCAD><EFBFBD>a<EFBFBD>(<28>L[<5B>jx<6A><78><EFBFBD><04><><EFBFBD><EFBFBD>Ow<4F><77>yi<79><69>QA<51><41>5<EFBFBD><35>bZ<62>
|
||||
<EFBFBD><EFBFBD>q=FO<46><4F><EFBFBD><EFBFBD>F<EFBFBD>&}<7D><><1D>*<2A>;z<0F><>;<3B><><EFBFBD><1A><><1B><><EFBFBD>OAq<41>˔f9<66>b<EFBFBD><62><EFBFBD>p<>O<EFBFBD>nv<6E><76>
|
||||
endstream
|
||||
endobj
|
||||
4 0 obj
|
||||
310
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/ExtGState <<
|
||||
/a0 << /CA 1 /ca 1 >>
|
||||
>>
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<< /Type /Page
|
||||
/Parent 1 0 R
|
||||
/MediaBox [ 0 0 15.75 15.75 ]
|
||||
/Contents 3 0 R
|
||||
/Group <<
|
||||
/Type /Group
|
||||
/S /Transparency
|
||||
/I true
|
||||
/CS /DeviceRGB
|
||||
>>
|
||||
/Resources 2 0 R
|
||||
>>
|
||||
endobj
|
||||
1 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [ 5 0 R ]
|
||||
/Count 1
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<< /Creator (cairo 1.14.10 (http://cairographics.org))
|
||||
/Producer (cairo 1.14.10 (http://cairographics.org))
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 1 0 R
|
||||
>>
|
||||
endobj
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000000714 00000 n
|
||||
0000000424 00000 n
|
||||
0000000015 00000 n
|
||||
0000000402 00000 n
|
||||
0000000496 00000 n
|
||||
0000000779 00000 n
|
||||
0000000908 00000 n
|
||||
trailer
|
||||
<< /Size 8
|
||||
/Root 7 0 R
|
||||
/Info 6 0 R
|
||||
>>
|
||||
startxref
|
||||
960
|
||||
69
hammerspoon/Spoons/PushToTalk.spoon/unrecord.pdf
Normal file
69
hammerspoon/Spoons/PushToTalk.spoon/unrecord.pdf
Normal file
@@ -0,0 +1,69 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD>
|
||||
3 0 obj
|
||||
<< /Length 4 0 R
|
||||
/Filter /FlateDecode
|
||||
>>
|
||||
stream
|
||||
x<EFBFBD>]<5D>=
|
||||
A<0C><><EFBFBD><EFBFBD>]<5D><>Lv<4C>{A<>X-<2D>BFP<46>-<0B><><EFBFBD>m<EFBFBD>C<><43><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۛ<><DB9B>&a<><61><EFBFBD><EFBFBD>!<21>]<5D><16>i<EFBFBD><0B><>7<EFBFBD>h,<2C>4<EFBFBD><06>qg<>3:<3A>pp+<2B>B<EFBFBD><42>P$<24><> <09><><EFBFBD><EFBFBD><EFBFBD>jN<6A><4E>Rߘ:E֬k&c<><63><EFBFBD>km<6B><6D><1A><08>-?<3F><12><><EFBFBD>Ϙh<CF98>/C3b
|
||||
endstream
|
||||
endobj
|
||||
4 0 obj
|
||||
149
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/ExtGState <<
|
||||
/a0 << /CA 1 /ca 1 >>
|
||||
>>
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<< /Type /Page
|
||||
/Parent 1 0 R
|
||||
/MediaBox [ 0 0 15.75 15.75 ]
|
||||
/Contents 3 0 R
|
||||
/Group <<
|
||||
/Type /Group
|
||||
/S /Transparency
|
||||
/I true
|
||||
/CS /DeviceRGB
|
||||
>>
|
||||
/Resources 2 0 R
|
||||
>>
|
||||
endobj
|
||||
1 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [ 5 0 R ]
|
||||
/Count 1
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<< /Creator (cairo 1.14.10 (http://cairographics.org))
|
||||
/Producer (cairo 1.14.10 (http://cairographics.org))
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 1 0 R
|
||||
>>
|
||||
endobj
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000000553 00000 n
|
||||
0000000263 00000 n
|
||||
0000000015 00000 n
|
||||
0000000241 00000 n
|
||||
0000000335 00000 n
|
||||
0000000618 00000 n
|
||||
0000000747 00000 n
|
||||
trailer
|
||||
<< /Size 8
|
||||
/Root 7 0 R
|
||||
/Info 6 0 R
|
||||
>>
|
||||
startxref
|
||||
799
|
||||
%%EOF
|
||||
@@ -28,6 +28,11 @@ hs.loadSpoon('HeadphoneAutoPause')
|
||||
spoon.HeadphoneAutoPause.autoResume = false
|
||||
spoon.HeadphoneAutoPause:start()
|
||||
|
||||
-- Enable push-to-talk microphone functionality when specific apps are running.
|
||||
hs.loadSpoon('PushToTalk')
|
||||
spoon.PushToTalk.app_switcher = { ['TeamSpeak 3'] = 'push-to-talk' }
|
||||
spoon.PushToTalk:start()
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Host specific configuration
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user