--http://forum.farmanager.com/viewtopic.php?f=15&t=8093&p=131056#p131056
--https://msdn.microsoft.com/library/ms649016#_win32_Copying_Information_to_the_Clipboard
local ffi = require"ffi"
ffi.cdef[[
HWND GetConsoleWindow(void);//https://msdn.microsoft.com/library/ms683175
BOOL OpenClipboard(HWND hWndNewOwner);//_In_opt_ //https://msdn.microsoft.com/library/ms649048
BOOL CloseClipboard(void); //https://msdn.microsoft.com/library/ms649035
HANDLE GetClipboardData(UINT uFormat); //https://msdn.microsoft.com/library/ms649039
HANDLE SetClipboardData( //https://msdn.microsoft.com/library/ms649051
UINT uFormat,//_In_
HANDLE hMem //_In_opt_
);
BOOL EmptyClipboard(void); //https://msdn.microsoft.com/library/ms649037
HWND GetClipboardOwner(void); //https://msdn.microsoft.com/library/ms649041
HGLOBAL GlobalAlloc( //https://msdn.microsoft.com/library/aa366574
UINT uFlags,
SIZE_T dwBytes
);
HGLOBAL GlobalFree(HGLOBAL hMem); //https://msdn.microsoft.com/library/aa366579
LPVOID GlobalLock(HGLOBAL hMem); //https://msdn.microsoft.com/library/aa366584
BOOL GlobalUnlock(HGLOBAL hMem); //https://msdn.microsoft.com/library/aa366595
DWORD GetWindowThreadProcessId( //https://msdn.microsoft.com/library/ms633522
HWND hWnd, //_In_
LPDWORD lpdwProcessId //_Out_opt_
);
DWORD GetProcessImageFileNameW( //https://msdn.microsoft.com/library/ms683217
HANDLE hProcess, //_In_
LPTSTR lpImageFileName, //_Out_
DWORD nSize //_In_
);
HANDLE OpenProcess( //https://msdn.microsoft.com/library/ms684320
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
);
BOOL IsClipboardFormatAvailable(UINT format); //https://msdn.microsoft.com/library/ms649047
UINT EnumClipboardFormats(UINT format); //_In_ //https://msdn.microsoft.com/library/ms649038
]]
local C = ffi.C
local CF_TEXT = 1
local CF_LOCALE = 16
local GMEM_MOVEABLE = 0x0002
--local PROCESS_VM_READ = 0x0010
local PROCESS_QUERY_INFORMATION = 0x0400
local PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
local maxlen = 256
local buff = ffi.new("wchar_t[?]",maxlen)
local PSAPI = ffi.load"psapi"
local function GetClipboardOwnerExe()
local HWND = C.GetClipboardOwner()
local lpdwProcessId = ffi.new("DWORD[1]")
if C.GetWindowThreadProcessId(HWND,lpdwProcessId)~=0 then
local dwProcessId = lpdwProcessId[0]
local hProcess = C.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,0,dwProcessId)
--local hProcess = C.OpenProcess(bit64.bor(PROCESS_VM_READ,PROCESS_QUERY_LIMITED_INFORMATION),0,dwProcessId)
if hProcess==nil then far.Message("OpenProcess",nil,nil,"e"); return end
local c = PSAPI.GetProcessImageFileNameW(hProcess,ffi.cast("void*",buff),maxlen)
--local c = PSAPI.GetModuleFileNameExW(hProcess,nil,ffi.cast("void*",buff),maxlen)
if c~=0 then
return win.Utf16ToUtf8(ffi.string(buff,c*ffi.sizeof"wchar_t")):match"([^\\]+)%.exe$":lower()
else
far.Message("GetModuleFileNameExW",nil,nil,"e")
end
end
end
local function GetClipboardData(format,getf)
local hglb = C.GetClipboardData(format)
if hglb~=0 then
local lpstr = C.GlobalLock(hglb)
if lpstr~=nil then
local out = (getf or ffi.string)(lpstr)
C.GlobalUnlock(hglb)
return out
end
end
end
local function SetClipboardData(format,data,size,copyf)
local hglbCopy = C.GlobalAlloc(GMEM_MOVEABLE,size)
if hglbCopy~=nil then
local lptstrCopy = C.GlobalLock(hglbCopy)
if lptstrCopy~=nil then
(copyf or ffi.copy)(lptstrCopy,data)
if C.GlobalUnlock(hglbCopy)==0 then
return C.SetClipboardData(format,hglbCopy)~=nil
end
end
C.GlobalFree(hglbCopy)
end
end
local ru_RU = 0x419 --https://msdn.microsoft.com/en-us/goglobal/bb896001.aspx
local function fixUnicodeText()
if C.IsClipboardFormatAvailable(CF_TEXT) and C.OpenClipboard(C.GetConsoleWindow())~=0 then
local success
if C.EnumClipboardFormats(0)==CF_TEXT then
local locale = GetClipboardData(CF_LOCALE,function(buf)return ffi.cast("LCID*",buf)[0] end)
if locale~=ru_RU then
local ansi = GetClipboardData(CF_TEXT)
if ansi then
C.EmptyClipboard()
if SetClipboardData(CF_TEXT,ansi,ansi:len()+1) then
success = SetClipboardData(CF_LOCALE,ru_RU,ffi.sizeof"LCID",function(buf,data)
ffi.cast("LCID*",buf)[0] = data
end)
end
if not success then far.Message("SetClipboardData",nil,nil,"ew") end
end
end
end
C.CloseClipboard()
return success
end
end
local legacy = {["1cv7s"]=true}
Macro { description="исправление кривого юникода в буфера обмена";
area="Editor Dialog Shell QView Tree Info"; key="ShiftIns";
id="A012927B-C307-4177-A8BB-FE3C3EB1921C";
condition=function()
if not Area.Dialog or Dlg.ItemType==far.Flags.DI_EDIT then
local exe = GetClipboardOwnerExe()
if exe and legacy[exe] then
fixUnicodeText()
end
end
end;
action=function()end;
}