119 lines
4.7 KiB
Lua
119 lines
4.7 KiB
Lua
--- === hs.pasteboard ===
|
|
---
|
|
--- Inspect/manipulate pasteboards (more commonly called clipboards). Both the system default pasteboard and custom named pasteboards can be interacted with.
|
|
---
|
|
--- This module is based partially on code from the previous incarnation of Mjolnir by [Steven Degutis](https://github.com/sdegutis/).
|
|
|
|
local module = require("hs.libpasteboard")
|
|
module.watcher = require("hs.libpasteboardwatcher")
|
|
|
|
local timer = require("hs.timer")
|
|
|
|
-- make sure the convertors for types we can recognize are loaded
|
|
require("hs.image")
|
|
require("hs.sound")
|
|
require("hs.styledtext")
|
|
require("hs.drawing.color")
|
|
require("hs.sharing")
|
|
|
|
-- Public interface ------------------------------------------------------
|
|
|
|
--- hs.pasteboard.readAllData([name]) -> table
|
|
--- Function
|
|
--- Returns all values in the first item on the pasteboard in a table that maps a UTI value to the raw data of the item
|
|
---
|
|
--- Parameters:
|
|
--- * name - an optional string indicating the pasteboard name. If nil or not present, defaults to the system pasteboard.
|
|
---
|
|
--- Returns:
|
|
--- a mapping from a UTI value to the raw data
|
|
module.readAllData = function (name)
|
|
local contents = {}
|
|
for _, uti in ipairs(module.contentTypes(name)) do
|
|
contents[uti] = module.readDataForUTI(name, uti)
|
|
end
|
|
return contents
|
|
end
|
|
|
|
--- hs.pasteboard.writeAllData([name], table) -> boolean
|
|
--- Function
|
|
--- Stores in the pasteboard a given table of UTI to data mapping all at once
|
|
---
|
|
--- Parameters:
|
|
--- * name - an optional string indicating the pasteboard name. If nil or not present, defaults to the system pasteboard.
|
|
--- * a mapping from a UTI value to the raw data
|
|
---
|
|
--- Returns:
|
|
--- * True if the operation succeeded, otherwise false (which most likely means ownership of the pasteboard has changed)
|
|
module.writeAllData = function (...)
|
|
local name, contents
|
|
if #{...} == 1 then
|
|
contents = ...
|
|
else
|
|
name, contents = ...
|
|
end
|
|
|
|
local ok = true
|
|
module.clearContents(name)
|
|
for uti, data in pairs(contents) do
|
|
ok = ok and module.writeDataForUTI(name, uti, data, true)
|
|
end
|
|
return ok
|
|
end
|
|
|
|
--- hs.pasteboard.callbackWhenChanged([name], [timeout], callback) -> None
|
|
--- Function
|
|
--- Invokes callback when the specified pasteoard has changed or the timeout is reached.
|
|
---
|
|
--- Parameters:
|
|
--- * `name` - an optional string indicating the pasteboard name. If nil or not present, defaults to the system pasteboard.
|
|
--- * `timeout` - an optional number, default 2.0, specifying the time in seconds that this function should wait for a change to the specified pasteboard before timing out.
|
|
--- * `callback` - a required callback function that will be invoked when either the specified pasteboard contents have changed or the timeout has been reached. The function should expect one boolean argument, true if the pasteboard contents have changed or false if timeout has been reached.
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
---
|
|
--- Notes:
|
|
--- * This function can be used to capture the results of a copy operation issued programatically with `hs.application:selectMenuItem` or `hs.eventtap.keyStroke` without resorting to creating your own timers:
|
|
--- ~~~
|
|
--- hs.eventtap.keyStroke({"cmd"}, "c", 0) -- or whatever method you want to trigger the copy
|
|
--- hs.pasteboard.callbackWhenChanged(5, function(state)
|
|
--- if state then
|
|
--- local contents = hs.pasteboard.getContents()
|
|
--- -- do what you want with contents
|
|
--- else
|
|
--- error("copy timeout") -- or whatever fallback you want when it timesout
|
|
--- end
|
|
--- end)
|
|
--- ~~~
|
|
module.callbackWhenChanged = function(...)
|
|
local name, timeout, callback = nil, 2.0, nil
|
|
for _, v in ipairs({...}) do
|
|
if type(v) == "number" then
|
|
timeout = v
|
|
elseif type(v) == "nil" or type(v) == "string" then
|
|
name = v
|
|
elseif type(v) == "function" or (getmetatable(v) or {}).__call then
|
|
callback = v
|
|
end
|
|
end
|
|
assert(type(name) == "nil" or type(name) == "string", "pasteboard must be a string or nil")
|
|
assert(type(timeout) == "number", "timeout must be a number")
|
|
assert(
|
|
type(callback) == "function" or (getmetatable(callback) or {}).__call,
|
|
"callback must be a function"
|
|
)
|
|
|
|
local longTask
|
|
longTask = coroutine.wrap(function(start, count)
|
|
while (timer.secondsSinceEpoch() - start < timeout) and (module.changeCount(name) == count) do
|
|
coroutine.applicationYield() -- luacheck: ignore
|
|
end
|
|
callback(module.changeCount(name) ~= count)
|
|
longTask = nil -- referncing here makes it an upvalue, so it won't be collected
|
|
end)
|
|
longTask(timer.secondsSinceEpoch(), module.changeCount(name))
|
|
end
|
|
|
|
return module
|