如何在Hammerspoon中通过Karabiner使用带非标准按键的键盘?
问题背景
我为Mac连接了一款带有额外非标准按键的键盘。测试Hammerspoon的init.lua代码时,发现部分按键无法绑定:
local hyper = {"cmd", "alt", "ctrl", "shift"} hs.hotkey.bind(hyper, "E", function() hs.alert.show("Hyper E") end) hs.hotkey.bind(nil, "help", function() hs.alert.show("HELP") -- 可以正常工作 end) -- 取消注释后重载Hammerspoon会报错 -- hs.hotkey.bind(nil, "copy", function() -- hs.alert.show("COPY") -- 错误 -- end)
取消注释copy键绑定后,出现以下错误:
2022-11-28 11:28:06: *** ERROR: ...merspoon.app/Contents/Resources/extensions/hs/hotkey.lua:415: Invalid key: copy - this may mean that the key requested does not exist in your keymap (particularly if you switch keyboard layouts frequently)
macOS会静默忽略这些非标准按键,但Karabiner-Elements可以正确识别所有按键,其中copy键的事件信息为:
{ "type": "down", "name": {"key_code":"copy"}, "usagePage": "7 (0x0007)", "usage": "124 (0x007c)", "misc": "" }
问题:是否可以无需创建macOS键盘映射文件,仅通过Karabiner在Hammerspoon中使用这类非标准按键(比如copy键)?

解决方案
可以实现,有两种常用方法:
方法一:用Karabiner将非标准按键映射为Hammerspoon可识别的组合键
这种方法通过Karabiner把非标准按键转成Hammerspoon支持的组合键,再进行绑定,操作简单直观:
添加Karabiner自定义规则
打开Karabiner-Elements,进入「Complex Modifications」→「Add rule」→「Import more rules from the internet (open a browser)」,或者直接编辑~/.config/karabiner/karabiner.json,添加如下规则:{ "title": "非标准键盘按键映射", "rules": [ { "description": "将copy键映射为Hyper+C(cmd+ctrl+alt+shift+C)", "manipulators": [ { "type": "basic", "from": { "key_code": "copy" }, "to": [ { "key_code": "c", "modifiers": ["command", "control", "option", "shift"] } ] } ] } ] }在Hammerspoon中绑定映射后的组合键
修改init.lua,绑定刚才的Hyper+C组合键:local hyper = {"cmd", "alt", "ctrl", "shift"} hs.hotkey.bind(hyper, "C", function() hs.alert.show("COPY 按键触发") -- 可添加实际功能,比如执行系统复制: -- hs.eventtap.keyStroke({"cmd"}, "c") end)
方法二:Hammerspoon直接监听原始HID事件
无需Karabiner,直接通过Hammerspoon的事件监听捕获非标准按键的原始HID事件,需要用到Karabiner识别到的usagePage和usage值:
修改init.lua,添加事件监听:
-- 监听copy键的按下事件(usagePage=7,usage=124) local copyEventTap = hs.eventtap.new({hs.eventtap.event.types.keyDown}, function(event) local usagePage = event:property(hs.eventtap.event.properties.keyboardEventHIDUsagePage) local usage = event:property(hs.eventtap.event.properties.keyboardEventHIDUsage) -- 匹配copy键的HID参数 if usagePage == 7 and usage == 124 then hs.alert.show("COPY 按键触发") return true -- 阻止事件传递给系统,避免冲突 end return false end) copyEventTap:start()
这种方法不需要额外的Karabiner映射,直接在Hammerspoon中处理原始事件,但需要确保usagePage和usage值与Karabiner识别的一致。
内容的提问来源于stack exchange,提问作者clt60

