26 (изменено: stealzy, 2017-05-03 22:09:09)

Re: AHK: Еще один заменитель Punto Switcher'a

Почти полностью переписал скрипт.

По заданной ГК исправляется последний набранный текст, таковым считается любой текст,
не прерывающийся нажатием клавиш:
мыши, навигации (←↑↓→Pg*, Home, End), модификаторов (Alt Ctrl Win), Enter, Esc, F[1-12].
Полный список прерывающих клавиш содержится в методе _GetInputText().
Можно добавить туда пробел - тогда будет исправлятся только последнее слово.
Можно исключить Enter - тогда можно исправлять абзацами .
После исправления текста переключается раскладка.
Если выделен текст, то исправлен будет он.
(Большинством символов в выделенном будет определена раскладка, символы из которой необходимо исправить.)

+ Тех. особенности:

• Использует команду Input для взятия последнего введенного текста,
если переменная последнего введенного текста пуста, то ^{Ins} и взятие из буфера обмена (выделенный текст)
(если использована одна из EndKeys клавиш, описанных в методе _GetInputText() или клик мышью, переменная последнего введенного текста обнуляется).
• Текст исправляется с помощью захардкоженного соответствия латинских и кириллических символов в стандартных раскладках (строки Lat:="~QWER... и Cyr:="ЁЙЦУК..., описанные в методе _GetTextInOppositeLayout()).
Направление исправления выбирается на основе тек.раскладки, для выделенного текста - на основе большинства символов в тексте.
• Использует BackSpace для стирания последнего введенного текста, и SendInput для ввода исправленного.

Ограничения: в одном скрипте с переключалкой нежелательно использовать горячие клавиши на клики мышью или клавиши модификаторы (переключалка устанавливает свои прозрачные ГК на мышь для запрета исправления введенного текста после клика мышью).

#SingleInstance, force
#NoEnv
; #NoTrayIcon
P := new Punto
corr := ObjBindMethod(P, "CorrectionEnteredText")
Hotkey % "Pause", % corr
; togg := ObjBindMethod(P, "ToggleLayout")
; Hotkey % "!" Format("vk{:02x}", GetKeyVK("R")), % corr
Return

Class Punto {
	__New() {
		; Workaround for include mouse button in Input EndKeys
			_InputFn := ObjBindMethod(this, "_Input")
			_InputModFn := ObjBindMethod(this, "_Input", keyModifier := true)
			Hotkey ~*LButton, % _InputFn
			Hotkey ~*RButton, % _InputFn
			Hotkey ~*MButton, % _InputFn
		; Workaround for run CorrectionEnteredText() from hotkey including modifier keys:
		; you can't put LAlt in EndKeys if you run correction method by hotkey contain Alt (!R).
			Hotkey ~*LControl, % _InputModFn
			Hotkey ~*RControl, % _InputModFn
			Hotkey ~*LAlt, % _InputModFn
			Hotkey ~*RAlt, % _InputModFn
			Hotkey ~*LWin, % _InputModFn
			Hotkey ~*RWin, % _InputModFn
		timer := ObjBindMethod(this, "_GetInputText")
		SetTimer % timer, -1
	}
	_Input(keyModifier:=false) {
		If keyModifier ; Workaround because bug with using Hotkey ~*LAlt Up,
			KeyWait, % LTrim(A_ThisHotkey, "~*")
		Input
	}
	_GetInputText() {
		Input text, i v, {Enter}{NumpadEnter}{Tab}{Backspace}{Escape}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{Capslock}{Numlock}{PrintScreen}{Pause}
		this.ReplaceAfter := this.ReplaceAfter ? this._ReplaceText(text) :
		timer := ObjBindMethod(this, "_GetInputText")
		SetTimer % timer, -1
	}

	CorrectionEnteredText() {
		this.ReplaceAfter:=true
		Input
	}

	_ReplaceText(text) {
		StringLen count, text
		if (count>0)	; если вводился текст
			SendInput {BS %count%}
		else { 				; если выделен текст (при выделении используются кнопки мыши или шифт с навигационными кл. => text="" => count=0)
			cliptmp:=Clipboard
			Clipboard =
			SendPlay ^{Ins}
			Send ^{vk43}
			ClipWait .7, 1
			clipNew:=Clipboard
			if (clipNew != "") {
				text:=Clipboard
				fromClip:=true
			} else {
				Tooltip Выделите текст для исправления, A_CaretX+20, A_CaretY-3
				SetTimer TToff, -1000
				Return

				TToff:
					ToolTip
					Return
			}
			Clipboard:=cliptmp
		}

		substituteText := this._GetTextInOppositeLayout(text, fromClip, LayoutNeedToggle)
		(!fromClip || LayoutNeedToggle)  ?  this.ToggleLayout()
		Sleep 50 ; без задержки появляются баги со знаками пунктуации
		SetKeyDelay 50, 50
		SendInput {Raw}%substituteText%
		Return
	}
	_GetTextInOppositeLayout(text, fromClip, ByRef LayoutNeedToggle) {
		static Lat:="~QWERTYUIOP{}ASDFGHJKL:""ZXCVBNM<>``qwertyuiop[]asdfghjkl;'zxcvbnm,./|?@#$^&"
		, Cyr:="ЁЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮёйцукенгшщзхъфывапролджэячсмитьбю./,""№;:?"

		En := (this.GetInputHKL() = 0x04090409)
		If fromClip {
			; для выделенного текста определяем принадлежность большинства символов к той или иной раскладке
			u := 0
			Loop, parse, text
			{
				OutputDebug % (A_LoopField = "`n") " " (A_LoopField = "`r")
				LatSym := InStr(Lat, A_LoopField), CyrSym := InStr(Cyr, A_LoopField)
				if (LatSym && !CyrSym)
					++u
				else if (CyrSym && !LatSym)
					--u
			}

			failureLayout:= (u>0) ? Lat : Cyr
			correctLayout := (u>0) ? Cyr : Lat
			LayoutNeedToggle := En ^ (u<=0)
		}
		Else {
			; для простого переключения основываемся на тек. раскладке
			failureLayout:= En ? Lat : Cyr
			correctLayout := En ? Cyr : Lat
		}

		Loop, parse, text,, `r ; `r — hack for Send command, because it regards `r`n as separate \n
		{
			if (symbolNum := InStr(failureLayout, A_LoopField, CaseSensitive:=true))
				substituteText .= SubStr(correctLayout, symbolNum, 1)
			else
				substituteText .= A_LoopField
		}
		Return substituteText
	}
	ToggleLayout() {
		PostMessage, 0x50, 2,,, % (hWndOwn := DllCall("GetWindow", Ptr, hWnd:=WinActive("A"), UInt, GW_OWNER := 4, Ptr)) ? "ahk_id" hWndOwn : "ahk_id" hWnd
	}
	GetInputHKL() {
		hWnd := WinExist("A")
		WinGetClass, Class
		if (Class == "ConsoleWindowClass") {
				WinGet, consolePID, PID
				DllCall("AttachConsole", Ptr, consolePID)
				VarSetCapacity(buff, 16)
				DllCall("GetConsoleKeyboardLayoutName", Str, buff)
				DllCall("FreeConsole")
				HKL := "0x" . SubStr(buff, -3)
		} else
			HKL := DllCall("GetKeyboardLayout", Ptr, DllCall("GetWindowThreadProcessId", Ptr, hWnd, UInt, 0, Ptr), Ptr)
		return HKL
	}
}

27

Re: AHK: Еще один заменитель Punto Switcher'a

EndKeys хороши наглядностью и простотой редактирования - возиться с командами Hotkey будет муторнее. Кнопки мыши тоже можно туда вписать - не знаю, почему раньше не сделал этого.

28

Re: AHK: Еще один заменитель Punto Switcher'a

Попробуйте, у меня не вышло.

29

Re: AHK: Еще один заменитель Punto Switcher'a

В старом скрипте если дописать в endkey {LButton}{RButton}{MButton} и удалить горячие клавиши все работает как надо. Т.е. Input отрабатывает нажатия клавиш мыши.

30 (изменено: stealzy, 2017-03-24 19:55:57)

Re: AHK: Еще один заменитель Punto Switcher'a

Я пробовал именно так. Попробуйте простой Input и MsgBox за ним чтобы убедиться.

Input text,, {LButton}{End}
MsgBox % text
ExitApp

31

Re: AHK: Еще один заменитель Punto Switcher'a

Действительно. И когда-то я это явно пробовал. Ума не приложу только почему это делает невозможным исправление раскладки после клика мышью в описанном варианте. Скорее всего, тут что-то в других скриптах.

32 (изменено: stealzy, 2017-03-25 00:10:05)

Re: AHK: Еще один заменитель Punto Switcher'a

Krot66, так это я намеренно сделал )). После клика курсор может оказаться в другом поле, и туда будут посланы нажатия BackSpace и введен тест из предыдущего поля. Можно конечно проверять совпадене контрола по таймеру, но ведь можно кликнуть в тот же самый контрол в середину текста, результат можете себе представить.
У меня юзкейс такой: неправильно начал набирать → увидел → нажал ГК для исправления.
Мне просто ни разу не понадобилось кликать мышкой м/у начальным и конечными пунктами, а вы зачем кликаете?

В методе __New() уберите хоткеи если так угодно.

33

Re: AHK: Еще один заменитель Punto Switcher'a

В скрипте из первого поста при нажатии на горячую клавишу отправляется последнее сконвертированное слово. В скрипте из 26-го поста даже при выделении слова пишет "Выделите текст для исправления". Это только у меня так?

Win10x64, AHK v1.1.25

34 (изменено: stealzy, 2017-03-26 13:31:33)

Re: AHK: Еще один заменитель Punto Switcher'a

becauseim, спс за отзыв, попробуйте сейчас из 26 поста.

35

Re: AHK: Еще один заменитель Punto Switcher'a

Дальнейшая разработка вопроса.

36 (изменено: becauseim, 2017-05-03 20:07:23)

Re: AHK: Еще один заменитель Punto Switcher'a

stealzy, реагирует на выделенные слова по-прежнему. При конвертировании набранного слова на англ., конвертирует слово дважды, сначала на рус., затем собратно. Подумал, что запущен Punto Switcher, но нет. Другие скрипты тоже закрыл для чистоты теста.

Win10x64, AHK v1.1.25

37 (изменено: stealzy, 2017-05-03 20:52:48)

Re: AHK: Еще один заменитель Punto Switcher'a

becauseim, покажите содержимое файла log.txt после воспроизведения проблемы.

#SingleInstance, force
#NoEnv
; #NoTrayIcon
P := new Punto
corr := ObjBindMethod(P, "CorrectionEnteredText")
Hotkey % "Pause", % corr
Return

Class Punto {
	__New() {
		Log("__New")
		; Workaround for include mouse button in Input EndKeys
			_InputFn := ObjBindMethod(this, "_Input")
			_InputModFn := ObjBindMethod(this, "_Input", keyModifier := true)
			Hotkey ~*LButton, % _InputFn
			Hotkey ~*RButton, % _InputFn
			Hotkey ~*MButton, % _InputFn
		; Workaround for run CorrectionEnteredText() from hotkey including modifier keys:
		; you can't put LAlt in EndKeys if you run correction method by hotkey contain Alt (!R).
			Hotkey ~*LControl, % _InputModFn
			Hotkey ~*RControl, % _InputModFn
			Hotkey ~*LAlt, % _InputModFn
			Hotkey ~*RAlt, % _InputModFn
			Hotkey ~*LWin, % _InputModFn
			Hotkey ~*RWin, % _InputModFn
		timer := ObjBindMethod(this, "_GetInputText")
		SetTimer % timer, -1
	}
	_Input(keyModifier:=false) {
		Log("_Input")
		If keyModifier ; Workaround because bug with using Hotkey ~*LAlt Up,
			KeyWait, % LTrim(A_ThisHotkey, "~*")
		Input
	}
	_GetInputText() {
		Log("_GetInputText")
		Input text, i v, {Enter}{NumpadEnter}{Tab}{Backspace}{Escape}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{Capslock}{Numlock}{PrintScreen}{Pause}
		this.ReplaceAfter := this.ReplaceAfter ? this._ReplaceText(text) :
		timer := ObjBindMethod(this, "_GetInputText")
		SetTimer % timer, -1
	}

	CorrectionEnteredText() {
		Log("`nCorrectionEnteredText")
		this.ReplaceAfter:=true
		Input
	}

	_ReplaceText(text) {
		Log("_ReplaceText(" text ")")
		StringLen count, text
		if (count>0)	; если вводился текст
			SendInput {BS %count%}
		else { 				; если выделен текст (при выделении используются кнопки мыши или шифт с навигационными кл. => text="" => count=0)
			cliptmp:=Clipboard
			Clipboard =
			SendPlay ^{Ins}
			ClipWait .2, 1
			clipNew:=Clipboard
			if (clipNew != "") {
				text:=Clipboard
				Log("_ReplaceText: clipBoard = " text)
				fromClip:=true
			} else {
				Tooltip Выделите текст для исправления, A_CaretX+20, A_CaretY-3
				SetTimer TToff, -1000
				Return

				TToff:
					ToolTip
					Return
			}
			Clipboard:=cliptmp
		}

		substituteText := this._GetTextInOppositeLayout(text, fromClip, LayoutNeedToggle)
		(!fromClip || LayoutNeedToggle)  ?  this.ToggleLayout()
		Sleep 50 ; без задержки появляются баги со знаками пунктуации
		SetKeyDelay 50, 50
		SendInput {Raw}%substituteText%
		Return
	}
	_GetTextInOppositeLayout(text, fromClip, ByRef LayoutNeedToggle) {
		static Lat:="~QWERTYUIOP{}ASDFGHJKL:""ZXCVBNM<>``qwertyuiop[]asdfghjkl;'zxcvbnm,./|?@#$^&"
		, Cyr:="ЁЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮёйцукенгшщзхъфывапролджэячсмитьбю./,""№;:?"

		En := (this.GetInputHKL() = 0x04090409)
		If fromClip {
			; для выделенного текста определяем принадлежность большинства символов к той или иной раскладке
			u := 0
			Loop, parse, text
			{
				OutputDebug % (A_LoopField = "`n") " " (A_LoopField = "`r")
				LatSym := InStr(Lat, A_LoopField), CyrSym := InStr(Cyr, A_LoopField)
				if (LatSym && !CyrSym)
					++u
				else if (CyrSym && !LatSym)
					--u
			}

			failureLayout:= (u>0) ? Lat : Cyr
			correctLayout := (u>0) ? Cyr : Lat
			LayoutNeedToggle := En ^ (u<=0)
		}
		Else {
			; для простого переключения основываемся на тек. раскладке
			failureLayout:= En ? Lat : Cyr
			correctLayout := En ? Cyr : Lat
		}

		Loop, parse, text,, `r ; `r — hack for Send command, because it regards `r`n as separate \n
		{
			if (symbolNum := InStr(failureLayout, A_LoopField, CaseSensitive:=true))
				substituteText .= SubStr(correctLayout, symbolNum, 1)
			else
				substituteText .= A_LoopField
		}
		Return substituteText
	}
	ToggleLayout() {
		Log("ToggleLayout")
		PostMessage, 0x50, 2,,, % (hWndOwn := DllCall("GetWindow", Ptr, hWnd:=WinActive("A"), UInt, GW_OWNER := 4, Ptr)) ? "ahk_id" hWndOwn : "ahk_id" hWnd
	}
	GetInputHKL() {
		hWnd := WinExist("A")
		WinGetClass, Class
		if (Class == "ConsoleWindowClass") {
				WinGet, consolePID, PID
				DllCall("AttachConsole", Ptr, consolePID)
				VarSetCapacity(buff, 16)
				DllCall("GetConsoleKeyboardLayoutName", Str, buff)
				DllCall("FreeConsole")
				HKL := "0x" . SubStr(buff, -3)
		} else
			HKL := DllCall("GetKeyboardLayout", Ptr, DllCall("GetWindowThreadProcessId", Ptr, hWnd, UInt, 0, Ptr), Ptr)
		return HKL
	}
}

Log(str) {
	FileAppend % str "`n", %A_ScriptDir%\log.txt
}

Сам за время использования скрипта на 2 семерках ни разу не сталкивался, так что гадать не буду.

реагирует на выделенные слова по-прежнему

Это как? Совсем не конвертирует выделенное или все-таки дважды?

38 (изменено: becauseim, 2017-05-03 20:59:20)

Re: AHK: Еще один заменитель Punto Switcher'a

stealzy, сейчас вроде все работает кроме конвертирования выделенных слов. Т.е. выдает сообщение о том, что ничего не выделено. Наверное, в Win 10 что-то работает иначе.

Забегая вперед, если я выделю слова, набранные и на латинице и на кириллице, весь текст будет сконвертирован на противоположный или же приравняется к раскладке, в которой введено последнее или первое выделенное слово?

По какому принципу скрипт берет под конвертацию сразу несколько последних введенных слов?

Post's attachments

log.txt 4.79 kb, 2 downloads since 2017-05-03 

You don't have the permssions to download the attachments of this post.
Win10x64, AHK v1.1.25

39 (изменено: stealzy, 2017-05-03 22:05:57)

Re: AHK: Еще один заменитель Punto Switcher'a

becauseim, тогда и лог не нужен. Видимо просто в буфер обмена при копировании ничего ни попадает.
Судя по логу, единственная строка, которую вы пытались исправить выделением, была "привет воарплор", так?
Я использовал SendPlay ^{Ins}, сейчас добавил Send ^{vk43}, так работает?
Что касается логики исправления выделенного, я пробовал следующие варианты:
1) определяется текущая раскладка, все символы из нее в выделенном конвертируются.
2) каждый символ из одной раскладки переходил в другую.
Проблема в том, что делать с символами, присутствующими в обеих раскладках и находящимися на разных клавишах (,.;" etc).
3) определяем к какой раскладке однозначно относиться большинство символов, и исправляем только в этом направлении.
Сейчас использую последний.
Вообще выделением пользуюсь редко, хватает обычного режима.

40 (изменено: becauseim, 2017-05-03 21:47:39)

Re: AHK: Еще один заменитель Punto Switcher'a

stealzy, сейчас выделенные слова конвертируются. Но, как мне кажется, удобнее было бы, если каждый буквенный символ конвертировался на противоположный вне зависимости от преобладания символов. Это необходимо для того, чтобы сконвертировать набранный ранее текст, который состоял из слов на разных языках. Здесь я описывал эту проблему для другого схожего скрипта, но так и не дождался решения.

И мне все-таки интересно, по какому принципу скрипт берет под конвертацию сразу несколько последних введенных слов? Потому что я привык к тому, как работает обычный Punto Switcher, который конвертирует всегда только одно последнее набранное слово. А сам Punto Switcher использовать не могу, т.к. из-за него некорректно срабатывают некоторые скрипты на AHK.

Win10x64, AHK v1.1.25

41

Re: AHK: Еще один заменитель Punto Switcher'a

Ранние версии скриптов просто брали и перелопачивали с одной раскладки на противоположную. Но в этом есть изъян: может выйти так, что в итоговой строке будут соседствовать русские и латинские символы. Этот способ позволяет избегать подобного. Можно, конечно, сделать "голосование", но это муторно да и нет смысла.

42 (изменено: stealzy, 2017-05-03 22:03:13)

Re: AHK: Еще один заменитель Punto Switcher'a

По выделенному тексту, что предлагаете делать с проблемой по пункту 2?
";" - оставить как есть или это буква "ж"?

по какому принципу скрипт берет под конвертацию сразу несколько последних введенных слов

Описания из 26 поста недостаточно?

только одно последнее набранное слово

См. там же. Дело вкуса, конечно. Судя по тому, что вы меняете раскладку и продолжаете набор текста, не глядя на экран, вам этого будет мало.

43

Re: AHK: Еще один заменитель Punto Switcher'a

Просто нужно добавить окно настроек и все разногласия вынести в эти настройки, чтобы каждый настраивал под себя.

Win 7 x64
AHK v1.1.24.00
                       Справка тебе в помощь.

44

Re: AHK: Еще один заменитель Punto Switcher'a

stealzy пишет:

";" - оставить как есть или это буква "ж"?

Думаю, стоит конвертировать. Например, я хочу напечатать слово "жизнь", после которого поставить точку с запятой. Но если я не переключил раскладку, то у меня невольно выйдет следующее: ;bpym$
Если же вместо знака $ там находится ;, значит, я был намерен написать слово "жизньж".

Возможно, я не учел всех возможных моментов, поэтому, поправьте, если не прав.

Win10x64, AHK v1.1.25