<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Серый форум &mdash; AHK: Класс для операций с раскладками]]></title>
		<link>http://forum.script-coding.com/viewtopic.php?id=12452</link>
		<atom:link href="http://forum.script-coding.com/extern.php?action=feed&amp;tid=12452&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «AHK: Класс для операций с раскладками».]]></description>
		<lastBuildDate>Thu, 16 Feb 2017 19:21:41 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: AHK: Класс для операций с раскладками]]></title>
			<link>http://forum.script-coding.com/viewtopic.php?pid=112664#p112664</link>
			<description><![CDATA[<div class="quotebox"><cite>stealzy пишет:</cite><blockquote><p>Возможно для неактивного окна стоит брать список контролов, и слать всем?</p></blockquote></div><p>Хорошая догадка, только бывают окна, где нет контролов, поэтому нужно слать ещё и самому окну.</p><div class="quotebox"><cite>stealzy пишет:</cite><blockquote><p>С параметром Forward тогда не выйдет.</p></blockquote></div><p>Да, но можно определять текущую раскладку, и слать следующую в списке.</p><div class="quotebox"><cite>stealzy пишет:</cite><blockquote><p>По параметру INPUTLANGCHANGE_SYSCHARSET</p></blockquote></div><p>Не заморачивайся, там куда-то совсем глубоко копать нужно, на практике его влияния замечено не было.</p><p>Заметил несколько недочётов:</p><div class="quotebox"><blockquote><div class="codebox"><pre><code>VarSetCapacity(KLID, 8*(A_IsUnicode+1))</code></pre></div></blockquote></div><p>Такая конструкция в ANSI-версии не сработает, там A_IsUnicode равно пустому значению.<br /></p><div class="quotebox"><blockquote><div class="codebox"><pre><code>Hex(num) {
	OldFormat := A_FormatInteger
	SetFormat, Integer, Hex
	num += 0
	SetFormat, Integer, %OldFormat%
	Return num
}</code></pre></div></blockquote></div><p>Устаревший способ. Сейчас для преобразования в hex есть функция Format().</p>]]></description>
			<author><![CDATA[null@example.com (teadrinker)]]></author>
			<pubDate>Thu, 16 Feb 2017 19:21:41 +0000</pubDate>
			<guid>http://forum.script-coding.com/viewtopic.php?pid=112664#p112664</guid>
		</item>
		<item>
			<title><![CDATA[AHK: Класс для операций с раскладками]]></title>
			<link>http://forum.script-coding.com/viewtopic.php?pid=112633#p112633</link>
			<description><![CDATA[<p>Получение информации о раскладках: текущая раскладка в окне, список загруженных раскладок в системе;<br />Установка раскладки: следующей/предыдущей в списке, другой локали (языка), конкретной раскладки по имени, по идентификатору, по номеру. В окне или во всех окнах.<br /></p><div class="codebox"><pre><code>#SingleInstance force
Loop % Lyt.GetList().MaxIndex()
	str .= A_Index &quot;: &quot; Lyt.GetList()[A_Index].LocName &quot; - &quot; Lyt.GetList()[A_Index].LayoutName
	. &quot;`n&quot; Format(&quot;{:#010x}&quot;, Lyt.GetList()[A_Index].hkl) &quot;`n&quot;

MsgBox,, Your system loaded layout list, % str &quot;`n&quot; defaulSystemLayout
F1::ToolTip % Lyt.Set(&quot;EN&quot;)           ; set first EN locale layout in system loaded layout list
F2::ToolTip % Lyt.Set(&quot;switch&quot;)       ; switch input locale. Lyt.Set() do the same.
F3::ToolTip % Lyt.Set(&quot;forward&quot;)      ; move forward (cycle) in layout list
F4::ToolTip % Lyt.Set(2)              ; set second layout in list
F7::ToolTip % Lyt.Set(&quot;-EN&quot;)          ; set first non-english layout in list
F8::ToolTip % Lyt.Set(0x4090409)      ; set en-US layout by HKL
F9::Lyt.Set(&quot;forward&quot;, WinExist(&quot;AutoHotkey Help ahk_class HH Parent&quot;)) ; in AutoHotkey.chm windows
F10::Lyt.Set(&quot;en&quot;, &quot;AutoHotkey Help ahk_class HH Parent&quot;)
F11::MsgBox % Lyt.GetLayoutName(&quot;AutoHotkey Help ahk_class HH Parent&quot;)
F12::MsgBox % &quot;HKL: &quot; Format(&quot;{:#010x}&quot;, Lyt.GetInputHKL()) &quot;`n№: &quot; Lyt.GetNum() &quot; in system loaded list&quot;
 . &quot;`nLayoutName: &quot; Lyt.GetLayoutName() &quot;`nLocale: &quot; Lyt.GetLocaleName()
 . &quot; (&quot; Lyt.GetLocaleName(,, true) &quot;)`n&quot; Lyt.GetList()[3].KLID
; . &quot;`n&quot; Lyt.GetList()[2].LayoutName &quot; &quot; Lyt.GetList()[2].LocName &quot; &quot; Lyt.GetList()[2].LocFullName
Esc::ExitApp

Class Lyt {
	static SISO639LANGNAME            := 0x0059 ; ISO abbreviated language name, eg &quot;EN&quot;
	static LOCALE_SENGLANGUAGE        := 0x1001 ; Full language name, eg &quot;English&quot;
	static WM_INPUTLANGCHANGEREQUEST  := 0x0050
	static INPUTLANGCHANGE_FORWARD    := 0x0002
	static INPUTLANGCHANGE_BACKWARD   := 0x0004
	static KLIDsREG_PATH              := &quot;HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\&quot;
	; =========================================================================================================
	; PUBLIC METHOD Set()
	; Parameters:     arg (optional)   - (switch / forward / backward / 2-letter locale indicator name (EN) /
	;  / number of layout in system loaded layout list / language id e.g. HKL (0x04090409)). Default: switch
	;                 win (optional)   - (ahk format WinTitle / hWnd / &quot;global&quot;). Default: Active Window
	; Return value:   empty or description of error
	; =========================================================================================================
	Set(arg := &quot;switch&quot;, win := &quot;&quot;) {
		IfEqual win, 0, Return &quot;Window not found&quot;
		hWnd := (win = &quot;&quot;)
						? WinExist(&quot;A&quot;)
						: ( win + 0
								? WinExist(&quot;ahk_id&quot; win)
								: win = &quot;global&quot;
									? win
									: WinExist(win) )
		IfEqual hWnd, 0, Return &quot;Window not found&quot; ; WinExist() return 0

		if (arg = &quot;forward&quot;) {
			Return this.ChangeCommon(, this.INPUTLANGCHANGE_FORWARD, hWnd)
		} else if (arg = &quot;backward&quot;) {
			Return this.ChangeCommon(, this.INPUTLANGCHANGE_BACKWARD, hWnd)
		} else if (arg = &quot;switch&quot;) {
			tmphWnd := (hWnd = &quot;global&quot;) ? WinExist(&quot;A&quot;) : hWnd
			HKL := this.GetInputHKL(tmphWnd)
			HKL_Number := this.GetNum(,HKL)
			LytList := this.GetList()
			Loop % HKL_Number - 1 {
				If (LytList[A_Index].hkl &amp; 0xFFFF  !=  HKL &amp; 0xFFFF)
					Return this.ChangeCommon(LytList[A_Index].hkl,, hWnd)
			}
			Loop % LytList.MaxIndex() - HKL_Number
				If (LytList[A_Index + HKL_Number].hkl &amp; 0xFFFF  !=  HKL &amp; 0xFFFF)
					Return this.ChangeCommon(LytList[A_Index + HKL_Number].hkl,, hWnd)
		} else if (arg ~= &quot;^-?[A-z]{2}&quot;) {
			invert := ((SubStr(arg, 1, 1) = &quot;-&quot;) &amp;&amp; (arg := SubStr(arg, 2, 2))) ? true : false
			For index, layout in this.GetList()
				if (InStr(layout.LocName, arg) ^ invert)
					Return this.ChangeCommon(layout.hkl,, hWnd)
			Return &quot;HKL from this locale not found in system loaded layout list&quot;
		} else if (arg &gt; 0 &amp;&amp; arg &lt;= this.GetList().MaxIndex()) { ; HKL number in system loaded layout list
			Return this.ChangeCommon(this.GetList()[arg].hkl,, hWnd)
		} else if (arg &gt; 0x400 || arg &lt; 0) { ; HKL handle input
			For index, layout in this.GetList()
				if layout.hkl = arg
					Return this.ChangeCommon(arg,, hWnd)
			Return &quot;This HKL not found in system loaded layout list&quot;
		} else
			Return &quot;Not valid input&quot;
	}
	ChangeCommon(HKL := 0, INPUTLANGCHANGE := 0, hWnd := 0) {
		Return (hWnd = &quot;global&quot;)
			? this.ChangeGlobal(HKL, INPUTLANGCHANGE)
			: this.ChangeWindow(HKL, INPUTLANGCHANGE, hWnd)
	}
	ChangeGlobal(HKL, INPUTLANGCHANGE) { ; in all windows
		If (INPUTLANGCHANGE != 0)
			Return &quot;FORWARD and BACKWARD not support with global parametr.&quot;
		IfNotEqual A_DetectHiddenWindows, On, DetectHiddenWindows % (prevDHW := &quot;Off&quot;) ? &quot;On&quot; : &quot;&quot;
		WinGet List, List
		Loop % List
			this.Change(HKL, INPUTLANGCHANGE, List%A_Index%)
		DetectHiddenWindows % prevDHW
	}
	ChangeWindow(HKL, INPUTLANGCHANGE, hWnd) {
		static hTaskBarHwnd := WinExist(&quot;ahk_class Shell_TrayWnd ahk_exe explorer.exe&quot;)
		(hWnd = hTaskBarHwnd)
		 ? this.ChangeTaskBar(HKL, INPUTLANGCHANGE, hTaskBarHwnd)
		 : this.Change(HKL, INPUTLANGCHANGE, hWnd)
	}
	ChangeTaskBar(HKL, INPUTLANGCHANGE, hTaskBarHwnd) {
		static hStartMenu, hLangBarInd, hDV2CH
		IfNotEqual A_DetectHiddenWindows, On, DetectHiddenWindows % (prevDHW := &quot;Off&quot;) ? &quot;On&quot; : &quot;&quot;
		hStartMenu := hStartMenu  ? hStartMenu  : WinExist(&quot;ahk_classNativeHWNDHost ahk_exeexplorer.exe&quot;)
		hLangBarInd:= hLangBarInd ? hLangBarInd : WinExist(&quot;ahk_classCiceroUIWndFrame ahk_exeexplorer.exe&quot;)
		hDV2CH     := hDV2CH      ? hDV2CH      : WinExist(&quot;ahk_classDV2ControlHost ahk_exeexplorer.exe&quot;)

		this.Change(HKL, INPUTLANGCHANGE, hTaskBarHwnd)
		this.Change(HKL, INPUTLANGCHANGE, hStartMenu)
		If INPUTLANGCHANGE {
			Sleep 20
			HKL := this.GetInputHKL(hStartMenu), INPUTLANGCHANGE := 0
		}
		; to update Language bar indicator
		this.Change(HKL, INPUTLANGCHANGE, hLangBarInd)
		this.Change(HKL, INPUTLANGCHANGE, hDV2CH)
		DetectHiddenWindows % prevDHW
	}
	Change(HKL, INPUTLANGCHANGE, hWnd) {
		PostMessage, this.WM_INPUTLANGCHANGEREQUEST, % HKL ? &quot;&quot; : INPUTLANGCHANGE, % HKL ? HKL : &quot;&quot;,
		, % &quot;ahk_id&quot; ((hWndOwn := DllCall(&quot;GetWindow&quot;, Ptr,hWnd, UInt,GW_OWNER:=4, Ptr)) ? hWndOwn : hWnd)
	}

	GetNum(win := &quot;&quot;, HKL := 0) { ; layout Number in system loaded layout list
		HKL ? : HKL := this.GetInputHKL(win)
		If HKL {
			For index, layout in this.GetList()
				if (layout.hkl = HKL)
					Return index
		}
		Else If (KLID := this.KLID, this.KLID := &quot;&quot;)
			For index, layout in this.GetList()
				if (layout.KLID = KLID)
					Return index
	}
	GetList() { ; List of system loaded layouts
		static aLayouts
		If IsObject(aLayouts)
			Return aLayouts
		Else {
			aLayouts := []
			Size := DllCall(&quot;GetKeyboardLayoutList&quot;, &quot;UInt&quot;, 0, &quot;Ptr&quot;, 0)
			VarSetCapacity(List, A_PtrSize*Size)
			Size := DllCall(&quot;GetKeyboardLayoutList&quot;, Int, Size, Str, List)
			Loop % Size {
				aLayouts[A_Index] := {}
				aLayouts[A_Index].hkl := NumGet(List, A_PtrSize*(A_Index - 1))
				aLayouts[A_Index].LocName := this.GetLocaleName(, aLayouts[A_Index].hkl)
				aLayouts[A_Index].LocFullName := this.GetLocaleName(, aLayouts[A_Index].hkl, true)
				aLayouts[A_Index].LayoutName := this.GetLayoutName(, aLayouts[A_Index].hkl)
				aLayouts[A_Index].KLID := this.GetKLIDfromHKL(aLayouts[A_Index].hkl)
			}
			Return aLayouts
		}
	}
	GetLocaleName(win := &quot;&quot;, HKL := false, FullName := false) { ; e.g. &quot;EN&quot;
		HKL ? : HKL := this.GetInputHKL(win)
		If HKL
			LocID := HKL &amp; 0xFFFF
		Else If (HKL = 0)  ;ConsoleWindow
			LocID := &quot;0x&quot; . SubStr(this.KLID, -3), this.KLID := &quot;&quot;
		Else
			Return

		LCType := FullName ? this.LOCALE_SENGLANGUAGE : this.SISO639LANGNAME
		Size := (DllCall(&quot;GetLocaleInfo&quot;, UInt, LocID, UInt, LCType, UInt, 0, UInt, 0) * 2)
		VarSetCapacity(localeSig, Size, 0)
		DllCall(&quot;GetLocaleInfo&quot;, UInt, LocID, UInt, LCType, Str, localeSig, UInt, Size)
		Return localeSig
	}
	GetLayoutName(win := &quot;&quot;, HKL := false) { ; Layout name in OS display lang: &quot;US&quot;, &quot;United States-Dvorak&quot;
		HKL ? : HKL := this.GetInputHKL(win)
		If HKL
			KLID := this.GetKLIDfromHKL(HKL)
		Else If (HKL = 0)  ;ConsoleWindow
			KLID := this.KLID, this.KLID := &quot;&quot;
		Else
			Return

		RegRead LayoutName, % this.KLIDsREG_PATH KLID, Layout Display Name
		DllCall(&quot;Shlwapi.dll\SHLoadIndirectString&quot;, Ptr,&amp;LayoutName, Ptr,&amp;LayoutName, UInt,outBufSize:=50, UInt,0)
		if !LayoutName
			RegRead LayoutName, % this.KLIDsREG_PATH KLID, Layout Text

		Return LayoutName
	}
	; Only for loaded in system layouts
	GetKLIDfromHKL(HKL) {
		VarSetCapacity(KLID, 8 * (A_IsUnicode ? 2 : 1))

		priorHKL := DllCall(&quot;GetKeyboardLayout&quot;, Ptr,DllCall(&quot;GetWindowThreadProcessId&quot;, Ptr,0, UInt,0, Ptr), Ptr)
		if !DllCall(&quot;ActivateKeyboardLayout&quot;, Ptr,HKL, UInt,0)
		|| !DllCall(&quot;GetKeyboardLayoutName&quot;, Ptr,&amp;KLID)
			Return false
		DllCall(&quot;ActivateKeyboardLayout&quot;, Ptr,priorHKL, UInt,0)

		Return StrGet(&amp;KLID)
	}
	; =========================================================================================================
	; PUBLIC METHOD GetInputHKL()
	; Parameters:     win (optional)   - (&quot;&quot; / hWnd / WinTitle). Default: &quot;&quot; — Active Window
	; Return value:   HKL of window / if handle incorrect, system default layout HKL return / 0 - if KLID found
	; =========================================================================================================
	GetInputHKL(win := &quot;&quot;) {
		If win = 0
			Return,, ErrorLevel := &quot;Window not found&quot;
		hWnd := (win = &quot;&quot;)
						? WinExist(&quot;A&quot;)
						: win + 0
							? WinExist(&quot;ahk_id&quot; win)
							: WinExist(win)
		If hWnd = 0
			Return,, ErrorLevel := &quot;Window &quot; win &quot; not found&quot;

		WinGetClass class
		if (class == &quot;ConsoleWindowClass&quot;) {
				WinGet consolePID, PID
				DllCall(&quot;AttachConsole&quot;, Ptr, consolePID)
				VarSetCapacity(KLID, 16)
				DllCall(&quot;GetConsoleKeyboardLayoutName&quot;, Str, KLID)
				DllCall(&quot;FreeConsole&quot;)
				this.KLID := KLID
				Return 0
		} else {
			; Dvorak on OSx64 0xfffffffff0020409 = -268303351   -&gt;   0xf0020409 = 4026663945 Dvorak on OSx86
			HKL:=DllCall(&quot;GetKeyboardLayout&quot;, Ptr,DllCall(&quot;GetWindowThreadProcessId&quot;, Ptr,hWnd, UInt,0, Ptr), Ptr)
			Return HKL &amp; ((1 &lt;&lt; 8*A_PtrSize) - 1)
		}
	}
}

hex(n) {
	Return Format(&quot;{:#0x}&quot;, n)
}
/*
~LShift Up::(A_PriorKey = &quot;LShift&quot;) ? Lyt.Set(&quot;EN&quot;)
~RShift Up::(A_PriorKey = &quot;RShift&quot;) ? Lyt.Set(&quot;RU&quot;)

#Space::PostMessage WM_INPUTLANGCHANGEREQUEST:=0x50, INPUTLANGCHANGE_FORWARD:=0x2,,, % (hWndOwn := DllCall(&quot;GetWindow&quot;, Ptr, hWnd:=WinExist(&quot;A&quot;), UInt, GW_OWNER := 4, Ptr)) ? &quot;ahk_id&quot; hWndOwn : &quot;ahk_id&quot; hWnd
</code></pre></div><p>Компиляция найденного на форуме, плюс определение 2-буквенного имени языка, взятие отображаемого имени раскладки из реестра при отсутствии в dll ресурса, исправления для работы в x64 ОС и x64 AutoHotkey, обработка HKL/KLID/LocID.<br />Fix: Полноценно работает с панелью задач благодаря наводке от <strong>Malcev</strong>. <br />Upd: Многое переписано и исправлено.</p>]]></description>
			<author><![CDATA[null@example.com (stealzy)]]></author>
			<pubDate>Thu, 16 Feb 2017 03:10:01 +0000</pubDate>
			<guid>http://forum.script-coding.com/viewtopic.php?pid=112633#p112633</guid>
		</item>
	</channel>
</rss>
