Spoons
Spoons copied to clipboard
[VolumeScroll] spoon does not work.
The VolumeScroll spoon has several problems:
- When started via
spoon.VolumeScroll.start()*** ERROR: .../leftium/.hammerspoon/Spoons/VolumeScroll.spoon/init.lua:64: attempt to index a nil value (local 'self')
- Starting this way works:
spoon.VolumeScroll.start({ "cmd", "alt"})But now on mouse scroll:ERROR: LuaSkin: hs.eventtap callback error: .../leftium/.hammerspoon/Spoons/VolumeScroll.spoon/init.lua:49: attempt to call a nil value (method 'sameMods')
- So I removed all the checks for modifiers to see how the volume control part works...
- The volume control works for a while, but the event tap eventually just stops getting events.
- Also the volume control felt "mushy." I think 1% volume steps feel too small?
Detailed steps:
- Downloaded VolumeScroll.spoon.zip from https://www.hammerspoon.org/Spoons/VolumeScroll.html
- Extracted zip file; double-clicked VolumeScroll.spoon to install.
- Added these lines to my ~/.hammerspoon/init.lua:
hs.loadSpoon("VolumeScroll")
spoon.VolumeScroll.start({ "cmd", "alt"})
Environment:
- MacOS 15.5 (24F74)
- Hammerspoon version 1.0.0 (6864)
Here is a similar Spoon I wrote for myself (with assistance from AI; my first Lua script):
- Simply start with
hs.loadSpoon("VolumeControl") - SHIFT + scroll to adjust volume
- SHIFT + middle mouse to toggle mute
- Small scrolls for small volume steps, large scrolls for large steps
- Avoids the problem where event tap stops receiving events
I was hoping to use VolumeScroll as a model for re-writing this as a good spoon (like is it bad events are set up in :init?), but this just works:
-- ~/.hammerspoon/Spoons/VolumeControl.spoon/init.lua
print("🔧 VolumeControl.spoon loading…")
local obj = {}
obj.__index = obj
local types = hs.eventtap.event.types
local props = hs.eventtap.event.properties
local sendKey = function(key)
hs.eventtap.event.newSystemKeyEvent(key, true ):post()
hs.eventtap.event.newSystemKeyEvent(key, false):post()
print(string.format('Sent key event: %s', key))
end
function obj:init()
print("🔧 VolumeControl:init() called")
-- SHIFT+scroll → adjust volume
self.scrollTap = hs.eventtap.new({ types.scrollWheel }, function(evt)
local flags = evt:getFlags()
if not flags.shift then return false end
local axis = props.scrollWheelEventDeltaAxis2 or
props.scrollWheelEventDeltaAxis1
local delta = evt:getProperty(axis)
if delta > 0 then sendKey('SOUND_UP')
elseif delta < 0 then sendKey('SOUND_DOWN') end
return true
end):start()
-- SHIFT + middle-click → MUTE
self.muteTap = hs.eventtap.new({ types.otherMouseUp }, function(evt)
if not evt:getFlags().shift or
evt:getProperty(props.mouseEventButtonNumber) ~= 2
then return false end
sendKey('MUTE')
return true
end):start()
end
return obj