Permalink
Switch branches/tags
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
246 lines (214 sloc) 6.1 KB
--proc/system/clipboard: clipboard API
--Written by Cosmin Apreutesei. Public Domain.
setfenv(1, require'winapi')
require'winapi.memory'
-- Predefined Clipboard Formats
CF_NAMES = constants{
CF_TEXT = 1,
CF_BITMAP = 2, --only for DDBs, doesn't work with DIBs!
CF_METAFILEPICT = 3,
CF_SYLK = 4,
CF_DIF = 5,
CF_TIFF = 6,
CF_OEMTEXT = 7,
CF_DIB = 8, --DIB without alpha
CF_PALETTE = 9,
CF_PENDATA = 10,
CF_RIFF = 11,
CF_WAVE = 12,
CF_UNICODETEXT = 13,
CF_ENHMETAFILE = 14,
CF_HDROP = 15,
CF_LOCALE = 16,
CF_DIBV5 = 17, --DIB with alpha
CF_OWNERDISPLAY = 0x0080,
CF_DSPTEXT = 0x0081,
CF_DSPBITMAP = 0x0082,
CF_DSPMETAFILEPICT = 0x0083,
CF_DSPENHMETAFILE = 0x008E,
}
-- "Private" formats don't get GlobalFree()'d
CF_PRIVATEFIRST = 0x0200
CF_PRIVATELAST = 0x02FF
-- "GDIOBJ" formats do get DeleteObject()'d
CF_GDIOBJFIRST = 0x0300
CF_GDIOBJLAST = 0x03FF
ffi.cdef[[
BOOL OpenClipboard(HWND hWndNewOwner);
BOOL CloseClipboard(void);
BOOL IsClipboardFormatAvailable(UINT format);
int CountClipboardFormats(void);
HANDLE GetClipboardData(UINT uFormat);
BOOL EmptyClipboard(void);
HANDLE SetClipboardData(UINT uFormat, HANDLE hMem);
UINT EnumClipboardFormats(UINT format);
int GetClipboardFormatNameW(UINT format, LPWSTR lpszFormatName, int cchMaxCount);
UINT RegisterClipboardFormatW(LPWSTR lpszFormat);
]]
function OpenClipboard(hwnd)
return C.OpenClipboard(hwnd) ~= 0
end
function CloseClipboard(hwnd)
return checknz(C.CloseClipboard())
end
function IsClipboardFormatAvailable(format)
return C.IsClipboardFormatAvailable(flags(format)) ~= 0
end
function CountClipboardFormats()
return callnz2(C.CountClipboardFormats)
end
function GetClipboardData(uFormat)
return checkh(C.GetClipboardData(flags(uFormat)))
end
function EmptyClipboard()
checknz(C.EmptyClipboard())
end
function SetClipboardData(format, hmem)
return checkh(C.SetClipboardData(flags(format), hmem))
end
function EnumClipboardFormats(last_format)
local ret = callnz2(C.EnumClipboardFormats, last_format or 0)
return ret ~= 0 and ret or nil
end
function GetClipboardFormatName(format, buf, sz)
if not buf then buf, sz = WCS(sz) end
sz = checknz(C.GetClipboardFormatNameW(format, buf, sz))
return buf, sz
end
function RegisterClipboardFormat(name)
return checknz(C.RegisterClipboardFormatW(wcs(name)))
end
--hi-level API: get/set data from/to clipboard.
--custom functions, don't look them up in msdn.
--return a list of available clipboard formats, in original order.
function GetClipboardFormats()
local format
local t = {}
repeat
format = EnumClipboardFormats(format)
t[#t+1] = format
until not format
return t
end
--return a list of available clipboard format names, in original order.
--for built-in formats, the format number is returned instead.
function GetClipboardFormatNames()
local t = GetClipboardFormats()
local buf, sz
for i=1,#t do
local format = t[i]
local name
if CF_NAMES[format] then
name = format
else
if not buf then buf, sz = WCS() end
name = mbs(GetClipboardFormatName(format, buf, sz))
end
t[i] = name
end
return t
end
--get the data buffer of a specific format, pass it to a function,
--and return the result of that function.
function GetClipboardDataBuffer(format, copy)
if not IsClipboardFormatAvailable(format) then
return
end
return glue.fcall(function(finally)
local h = GetClipboardData(format)
local buf = GlobalLock(h)
if not buf then return end
finally(function() GlobalUnlock(h) end)
local sz = GlobalSize(h)
return copy(buf, sz)
end)
end
--set the clipboard data for a specific format from a buffer or string.
--you can pass a buffer and a size, or just the size and a copy function.
function SetClipboardDataBuffer(format, srcbuf, sz, copy)
--windows will own this memory, no need to free it.
glue.fcall(function(finally, onerror)
sz = sz or #buf
local h = GlobalAlloc(bit.bor(GMEM_MOVEABLE, GMEM_ZEROINIT, GMEM_SHARE), sz)
onerror(function() GlobalFree(h) end)
local buf = GlobalLock(h)
finally(function() GlobalUnlock(h) end)
if copy then
copy(buf, sz)
else
ffi.copy(buf, srcbuf, sz)
end
SetClipboardData(format, h)
end)
end
--get utf8 text out of the clipboard.
function GetClipboardText()
return GetClipboardDataBuffer(CF_UNICODETEXT, function(buf)
return mbs(ffi.cast('WCHAR*', buf))
end)
end
--set utf8 text into the clipboard.
function SetClipboardText(s)
local buf = wcs(s)
SetClipboardDataBuffer(CF_UNICODETEXT, buf, ffi.sizeof(buf))
end
--get a list of files from clipboard.
function GetClipboardFiles()
require'winapi.shellapi'
return GetClipboardDataBuffer(CF_HDROP, function(buf)
local hdrop = ffi.cast('HDROP', buf)
return DragQueryFiles(hdrop)
end)
end
--put a list of files in clipboard.
function SetClipboardFiles(files)
require'winapi.shellapi'
local df = DROPFILES(files)
return SetClipboardDataBuffer(CF_HDROP, df, ffi.sizeof(df))
end
--test/demo
if not ... then
if not OpenClipboard() then
error'OpenClipboard() failed'
end
print''
print'clipboard as found:'
print''
for i,format in ipairs(GetClipboardFormats()) do
local name
if CF_NAMES[format] then
name = CF_NAMES[format]
else
name = mbs(GetClipboardFormatName(format))
end
print('>' .. name)
if format == CF_UNICODETEXT then
print(GetClipboardText())
elseif format == CF_HDROP then
require'pp'(GetClipboardFiles())
else
GetClipboardDataBuffer(format, function(buf, sz)
print(buf, sz, name)
end)
end
end
print''
print'utf8 text:'
print''
local s = 'hello from the clipboard!'
EmptyClipboard()
SetClipboardText(s)
assert(#GetClipboardFormatNames() == 1)
assert(GetClipboardFormatNames()[1] == CF_UNICODETEXT)
assert(GetClipboardText() == s)
print(GetClipboardText())
print''
print'list of files:'
print''
EmptyClipboard()
SetClipboardFiles{'file1', 'file2', 'file3'}
assert(#GetClipboardFiles() == 3)
assert(GetClipboardFiles()[3] == 'file3')
require'pp'(GetClipboardFiles())
CloseClipboard()
end