├── modules
├── hotkey.lua
├── reload.lua
├── system.lua
├── launcher.lua
└── windows.lua
├── init.lua
├── .gitignore
├── LICENSE
├── README_zh-CN.md
└── README.md
/modules/hotkey.lua:
--------------------------------------------------------------------------------
1 | hyper = {"cmd", "ctrl", "alt"}
2 | hyperShift = {"alt", "shift"}
3 | hyperCtrl = {"alt", "ctrl"}
4 | hyperAlt = {"ctrl", "alt", "shift"}
--------------------------------------------------------------------------------
/init.lua:
--------------------------------------------------------------------------------
1 | require "modules/reload"
2 | require "modules/hotkey"
3 | require "modules/system"
4 | require "modules/windows"
5 | require "modules/launcher"
6 | require "modules/wifi"
7 | require "modules/timer"
8 |
--------------------------------------------------------------------------------
/modules/reload.lua:
--------------------------------------------------------------------------------
1 | local pathwatcher = require "hs.pathwatcher"
2 | local alert = require "hs.alert"
3 |
4 | -- http://www.hammerspoon.org/go/#fancyreload
5 | function reloadConfig(files)
6 | doReload = false
7 | for _, file in pairs(files) do
8 | if file:sub(-4) == ".lua" then
9 | doReload = true
10 | end
11 | end
12 | if doReload then
13 | hs.reload()
14 | end
15 | end
16 |
17 | pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon", reloadConfig):start()
18 | alert.show("Hammerspoon Config Reloaded")
19 |
--------------------------------------------------------------------------------
/modules/system.lua:
--------------------------------------------------------------------------------
1 | local hotkey = require "hs.hotkey"
2 | local caffeinate = require "hs.caffeinate"
3 | local audiodevice = require "hs.audiodevice"
4 |
5 | hotkey.bind(hyper, "L", function()
6 | caffeinate.lockScreen()
7 | -- caffeinate.startScreensaver()
8 | end)
9 |
10 | -- mute on sleep
11 | function muteOnWake(eventType)
12 | if (eventType == caffeinate.watcher.systemDidWake) then
13 | local output = audiodevice.defaultOutputDevice()
14 | output:setMuted(true)
15 | end
16 | end
17 | caffeinateWatcher = caffeinate.watcher.new(muteOnWake)
18 | caffeinateWatcher:start()
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/macos
3 |
4 | ### macOS ###
5 | *.DS_Store
6 | .AppleDouble
7 | .LSOverride
8 |
9 | # Icon must end with two \r
10 | Icon
11 |
12 | # Thumbnails
13 | ._*
14 |
15 | # Files that might appear in the root of a volume
16 | .DocumentRevisions-V100
17 | .fseventsd
18 | .Spotlight-V100
19 | .TemporaryItems
20 | .Trashes
21 | .VolumeIcon.icns
22 | .com.apple.timemachine.donotpresent
23 |
24 | # Directories potentially created on remote AFP share
25 | .AppleDB
26 | .AppleDesktop
27 | Network Trash Folder
28 | Temporary Items
29 | .apdisk
30 |
31 | # End of https://www.gitignore.io/api/macos
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 greyby
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/modules/launcher.lua:
--------------------------------------------------------------------------------
1 | local hotkey = require "hs.hotkey"
2 | local grid = require "hs.grid"
3 | local window = require "hs.window"
4 | local application = require "hs.application"
5 | local appfinder = require "hs.appfinder"
6 | local fnutils = require "hs.fnutils"
7 |
8 | grid.setMargins({0, 0})
9 |
10 | applist = {
11 | {shortcut = 'I',appname = 'IntelliJ IDEA CE'},
12 | {shortcut = 'C',appname = 'Google Chrome'},
13 | {shortcut = 'K',appname = 'iTerm'},
14 | {shortcut = 'D',appname = 'Finder'},
15 | {shortcut = 'Y',appname = 'Activity Monitor'},
16 | {shortcut = 'P',appname = 'System Preferences'},
17 | }
18 |
19 | fnutils.each(applist, function(entry)
20 | hotkey.bind({'ctrl', 'alt', 'cmd'}, entry.shortcut, entry.appname, function()
21 | application.launchOrFocus(entry.appname)
22 | -- toggle_application(applist[i].appname)
23 | end)
24 | end)
25 |
26 | -- Toggle an application between being the frontmost app, and being hidden
27 | function toggle_application(_app)
28 | local app = appfinder.appFromName(_app)
29 | if not app then
30 | application.launchOrFocus(_app)
31 | return
32 | end
33 | local mainwin = app:mainWindow()
34 | if mainwin then
35 | if mainwin == window.focusedWindow() then
36 | mainwin:application():hide()
37 | else
38 | mainwin:application():activate(true)
39 | mainwin:application():unhide()
40 | mainwin:focus()
41 | end
42 | end
43 | end
--------------------------------------------------------------------------------
/README_zh-CN.md:
--------------------------------------------------------------------------------
1 | # Hammerspoon 配置
2 |
3 | ## 使用方法
4 |
5 | 1. 安装 [Hammerspoon](http://www.hammerspoon.org/)
6 | 2. `git clone https://github.com/greyby/hammerspoon.git ~/.hammerspoon`
7 |
8 | ## 快捷键图标
9 | | | 键位 |
10 | | --------- | -------------- |
11 | | ⇧ | Shift |
12 | | ⌃ | Control |
13 | | ⌥ | Option |
14 | | ⌘ | Command |
15 |
16 | ## 功能
17 |
18 | ### 窗口管理
19 |
20 | #### 1/2 屏幕
21 |
22 | * ⌃⌥⌘ + ← 将当前窗口移动到左半屏
23 | * ⌃⌥⌘ + → 将当前窗口移动到右半屏
24 | * ⌃⌥⌘ + ↑ 将当前窗口移动到上半屏
25 | * ⌃⌥⌘ + ↓ 将当前窗口移动到下半屏
26 |
27 | #### 1/4 屏幕
28 |
29 | * ⌃⌥⇧ + ← 将当前窗口移动到左上 1/4 屏
30 | * ⌃⌥⇧ + → 将当前窗口移动到右下 1/4 屏
31 | * ⌃⌥⇧ + ↑ 将当前窗口移动到右上 1/4 屏
32 | * ⌃⌥⇧ + ↓ 将当前窗口移动到左下 1/4 屏
33 |
34 | #### 多个显示器
35 |
36 | ##### 移动光标
37 |
38 | * ⌃⌥ + ← 把光标移动到下一个显示器
39 | * ⌃⌥ + → 把光标移动到上一个显示器
40 |
41 | ##### 移动窗口
42 |
43 | * ⇧⌥ + ← 将当前活动窗口移动到上一个显示器
44 | * ⇧⌥ + → 将当前活动窗口移动到下一个显示器
45 | * ⇧⌥ + 1 将当前活动窗口移动到第一个显示器并窗口最大化
46 | * ⇧⌥ + 2 将当前活动窗口移动到第二个显示器并窗口最大化
47 |
48 |
49 | #### 其它
50 |
51 | * ⌃⌥⌘ + F 全屏
52 | * ⌃⌥⌘ + M 最大化窗口
53 | * ⌃⌥⌘ + C 将窗口放到中间
54 | * ⇧⌥ + H 切换活动窗口
55 | * ⇧⌥ + / 显示窗口切换的快捷键
56 |
57 | ### 系统工具
58 |
59 | * ⌃⌥⌘ + L 锁屏
60 |
61 | ### 快速启动
62 |
63 | * ⌃⌥⌘ + I `IntelliJ IDEA CE`
64 | * ⌃⌥⌘ + C `Google Chrome`
65 | * ⌃⌥⌘ + K `iTerm`
66 | * ⌃⌥⌘ + D `Finder`
67 | * ⌃⌥⌘ + Y `Activity Monitor`
68 | * ⌃⌥⌘ + P `System Preferences`
69 | * ⌃⌥⌘ + V `Visual Studio Code`
70 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hammerspoon Configuration
2 |
3 | ## Usage
4 |
5 | 1. Install [Hammerspoon](http://www.hammerspoon.org/)
6 | 2. `git clone https://github.com/greyby/hammerspoon.git ~/.hammerspoon`
7 |
8 | ## Modifier keys
9 | | | Key |
10 | | --------- | -------------- |
11 | | ⇧ | Shift |
12 | | ⌃ | Control |
13 | | ⌥ | Option |
14 | | ⌘ | Command |
15 |
16 | ## Features
17 |
18 | ### Window Management
19 |
20 | #### Split Screen Actions
21 |
22 | * ⌃⌥⌘ + ← Left half
23 | * ⌃⌥⌘ + → Right half
24 | * ⌃⌥⌘ + ↑ Top half
25 | * ⌃⌥⌘ + ↓ Bottom half
26 |
27 | #### Quarter Screen Actions
28 |
29 | * ⌃⌥⇧ + ← Left top quarter
30 | * ⌃⌥⇧ + → Right bottom quarter
31 | * ⌃⌥⇧ + ↑ Right top quarter
32 | * ⌃⌥⇧ + ↓ Left bottom quarter
33 |
34 | #### Multiple Monitor
35 |
36 | ##### Move Cursor
37 |
38 | * ⌃⌥ + ← Move cursor to next monitor
39 | * ⌃⌥ + → Move cursor to previous monitor
40 |
41 | ##### Move Windows
42 |
43 | * ⇧⌥ + ← Move active window to previous monitor
44 | * ⇧⌥ + → Move active window to next monitor
45 | * ⇧⌥ + 1 Move active window to monitor 1 and maximize the window
46 | * ⇧⌥ + 2 Move active window to monitor 2 and maximize the window
47 |
48 |
49 | #### Other
50 |
51 | * ⌃⌥⌘ + F Full Screen
52 | * ⌃⌥⌘ + M Maximize Window
53 | * ⌃⌥⌘ + C Window Center
54 |
55 |
56 | * ⇧⌥ + H Switch active window
57 | * ⇧⌥ + / Display a keyboard hint for switching focus to each window
58 |
59 | ### System Tools
60 |
61 | * ⌃⌥⌘ + L Lock Screen
62 |
63 | ### Launch Application
64 |
65 | * ⌃⌥⌘ + I `IntelliJ IDEA CE`
66 | * ⌃⌥⌘ + C `Google Chrome`
67 | * ⌃⌥⌘ + K `iTerm`
68 | * ⌃⌥⌘ + D `Finder`
69 | * ⌃⌥⌘ + Y `Activity Monitor`
70 | * ⌃⌥⌘ + P `System Preferences`
--------------------------------------------------------------------------------
/modules/windows.lua:
--------------------------------------------------------------------------------
1 | -- window management
2 | local application = require "hs.application"
3 | local hotkey = require "hs.hotkey"
4 | local window = require "hs.window"
5 | local layout = require "hs.layout"
6 | local grid = require "hs.grid"
7 | local hints = require "hs.hints"
8 | local screen = require "hs.screen"
9 | local alert = require "hs.alert"
10 | local fnutils = require "hs.fnutils"
11 | local geometry = require "hs.geometry"
12 | local mouse = require "hs.mouse"
13 |
14 | -- default 0.2
15 | window.animationDuration = 0
16 |
17 | -- left half
18 | hotkey.bind(hyper, "Left", function()
19 | if window.focusedWindow() then
20 | window.focusedWindow():moveToUnit(layout.left50)
21 | else
22 | alert.show("No active window")
23 | end
24 | end)
25 |
26 | -- right half
27 | hotkey.bind(hyper, "Right", function()
28 | window.focusedWindow():moveToUnit(layout.right50)
29 | end)
30 |
31 | -- top half
32 | hotkey.bind(hyper, "Up", function()
33 | window.focusedWindow():moveToUnit'[0,0,100,50]'
34 | end)
35 |
36 | -- bottom half
37 | hotkey.bind(hyper, "Down", function()
38 | window.focusedWindow():moveToUnit'[0,50,100,100]'
39 | end)
40 |
41 | -- left top quarter
42 | hotkey.bind(hyperAlt, "Left", function()
43 | window.focusedWindow():moveToUnit'[0,0,50,50]'
44 | end)
45 |
46 | -- right bottom quarter
47 | hotkey.bind(hyperAlt, "Right", function()
48 | window.focusedWindow():moveToUnit'[50,50,100,100]'
49 | end)
50 |
51 | -- right top quarter
52 | hotkey.bind(hyperAlt, "Up", function()
53 | window.focusedWindow():moveToUnit'[50,0,100,50]'
54 | end)
55 |
56 | -- left bottom quarter
57 | hotkey.bind(hyperAlt, "Down", function()
58 | window.focusedWindow():moveToUnit'[0,50,50,100]'
59 | end)
60 |
61 | -- full screen
62 | hotkey.bind(hyper, 'F', function()
63 | window.focusedWindow():toggleFullScreen()
64 | end)
65 |
66 | -- center window
67 | hotkey.bind(hyper, 'C', function()
68 | window.focusedWindow():centerOnScreen()
69 | end)
70 |
71 | -- maximize window
72 | hotkey.bind(hyper, 'M', function() toggle_maximize() end)
73 |
74 | -- defines for window maximize toggler
75 | local frameCache = {}
76 | -- toggle a window between its normal size, and being maximized
77 | function toggle_maximize()
78 | local win = window.focusedWindow()
79 | if frameCache[win:id()] then
80 | win:setFrame(frameCache[win:id()])
81 | frameCache[win:id()] = nil
82 | else
83 | frameCache[win:id()] = win:frame()
84 | win:maximize()
85 | end
86 | end
87 |
88 | -- display a keyboard hint for switching focus to each window
89 | hotkey.bind(hyperShift, '/', function()
90 | hints.windowHints()
91 | -- Display current application window
92 | -- hints.windowHints(hs.window.focusedWindow():application():allWindows())
93 | end)
94 |
95 | -- switch active window
96 | hotkey.bind(hyperShift, "H", function()
97 | window.switcher.nextWindow()
98 | end)
99 |
100 | -- move active window to previous monitor
101 | hotkey.bind(hyperShift, "Left", function()
102 | window.focusedWindow():moveOneScreenWest()
103 | end)
104 |
105 | -- move active window to next monitor
106 | hotkey.bind(hyperShift, "Right", function()
107 | window.focusedWindow():moveOneScreenEast()
108 | end)
109 |
110 | -- move cursor to previous monitor
111 | hotkey.bind(hyperCtrl, "Left", function ()
112 | focusScreen(window.focusedWindow():screen():previous())
113 | end)
114 |
115 | -- move cursor to next monitor
116 | hotkey.bind(hyperCtrl, "Right", function ()
117 | focusScreen(window.focusedWindow():screen():next())
118 | end)
119 |
120 |
121 | --Predicate that checks if a window belongs to a screen
122 | function isInScreen(screen, win)
123 | return win:screen() == screen
124 | end
125 |
126 | function focusScreen(screen)
127 | --Get windows within screen, ordered from front to back.
128 | --If no windows exist, bring focus to desktop. Otherwise, set focus on
129 | --front-most application window.
130 | local windows = fnutils.filter(
131 | window.orderedWindows(),
132 | fnutils.partial(isInScreen, screen))
133 | local windowToFocus = #windows > 0 and windows[1] or window.desktop()
134 | windowToFocus:focus()
135 |
136 | -- move cursor to center of screen
137 | local pt = geometry.rectMidPoint(screen:fullFrame())
138 | mouse.setAbsolutePosition(pt)
139 | end
140 |
141 | -- maximized active window and move to selected monitor
142 | moveto = function(win, n)
143 | local screens = screen.allScreens()
144 | if n > #screens then
145 | alert.show("Only " .. #screens .. " monitors ")
146 | else
147 | local toWin = screen.allScreens()[n]:name()
148 | alert.show("Move " .. win:application():name() .. " to " .. toWin)
149 |
150 | layout.apply({{nil, win:title(), toWin, layout.maximized, nil, nil}})
151 |
152 | end
153 | end
154 |
155 | -- move cursor to monitor 1 and maximize the window
156 | hotkey.bind(hyperShift, "1", function()
157 | local win = window.focusedWindow()
158 | moveto(win, 1)
159 | end)
160 |
161 | hotkey.bind(hyperShift, "2", function()
162 | local win = window.focusedWindow()
163 | moveto(win, 2)
164 | end)
165 |
166 | hotkey.bind(hyperShift, "3", function()
167 | local win = window.focusedWindow()
168 | moveto(win, 3)
169 | end)
--------------------------------------------------------------------------------