Ф-ция kbdLayoutFunc() в macro.cpp возвращает 0 на десятке.
Недокументенная функа GetConsoleKeyboardLayoutNameW возвращает ошибку на 10ке, так что дополнительные проверки не требуются. Просто в console.cpp функцию console::GetKeyboardLayoutName(string &strName) чуть переделать и вместо return false добавить дополнительный if с вызовом GetKeyboardLayoutName (у них с уже использованной формат вывода подходящий). А уж если эта не удалась - тогда return false
Глюки и баги, появившиеся в «ночных сборках»
Posted: Wed 21 Aug, 2019 18:46
by DrKnS
Pasha_ZZZ wrote: ↑Wed 21 Aug, 2019 15:43вместо return false добавить дополнительный if с вызовом GetKeyboardLayoutName
А смысл этого?
GetKeyboardLayoutName всегда возвращает тот layout, который был в момент запуска консоли, и нет, в 10 это не починили.
Именно поэтому в Far используется недокументированная альтернатива.
Лучше уж фейл, чем возвращать шопопало.
DrKnS wrote: ↑Wed 21 Aug, 2019 18:46
GetKeyboardLayoutName всегда возвращает тот layout, который был в момент запуска консоли
Вроде как ф-я сама по себе работает, просто для консоли нет нормального способа найти нужный аргумент.
Нарылся такой проект на гитхабе -- https://github.com/Elfy/getconkbl,
не проверял, даже если работает - это просто некоторая эвристика, никаких гарантий, ну и слишком много приседаний.
Глюки и баги, появившиеся в «ночных сборках»
Posted: Fri 23 Aug, 2019 13:14
by 2useven10
2useven10 wrote: ↑Wed 21 Aug, 2019 20:17
не проверял,
Проверил. Код можно сильно упростить, оставив только 2 toolhelp снимка (процессы и потоки) и пробег по ним.
Среди потоков conhost.exe, владельцем которого является фар, дейтвительно есть такой с которым GetKeyboardLayout(thread_id) отдаёт текущий (а не тот что был при старте) KbdLayout. Но у меня на Win10 это третий поток из 5 (а не второй из 4 как в гитхабовских сорсах).
Как вытаскивать правильный может знать только M$.
Получение текущей раскладки в Windows 10
Posted: Fri 23 Aug, 2019 14:13
by 2useven10
Можно, конечно, выбирать отличающийся (если есть). Для макроса приемлемый вариант, для far сомнительный.
local ffi = require("ffi")
local kernel = ffi.C
local user = ffi.load("user32.dll")
local INVALID_HANDLE_VALUE = ffi.cast("HANDLE", -1)
local TH32CS_SNAPPROCESS = 0x00000002
local TH32CS_SNAPTHREAD = 0x00000004
local mask = 0xFFFFFFFF
ffi.cdef([[
DWORD GetCurrentProcessId(void);
HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID);
BOOL CloseHandle(HANDLE hObject);
typedef struct {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID;
intptr_t th32DefaultHeapID; // ULONG_PTR
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
CHAR szExeFile[260]; // Path [MAX_PATH]
} PROCESSENTRY32;
BOOL Process32First(HANDLE hSnapshot, PROCESSENTRY32 *pe);
BOOL Process32Next(HANDLE hSnapshot, PROCESSENTRY32 *pe);
typedef struct {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ThreadID;
DWORD th32OwnerProcessID;
LONG tpBasePri;
LONG tpDeltaPri;
DWORD dwFlags;
} THREADENTRY32;
BOOL Thread32First(HANDLE hSnapshot, THREADENTRY32 *te);
BOOL Thread32Next(HANDLE hSnapshot, THREADENTRY32 *te);
HANDLE GetKeyboardLayout(DWORD threadId);
DWORD GetWindowThreadProcessId(HWND hWnd, LPDWORD lpdwProcessId);
HWND GetForegroundWindow(void);
]])
local function KbdLayout()
local layout = tonumber(Far.KbdLayout())
if layout ~= 0 then return band(mask, layout) end
local pe = ffi.new("PROCESSENTRY32"); pe.dwSize = ffi.sizeof("PROCESSENTRY32")
local sh = kernel.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
if sh == INVALID_HANDLE_VALUE then return 0 end
local far_pid = kernel.GetCurrentProcessId()
local far_conhost_pid = 0
local work = kernel.Process32First(sh, pe)
while work ~= 0 do
if pe.th32ParentProcessID == far_pid then
local name = ffi.string(pe.szExeFile)
if name == "conhost.exe" then
far_conhost_pid = pe.th32ProcessID
break
end
end
work = kernel.Process32Next(sh, pe);
end
kernel.CloseHandle(sh)
if far_conhost_pid == 0 then -- no conhost found probably far+conemu: GUI case
local wnd = user.GetForegroundWindow()
local thw = user.GetWindowThreadProcessId(wnd, ffi.NULL)
return band(mask, tonumber(ffi.cast("intptr_t",kernel.GetKeyboardLayout(thw))))
end
local te = ffi.new("THREADENTRY32"); te.dwSize = ffi.sizeof("THREADENTRY32")
sh = kernel.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if sh == INVALID_HANDLE_VALUE then return 0 end
local lng0 = tonumber(ffi.cast("intptr_t", user.GetKeyboardLayout(0)))
local lng = 0
work = kernel.Thread32First(sh, te)
while work ~= 0 do
if te.th32OwnerProcessID == far_conhost_pid then
lng = tonumber(ffi.cast("intptr_t", user.GetKeyboardLayout(te.th32ThreadID)))
if lng ~=0 and lng ~= lng0 then break end
end
work = kernel.Thread32Next(sh, te)
end
kernel.CloseHandle(sh)
if lng == 0 then lng = lng0 end
return band(mask, lng)
end
far.Show(("0x%08X"):format(KbdLayout()))
вроде бы работает...
Получение текущей раскладки в Windows 10
Posted: Sat 24 Aug, 2019 00:33
by 2useven10
Старшая половина почему-то через GetKeyboardLayout() и GetkeyboardLayoutName() при переключении на русский отличается.
И 16 бит вполне хватает для выяснения факта переключения, поэтому обрезано.
PS: в скрипте была глобальная переменная - исправил. Может и ещё есть косяки - сообщайте...
Получение текущей раскладки в Windows 10
Posted: Sat 24 Aug, 2019 06:51
by 2useven10
скрипт поправлен -- должен работать под ConEmu.
Получение текущей раскладки в Windows 10
Posted: Sat 24 Aug, 2019 11:43
by Shmuel
2useven10, это функция определения текущей раскладки. А как обстоят дела в Windows 10 с переключением раскладки (Far.KbdLayout(1), Far.KbdLayout(-1)) - это работает из коробки?
Получение текущей раскладки в Windows 10
Posted: Sat 24 Aug, 2019 12:08
by 2useven10
У меня переключается нормально -- 1, -1, 0x04090409, 0x04190419
Получение текущей раскладки в Windows 10
Posted: Sat 24 Aug, 2019 12:19
by Shmuel
А переключение в определённую раскладку работает (Far.KbdLayout(0x0409 или 0x0419) ?
Получение текущей раскладки в Windows 10
Posted: Sat 24 Aug, 2019 12:23
by John Doe
Shmuel wrote: ↑Sat 24 Aug, 2019 12:19
А переключение в определённую раскладку работает (Far.KbdLayout(0x0409 или 0x0419) ?