599 lines
23 KiB
Lua
599 lines
23 KiB
Lua
--- === hs.hotkey ===
|
|
---
|
|
--- Create and manage global keyboard shortcuts
|
|
|
|
local hotkey = require "hs.libhotkey"
|
|
local keycodes = require "hs.keycodes"
|
|
local alert = require'hs.alert'
|
|
local log = require'hs.logger'.new('hotkey','info')
|
|
hotkey.setLogLevel=log.setLogLevel
|
|
hotkey.getLogLevel=log.getLogLevel
|
|
|
|
local tonumber,pairs,ipairs,type,tremove,tinsert,tconcat,tsort = tonumber,pairs,ipairs,type,table.remove,table.insert,table.concat,table.sort
|
|
local supper,slower,sfind=string.upper,string.lower,string.find
|
|
|
|
--local function error(err,lvl) return hs.showError(err,(lvl or 1)+1,true) end -- this should go away, #477
|
|
|
|
local function getKeycode(s)
|
|
local n
|
|
if type(s)=='number' then n=s
|
|
elseif type(s)~='string' then error('key must be a string or a number',3)
|
|
elseif (s:sub(1, 1) == '#') then n=tonumber(s:sub(2))
|
|
else n=keycodes.map[slower(s)] end
|
|
if not n then error('Invalid key: '..s..' - this may mean that the key requested does not exist in your keymap (particularly if you switch keyboard layouts frequently)',3) end
|
|
return n
|
|
end
|
|
|
|
-- all enabled hotkeys go here; every key is a keyboard combination (string), associated value is a stack (list) of lightweight
|
|
-- hotkey objects, created in new(); the currently enabled hotkey sits at the top of the stack
|
|
local hotkeys = {}
|
|
|
|
--- hs.hotkey.alertDuration
|
|
--- Variable
|
|
--- Duration of the alert shown when a hotkey created with a `message` parameter is triggered, in seconds. Default is 1.
|
|
---
|
|
--- Usage:
|
|
--- hs.hotkey.alertDuration = 2.5 -- alert stays on screen a bit longer
|
|
--- hs.hotkey.alertDuration = 0 -- hotkey alerts are disabled
|
|
hotkey.alertDuration = 1
|
|
|
|
--- hs.hotkey:enable() -> hs.hotkey object | nil
|
|
--- Method
|
|
--- Enables a hotkey object
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * The `hs.hotkey` object for method chaining or nil if the hotkey could not be enabled for some reason.
|
|
---
|
|
--- Notes:
|
|
--- * When you enable a hotkey that uses the same keyboard combination as another previously-enabled hotkey, the old
|
|
--- one will stop working as it's being "shadowed" by the new one. As soon as the new hotkey is disabled or deleted
|
|
--- the old one will trigger again.
|
|
local function enable(self,force,isModal)
|
|
-- force is there just in case it'll be needed down the line; not exposed as public API for now
|
|
-- isModal is only used to differentiate loglevel (modals can cause a lot of shadowing/unshadowing)
|
|
|
|
-- this ensures "nested shadowing" behaviour; i.e. can't re-enable a hotkey that is currently shadowed (unless force),
|
|
-- must wait for the current top dog to get disabled
|
|
if not force and self.enabled then log.v('Hotkey already enabled') return self end
|
|
local idx = self.idx
|
|
if not idx or not hotkeys[idx] then log.e('The hotkey was deleted, cannot enable it') return end
|
|
for i=#hotkeys[idx],1,-1 do
|
|
local hk=hotkeys[idx][i]
|
|
if hk==self then tremove(hotkeys[idx],i) -- this hotkey will go to the top of the stack
|
|
elseif hk.enabled then log.i('Disabled previous hotkey '..hk.msg) end --shadow previous hotkeys
|
|
hk._hk:disable() --objc
|
|
end
|
|
self.enabled = true
|
|
local returnVal = self._hk:enable() --objc
|
|
if returnVal ~= nil then
|
|
log[isModal and 'df' or 'f']('Enabled hotkey %s%s',self.msg,isModal and ' (in modal)' or '')
|
|
tinsert(hotkeys[idx],self) -- bring to the top of the stack
|
|
-- return returnVal
|
|
return self
|
|
else
|
|
self.enabled = false
|
|
return nil
|
|
end
|
|
end
|
|
|
|
--- hs.hotkey:disable() -> hs.hotkey object
|
|
--- Method
|
|
--- Disables a hotkey object
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * The `hs.hotkey` object for method chaining
|
|
local function disable(self,isModal)
|
|
if not self.enabled then return self end
|
|
local idx = self.idx
|
|
if not idx or not hotkeys[idx] then log.w('The hotkey was deleted, cannot disable it') return end
|
|
self.enabled = nil
|
|
self._hk:disable() --objc
|
|
log[isModal and 'df' or 'f']('Disabled hotkey %s%s',self.msg,isModal and ' (in modal)' or '')
|
|
for i=#hotkeys[idx],1,-1 do --scan the stack top-to-bottom
|
|
if hotkeys[idx][i].enabled then
|
|
log.i('Re-enabled previous hotkey '..hotkeys[idx][i].msg)
|
|
hotkeys[idx][i]._hk:enable() --unshadow previous top dog and exit
|
|
break
|
|
end
|
|
end
|
|
return self
|
|
end
|
|
|
|
--- hs.hotkey:delete()
|
|
--- Method
|
|
--- Disables and deletes a hotkey object
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
local function delete(self)
|
|
local idx=self.idx
|
|
if not idx or not hotkeys[idx] then log.w('The hotkey has already been deleted') return end --?
|
|
disable(self)
|
|
for i,hk in ipairs(hotkeys[idx]) do if hk==self then tremove(hotkeys[idx],i) break end end
|
|
log.i('Deleted hotkey '..self.msg)
|
|
for k in pairs(self) do self[k]=nil end --gc
|
|
end
|
|
|
|
|
|
local function getMods(mods)
|
|
local r={}
|
|
if not mods then return r end
|
|
if type(mods)=='table' then mods=tconcat(mods,'-') end
|
|
if type(mods)~='string' then error('mods must be a string or a table of strings',3) end
|
|
-- super simple substring search for mod names in a string
|
|
mods=slower(mods)
|
|
local function find(ps)
|
|
for _,s in ipairs(ps) do
|
|
if sfind(mods,s,1,true) then r[#r+1]=ps[#ps] return end
|
|
end
|
|
end
|
|
find{'cmd','command','⌘'} find{'ctrl','control','⌃'}
|
|
find{'alt','option','⌥'} find{'shift','⇧'}
|
|
return r --pass a list of unicode symbols to objc
|
|
end
|
|
|
|
local CONCAVE_DIAMOND='✧' -- used for HYPER
|
|
local function getIndex(modsID,keycode) -- key for hotkeys table
|
|
local mods = getMods(modsID)
|
|
mods = #mods>=4 and CONCAVE_DIAMOND or tconcat(mods)
|
|
local key=keycodes.map[keycode]
|
|
key=key and supper(key) or '[#'..keycode..']'
|
|
return mods..key
|
|
end
|
|
|
|
local function getFunc(f)
|
|
if f == nil then return nil end
|
|
if type(f) == 'function' then return f end
|
|
if type(f) == 'table' then
|
|
local m = getmetatable(f)
|
|
if m and m.__call and type(m.__call) == 'function' then
|
|
return function() m.__call(f) end
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
--- hs.hotkey.new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> hs.hotkey object
|
|
--- Constructor
|
|
--- Creates a new hotkey
|
|
---
|
|
--- Parameters:
|
|
--- * mods - A table or a string containing (as elements, or as substrings with any separator) the keyboard modifiers required,
|
|
--- which should be zero or more of the following:
|
|
--- * "cmd", "command" or "⌘"
|
|
--- * "ctrl", "control" or "⌃"
|
|
--- * "alt", "option" or "⌥"
|
|
--- * "shift" or "⇧"
|
|
--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number
|
|
--- * message - (optional) A string containing a message to be displayed via `hs.alert()` when the hotkey has been
|
|
--- triggered; if omitted, no alert will be shown
|
|
--- * pressedfn - A function that will be called when the hotkey has been pressed, or nil
|
|
--- * releasedfn - A function that will be called when the hotkey has been released, or nil
|
|
--- * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
|
|
---
|
|
--- Returns:
|
|
--- * A new `hs.hotkey` object or nil if the hotkey could not be enabled
|
|
---
|
|
--- Notes:
|
|
--- * You can create multiple `hs.hotkey` objects for the same keyboard combination, but only one can be active
|
|
--- at any given time - see `hs.hotkey:enable()`
|
|
--- * If `message` is the empty string `""`, the alert will just show the triggered keyboard combination
|
|
--- * If you don't want any alert, you must *actually* omit the `message` parameter; a `nil` in 3rd position
|
|
--- will be interpreted as a missing `pressedfn`
|
|
--- * You must pass at least one of `pressedfn`, `releasedfn` or `repeatfn`; to delete a hotkey, use `hs.hotkey:delete()`
|
|
|
|
function hotkey.new(mods, key, message, pressedfn, releasedfn, repeatfn)
|
|
local keycode = getKeycode(key)
|
|
mods = getMods(mods)
|
|
-- message can be omitted
|
|
if message==nil or getFunc(message) then
|
|
repeatfn=releasedfn releasedfn=pressedfn pressedfn=message message=nil -- shift down arguments
|
|
end
|
|
pressedfn = getFunc(pressedfn)
|
|
releasedfn = getFunc(releasedfn)
|
|
repeatfn = getFunc(repeatfn)
|
|
if not pressedfn and not releasedfn and not repeatfn then
|
|
error('At least one of pressedfn, releasedfn or repeatfn must be a function',2) end
|
|
if type(message)~='string' then message=nil end
|
|
local idx = getIndex(mods,keycode)
|
|
local msg=(message and #message>0) and idx..': '..message or idx
|
|
if message then
|
|
local actualfn=pressedfn or releasedfn or repeatfn -- which function will be wrapped to provide an alert (the first valid one)
|
|
local fnalert=function()alert(msg,hotkey.alertDuration or 0)actualfn()end -- wrapper
|
|
if pressedfn then pressedfn=fnalert -- substitute 'actualfn' with wrapper
|
|
elseif releasedfn then releasedfn=fnalert
|
|
elseif repeatfn then repeatfn=fnalert end
|
|
end
|
|
-- the lightweight hotkey object; _hk=objc userdata; then msg, idx, and the methods
|
|
local hk = {_hk=hotkey._new(mods, keycode, pressedfn, releasedfn, repeatfn),enable=enable,disable=disable,delete=delete,msg=msg,idx=idx}
|
|
log.v('Created hotkey for '..idx)
|
|
local h = hotkeys[idx] or {} -- create stack if this is the first hotkey for a given key combo
|
|
h[#h+1] = hk -- go on top of the stack
|
|
hotkeys[idx] = h
|
|
return hk
|
|
end
|
|
|
|
--- hs.hotkey.systemAssigned(mods, key) -> table | false
|
|
--- Function
|
|
--- Examine whether a potential hotkey is in use by the macOS system such as the Screen Capture, Universal Access, and Keyboard Navigation keys.
|
|
---
|
|
--- Parameters:
|
|
--- * mods - A table or a string containing (as elements, or as substrings with any separator) the keyboard modifiers required,
|
|
--- which should be zero or more of the following:
|
|
--- * "cmd", "command" or "⌘"
|
|
--- * "ctrl", "control" or "⌃"
|
|
--- * "alt", "option" or "⌥"
|
|
--- * "shift" or "⇧"
|
|
--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number
|
|
---
|
|
--- Returns:
|
|
--- * if the hotkey combination is in use by a system function, returns a table containing the following keys:
|
|
--- * keycode - the numberic keycode for the hotkey
|
|
--- * mods - a numeric representation of the modifier flags for the htokey
|
|
--- * enabled - a boolean indicating whether or not the key is currently enabled
|
|
--- * if the hotkey combination is not in use by the operating system, returns the boolean value `false`
|
|
---
|
|
--- Notes:
|
|
--- * this is provided for informational purposes and does not provide a reliable test as to whether or not Hammerspoon can use the combination to create a custom hotkey -- some combinations which return a table can be over-ridden by Hammerspoon while others cannot. See also [hs.hotkey.assignable](#assignable).
|
|
local originalSystemAssigned = hotkey.systemAssigned
|
|
function hotkey.systemAssigned(mods, key)
|
|
local keycode = getKeycode(key)
|
|
mods = getMods(mods)
|
|
return originalSystemAssigned(mods, keycode)
|
|
end
|
|
|
|
--- hs.hotkey.assignable(mods, key) -> boolean
|
|
--- Function
|
|
--- Determines whether the hotkey combination can be assigned a callback through Hammerspoon.
|
|
---
|
|
--- Parameters:
|
|
--- * mods - A table or a string containing (as elements, or as substrings with any separator) the keyboard modifiers required,
|
|
--- which should be zero or more of the following:
|
|
--- * "cmd", "command" or "⌘"
|
|
--- * "ctrl", "control" or "⌃"
|
|
--- * "alt", "option" or "⌥"
|
|
--- * "shift" or "⇧"
|
|
--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number
|
|
---
|
|
--- Returns:
|
|
--- * a boolean value, true if the hotkey combination can be given an assignment by Hammerspoon or false if it cannot.
|
|
---
|
|
--- Notes:
|
|
--- * The most common reason a hotkey combination cannot be given an assignment by Hammerspoon is because it is in use by the Mac operating system -- see the Shortcuts tab of Keyboard in the System Preferences application or [hs.hotkey.systemAssigned](#systemAssigned).
|
|
function hotkey.assignable(mods, key)
|
|
local k = hotkey.new(mods, key, function() end)
|
|
local prevLevel = hs.luaSkinLog.level
|
|
-- supress luaSkinLog error if binding fails
|
|
hs.luaSkinLog.level = 0
|
|
local status = k._hk:enable()
|
|
if status then k._hk:disable() end
|
|
k.enabled = false
|
|
hs.luaSkinLog.level = prevLevel
|
|
return status and true or false
|
|
end
|
|
|
|
--- hs.hotkey.disableAll(mods, key)
|
|
--- Function
|
|
--- Disables all previously set callbacks for a given keyboard combination
|
|
---
|
|
--- Parameters:
|
|
--- * mods - A table or a string containing (as elements, or as substrings with any separator) the keyboard modifiers required,
|
|
--- which should be zero or more of the following:
|
|
--- * "cmd", "command" or "⌘"
|
|
--- * "ctrl", "control" or "⌃"
|
|
--- * "alt", "option" or "⌥"
|
|
--- * "shift" or "⇧"
|
|
--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
function hotkey.disableAll(mods,key)
|
|
local idx=getIndex(mods,getKeycode(key))
|
|
for _,hk in ipairs(hotkeys[idx] or {}) do hk:disable() end
|
|
end
|
|
|
|
--- hs.hotkey.deleteAll(mods, key)
|
|
--- Function
|
|
--- Deletes all previously set callbacks for a given keyboard combination
|
|
---
|
|
--- Parameters:
|
|
--- * mods - A table or a string containing (as elements, or as substrings with any separator) the keyboard modifiers required,
|
|
--- which should be zero or more of the following:
|
|
--- * "cmd", "command" or "⌘"
|
|
--- * "ctrl", "control" or "⌃"
|
|
--- * "alt", "option" or "⌥"
|
|
--- * "shift" or "⇧"
|
|
--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
function hotkey.deleteAll(mods,key)
|
|
local idx=getIndex(mods,getKeycode(key))
|
|
local t=hotkeys[idx] or {}
|
|
for i=#t,1,-1 do t[i]:delete() end
|
|
hotkeys[idx]=nil
|
|
end
|
|
|
|
--- hs.hotkey.getHotkeys() -> table
|
|
--- Function
|
|
--- Returns a list of all currently active hotkeys
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * A table containing the hotkeys that are active, i.e. enabled and not "shadowed", in the current context
|
|
--- (usually, the global hotkey context, but it could be a modal hotkey context). Every element in the list
|
|
--- is a table with two fields:
|
|
--- * idx - a string describing the keyboard combination for the hotkey
|
|
--- * msg - the hotkey message, if provided when the hotkey was created (prefixed with the keyboard combination)
|
|
|
|
--- hs.hotkey.showHotkeys(mods, key) -> hs.hotkey object
|
|
--- Function
|
|
--- Creates (and enables) a hotkey that shows all currently active hotkeys (i.e. enabled and not "shadowed" in the current context) while pressed
|
|
---
|
|
--- Parameters:
|
|
--- * mods - A table or a string containing (as elements, or as substrings with any separator) the keyboard modifiers required,
|
|
--- which should be zero or more of the following:
|
|
--- * "cmd", "command" or "⌘"
|
|
--- * "ctrl", "control" or "⌃"
|
|
--- * "alt", "option" or "⌥"
|
|
--- * "shift" or "⇧"
|
|
--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number
|
|
---
|
|
--- Returns:
|
|
--- * The new `hs.hotkey` object
|
|
|
|
local helpHotkey
|
|
function hotkey.getHotkeys()
|
|
local t={}
|
|
for _,hks in pairs(hotkeys) do
|
|
for i=#hks,1,-1 do
|
|
if hks[i].enabled and hks[i]~=helpHotkey then
|
|
t[#t+1] = hks[i]
|
|
break
|
|
end
|
|
end
|
|
end
|
|
tsort(t,function(a,b)if#a.idx==#b.idx then return a.idx<b.idx else return #a.idx<#b.idx end end)
|
|
if helpHotkey then tinsert(t,1,helpHotkey) end
|
|
return t
|
|
end
|
|
|
|
local function showHelp()
|
|
local t=hotkey.getHotkeys()
|
|
-- hs.alert(helpHotkey.msg,3600)
|
|
local s=''
|
|
for i=2,#t do s=s..t[i].msg..'\n' end
|
|
alert(s:sub(1,-2),3600)
|
|
end
|
|
function hotkey.showHotkeys(mods,key)
|
|
if helpHotkey then delete(helpHotkey) end
|
|
helpHotkey = hotkey.bind(mods,key,'Show active hotkeys',showHelp,alert.closeAll)
|
|
return helpHotkey
|
|
end
|
|
|
|
--- hs.hotkey.bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> hs.hotkey object
|
|
--- Constructor
|
|
--- Creates a new hotkey and enables it immediately
|
|
---
|
|
--- Parameters:
|
|
--- * mods - A table or a string containing (as elements, or as substrings with any separator) the keyboard modifiers required,
|
|
--- which should be zero or more of the following:
|
|
--- * "cmd", "command" or "⌘"
|
|
--- * "ctrl", "control" or "⌃"
|
|
--- * "alt", "option" or "⌥"
|
|
--- * "shift" or "⇧"
|
|
--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number
|
|
--- * message - (optional) A string containing a message to be displayed via `hs.alert()` when the hotkey has been
|
|
--- triggered; if omitted, no alert will be shown
|
|
--- * pressedfn - A function that will be called when the hotkey has been pressed, or nil
|
|
--- * releasedfn - A function that will be called when the hotkey has been released, or nil
|
|
--- * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
|
|
---
|
|
--- Returns:
|
|
--- * A new `hs.hotkey` object or nil if the hotkey could not be enabled
|
|
---
|
|
--- Notes:
|
|
--- * This function is just a wrapper that performs `hs.hotkey.new(...):enable()`
|
|
--- * You can create multiple `hs.hotkey` objects for the same keyboard combination, but only one can be active
|
|
--- at any given time - see `hs.hotkey:enable()`
|
|
--- * If `message` is the empty string `""`, the alert will just show the triggered keyboard combination
|
|
--- * If you don't want any alert, you must *actually* omit the `message` parameter; a `nil` in 3rd position
|
|
--- will be interpreted as a missing `pressedfn`
|
|
--- * You must pass at least one of `pressedfn`, `releasedfn` or `repeatfn`; to delete a hotkey, use `hs.hotkey:delete()`
|
|
function hotkey.bind(...)
|
|
return hotkey.new(...):enable()
|
|
end
|
|
|
|
--- hs.hotkey.bindSpec(keyspec, ...) -> hs.hotkey object
|
|
--- Constructor
|
|
--- Creates a hotkey and enables it immediately
|
|
---
|
|
--- Parameters:
|
|
--- * keyspec - A table containing two items:
|
|
--- * first, a table containing keyboard modifiers, as specified in `hs.hotkey.bind()`
|
|
--- * second, a string containing the name of a keyboard key, as specified in `hs.hotkey.bind()`
|
|
--- * ... - All remaining arguments are as specified in `hs.hotkey.bind()`
|
|
---
|
|
--- Returns:
|
|
--- * A new `hs.hotkey` object for method chaining
|
|
---
|
|
--- Notes:
|
|
--- * This function is just a wrapper that performs `hs.hotkey.bind(keyspec[1], keyspec[2], ...)`
|
|
function hotkey.bindSpec(keyspec, ...)
|
|
return hotkey.bind(keyspec[1], keyspec[2], ...)
|
|
end
|
|
|
|
--- === hs.hotkey.modal ===
|
|
---
|
|
--- Create/manage modal keyboard shortcut environments
|
|
---
|
|
--- Usage:
|
|
--- ```lua
|
|
--- k = hs.hotkey.modal.new('cmd-shift', 'd')
|
|
--- function k:entered() hs.alert'Entered mode' end
|
|
--- function k:exited() hs.alert'Exited mode' end
|
|
--- k:bind('', 'escape', function() k:exit() end)
|
|
--- k:bind('', 'J', 'Pressed J',function() print'let the record show that J was pressed' end)```
|
|
|
|
hotkey.modal = {}
|
|
hotkey.modal.__index = hotkey.modal
|
|
|
|
--- hs.hotkey.modal:entered()
|
|
--- Method
|
|
--- Optional callback for when a modal is entered
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
---
|
|
--- Notes:
|
|
--- * This is a pre-existing function that you should override if you need to use it; the default implementation does nothing.
|
|
function hotkey.modal:entered() -- luacheck: ignore
|
|
end
|
|
|
|
--- hs.hotkey.modal:exited()
|
|
--- Method
|
|
--- Optional callback for when a modal is exited
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
---
|
|
--- Notes:
|
|
--- * This is a pre-existing function that you should override if you need to use it; the default implementation does nothing.
|
|
function hotkey.modal:exited() -- luacheck: ignore
|
|
end
|
|
|
|
--- hs.hotkey.modal:bind(mods, key, message, pressedfn, releasedfn, repeatfn) -> hs.hotkey.modal object
|
|
--- Method
|
|
--- Creates a hotkey that is enabled/disabled as the modal is entered/exited
|
|
---
|
|
--- Parameters:
|
|
--- * mods - A table or a string containing (as elements, or as substrings with any separator) the keyboard modifiers required,
|
|
--- which should be zero or more of the following:
|
|
--- * "cmd", "command" or "⌘"
|
|
--- * "ctrl", "control" or "⌃"
|
|
--- * "alt", "option" or "⌥"
|
|
--- * "shift" or "⇧"
|
|
--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number
|
|
--- * message - A string containing a message to be displayed via `hs.alert()` when the hotkey has been triggered, or nil for no alert
|
|
--- * pressedfn - A function that will be called when the hotkey has been pressed, or nil
|
|
--- * releasedfn - A function that will be called when the hotkey has been released, or nil
|
|
--- * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
|
|
---
|
|
--- Returns:
|
|
--- * The `hs.hotkey.modal` object for method chaining
|
|
function hotkey.modal:bind(...)
|
|
tinsert(self.keys, hotkey.new(...))
|
|
return self
|
|
end
|
|
|
|
--- hs.hotkey.modal:enter() -> hs.hotkey.modal object
|
|
--- Method
|
|
--- Enters a modal state
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * The `hs.hotkey.modal` object for method chaining
|
|
---
|
|
--- Notes:
|
|
--- * This method will enable all of the hotkeys defined in the modal state via `hs.hotkey.modal:bind()`,
|
|
--- and disable the hotkey that entered the modal state (if one was defined)
|
|
--- * If the modal state was created with a keyboard combination, this method will be called automatically
|
|
function hotkey.modal:enter()
|
|
log.d('Entering modal')
|
|
if (self.k) then
|
|
disable(self.k)
|
|
end
|
|
for _,hk in ipairs(self.keys) do enable(hk,nil,true) end
|
|
self:entered()
|
|
return self
|
|
end
|
|
|
|
--- hs.hotkey.modal:exit() -> hs.hotkey.modal object
|
|
--- Method
|
|
--- Exits a modal state
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * The `hs.hotkey.modal` object for method chaining
|
|
---
|
|
--- Notes:
|
|
--- * This method will disable all of the hotkeys defined in the modal state, and enable the hotkey for entering the modal state (if one was defined)
|
|
function hotkey.modal:exit()
|
|
for _,hk in ipairs(self.keys) do disable(hk,true) end
|
|
if (self.k) then
|
|
enable(self.k)
|
|
end
|
|
self:exited()
|
|
log.d('Exited modal')
|
|
return self
|
|
end
|
|
|
|
--- hs.hotkey.modal.new(mods, key, message) -> hs.hotkey.modal object
|
|
--- Constructor
|
|
--- Creates a new modal state, optionally with a global keyboard combination to trigger it
|
|
---
|
|
--- Parameters:
|
|
--- * mods - A table or a string containing (as elements, or as substrings with any separator) the keyboard modifiers required,
|
|
--- which should be zero or more of the following:
|
|
--- * "cmd", "command" or "⌘"
|
|
--- * "ctrl", "control" or "⌃"
|
|
--- * "alt", "option" or "⌥"
|
|
--- * "shift" or "⇧"
|
|
--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number
|
|
--- * message - A string containing a message to be displayed via `hs.alert()` when the hotkey has been triggered, or nil for no alert
|
|
---
|
|
--- Returns:
|
|
--- * A new `hs.hotkey.modal` object
|
|
---
|
|
--- Notes:
|
|
--- * If `key` is nil, no global hotkey will be registered (all other parameters will be ignored)
|
|
function hotkey.modal.new(mods, key, message)
|
|
local m = setmetatable({keys = {}}, hotkey.modal)
|
|
if (key) then
|
|
m.k = hotkey.bind(mods, key, message, function() m:enter() end)
|
|
end
|
|
log.d('Created modal hotkey')
|
|
return m
|
|
end
|
|
|
|
--- hs.hotkey.modal:delete()
|
|
--- Method
|
|
--- Deletes a modal hotkey object without calling :exited()
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
function hotkey.modal:delete()
|
|
for _,hk in ipairs(self.keys) do
|
|
delete(hk)
|
|
end
|
|
if (self.k) then
|
|
self.k:delete()
|
|
end
|
|
end
|
|
|
|
return hotkey
|