hammerspoon: sync
This commit is contained in:
325
hammerspoon/.hammerspoon/init.lua
Normal file
325
hammerspoon/.hammerspoon/init.lua
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
--------------------------------------------------------------------------
|
||||||
|
hyperModeAppMappings = {
|
||||||
|
{ 'a', 'Alacritty' }, -- "A" for "Apple Music"
|
||||||
|
{ 's', 'Safari' }, -- "S" for "Safari"
|
||||||
|
{ 'c', 'Telegram' }, -- "C for "Chat"
|
||||||
|
{ 'd', 'Discord' }, -- "D for "Discord"
|
||||||
|
{ 'f', 'Finder' }, -- "F" for "Finder"
|
||||||
|
{ 'g', 'Mail' }, -- "G" for "Gmail"
|
||||||
|
{ 'z', 'Slack' }, -- "Z" for "zzz"
|
||||||
|
{ 'n', 'Notion' }, -- "N" for "Notion"
|
||||||
|
{ 'm', 'Music' }, -- "M" for "Music"
|
||||||
|
{ 'w', 'World of Warcraft Classic' }, -- "W" for "World of Warcraft"
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, mapping in ipairs(hyperModeAppMappings) do
|
||||||
|
local key = mapping[1]
|
||||||
|
local app = mapping[2]
|
||||||
|
hs.hotkey.bind({'shift', 'ctrl', 'alt', 'cmd'}, key, function()
|
||||||
|
if (type(app) == 'string') then
|
||||||
|
hs.application.open(app)
|
||||||
|
elseif (type(app) == 'function') then
|
||||||
|
app()
|
||||||
|
else
|
||||||
|
hs.logger.new('hyper'):e('Invalid mapping for Hyper +', key)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
hs.window.animationDuration = 0
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | | |
|
||||||
|
-- | HERE | |
|
||||||
|
-- | | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.left(win)
|
||||||
|
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
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | | |
|
||||||
|
-- | | HERE |
|
||||||
|
-- | | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.right(win)
|
||||||
|
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
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | HERE |
|
||||||
|
-- +-----------------+
|
||||||
|
-- | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.up(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:frame()
|
||||||
|
|
||||||
|
f.x = max.x
|
||||||
|
f.w = max.w
|
||||||
|
f.y = max.y
|
||||||
|
f.h = max.h / 2
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | |
|
||||||
|
-- +-----------------+
|
||||||
|
-- | HERE |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.down(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:frame()
|
||||||
|
|
||||||
|
f.x = max.x
|
||||||
|
f.w = max.w
|
||||||
|
f.y = max.y + (max.h / 2)
|
||||||
|
f.h = max.h / 2
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | HERE | |
|
||||||
|
-- +--------+ |
|
||||||
|
-- | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.upLeft(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:fullFrame()
|
||||||
|
|
||||||
|
f.x = max.x
|
||||||
|
f.y = max.y
|
||||||
|
f.w = max.w/2
|
||||||
|
f.h = max.h/2
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | |
|
||||||
|
-- +--------+ |
|
||||||
|
-- | HERE | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.downLeft(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:fullFrame()
|
||||||
|
|
||||||
|
f.x = max.x
|
||||||
|
f.y = max.y + (max.h / 2)
|
||||||
|
f.w = max.w/2
|
||||||
|
f.h = max.h/2
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | |
|
||||||
|
-- | +--------|
|
||||||
|
-- | | HERE |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.downRight(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:fullFrame()
|
||||||
|
|
||||||
|
f.x = max.x + (max.w / 2)
|
||||||
|
f.y = max.y + (max.h / 2)
|
||||||
|
f.w = max.w/2
|
||||||
|
f.h = max.h/2
|
||||||
|
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | | HERE |
|
||||||
|
-- | +--------|
|
||||||
|
-- | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.upRight(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:fullFrame()
|
||||||
|
|
||||||
|
f.x = max.x + (max.w / 2)
|
||||||
|
f.y = max.y
|
||||||
|
f.w = max.w/2
|
||||||
|
f.h = max.h/2
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +--------------+
|
||||||
|
-- | | | |
|
||||||
|
-- | | HERE | |
|
||||||
|
-- | | | |
|
||||||
|
-- +---------------+
|
||||||
|
function hs.window.centerWithFullHeight(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:fullFrame()
|
||||||
|
|
||||||
|
f.x = max.x + (max.w / 5)
|
||||||
|
f.w = max.w * 3/5
|
||||||
|
f.y = max.y
|
||||||
|
f.h = max.h
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | | |
|
||||||
|
-- | HERE | |
|
||||||
|
-- | | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.left40(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:frame()
|
||||||
|
|
||||||
|
f.x = max.x
|
||||||
|
f.y = max.y
|
||||||
|
f.w = max.w * 0.4
|
||||||
|
f.h = max.h
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | | |
|
||||||
|
-- | | HERE |
|
||||||
|
-- | | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.right60(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:frame()
|
||||||
|
|
||||||
|
f.x = max.x + (max.w * 0.4)
|
||||||
|
f.y = max.y
|
||||||
|
f.w = max.w * 0.6
|
||||||
|
f.h = max.h
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
function hs.window.nextScreen(win)
|
||||||
|
local currentScreen = win:screen()
|
||||||
|
local allScreens = hs.screen.allScreens()
|
||||||
|
currentScreenIndex = hs.fnutils.indexOf(allScreens, currentScreen)
|
||||||
|
nextScreenIndex = currentScreenIndex + 1
|
||||||
|
|
||||||
|
if allScreens[nextScreenIndex] then
|
||||||
|
win:moveToScreen(allScreens[nextScreenIndex])
|
||||||
|
else
|
||||||
|
win:moveToScreen(allScreens[1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
windowLayoutMode = hs.hotkey.modal.new({}, 'F16')
|
||||||
|
|
||||||
|
windowLayoutMode.entered = function()
|
||||||
|
windowLayoutMode.statusMessage:show()
|
||||||
|
end
|
||||||
|
windowLayoutMode.exited = function()
|
||||||
|
windowLayoutMode.statusMessage:hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Bind the given key to call the given function and exit WindowLayout mode
|
||||||
|
function windowLayoutMode.bindWithAutomaticExit(mode, modifiers, key, fn)
|
||||||
|
mode:bind(modifiers, key, function()
|
||||||
|
mode:exit()
|
||||||
|
fn()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local status, windowMappings = pcall(require, 'keyboard.windows-bindings')
|
||||||
|
|
||||||
|
-- if not status then
|
||||||
|
-- windowMappings = require('keyboard.windows-bindings-defaults')
|
||||||
|
-- end
|
||||||
|
|
||||||
|
local windowMappings = {
|
||||||
|
modifiers = {'ctrl'},
|
||||||
|
showHelp = false,
|
||||||
|
trigger = 's',
|
||||||
|
mappings = {
|
||||||
|
{ {}, 'return', 'maximize' },
|
||||||
|
{ {}, 'space', 'centerWithFullHeight' },
|
||||||
|
{ {}, 'h', 'left' },
|
||||||
|
{ {}, 'j', 'down' },
|
||||||
|
{ {}, 'k', 'up' },
|
||||||
|
{ {}, 'l', 'right' },
|
||||||
|
{ {'shift'}, 'h', 'left40' },
|
||||||
|
{ {'shift'}, 'l', 'right60' },
|
||||||
|
{ {}, 'i', 'upLeft' },
|
||||||
|
{ {}, 'o', 'upRight' },
|
||||||
|
{ {}, ',', 'downLeft' },
|
||||||
|
{ {}, '.', 'downRight' },
|
||||||
|
{ {}, 'n', 'nextScreen' },
|
||||||
|
{ {}, 'right', 'moveOneScreenEast' },
|
||||||
|
{ {}, 'left', 'moveOneScreenWest' },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local modifiers = windowMappings.modifiers
|
||||||
|
local showHelp = windowMappings.showHelp
|
||||||
|
local trigger = windowMappings.trigger
|
||||||
|
local mappings = windowMappings.mappings
|
||||||
|
|
||||||
|
function getModifiersStr(modifiers)
|
||||||
|
local modMap = { shift = '⇧', ctrl = '⌃', alt = '⌥', cmd = '⌘' }
|
||||||
|
local retVal = ''
|
||||||
|
|
||||||
|
for i, v in ipairs(modifiers) do
|
||||||
|
retVal = retVal .. modMap[v]
|
||||||
|
end
|
||||||
|
|
||||||
|
return retVal
|
||||||
|
end
|
||||||
|
|
||||||
|
local msgStr = getModifiersStr(modifiers)
|
||||||
|
msgStr = 'Window Layout Mode (' .. msgStr .. (string.len(msgStr) > 0 and '+' or '') .. trigger .. ')'
|
||||||
|
|
||||||
|
for i, mapping in ipairs(mappings) do
|
||||||
|
local modifiers, trigger, winFunction = table.unpack(mapping)
|
||||||
|
local hotKeyStr = getModifiersStr(modifiers)
|
||||||
|
|
||||||
|
if showHelp == true then
|
||||||
|
if string.len(hotKeyStr) > 0 then
|
||||||
|
msgStr = msgStr .. (string.format('\n%10s+%s => %s', hotKeyStr, trigger, winFunction))
|
||||||
|
else
|
||||||
|
msgStr = msgStr .. (string.format('\n%11s => %s', trigger, winFunction))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
windowLayoutMode:bindWithAutomaticExit(modifiers, trigger, function()
|
||||||
|
--example: hs.window.focusedWindow():upRight()
|
||||||
|
local fw = hs.window.focusedWindow()
|
||||||
|
fw[winFunction](fw)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local message = require('keyboard.status-message')
|
||||||
|
windowLayoutMode.statusMessage = message.new(msgStr)
|
||||||
|
|
||||||
|
-- Use modifiers+trigger to toggle WindowLayout Mode
|
||||||
|
hs.hotkey.bind(modifiers, trigger, function()
|
||||||
|
windowLayoutMode:enter()
|
||||||
|
end)
|
||||||
|
windowLayoutMode:bind(modifiers, trigger, function()
|
||||||
|
windowLayoutMode:exit()
|
||||||
|
end)
|
||||||
43
hammerspoon/.hammerspoon/keyboard/control-escape.lua
Normal file
43
hammerspoon/.hammerspoon/keyboard/control-escape.lua
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
-- Credit for this implementation goes to @arbelt and @jasoncodes 🙇⚡️😻
|
||||||
|
--
|
||||||
|
-- https://gist.github.com/arbelt/b91e1f38a0880afb316dd5b5732759f1
|
||||||
|
-- https://github.com/jasoncodes/dotfiles/blob/ac9f3ac/hammerspoon/control_escape.lua
|
||||||
|
|
||||||
|
sendEscape = false
|
||||||
|
lastMods = {}
|
||||||
|
|
||||||
|
ctrlKeyHandler = function()
|
||||||
|
sendEscape = false
|
||||||
|
end
|
||||||
|
|
||||||
|
ctrlKeyTimer = hs.timer.delayed.new(0.15, ctrlKeyHandler)
|
||||||
|
|
||||||
|
ctrlHandler = function(evt)
|
||||||
|
local newMods = evt:getFlags()
|
||||||
|
if lastMods["ctrl"] == newMods["ctrl"] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if not lastMods["ctrl"] then
|
||||||
|
lastMods = newMods
|
||||||
|
sendEscape = true
|
||||||
|
ctrlKeyTimer:start()
|
||||||
|
else
|
||||||
|
if sendEscape then
|
||||||
|
keyUpDown({}, 'escape')
|
||||||
|
end
|
||||||
|
lastMods = newMods
|
||||||
|
ctrlKeyTimer:stop()
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
ctrlTap = hs.eventtap.new({hs.eventtap.event.types.flagsChanged}, ctrlHandler)
|
||||||
|
ctrlTap:start()
|
||||||
|
|
||||||
|
otherHandler = function(evt)
|
||||||
|
sendEscape = false
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
otherTap = hs.eventtap.new({hs.eventtap.event.types.keyDown}, otherHandler)
|
||||||
|
otherTap:start()
|
||||||
70
hammerspoon/.hammerspoon/keyboard/delete-words.lua
Normal file
70
hammerspoon/.hammerspoon/keyboard/delete-words.lua
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
local log = hs.logger.new('delete-words.lua', 'debug')
|
||||||
|
|
||||||
|
local isInTerminal = function()
|
||||||
|
app = hs.application.frontmostApplication():name()
|
||||||
|
return app == 'iTerm2' or app == 'Terminal'
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Use option + h to delete previous word
|
||||||
|
hs.hotkey.bind({'alt'}, 'h', function()
|
||||||
|
if isInTerminal() then
|
||||||
|
keyUpDown({'ctrl'}, 'w')
|
||||||
|
else
|
||||||
|
keyUpDown({'alt'}, 'delete')
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Use option + l to delete next word
|
||||||
|
hs.hotkey.bind({'alt'}, 'l', function()
|
||||||
|
if isInTerminal() then
|
||||||
|
keyUpDown({}, 'escape')
|
||||||
|
keyUpDown({}, 'd')
|
||||||
|
else
|
||||||
|
keyUpDown({'alt'}, 'forwarddelete')
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Use control + u to delete to beginning of line
|
||||||
|
--
|
||||||
|
-- In bash, control + u automatically deletes to the beginning of the line, so
|
||||||
|
-- we don't need (or want) this hotkey in the terminal. If this hotkey was
|
||||||
|
-- enabled in the terminal, it would break the standard control + u behavior.
|
||||||
|
-- Therefore, we only enable this hotkey for non-terminal apps.
|
||||||
|
local wf = hs.window.filter.new():setFilters({iTerm2 = false, Terminal = false})
|
||||||
|
enableHotkeyForWindowsMatchingFilter(wf, hs.hotkey.new({'ctrl'}, 'u', function()
|
||||||
|
keyUpDown({'cmd'}, 'delete')
|
||||||
|
end))
|
||||||
|
|
||||||
|
-- Use control + ; to delete to end of line
|
||||||
|
--
|
||||||
|
-- I prefer to use control+h/j/k/l to move left/down/up/right by one pane in all
|
||||||
|
-- multi-pane apps (e.g., iTerm, various editors). That's convenient and
|
||||||
|
-- consistent, but it conflicts with the default macOS binding for deleting to
|
||||||
|
-- the end of the line (i.e., control+k). To maintain that very useful
|
||||||
|
-- functionality, and to keep it on the home row, this hotkey binds control+; to
|
||||||
|
-- delete to the end of the line.
|
||||||
|
hs.hotkey.bind({'ctrl'}, ';', function()
|
||||||
|
-- If we're in the terminal, then temporarily disable our custom control+k
|
||||||
|
-- hotkey used for pane navigation, then fire control+k to delete to the end
|
||||||
|
-- of the line, and then renable the control+k hotkey.
|
||||||
|
--
|
||||||
|
-- If we're not in the terminal, then just select to the end of the line and
|
||||||
|
-- then delete the selected text.
|
||||||
|
if isInTerminal() then
|
||||||
|
hotkeyForControlK = hs.fnutils.find(hs.hotkey.getHotkeys(), function(hotkey)
|
||||||
|
return hotkey.idx == '⌃K'
|
||||||
|
end)
|
||||||
|
if hotkeyForControlK then hotkeyForControlK:disable() end
|
||||||
|
|
||||||
|
keyUpDown({'ctrl'}, 'k')
|
||||||
|
|
||||||
|
-- Allow some time for the control+k keystroke to fire asynchronously before
|
||||||
|
-- we re-enable our custom control+k hotkey.
|
||||||
|
hs.timer.doAfter(0.2, function()
|
||||||
|
if hotkeyForControlK then hotkeyForControlK:enable() end
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
keyUpDown({'cmd', 'shift'}, 'right')
|
||||||
|
keyUpDown({}, 'forwarddelete')
|
||||||
|
end
|
||||||
|
end)
|
||||||
14
hammerspoon/.hammerspoon/keyboard/hyper-apps-defaults.lua
Normal file
14
hammerspoon/.hammerspoon/keyboard/hyper-apps-defaults.lua
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
-- Default keybindings for launching apps in Hyper Mode
|
||||||
|
--
|
||||||
|
-- To launch _your_ most commonly-used apps via Hyper Mode, create a copy of
|
||||||
|
-- this file, save it as `hyper-apps.lua`, and edit the table below to configure
|
||||||
|
-- your preferred shortcuts.
|
||||||
|
return {
|
||||||
|
{ 'a', 'Alacritty' }, -- "A" for "Apple Music"
|
||||||
|
{ 's', 'Safari' }, -- "B" for "Browser"
|
||||||
|
{ 'c', 'Telegram' }, -- "C for "Chat"
|
||||||
|
{ 'f', 'Finder' }, -- "F" for "Finder"
|
||||||
|
{ 'g', 'Mail' }, -- "G" for "Gmail"
|
||||||
|
{ 'z', 'Slack' }, -- "S" for "Slack"
|
||||||
|
-- { 't', 'Telegram' }, -- "T" for "Terminal"
|
||||||
|
}
|
||||||
19
hammerspoon/.hammerspoon/keyboard/hyper.lua
Normal file
19
hammerspoon/.hammerspoon/keyboard/hyper.lua
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
local status, hyperModeAppMappings = pcall(require, 'keyboard.hyper-apps')
|
||||||
|
|
||||||
|
if not status then
|
||||||
|
hyperModeAppMappings = require('keyboard.hyper-apps-defaults')
|
||||||
|
end
|
||||||
|
|
||||||
|
for i, mapping in ipairs(hyperModeAppMappings) do
|
||||||
|
local key = mapping[1]
|
||||||
|
local app = mapping[2]
|
||||||
|
hs.hotkey.bind({'shift', 'ctrl', 'alt', 'cmd'}, key, function()
|
||||||
|
if (type(app) == 'string') then
|
||||||
|
hs.application.open(app)
|
||||||
|
elseif (type(app) == 'function') then
|
||||||
|
app()
|
||||||
|
else
|
||||||
|
hs.logger.new('hyper'):e('Invalid mapping for Hyper +', key)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
42
hammerspoon/.hammerspoon/keyboard/init.lua
Normal file
42
hammerspoon/.hammerspoon/keyboard/init.lua
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
local log = hs.logger.new('init.lua', 'debug')
|
||||||
|
|
||||||
|
-- Use Control+` to reload Hammerspoon config
|
||||||
|
hs.hotkey.bind({'ctrl'}, '`', nil, function()
|
||||||
|
hs.reload()
|
||||||
|
end)
|
||||||
|
|
||||||
|
keyUpDown = function(modifiers, key)
|
||||||
|
-- Un-comment & reload config to log each keystroke that we're triggering
|
||||||
|
-- log.d('Sending keystroke:', hs.inspect(modifiers), key)
|
||||||
|
|
||||||
|
hs.eventtap.keyStroke(modifiers, key, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Subscribe to the necessary events on the given window filter such that the
|
||||||
|
-- given hotkey is enabled for windows that match the window filter and disabled
|
||||||
|
-- for windows that don't match the window filter.
|
||||||
|
--
|
||||||
|
-- windowFilter - An hs.window.filter object describing the windows for which
|
||||||
|
-- the hotkey should be enabled.
|
||||||
|
-- hotkey - The hs.hotkey object to enable/disable.
|
||||||
|
--
|
||||||
|
-- Returns nothing.
|
||||||
|
enableHotkeyForWindowsMatchingFilter = function(windowFilter, hotkey)
|
||||||
|
windowFilter:subscribe(hs.window.filter.windowFocused, function()
|
||||||
|
hotkey:enable()
|
||||||
|
end)
|
||||||
|
|
||||||
|
windowFilter:subscribe(hs.window.filter.windowUnfocused, function()
|
||||||
|
hotkey:disable()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
require('keyboard.control-escape')
|
||||||
|
require('keyboard.delete-words')
|
||||||
|
require('keyboard.hyper')
|
||||||
|
require('keyboard.markdown')
|
||||||
|
require('keyboard.microphone')
|
||||||
|
require('keyboard.panes')
|
||||||
|
require('keyboard.windows')
|
||||||
|
|
||||||
|
hs.notify.new({title='Hammerspoon', informativeText='Ready to rock 🤘'}):send()
|
||||||
112
hammerspoon/.hammerspoon/keyboard/markdown.lua
Normal file
112
hammerspoon/.hammerspoon/keyboard/markdown.lua
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
function wrapSelectedText(wrapCharacters)
|
||||||
|
-- Preserve the current contents of the system clipboard
|
||||||
|
local originalClipboardContents = hs.pasteboard.getContents()
|
||||||
|
|
||||||
|
-- Copy the currently-selected text to the system clipboard
|
||||||
|
keyUpDown('cmd', 'c')
|
||||||
|
|
||||||
|
-- Allow some time for the command+c keystroke to fire asynchronously before
|
||||||
|
-- we try to read from the clipboard
|
||||||
|
hs.timer.doAfter(0.2, function()
|
||||||
|
-- Construct the formatted output and paste it over top of the
|
||||||
|
-- currently-selected text
|
||||||
|
local selectedText = hs.pasteboard.getContents()
|
||||||
|
local wrappedText = wrapCharacters .. selectedText .. wrapCharacters
|
||||||
|
hs.pasteboard.setContents(wrappedText)
|
||||||
|
keyUpDown('cmd', 'v')
|
||||||
|
|
||||||
|
-- Allow some time for the command+v keystroke to fire asynchronously before
|
||||||
|
-- we restore the original clipboard
|
||||||
|
hs.timer.doAfter(0.2, function()
|
||||||
|
hs.pasteboard.setContents(originalClipboardContents)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function inlineLink()
|
||||||
|
-- Fetch URL from the system clipboard
|
||||||
|
local linkUrl = hs.pasteboard.getContents()
|
||||||
|
|
||||||
|
-- Copy the currently-selected text to use as the link text
|
||||||
|
keyUpDown('cmd', 'c')
|
||||||
|
|
||||||
|
-- Allow some time for the command+c keystroke to fire asynchronously before
|
||||||
|
-- we try to read from the clipboard
|
||||||
|
hs.timer.doAfter(0.2, function()
|
||||||
|
-- Construct the formatted output and paste it over top of the
|
||||||
|
-- currently-selected text
|
||||||
|
local linkText = hs.pasteboard.getContents()
|
||||||
|
local markdown = '[' .. linkText .. '](' .. linkUrl .. ')'
|
||||||
|
hs.pasteboard.setContents(markdown)
|
||||||
|
keyUpDown('cmd', 'v')
|
||||||
|
|
||||||
|
-- Allow some time for the command+v keystroke to fire asynchronously before
|
||||||
|
-- we restore the original clipboard
|
||||||
|
hs.timer.doAfter(0.2, function()
|
||||||
|
hs.pasteboard.setContents(linkUrl)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Define Markdown Mode
|
||||||
|
--
|
||||||
|
-- Markdown Mode allows you to perform common Markdown-formatting tasks anywhere
|
||||||
|
-- that you're editing text. Use Control+m to turn on Markdown mode. Then, use
|
||||||
|
-- any shortcut below to perform a formatting action. For example, to format the
|
||||||
|
-- selected text as bold in Markdown, hit Control+m, and then b.
|
||||||
|
--
|
||||||
|
-- b => wrap the selected text in double asterisks ("b" for "bold")
|
||||||
|
-- c => wrap the selected text in backticks ("c" for "code")
|
||||||
|
-- i => wrap the selected text in single asterisks ("i" for "italic")
|
||||||
|
-- s => wrap the selected text in double tildes ("s" for "strikethrough")
|
||||||
|
-- l => convert the currently-selected text to an inline link, using a URL
|
||||||
|
-- from the clipboard ("l" for "link")
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
markdownMode = hs.hotkey.modal.new({}, 'F20')
|
||||||
|
|
||||||
|
local message = require('keyboard.status-message')
|
||||||
|
markdownMode.statusMessage = message.new('Markdown Mode (control-m)')
|
||||||
|
markdownMode.entered = function()
|
||||||
|
markdownMode.statusMessage:show()
|
||||||
|
end
|
||||||
|
markdownMode.exited = function()
|
||||||
|
markdownMode.statusMessage:hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Bind the given key to call the given function and exit Markdown mode
|
||||||
|
function markdownMode.bindWithAutomaticExit(mode, key, fn)
|
||||||
|
mode:bind({}, key, function()
|
||||||
|
mode:exit()
|
||||||
|
fn()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
markdownMode:bindWithAutomaticExit('b', function()
|
||||||
|
wrapSelectedText('**')
|
||||||
|
end)
|
||||||
|
|
||||||
|
markdownMode:bindWithAutomaticExit('i', function()
|
||||||
|
wrapSelectedText('*')
|
||||||
|
end)
|
||||||
|
|
||||||
|
markdownMode:bindWithAutomaticExit('s', function()
|
||||||
|
wrapSelectedText('~~')
|
||||||
|
end)
|
||||||
|
|
||||||
|
markdownMode:bindWithAutomaticExit('l', function()
|
||||||
|
inlineLink()
|
||||||
|
end)
|
||||||
|
|
||||||
|
markdownMode:bindWithAutomaticExit('c', function()
|
||||||
|
wrapSelectedText('`')
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Use Control+m to toggle Markdown Mode
|
||||||
|
hs.hotkey.bind({'ctrl'}, 'm', function()
|
||||||
|
markdownMode:enter()
|
||||||
|
end)
|
||||||
|
markdownMode:bind({'ctrl'}, 'm', function()
|
||||||
|
markdownMode:exit()
|
||||||
|
end)
|
||||||
60
hammerspoon/.hammerspoon/keyboard/microphone.lua
Normal file
60
hammerspoon/.hammerspoon/keyboard/microphone.lua
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
local message = require('keyboard.status-message')
|
||||||
|
|
||||||
|
local messageMuting = message.new('muted 🎤')
|
||||||
|
local messageHot = message.new('hot 🎤')
|
||||||
|
local lastMods = {}
|
||||||
|
local recentlyClicked = false
|
||||||
|
local secondClick = false
|
||||||
|
|
||||||
|
displayStatus = function()
|
||||||
|
-- Check if the active mic is muted
|
||||||
|
if hs.audiodevice.defaultInputDevice():muted() then
|
||||||
|
messageMuting:notify()
|
||||||
|
else
|
||||||
|
messageHot:notify()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
displayStatus()
|
||||||
|
|
||||||
|
toggle = function(device)
|
||||||
|
if device:muted() then
|
||||||
|
device:setMuted(false)
|
||||||
|
else
|
||||||
|
device:setMuted(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
fnKeyHandler = function()
|
||||||
|
recentlyClicked = false
|
||||||
|
end
|
||||||
|
|
||||||
|
controlKeyTimer = hs.timer.delayed.new(0.3, fnKeyHandler)
|
||||||
|
|
||||||
|
fnHandler = function(event)
|
||||||
|
local device = hs.audiodevice.defaultInputDevice()
|
||||||
|
local newMods = event:getFlags()
|
||||||
|
|
||||||
|
-- fn keyDown
|
||||||
|
if newMods['fn'] == true then
|
||||||
|
toggle(device)
|
||||||
|
if recentlyClicked == true then
|
||||||
|
displayStatus()
|
||||||
|
secondClick = true
|
||||||
|
end
|
||||||
|
recentlyClicked = true
|
||||||
|
controlKeyTimer:start()
|
||||||
|
|
||||||
|
-- fn keyUp
|
||||||
|
elseif lastMods['fn'] == true and newMods['fn'] == nil then
|
||||||
|
if secondClick then
|
||||||
|
secondClick = false
|
||||||
|
else
|
||||||
|
toggle(device)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
lastMods = newMods
|
||||||
|
end
|
||||||
|
|
||||||
|
fnKey = hs.eventtap.new({hs.eventtap.event.types.flagsChanged}, fnHandler)
|
||||||
|
fnKey:start()
|
||||||
43
hammerspoon/.hammerspoon/keyboard/panes.lua
Normal file
43
hammerspoon/.hammerspoon/keyboard/panes.lua
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
local itermHotkeyMappings = {
|
||||||
|
-- Use control + dash to split panes horizontally
|
||||||
|
{
|
||||||
|
from = {{'ctrl'}, '-'},
|
||||||
|
to = {{'cmd', 'shift'}, 'd'}
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Use control + pipe to split panes vertically
|
||||||
|
{
|
||||||
|
from = {{'ctrl', 'shift'}, '\\'},
|
||||||
|
to = {{'cmd'}, 'd'}
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Use control + h/j/k/l to move left/down/up/right by one pane
|
||||||
|
{
|
||||||
|
from = {{'ctrl'}, 'h'},
|
||||||
|
to = {{'cmd', 'alt'}, 'left'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from = {{'ctrl'}, 'j'},
|
||||||
|
to = {{'cmd', 'alt'}, 'down'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from = {{'ctrl'}, 'k'},
|
||||||
|
to = {{'cmd', 'alt'}, 'up'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from = {{'ctrl'}, 'l'},
|
||||||
|
to = {{'cmd', 'alt'}, 'right'}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local terminalWindowFilter = hs.window.filter.new('iTerm2')
|
||||||
|
local itermHotkeys = hs.fnutils.each(itermHotkeyMappings, function(mapping)
|
||||||
|
local fromMods = mapping['from'][1]
|
||||||
|
local fromKey = mapping['from'][2]
|
||||||
|
local toMods = mapping['to'][1]
|
||||||
|
local toKey = mapping['to'][2]
|
||||||
|
local hotkey = hs.hotkey.new(fromMods, fromKey, function()
|
||||||
|
keyUpDown(toMods, toKey)
|
||||||
|
end)
|
||||||
|
enableHotkeyForWindowsMatchingFilter(terminalWindowFilter, hotkey)
|
||||||
|
end)
|
||||||
67
hammerspoon/.hammerspoon/keyboard/status-message.lua
Normal file
67
hammerspoon/.hammerspoon/keyboard/status-message.lua
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
local drawing = require 'hs.drawing'
|
||||||
|
local geometry = require 'hs.geometry'
|
||||||
|
local screen = require 'hs.screen'
|
||||||
|
local styledtext = require 'hs.styledtext'
|
||||||
|
|
||||||
|
local statusmessage = {}
|
||||||
|
statusmessage.new = function(messageText)
|
||||||
|
local buildParts = function(messageText)
|
||||||
|
local frame = screen.primaryScreen():frame()
|
||||||
|
|
||||||
|
local styledTextAttributes = {
|
||||||
|
font = { name = 'Monaco', size = 24 },
|
||||||
|
}
|
||||||
|
|
||||||
|
local styledText = styledtext.new('🔨 ' .. messageText, styledTextAttributes)
|
||||||
|
|
||||||
|
local styledTextSize = drawing.getTextDrawingSize(styledText)
|
||||||
|
local textRect = {
|
||||||
|
x = frame.w - styledTextSize.w - 40,
|
||||||
|
y = frame.h - styledTextSize.h,
|
||||||
|
w = styledTextSize.w + 40,
|
||||||
|
h = styledTextSize.h + 40,
|
||||||
|
}
|
||||||
|
local text = drawing.text(textRect, styledText):setAlpha(0.7)
|
||||||
|
|
||||||
|
local background = drawing.rectangle(
|
||||||
|
{
|
||||||
|
x = frame.w - styledTextSize.w - 45,
|
||||||
|
y = frame.h - styledTextSize.h - 3,
|
||||||
|
w = styledTextSize.w + 15,
|
||||||
|
h = styledTextSize.h + 6
|
||||||
|
}
|
||||||
|
)
|
||||||
|
background:setRoundedRectRadii(10, 10)
|
||||||
|
background:setFillColor({ red = 0, green = 0, blue = 0, alpha=0.6 })
|
||||||
|
|
||||||
|
return background, text
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
_buildParts = buildParts,
|
||||||
|
show = function(self)
|
||||||
|
self:hide()
|
||||||
|
|
||||||
|
self.background, self.text = self._buildParts(messageText)
|
||||||
|
self.background:show()
|
||||||
|
self.text:show()
|
||||||
|
end,
|
||||||
|
hide = function(self)
|
||||||
|
if self.background then
|
||||||
|
self.background:delete()
|
||||||
|
self.background = nil
|
||||||
|
end
|
||||||
|
if self.text then
|
||||||
|
self.text:delete()
|
||||||
|
self.text = nil
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
notify = function(self, seconds)
|
||||||
|
local seconds = seconds or 1
|
||||||
|
self:show()
|
||||||
|
hs.timer.delayed.new(seconds, function() self:hide() end):start()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return statusmessage
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
-- Default keybindings for WindowLayout Mode
|
||||||
|
--
|
||||||
|
-- To customize the key bindings for WindowLayout Mode, create a copy of this
|
||||||
|
-- file, save it as `windows-bindings.lua`, and edit the table below to
|
||||||
|
-- configure your preferred shortcuts.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Define WindowLayout Mode
|
||||||
|
--
|
||||||
|
-- WindowLayout Mode allows you to manage window layout using keyboard shortcuts
|
||||||
|
-- that are on the home row, or very close to it. Use Control+s to turn
|
||||||
|
-- on WindowLayout mode. Then, use any shortcut below to perform a window layout
|
||||||
|
-- action. For example, to send the window left, press and release
|
||||||
|
-- Control+s, and then press h.
|
||||||
|
--
|
||||||
|
-- h/j/k/l => send window to the left/bottom/top/right half of the screen
|
||||||
|
-- i => send window to the upper left quarter of the screen
|
||||||
|
-- o => send window to the upper right quarter of the screen
|
||||||
|
-- , => send window to the lower left quarter of the screen
|
||||||
|
-- . => send window to the lower right quarter of the screen
|
||||||
|
-- return => make window full screen
|
||||||
|
-- n => send window to the next monitor
|
||||||
|
-- left => send window to the monitor on the left (if there is one)
|
||||||
|
-- right => send window to the monitor on the right (if there is one)
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
return {
|
||||||
|
modifiers = {'ctrl'},
|
||||||
|
showHelp = false,
|
||||||
|
trigger = 's',
|
||||||
|
mappings = {
|
||||||
|
{ {}, 'return', 'maximize' },
|
||||||
|
{ {}, 'space', 'centerWithFullHeight' },
|
||||||
|
{ {}, 'h', 'left' },
|
||||||
|
{ {}, 'j', 'down' },
|
||||||
|
{ {}, 'k', 'up' },
|
||||||
|
{ {}, 'l', 'right' },
|
||||||
|
{ {'shift'}, 'h', 'left40' },
|
||||||
|
{ {'shift'}, 'l', 'right60' },
|
||||||
|
{ {}, 'i', 'upLeft' },
|
||||||
|
{ {}, 'o', 'upRight' },
|
||||||
|
{ {}, ',', 'downLeft' },
|
||||||
|
{ {}, '.', 'downRight' },
|
||||||
|
{ {}, 'n', 'nextScreen' },
|
||||||
|
{ {}, 'right', 'moveOneScreenEast' },
|
||||||
|
{ {}, 'left', 'moveOneScreenWest' },
|
||||||
|
}
|
||||||
|
}
|
||||||
274
hammerspoon/.hammerspoon/keyboard/windows.lua
Normal file
274
hammerspoon/.hammerspoon/keyboard/windows.lua
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
hs.window.animationDuration = 0
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | | |
|
||||||
|
-- | HERE | |
|
||||||
|
-- | | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.left(win)
|
||||||
|
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
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | | |
|
||||||
|
-- | | HERE |
|
||||||
|
-- | | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.right(win)
|
||||||
|
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
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | HERE |
|
||||||
|
-- +-----------------+
|
||||||
|
-- | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.up(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:frame()
|
||||||
|
|
||||||
|
f.x = max.x
|
||||||
|
f.w = max.w
|
||||||
|
f.y = max.y
|
||||||
|
f.h = max.h / 2
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | |
|
||||||
|
-- +-----------------+
|
||||||
|
-- | HERE |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.down(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:frame()
|
||||||
|
|
||||||
|
f.x = max.x
|
||||||
|
f.w = max.w
|
||||||
|
f.y = max.y + (max.h / 2)
|
||||||
|
f.h = max.h / 2
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | HERE | |
|
||||||
|
-- +--------+ |
|
||||||
|
-- | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.upLeft(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:fullFrame()
|
||||||
|
|
||||||
|
f.x = max.x
|
||||||
|
f.y = max.y
|
||||||
|
f.w = max.w/2
|
||||||
|
f.h = max.h/2
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | |
|
||||||
|
-- +--------+ |
|
||||||
|
-- | HERE | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.downLeft(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:fullFrame()
|
||||||
|
|
||||||
|
f.x = max.x
|
||||||
|
f.y = max.y + (max.h / 2)
|
||||||
|
f.w = max.w/2
|
||||||
|
f.h = max.h/2
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | |
|
||||||
|
-- | +--------|
|
||||||
|
-- | | HERE |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.downRight(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:fullFrame()
|
||||||
|
|
||||||
|
f.x = max.x + (max.w / 2)
|
||||||
|
f.y = max.y + (max.h / 2)
|
||||||
|
f.w = max.w/2
|
||||||
|
f.h = max.h/2
|
||||||
|
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | | HERE |
|
||||||
|
-- | +--------|
|
||||||
|
-- | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.upRight(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:fullFrame()
|
||||||
|
|
||||||
|
f.x = max.x + (max.w / 2)
|
||||||
|
f.y = max.y
|
||||||
|
f.w = max.w/2
|
||||||
|
f.h = max.h/2
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +--------------+
|
||||||
|
-- | | | |
|
||||||
|
-- | | HERE | |
|
||||||
|
-- | | | |
|
||||||
|
-- +---------------+
|
||||||
|
function hs.window.centerWithFullHeight(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:fullFrame()
|
||||||
|
|
||||||
|
f.x = max.x + (max.w / 5)
|
||||||
|
f.w = max.w * 3/5
|
||||||
|
f.y = max.y
|
||||||
|
f.h = max.h
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | | |
|
||||||
|
-- | HERE | |
|
||||||
|
-- | | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.left40(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:frame()
|
||||||
|
|
||||||
|
f.x = max.x
|
||||||
|
f.y = max.y
|
||||||
|
f.w = max.w * 0.4
|
||||||
|
f.h = max.h
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- +-----------------+
|
||||||
|
-- | | |
|
||||||
|
-- | | HERE |
|
||||||
|
-- | | |
|
||||||
|
-- +-----------------+
|
||||||
|
function hs.window.right60(win)
|
||||||
|
local f = win:frame()
|
||||||
|
local screen = win:screen()
|
||||||
|
local max = screen:frame()
|
||||||
|
|
||||||
|
f.x = max.x + (max.w * 0.4)
|
||||||
|
f.y = max.y
|
||||||
|
f.w = max.w * 0.6
|
||||||
|
f.h = max.h
|
||||||
|
win:setFrame(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
function hs.window.nextScreen(win)
|
||||||
|
local currentScreen = win:screen()
|
||||||
|
local allScreens = hs.screen.allScreens()
|
||||||
|
currentScreenIndex = hs.fnutils.indexOf(allScreens, currentScreen)
|
||||||
|
nextScreenIndex = currentScreenIndex + 1
|
||||||
|
|
||||||
|
if allScreens[nextScreenIndex] then
|
||||||
|
win:moveToScreen(allScreens[nextScreenIndex])
|
||||||
|
else
|
||||||
|
win:moveToScreen(allScreens[1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
windowLayoutMode = hs.hotkey.modal.new({}, 'F16')
|
||||||
|
|
||||||
|
windowLayoutMode.entered = function()
|
||||||
|
windowLayoutMode.statusMessage:show()
|
||||||
|
end
|
||||||
|
windowLayoutMode.exited = function()
|
||||||
|
windowLayoutMode.statusMessage:hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Bind the given key to call the given function and exit WindowLayout mode
|
||||||
|
function windowLayoutMode.bindWithAutomaticExit(mode, modifiers, key, fn)
|
||||||
|
mode:bind(modifiers, key, function()
|
||||||
|
mode:exit()
|
||||||
|
fn()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local status, windowMappings = pcall(require, 'keyboard.windows-bindings')
|
||||||
|
|
||||||
|
if not status then
|
||||||
|
windowMappings = require('keyboard.windows-bindings-defaults')
|
||||||
|
end
|
||||||
|
|
||||||
|
local modifiers = windowMappings.modifiers
|
||||||
|
local showHelp = windowMappings.showHelp
|
||||||
|
local trigger = windowMappings.trigger
|
||||||
|
local mappings = windowMappings.mappings
|
||||||
|
|
||||||
|
function getModifiersStr(modifiers)
|
||||||
|
local modMap = { shift = '⇧', ctrl = '⌃', alt = '⌥', cmd = '⌘' }
|
||||||
|
local retVal = ''
|
||||||
|
|
||||||
|
for i, v in ipairs(modifiers) do
|
||||||
|
retVal = retVal .. modMap[v]
|
||||||
|
end
|
||||||
|
|
||||||
|
return retVal
|
||||||
|
end
|
||||||
|
|
||||||
|
local msgStr = getModifiersStr(modifiers)
|
||||||
|
msgStr = 'Window Layout Mode (' .. msgStr .. (string.len(msgStr) > 0 and '+' or '') .. trigger .. ')'
|
||||||
|
|
||||||
|
for i, mapping in ipairs(mappings) do
|
||||||
|
local modifiers, trigger, winFunction = table.unpack(mapping)
|
||||||
|
local hotKeyStr = getModifiersStr(modifiers)
|
||||||
|
|
||||||
|
if showHelp == true then
|
||||||
|
if string.len(hotKeyStr) > 0 then
|
||||||
|
msgStr = msgStr .. (string.format('\n%10s+%s => %s', hotKeyStr, trigger, winFunction))
|
||||||
|
else
|
||||||
|
msgStr = msgStr .. (string.format('\n%11s => %s', trigger, winFunction))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
windowLayoutMode:bindWithAutomaticExit(modifiers, trigger, function()
|
||||||
|
--example: hs.window.focusedWindow():upRight()
|
||||||
|
local fw = hs.window.focusedWindow()
|
||||||
|
fw[winFunction](fw)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local message = require('keyboard.status-message')
|
||||||
|
windowLayoutMode.statusMessage = message.new(msgStr)
|
||||||
|
|
||||||
|
-- Use modifiers+trigger to toggle WindowLayout Mode
|
||||||
|
hs.hotkey.bind(modifiers, trigger, function()
|
||||||
|
windowLayoutMode:enter()
|
||||||
|
end)
|
||||||
|
windowLayoutMode:bind(modifiers, trigger, function()
|
||||||
|
windowLayoutMode:exit()
|
||||||
|
end)
|
||||||
Reference in New Issue
Block a user