Исправление некорректного юникода из буфера обмена

Здесь обсуждается всё, что касается макросов.
Smitis
Posts: 1493
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 14 times
Been thanked: 25 times
Contact:

Re: Вставка текста из буфера и обработка результата макросом

Post by Smitis » Fri 19 Jul, 2013 10:33

Latest post of the previous page:

LAT wrote:Для висты/семерки как-то так:
Я же и говорю - заменой файлов. И действительно, только для если нужны русский/английский.

2useven10, спасибо!
Макрос полезный. Я наконец смог из WinCC нормально текст скопировать.
Разум когда-нибудь победит.

User avatar
zg
zero-gravity
Posts: 5313
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 49 times
Contact:

Re: Вставка текста из буфера и обработка результата макросом

Post by zg » Fri 19 Jul, 2013 11:33

LAT wrote:Проблема с некоторыми (всеми?) такими кривыми программами лечится правкой реестра:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage]
"1250"="c_1251.nls"
"1251"="c_1251.nls"
"1252"="c_1251.nls"
"1253"="c_1251.nls"
Возможно, достаточно будет поправить только параметр "1252"
вот после таких чудо-хакеров звонят и жалуются, что символ евро не печатается.

Smitis
Posts: 1493
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 14 times
Been thanked: 25 times
Contact:

Re: Вставка текста из буфера и обработка результата макросом

Post by Smitis » Fri 19 Jul, 2013 11:39

zg wrote:вот после таких чудо-хакеров звонят и жалуются, что символ евро не печатается.
Иногда просто нет выбора - либо русские буквы в нужной программе, либо символ евро где-то ещё.
Разум когда-нибудь победит.

User avatar
zg
zero-gravity
Posts: 5313
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 49 times
Contact:

Re: Вставка текста из буфера и обработка результата макросом

Post by zg » Fri 19 Jul, 2013 12:58

Smitis wrote:Иногда просто нет выбора - либо русские буквы в нужной программе, либо символ евро где-то ещё.
в моём случае это было не так. чудо-хакер исправил реестр на всякий случай. ну и в данной теме это звучит тоже необоснованно.

User avatar
John Doe
Бюрократ
Posts: 11433
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 17 times
Been thanked: 102 times

Исправление некорректного юникода из буфера обмена

Post by John Doe » Wed 08 Jul, 2015 12:41

Альтернативная реализация макроса.
Используя ffi проверяет какому приложению принадлежит текущий буфер, и если это одно из заданных, то заново формирует CF_UNICODETEXT из CF_TEXT.
Написано исключительно из спортивного интереса.
  1. --http://forum.farmanager.com/viewtopic.php?f=15&t=8093&p=131056#p131056
  2. local ffi = require"ffi"
  3. ffi.cdef[[
  4. BOOL OpenClipboard(HWND hWndNewOwner);//_In_opt_ //https://msdn.microsoft.com/library/ms649048
  5. BOOL CloseClipboard(void); //https://msdn.microsoft.com/library/ms649035
  6. HANDLE GetClipboardData(UINT uFormat); //https://msdn.microsoft.com/library/ms649039
  7. HANDLE SetClipboardData( //https://msdn.microsoft.com/library/ms649051
  8.   UINT   uFormat,//_In_
  9.   HANDLE hMem    //_In_opt_
  10. );
  11. BOOL EmptyClipboard(void); //https://msdn.microsoft.com/library/ms649037
  12. HWND GetClipboardOwner(void); //https://msdn.microsoft.com/library/ms649041
  13. HGLOBAL GlobalAlloc( //https://msdn.microsoft.com/library/aa366574
  14.   UINT   uFlags,
  15.   SIZE_T dwBytes
  16. );
  17. HGLOBAL GlobalFree(HGLOBAL hMem); //https://msdn.microsoft.com/library/aa366579
  18. LPVOID GlobalLock(HGLOBAL hMem); //https://msdn.microsoft.com/library/aa366584
  19. BOOL GlobalUnlock(HGLOBAL hMem); //https://msdn.microsoft.com/library/aa366595
  20. DWORD GetWindowThreadProcessId(  //https://msdn.microsoft.com/library/ms633522
  21.   HWND    hWnd,         //_In_
  22.   LPDWORD lpdwProcessId //_Out_opt_
  23. );
  24. DWORD GetModuleFileNameExW( //https://msdn.microsoft.com/library/ms683198
  25.   HANDLE  hProcess,    //_In_
  26.   HMODULE hModule,     //_In_opt_
  27.   LPTSTR  lpFilename,  //_Out_
  28.   DWORD   nSize        //_In_
  29. );
  30. //DWORD GetProcessImageFileNameW( //https://msdn.microsoft.com/library/ms683217
  31. //  HANDLE hProcess,         //_In_
  32. //  LPTSTR lpImageFileName,  //_Out_
  33. //  DWORD  nSize             //_In_
  34. //);
  35. HANDLE OpenProcess( //https://msdn.microsoft.com/library/ms684320
  36.   DWORD dwDesiredAccess,
  37.   BOOL  bInheritHandle,
  38.   DWORD dwProcessId
  39. );
  40. BOOL IsClipboardFormatAvailable(UINT format); //https://msdn.microsoft.com/library/ms649047
  41. ]]
  42.  
  43. local C = ffi.C
  44. local CF_TEXT = 1
  45. --local CF_OEMTEXT = 7
  46. local CF_UNICODETEXT = 13
  47. local GMEM_MOVEABLE = 0x0002
  48. local PROCESS_VM_READ = 0x0010
  49. local PROCESS_QUERY_INFORMATION = 0x0400
  50.  
  51. local maxlen = 256
  52. local buff = ffi.new("wchar_t[?]",maxlen)
  53. local PSAPI = ffi.load"psapi"
  54. local function GetClipboardOwnerExe()
  55.   local HWND = C.GetClipboardOwner()
  56.   local lpdwProcessId = ffi.new("DWORD[1]")
  57.   if C.GetWindowThreadProcessId(HWND,lpdwProcessId)~=0 then
  58.     local dwProcessId = lpdwProcessId[0]
  59.     local hProcess =    C.OpenProcess(bit64.bor(PROCESS_VM_READ,PROCESS_QUERY_INFORMATION),0,dwProcessId)
  60.     if hProcess==nil then far.Message("",nil,nil,"e"); return end
  61.     --local c = PSAPI.GetProcessImageFileNameW(hProcess,ffi.cast("void*",buff),maxlen)
  62.     local c = PSAPI.GetModuleFileNameExW(hProcess,nil,ffi.cast("void*",buff),maxlen)
  63.     if c~=0 then
  64.       return win.Utf16ToUtf8(ffi.string(buff,c*ffi.sizeof"wchar_t")):match"([^\\]+)%.exe$":lower()
  65.     else
  66.       --far.Message("",nil,nil,"e")
  67.     end
  68.   end
  69. end
  70.  
  71. local function fixUnicodeText()
  72.   --based on sample from https://msdn.microsoft.com/library/ms64 ... _Clipboard
  73.   if C.IsClipboardFormatAvailable(CF_TEXT) and C.OpenClipboard(nil)~=0 then
  74.     local hglb = C.GetClipboardData(CF_TEXT)
  75.     local lpstr = C.GlobalLock(hglb)
  76.     local utf16
  77.     if lpstr~=nil then
  78.       local str = ffi.string(lpstr)
  79.       utf16 = win.MultiByteToWideChar(str,win.GetACP())
  80.       ---> set proper CF_UNICODETEXT
  81.       local hglbCopy = C.GlobalAlloc(GMEM_MOVEABLE,(str:len()+1)*ffi.sizeof"wchar_t");
  82.       if hglbCopy~=nil then
  83.         local lptstrCopy = ffi.gc(C.GlobalLock(hglbCopy),function()C.GlobalFree(hglbCopy)end)
  84.         if lptstrCopy~=nil then
  85.           ffi.copy(lptstrCopy,utf16.."\0")
  86.           if C.GlobalUnlock(hglbCopy)==0 and C.SetClipboardData(CF_UNICODETEXT,hglbCopy)~=nil then
  87.             ffi.gc(lptstrCopy,nil)
  88.           end
  89.         end
  90.       end
  91.       ---<
  92.       C.GlobalUnlock(hglb)
  93.     end
  94.     C.CloseClipboard()
  95.     --return win.Utf16ToUtf8(utf16)
  96.   end
  97. end
  98.  
  99. local legacy = {["1cv7s"]=true}
  100.  
  101. Macro { description="исправление кривого юникода в буфера обмена";
  102.   area="Editor Dialog Shell QView Tree Info"; key="ShiftIns";
  103.   uid="A012927B-C307-4177-A8BB-FE3C3EB1921C";
  104.   condition=function()
  105.     if not Area.Dialog or Dlg.ItemType==far.Flags.DI_EDIT then
  106.       local exe = GetClipboardOwnerExe()
  107.       return exe and legacy[exe]
  108.     end
  109.   end;
  110.   action=function()
  111.     fixUnicodeText()
  112.     Keys"AKey"
  113.   end;
  114. }
Update
Переделал:

User avatar
John Doe
Бюрократ
Posts: 11433
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 17 times
Been thanked: 102 times

Исправление некорректного юникода из буфера обмена

Post by John Doe » Sun 07 Aug, 2016 20:34

Упрощённая версия:
  1. --http://forum.farmanager.com/viewtopic.php?f=15&t=8093&p=131056#p131056
  2. local ffi = require"ffi"
  3. ffi.cdef[[
  4. BOOL OpenClipboard(HWND hWndNewOwner); //_In_opt_ //https://msdn.microsoft.com/library/ms649048
  5. BOOL CloseClipboard(void); //https://msdn.microsoft.com/library/ms649035
  6. HANDLE GetClipboardData(UINT uFormat); //https://msdn.microsoft.com/library/ms649039
  7. LPVOID GlobalLock(HGLOBAL hMem); //https://msdn.microsoft.com/library/aa366584
  8. BOOL GlobalUnlock(HGLOBAL hMem); //https://msdn.microsoft.com/library/aa366595
  9. BOOL IsClipboardFormatAvailable(UINT format); //https://msdn.microsoft.com/library/ms649047
  10. UINT EnumClipboardFormats(UINT format); //_In_ //https://msdn.microsoft.com/library/ms649038
  11. ]]
  12.  
  13. local C = ffi.C
  14. local CF_TEXT = 1
  15. local CF_LOCALE = 16
  16.  
  17. local function GetClipboardData(format,getf)
  18.   local hglb = C.GetClipboardData(format)
  19.   if hglb~=0 then
  20.     local lpstr = C.GlobalLock(hglb)
  21.     if lpstr~=nil then
  22.       local out = (getf or ffi.string)(lpstr)
  23.       C.GlobalUnlock(hglb)
  24.       return out
  25.     end
  26.   end
  27. end
  28.  
  29. local ru_RU = 0x419 --https://msdn.microsoft.com/en-us/goglobal/bb896001.aspx
  30. local function fixUnicodeText()
  31.   if C.IsClipboardFormatAvailable(CF_TEXT) and C.OpenClipboard(nil)~=0 then
  32.     local utf8
  33.     if C.EnumClipboardFormats(0)==CF_TEXT then
  34.       local locale = GetClipboardData(CF_LOCALE,function(buf)return ffi.cast("LCID*",buf)[0] end)
  35.       if locale~=ru_RU then
  36.         local ansi = GetClipboardData(CF_TEXT)
  37.         if ansi then
  38.           utf8 = win.Utf16ToUtf8(win.MultiByteToWideChar(ansi,win.GetACP()))
  39.         end
  40.       end
  41.     end
  42.     C.CloseClipboard()
  43.     return utf8
  44.   end
  45. end
  46.  
  47. local text
  48. Macro { description="исправление кривого юникода в буфера обмена";
  49.   area="Editor Dialog Shell QView Tree Info"; key="ShiftIns";
  50.   id="A012927B-C307-4177-A8BB-FE3C3EB1921C";
  51.   condition=function()
  52.     if not Area.Dialog or Dlg.ItemType==far.Flags.DI_EDIT then
  53.       text = fixUnicodeText()
  54.       return text
  55.     end
  56.   end;
  57.   action=function()
  58.     mf.beep()
  59.     mf.print(text)
  60.   end;
  61. }

Post Reply

Return to “Обсуждение макросов”