local keymap = require 'keyboard.keymaps' local yabai_cmd = '/etc/profiles/per-user/rayandrew/bin/yabai' local jq_cmd = '/etc/profiles/per-user/rayandrew/bin/jq' local function yabai_query(query, jq_filter) local cmd = yabai_cmd .. ' -m query ' .. query if jq_filter then cmd = cmd .. ' | ' .. jq_cmd .. ' ' .. jq_filter end local handle = io.popen(cmd) local result = handle:read('*a'):gsub('%s+', '') handle:close() return result end local function yabai(commands, logic) local cmd_string = '' for i, cmd in ipairs(commands) do if i == 1 then cmd_string = yabai_cmd .. ' -m ' .. cmd else if logic == 'and' then cmd_string = cmd_string .. ' && ' .. yabai_cmd .. ' -m ' .. cmd elseif logic == 'or' then cmd_string = cmd_string .. ' || ' .. yabai_cmd .. ' -m ' .. cmd else cmd_string = cmd_string .. ' ; ' .. yabai_cmd .. ' -m ' .. cmd end end end os.execute(cmd_string) end local function yabai_key(opts) keymap.super { key = opts.key, mods = opts.mods, message = opts.message, fn = function() yabai(opts.commands, opts.logic) end, } end keymap.super { key = 'return', -- message = "Spawn Ghostty", fn = function() -- hs.application.launchOrFocus("Ghostty") -- hs.timer.doAfter(0.1, function() -- hs.eventtap.keyStroke({ "cmd" }, "n") -- end) os.execute 'open -na Ghostty' end, } yabai_key { key = 'f', commands = { 'window --toggle zoom-fullscreen' } } yabai_key { key = 'l', commands = { 'space --focus recent' } } yabai_key { key = 'm', commands = { 'space --toggle mission-control' } } yabai_key { key = 'p', commands = { 'window --toggle pip' } } yabai_key { key = 'g', commands = { 'space --toggle padding', 'space --toggle gap' } } yabai_key { key = 'r', commands = { 'space --rotate 90' } } yabai_key { key = 'space', commands = { 'window --toggle float', 'window --grid 4:4:1:1:2:2' } } yabai_key { key = "'", commands = { 'space --layout stack' } } yabai_key { key = ';', commands = { 'space --layout bsp' } } yabai_key { key = 'tab', commands = { 'space --focus recent' } } -- navigation yabai_key { key = 'h', commands = { 'window --focus west', 'display --focus west' }, logic = 'or' } yabai_key { key = 'j', commands = { 'window --focus south', 'display --focus south' }, logic = 'or' } yabai_key { key = 'k', commands = { 'window --focus north', 'display --focus north' }, logic = 'or' } yabai_key { key = 'l', commands = { 'window --focus east', 'display --focus east' }, logic = 'or' } -- move windows (swap within space, or move to adjacent display if at edge) yabai_key { mods = { 'shift' }, key = 'h', commands = { 'window --swap west', 'window --display west', 'display --focus west' }, logic = 'or' } yabai_key { mods = { 'shift' }, key = 'j', commands = { 'window --swap south', 'window --display south', 'display --focus south' }, logic = 'or' } yabai_key { mods = { 'shift' }, key = 'k', commands = { 'window --swap north', 'window --display north', 'display --focus north' }, logic = 'or' } yabai_key { mods = { 'shift' }, key = 'l', commands = { 'window --swap east', 'window --display east', 'display --focus east' }, logic = 'or' } -- spaces - focus space and its display local function focus_space(space_num) local display = yabai_query('--spaces', "'.[] | select(.index == " .. space_num .. ") | .display'") if display and display ~= '' then os.execute(yabai_cmd .. ' -m display --focus ' .. display) hs.timer.usleep(50000) -- 50ms delay end os.execute(yabai_cmd .. ' -m space --focus ' .. space_num) end keymap.super { key = '1', fn = function() focus_space(1) end } keymap.super { key = '2', fn = function() focus_space(2) end } keymap.super { key = '3', fn = function() focus_space(3) end } keymap.super { key = '4', fn = function() focus_space(4) end } keymap.super { key = '5', fn = function() focus_space(5) end } keymap.super { key = '6', fn = function() focus_space(6) end } keymap.super { key = '7', fn = function() focus_space(7) end } keymap.super { key = '8', fn = function() focus_space(8) end } keymap.super { key = '9', fn = function() focus_space(9) end } keymap.super { key = '0', fn = function() focus_space(10) end } -- move window to space and follow yabai_key { mods = { 'shift' }, key = '1', commands = { 'window --space 1', 'space --focus 1' } } yabai_key { mods = { 'shift' }, key = '2', commands = { 'window --space 2', 'space --focus 2' } } yabai_key { mods = { 'shift' }, key = '3', commands = { 'window --space 3', 'space --focus 3' } } yabai_key { mods = { 'shift' }, key = '4', commands = { 'window --space 4', 'space --focus 4' } } yabai_key { mods = { 'shift' }, key = '5', commands = { 'window --space 5', 'space --focus 5' } } yabai_key { mods = { 'shift' }, key = '6', commands = { 'window --space 6', 'space --focus 6' } } yabai_key { mods = { 'shift' }, key = '7', commands = { 'window --space 7', 'space --focus 7' } } yabai_key { mods = { 'shift' }, key = '8', commands = { 'window --space 8', 'space --focus 8' } } yabai_key { mods = { 'shift' }, key = '9', commands = { 'window --space 9', 'space --focus 9' } } yabai_key { mods = { 'shift' }, key = '0', commands = { 'window --space 10', 'space --focus 10' } } -- move current space between displays yabai_key { mods = { 'ctrl' }, key = 'h', message = 'Move space to left display', commands = { 'space --display west' } } yabai_key { mods = { 'ctrl' }, key = 'l', message = 'Move space to right display', commands = { 'space --display east' } } -- create new space and move window to it -- keymap.super { -- key = 'n', -- mods = { 'shift' }, -- message = 'Create new space and move window', -- fn = function() -- os.execute(yabai_cmd .. ' -m space --create') -- hs.timer.usleep(100000) -- 100ms -- -- local index = yabai_query('--spaces --display', '\'map(select(."is-native-fullscreen" == false))[-1].index\'') -- -- if index and index ~= '' then -- os.execute(yabai_cmd .. ' -m window --space ' .. index) -- os.execute(yabai_cmd .. ' -m space --focus ' .. index) -- end -- end, -- } -- split type - use insert direction to control next window placement -- yabai_key { key = 'v', commands = { 'window --insert east' } } -- yabai_key { mods = { 'shift' }, key = 'v', commands = { 'window --insert south' } } yabai_key { key = 'v', commands = { 'config split_type vertical' } } yabai_key { mods = { 'shift' }, key = 'v', commands = { 'config split_type horizontal' } } -- Resize mode local resize_mode = hs.hotkey.modal.new() -- Function to show resize mode indicator function resize_mode:entered() hs.alert.show('Resize Mode', { textSize = 20, radius = 10 }, 999999) end function resize_mode:exited() hs.alert.closeAll() end -- Enter resize mode keymap.super { key = 'r', message = 'Enter resize mode', fn = function() resize_mode:enter() end, } -- Exit resize mode (escape or return) resize_mode:bind({}, 'escape', function() resize_mode:exit() end) resize_mode:bind({}, 'return', function() resize_mode:exit() end) -- Resize bindings (no modifiers needed in resize mode) resize_mode:bind({}, 'h', function() os.execute(yabai_cmd .. ' -m window --resize left:-20:0 || ' .. yabai_cmd .. ' -m window --resize right:-20:0') end) resize_mode:bind({}, 'j', function() os.execute(yabai_cmd .. ' -m window --resize bottom:0:20 || ' .. yabai_cmd .. ' -m window --resize top:0:20') end) resize_mode:bind({}, 'k', function() os.execute(yabai_cmd .. ' -m window --resize top:0:-20 || ' .. yabai_cmd .. ' -m window --resize bottom:0:-20') end) resize_mode:bind({}, 'l', function() os.execute(yabai_cmd .. ' -m window --resize right:20:0 || ' .. yabai_cmd .. ' -m window --resize left:20:0') end) -- Shift variants for larger increments resize_mode:bind( { 'shift' }, 'h', function() os.execute(yabai_cmd .. ' -m window --resize left:-50:0 || ' .. yabai_cmd .. ' -m window --resize right:-50:0') end ) resize_mode:bind({ 'shift' }, 'j', function() os.execute(yabai_cmd .. ' -m window --resize bottom:0:50 || ' .. yabai_cmd .. ' -m window --resize top:0:50') end) resize_mode:bind( { 'shift' }, 'k', function() os.execute(yabai_cmd .. ' -m window --resize top:0:-50 || ' .. yabai_cmd .. ' -m window --resize bottom:0:-50') end ) resize_mode:bind({ 'shift' }, 'l', function() os.execute(yabai_cmd .. ' -m window --resize right:50:0 || ' .. yabai_cmd .. ' -m window --resize left:50:0') end) -- Equalize windows resize_mode:bind({}, 'e', function() os.execute(yabai_cmd .. ' -m space --balance') resize_mode:exit() end) -- Toggle notes scratchpad keymap.super { key = 'n', message = 'Toggle notes scratchpad', fn = function() local result = yabai_query('--windows', '\'.[] | select(.scratchpad == "notes") | .id\'') if result == '' then local notes_dir = os.getenv 'HOME' .. '/NPersonal' os.execute('/etc/profiles/per-user/rayandrew/bin/kitty --title notes --directory ' .. notes_dir .. ' &') hs.timer.usleep(200000) end -- Toggle the scratchpad os.execute(yabai_cmd .. ' -m window --toggle notes') end, } keymap.super { key = 't', message = 'Toggle terminal scratchpad', fn = function() local result = yabai_query('--windows', '\'.[] | select(.scratchpad == "term") | .id\'') if result == '' then local home_dir = os.getenv 'HOME' os.execute('/etc/profiles/per-user/rayandrew/bin/kitty --title floaterm --directory ' .. home_dir .. ' &') hs.timer.usleep(200000) end -- Toggle the scratchpad os.execute(yabai_cmd .. ' -m window --toggle term') end, } -- keymap.super { -- key = 'e', -- message = 'Toggle explorer scratchpad', -- fn = function() -- local result = yabai_query('--windows', '\'.[] | select(.scratchpad == "explorer") | .id\'') -- -- if result == '' then -- local home_dir = os.getenv('HOME') -- os.execute('/etc/profiles/per-user/rayandrew/bin/kitty -o close_on_child_death=yes --title explorer --directory ' .. home_dir .. ' -e yazi &') -- hs.timer.usleep(200000) -- end -- -- -- Toggle the scratchpad -- os.execute(yabai_cmd .. ' -m window --toggle explorer') -- end, -- }