当前位置: 首页 > news >正文

Mac(四)自定义按键工具 Hammerspoon 的安装和使用

目录

    • 一、安装 Hammerspoon
      • 1. 官方安装(推荐)
      • 2. 手动安装
      • 3. 首次配置
      • 4. 配置文件结构
      • 5. 示例配置
      • 3. 重载配置
    • 二、实用代码片段
      • 1. 重新加载配置
      • 2. 快捷输入文字
      • 3. 打开网页
      • 5. 文字缩写填充
      • 6. 窗口大小变化
      • 7. 防沉迷提醒
      • 8. 剪切板历史
      • 9. 快速分屏(替代 Magnet)
      • 10. 应用启动
      • 11. 电量监控
      • 12. 网络切换
    • 三、调试与维护
      • 1. 控制台调试
      • 2. 常用命令
      • 3. 错误排查
    • 四、推荐插件及安装方式
      • 1. 主流插件安装指南 🔌
        • 第1步 SpoonInstall(插件管理器)
        • 第2步 WinWin(窗口管理增强)
        • 第3步 ClipboardTool(剪切板历史)
        • 第4步 FadeLogo(状态栏动画)
      • 2. 插件管理技巧
        • 自动更新插件
        • 插件冲突排查
      • 3. 社区资源
    • 五、扩展资源
      • 1. 官方文档
      • 2. 精品配置
      • 3. 小编配置

  • 官网地址: https://www.hammerspoon.org/
  • 官方文档: https://www.hammerspoon.org/go/
  • 官方下载: https://github.com/Hammerspoon/hammerspoon/releases/latest
  • GitHub: https://github.com/Hammerspoon/hammerspoon

🚀 Hammerspoon 是 macOS 上最强大的自动化工具,通过 Lua 脚本实现:

  • 全局快捷键自定义
  • 窗口管理自动化
  • 应用快速切换
  • 系统状态监控
  • 任意功能扩展

比 Karabiner 更轻量,比 BetterTouchTool 更自由!


一、安装 Hammerspoon

1. 官方安装(推荐)

brew install --cask hammerspoon

2. 手动安装

在 官网下载 之后,双击打开 → 拖拽到 Applications 文件夹

3. 首次配置

  1. 打开应用后,菜单栏会出现「🔨」图标
  2. 点击图标 → 「Open Config」打开配置文件目录
  3. 系统会要求授予「辅助功能」权限:
    • 系统设置 → 隐私与安全性 → 辅助功能
    • 勾选 Hammerspoon

4. 配置文件结构

~/.hammerspoon/
├── init.lua          -- 主入口文件
└── modules/          -- 自定义模块目录

5. 示例配置

init.lua 内容如下:

-- 超实用快捷键:⌃⌥⌘ + D 显示桌面
hs.hotkey.bind({'ctrl', 'alt', 'cmd'}, 'D', function()hs.osascript.applescript('tell application "Finder" to set desktop visible to true')
end)-- 窗口管理:⌃⌥ + 方向键快速调整窗口位置
hs.hotkey.bind({'ctrl', 'alt'}, 'Left', function()local win = hs.window.focusedWindow()win:moveToUnit({0, 0, 0.5, 1}) -- 左半屏
end)

3. 重载配置

点击菜单栏图标 → 「Reload Config」


二、实用代码片段

1. 重新加载配置

-- 示例快捷键:Ctrl+Alt+Cmd+R 重新加载配置
hs.hotkey.bind({"ctrl", "alt", "cmd"}, "R", function()hs.reload()
end)

2. 快捷输入文字

-- 定义通用函数:发送文本并回车
-- 终极稳定版(带输入法状态检测)
function sendTextAndEnter(text)-- 检测是否中文输入法local isChinese = (hs.keycodes.currentLayout():find("Chinese") ~= nil)if isChinese then-- 中文模式:切换英文布局hs.keycodes.setLayout("U.S.")hs.timer.usleep(50000) -- 等待50msend-- 分段输入核心逻辑for i = 1, #text, 3 do -- 每3个字符一组hs.eventtap.keyStrokes(text:sub(i, i+2))hs.timer.usleep(50000) -- 组间延迟50msend-- 恢复中文布局(如果需要)hs.timer.delayed.new(0.2, function()if isChinese thenhs.keycodes.setLayout("Chinese")endhs.eventtap.keyStroke({}, "return")end):start()
endhs.hotkey.bind({"ctrl"}, "s", function() sendTextAndEnter("收到") end)     -- Command+S → "收到"
hs.hotkey.bind({"ctrl"}, "h", function() sendTextAndEnter("好的") end)     -- Command+H → "好的"

3. 打开网页

-- 定义通用函数:打开URL
function openURL(url)hs.execute('open "' .. url .. '"')
end
-- 绑定网页快捷键
hs.hotkey.bind({"cmd"}, "1", function() openURL("https://www.baidu.com") end)      -- Command+1 → 百度
hs.hotkey.bind({"cmd"}, "2", function() openURL("https://blog.csdn.net/qq_33204709?type=blog") end) -- cmd+2 → 博客
hs.hotkey.bind({"cmd"}, "3", function() openURL("https://google.com/") end)        -- Command+3 → 谷歌
hs.hotkey.bind({"cmd"}, "4", function() openURL("https://cn.bing.com/") end)       -- Command+4 → 必应

5. 文字缩写填充

-- =============================================
-- 文本替换核心引擎
-- 特点:零误删、100%精确、支持所有输入法
-- =============================================-- 配置区(用户可修改)
local config = {triggers = {["sf"] = "SELECT * FROM ",["scf"] = "SELECT COUNT(*) FROM "},delay = 30000, -- 微秒级延迟 (30ms)maxBuffer = 10  -- 最大字符缓存
}-- 引擎核心(不要修改)
local buffer = ""
local isProcessing = falselocal function processBuffer()if isProcessing then return endisProcessing = truefor trigger, replacement in pairs(config.triggers) doif buffer:sub(-#trigger) == trigger then-- 精确删除(不使用循环避免误差)hs.eventtap.keyStrokes(string.rep("\b", #trigger))hs.timer.usleep(config.delay)-- 插入新内容hs.eventtap.keyStrokes(replacement)-- 重置状态buffer = ""isProcessing = falsereturn trueendendisProcessing = falsereturn false
end-- 事件监听(优化版)
local eventTap = hs.eventtap.new({hs.eventtap.event.types.keyDown}, function(e)-- 获取按键字符local char = hs.keycodes.map[e:getKeyCode()] or ""-- 过滤非字母键if not char:match("%a") thenbuffer = ""return falseend-- 更新缓冲区buffer = buffer .. charif #buffer > config.maxBuffer thenbuffer = buffer:sub(-config.maxBuffer)end-- 延迟处理确保稳定性hs.timer.doAfter(0.05, processBuffer) -- 50ms延迟return false
end)-- 安全启动
if hs.eventtap theneventTap:start()
elsehs.alert.show("初始化失败: 缺少eventtap模块", 2)
end

6. 窗口大小变化

-- 示例窗口管理:将当前窗口移到屏幕左侧
hs.hotkey.bind({"ctrl", "alt", "cmd"}, "Left", function()local win = hs.window.focusedWindow()local f = win:frame()local screen = win:screen()local max = screen:frame()f.x = max.xf.y = max.yf.w = max.w / 2f.h = max.hwin:setFrame(f)
end)-- 示例窗口管理:将当前窗口移到屏幕右侧
hs.hotkey.bind({"ctrl", "alt", "cmd"}, "Right", function()local win = hs.window.focusedWindow()local f = win:frame()local screen = win:screen()local max = screen:frame()f.x = max.x + (max.w / 2)f.y = max.yf.w = max.w / 2f.h = max.hwin:setFrame(f)
end)-- 按下ctrl+alt+x实现窗口最大化
hs.hotkey.bind({"ctrl", "cmd"}, "X", function()local win = hs.window.focusedWindow()if win then-- 最大化当前窗口win:maximize()elsehs.alert.show("没有聚焦的窗口")end
end)

7. 防沉迷提醒

-- 每30分钟提醒休息
workTimer = hs.timer.doEvery(30*60, function()hs.notify.new({title = "休息提醒",subTitle = "已经工作30分钟了",informativeText = "起来活动一下吧~"}):send()
end)

8. 剪切板历史

-- 需要安装clipboard插件
require("hs.clipboard")
hs.hotkey.bind({'cmd', 'shift'}, 'V', function()hs.clipboard.managerOnTop(true)
end)

9. 快速分屏(替代 Magnet)

-- 快速分屏
hs.hotkey.bind({'cmd', 'alt'}, 'Left', function()hs.window.focusedWindow():moveToUnit({0, 0, 0.5, 1})
end)hs.hotkey.bind({'cmd', 'alt'}, 'Right', function()hs.window.focusedWindow():moveToUnit({0.5, 0, 0.5, 1})
end)

10. 应用启动

-- ⌃⌥⌘ + V 打开 VSCode
hs.hotkey.bind({'ctrl', 'alt', 'cmd'}, 'V', function()hs.application.launchOrFocus("Visual Studio Code")
end)

11. 电量监控

-- 显示电池状态
function showBattery()local battery = hs.battery.percentage()hs.alert.show("🔋 电量: " .. battery .. "%")
end
hs.hotkey.bind({'ctrl', 'cmd'}, 'B', showBattery)

12. 网络切换

-- 切换WiFi
function toggleWIFI()hs.execute("/usr/sbin/networksetup -setairportpower en0 toggle")
end
hs.hotkey.bind({'ctrl', 'cmd'}, 'W', toggleWIFI)

三、调试与维护

1. 控制台调试

# 打开调试控制台
hs.openConsole()

2. 常用命令

hs.reload()          -- 重载配置
hs.alert("Hello!")   -- 显示提示
hs.openAbout()       -- 打开关于面板

3. 错误排查

  1. 查看控制台日志(菜单栏 → 「Console」)
  2. 检查权限设置
  3. 使用 hs.inspect(variable) 输出变量值

四、推荐插件及安装方式

1. 主流插件安装指南 🔌

所有插件需放置在 ~/.hammerspoon/Spoons/ 目录下,然后在 init.lua 中加载:

-- 加载插件示例
hs.loadSpoon("PluginName")
第1步 SpoonInstall(插件管理器)
-- 安装步骤:
-- 1. 下载插件
hs.execute('curl -fsSL https://github.com/Hammerspoon/Spoons/raw/master/Spoons/SpoonInstall.spoon.zip -o /tmp/SpoonInstall.zip')
-- 2. 解压到插件目录
hs.execute('unzip -oq /tmp/SpoonInstall.zip -d ~/.hammerspoon/Spoons/')
-- 3. 在配置中启用
hs.loadSpoon("SpoonInstall")-- 使用示例:安装其他插件
spoon.SpoonInstall:andUse("ClipboardTool", {repo = "https://github.com/Hammerspoon/Spoons",hotkeys = true
})
第2步 WinWin(窗口管理增强)
# 手动安装
cd ~/.hammerspoon/Spoons/
git clone https://github.com/asmagill/hs._asm.undocumented.winwin.git WinWin.spoon
-- 配置示例
hs.loadSpoon("WinWin")
spoon.WinWin:bindHotkeys({left50 = {{"ctrl", "alt"}, "Left"},right50 = {{"ctrl", "alt"}, "Right"}
})
第3步 ClipboardTool(剪切板历史)
-- 通过 SpoonInstall 安装
spoon.SpoonInstall:andUse("ClipboardTool", {config = {max_items = 20,show_copied_alert = true},hotkeys = {toggle = {{"cmd", "shift"}, "V"}}
})
第4步 FadeLogo(状态栏动画)
# 手动安装
curl -fsSL https://github.com/Hammerspoon/Spoons/raw/master/Spoons/FadeLogo.spoon.zip -o /tmp/FadeLogo.zip
unzip /tmp/FadeLogo.zip -d ~/.hammerspoon/Spoons/
-- 使用示例
hs.loadSpoon("FadeLogo")
spoon.FadeLogo:start()

2. 插件管理技巧

自动更新插件
-- 添加到 init.lua
function updateSpoons()hs.execute("find ~/.hammerspoon/Spoons -maxdepth 1 -type d -exec git -C {} pull \\;")hs.reload()
end
hs.hotkey.bind({"cmd", "ctrl"}, "U", updateSpoons)
插件冲突排查
  1. 在控制台输入 hs.spoons.list() 查看已加载插件
  2. 使用 hs.spoons.use("PluginName", { lazy = true }) 延迟加载
  3. 通过注释法隔离问题插件

💡 推荐组合:SpoonInstall + WinWin + ClipboardTool 满足90%日常需求


3. 社区资源

资源类型链接
官方插件库Hammerspoon/Spoons
配置分享Awesome Hammerspoon
插件开发指南Writing Spoons

五、扩展资源

1. 官方文档

  • Hammerspoon 官网
  • API 文档

2. 精品配置

# 克隆流行配置方案
git clone https://github.com/ashfinal/awesome-hammerspoon ~/.hammerspoon

3. 小编配置

-- =============================================
-- 初始化 Hammerspoon 配置
-- =============================================
hs.loadSpoon("SpoonInstall")-- =============================================
-- 通用函数:发送文本并回车(终极稳定版)
-- 特点:带输入法状态检测,分段输入防止卡顿
-- =============================================
function sendTextAndEnter(text)-- 检测是否中文输入法local isChinese = (hs.keycodes.currentLayout():find("Chinese") ~= nil)if isChinese then-- 中文模式:切换英文布局hs.keycodes.setLayout("U.S.")hs.timer.usleep(50000) -- 等待50msend-- 分段输入核心逻辑for i = 1, #text, 3 do -- 每3个字符一组hs.eventtap.keyStrokes(text:sub(i, i+2))hs.timer.usleep(50000) -- 组间延迟50msend-- 恢复中文布局(如果需要)hs.timer.delayed.new(0.2, function()if isChinese thenhs.keycodes.setLayout("Chinese")endhs.eventtap.keyStroke({}, "return")end):start()
end-- =============================================
-- 通用函数:打开URL
-- =============================================
function openURL(url)hs.execute('open "' .. url .. '"')
end-- =============================================
-- 通用函数:启动应用程序
-- 注意:Windows路径需要转换为Mac路径
-- =============================================
function launchApp(appPath)local macPath = string.gsub(appPath, "D:\\Program Files", "/Applications")hs.execute('open "' .. macPath .. '"')
end-- =============================================
-- 快捷键绑定:常用短语
-- =============================================
hs.hotkey.bind({"ctrl"}, "s", function() sendTextAndEnter("收到") end) -- Command+S → "收到"
hs.hotkey.bind({"ctrl"}, "h", function() sendTextAndEnter("好的") end) -- Command+H → "好的"-- =============================================
-- 快捷键绑定:网页快速访问
-- =============================================
hs.hotkey.bind({"ctrl"}, "1", function() openURL("https://www.baidu.com") end)      -- Command+1 → 百度
hs.hotkey.bind({"ctrl"}, "2", function() openURL("https://blog.csdn.net/qq_33204709?type=blog") end) -- cmd+2 → 博客
hs.hotkey.bind({"ctrl"}, "3", function() openURL("https://google.com/") end)        -- Command+3 → 谷歌
hs.hotkey.bind({"ctrl"}, "4", function() openURL("https://cn.bing.com/") end)       -- Command+4 → 必应-- =============================================
-- 快捷键绑定:媒体控制
-- =============================================
-- hs.hotkey.bind({"cmd"}, "6", function() 
--     hs.execute('osascript -e "tell application \\"Music\\" to playpause"') 
-- end) -- cmd+6 → 播放/暂停-- =============================================
-- 文本替换引擎
-- 特点:零误删、100%精确、支持所有输入法
-- =============================================
local config = {triggers = {["sf"] = "SELECT * FROM ",["scf"] = "SELECT COUNT(*) FROM "},delay = 30000, -- 微秒级延迟 (30ms)maxBuffer = 10  -- 最大字符缓存
}local buffer = ""
local isProcessing = falselocal function processBuffer()if isProcessing then return endisProcessing = truefor trigger, replacement in pairs(config.triggers) doif buffer:sub(-#trigger) == trigger then-- 精确删除(不使用循环避免误差)hs.eventtap.keyStrokes(string.rep("\b", #trigger))hs.timer.usleep(config.delay)-- 插入新内容hs.eventtap.keyStrokes(replacement)-- 重置状态buffer = ""isProcessing = falsereturn trueendendisProcessing = falsereturn false
endlocal eventTap = hs.eventtap.new({hs.eventtap.event.types.keyDown}, function(e)-- 获取按键字符local char = hs.keycodes.map[e:getKeyCode()] or ""-- 过滤非字母键if not char:match("%a") thenbuffer = ""return falseend-- 更新缓冲区buffer = buffer .. charif #buffer > config.maxBuffer thenbuffer = buffer:sub(-config.maxBuffer)end-- 延迟处理确保稳定性hs.timer.doAfter(0.05, processBuffer) -- 50ms延迟return false
end)-- 安全启动事件监听
if hs.eventtap theneventTap:start()
elsehs.alert.show("初始化失败: 缺少eventtap模块", 2)
end-- =============================================
-- 快捷键绑定:快速访问路径
-- =============================================
hs.hotkey.bind({"cmd"}, "e", function()local path = "/Users/acgkaka/my"local attr = hs.fs.attributes(path)local exists = attr ~= nilif exists thenhs.execute('open "' .. path .. '"')elsehs.alert.show("路径不存在: " .. path, 2)end
end)-- =============================================
-- 快捷键绑定:配置重载
-- =============================================
hs.hotkey.bind({"ctrl", "alt", "cmd"}, "R", function()hs.reload()
end)-- =============================================
-- 窗口管理快捷键
-- =============================================-- 将当前窗口移到屏幕左侧
-- hs.hotkey.bind({"ctrl", "alt", "cmd"}, "Left", function()
--     local win = hs.window.focusedWindow()
--     local f = win:frame()
--     local screen = win:screen()
--     local max = screen:frame()--     f.x = max.x
--     f.y = max.y
--     f.w = max.w / 2
--     f.h = max.h
--     win:setFrame(f)
-- end)-- -- 将当前窗口移到屏幕右侧
-- hs.hotkey.bind({"ctrl", "alt", "cmd"}, "Right", function()
--     local win = hs.window.focusedWindow()
--     local f = win:frame()
--     local screen = win:screen()
--     local max = screen:frame()--     f.x = max.x + (max.w / 2)
--     f.y = max.y
--     f.w = max.w / 2
--     f.h = max.h
--     win:setFrame(f)
-- end)-- -- 窗口最大化
-- hs.hotkey.bind({"ctrl", "cmd"}, "X", function()
--     local win = hs.window.focusedWindow()
--     if win then
--         win:maximize()
--     else
--         hs.alert.show("没有聚焦的窗口")
--     end
-- end)-- =============================================
-- 通用应用程序启动函数
-- =============================================
function launchOrFocusApp(appPath, showNotification)-- 检查应用是否存在if not hs.fs.attributes(appPath) thenhs.notify.new({title="Hammerspoon 错误", informativeText="未找到应用程序: "..appPath}):send()return falseend-- 启动或聚焦应用程序hs.application.launchOrFocus(appPath)-- 显示通知(如果需要)if showNotification thenlocal appName = appPath:match("([^/]+)%.app$") or appPathhs.notify.new({title="Hammerspoon", informativeText="已启动 "..appName}):send()endreturn true
end-- =============================================
-- 应用程序快速启动快捷键
-- =============================================-- 启动All应用
hs.hotkey.bind({"ctrl", "cmd", "shift"}, "f", function()launchOrFocusApp("/Applications/All.app", true)
end)-- 启动终端
hs.hotkey.bind({"ctrl", "cmd", "shift"}, "c", function()launchOrFocusApp("/System/Applications/Utilities/Terminal.app", true)
end)-- =============================================
-- 初始化完成提示
-- =============================================
hs.alert.show("Hammerspoon 配置已加载")

💡 终极提示:Hammerspoon 的威力在于 Lua 脚本的无限可能,从简单的快捷键到复杂的自动化工作流,只有想不到,没有做不到!

整理完毕,完结撒花~🌻

http://www.lryc.cn/news/623736.html

相关文章:

  • vue封装请求拦截器 响应拦截器
  • SCAI采用公平发射机制成功登陆LetsBonk,60%代币供应量已锁仓
  • 智能合约里的 “拒绝服务“ 攻击:让你的合约变成 “死机的手机“
  • 数学建模 14 中心对数比变换
  • 原子操作及基于原子操作的shared_ptr实现
  • Leaflet赋能:WebGIS视角下的省域区县天气可视化实战攻略
  • 数据结构:二叉搜索树(Binary Search Tree)
  • ansible管理变量和事实
  • 《Python学习之文件操作:从入门到精通》
  • 剑指offer第2版——面试题5:替换空格
  • Java注解学习记录
  • 26. 值传递和引用传递的区别的什么?为什么说Java中只有值传递
  • 大模型对齐算法合集(一)
  • Zemax 中的透镜设计 - 像差理论
  • 评测系统构建
  • 深入分析 Linux PCI Express 子系统
  • 计算机网络 TCP time_wait 状态 详解
  • 10 SQL进阶-SQL优化(8.15)
  • Matlab课程实践——基于MATLAB设计的计算器软件(简单、科学、电工、矩阵及贷款计算)
  • esp32(自定义分区)coredump
  • C语言私人学习笔记分享
  • 关于第一次接触Linux TCP/IP网络相关项目
  • 使用Ansys Fluent进行倒装芯片封装Theta-JA热阻表征
  • 计算机网络 OSI 七层模型和 TCP 五层模型
  • IP 分片和组装的具体过程
  • 数字货币的法律属性与监管完善路径探析
  • Trae 辅助下的 uni-app 跨端小程序工程化开发实践分享
  • 【Java后端】Spring Boot 集成 MyBatis-Plus 全攻略
  • 【昇腾】单张48G Atlas 300I Duo推理卡MindIE+WebUI方式跑14B大语言模型_20250817
  • 前端vue3+后端spring boot导出数据