Что нового

[заброшено] keyboard switcher - смена раскладки текста

mef-t

Осваивающий
Сообщения
306
Репутация
30
AutoIt: 3.3.8.1
Версия: 0.1.1.3

Категория: Автоматизация, Вспомогательные функции, Строки, Буфер обмена, Разное

Описание: Данная программа позволяет конвертировать выделенный текст или последнее слово (расположенное слева от указателя) из символов одной раскладки клавиатуры в другую.
Программа по горячей клавише "Ctrl + `" конвертирует заранее выделенный тест из русского языка в английский или обратно в случае ошибочно выбранной раскладки. Программа по горячей клавише "Break" конвертирует слово слева от курсора. После конвертации происходит смена раскладки. Перед конвертацией копируется содержимое буфера обмена. Затем выделенный текст помещается в буфер обмена, от туда считывается, преобразуется и затем через буфер обмена заменяет исходный. После конвертации возвращается исходное содержимое буфера обмена

Преимущества перед аналогами:
Программы, сразу считывающие выделенный текст, будут хорошо работать только в том случае, если им сделать поддержку всех возможных элементов редактирования, например "Scintilla", используемый в SciTE.
Программы, считывающие текст из буфера обмена (на примере SwitchIt) упускают то, что содержимое в буфере обмена может быть не только текстом. В этом случае, любое не текстовое содержимое теряется после применения программы
На текущий момент "keyboard switcher" так же сохраняет растровые изображения и списки файлов. В будущем и другие типы содержимого.

Рождение идеи:
Изначально пользовался Punto Switcher. На текущий момент он установлен дома. Но при доработке программы сменю. Из Punto мне требуется всего навсего конвертация текста с одной раскладки в другую и, очень редко, смена заглавных и прописных символов, при этом строго по моему усмотрению, а не по усмотрению программы. На текущей работе строгая политика безопасности. Лицензия Punto Switcher не позволяет использовать программу в коммерческих целях, а ее использование на работе как раз попадает под данный пункт. После недолгих страданий от навязавшейся привычки решил восполнить утрату и реализовать недостающий функции своими силами.

Код:
Код:
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=ico\ico2.ico
#AutoIt3Wrapper_Outfile=keyboard switcher.exe
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_Res_Comment=Программа для переключения раскладки клавиатуры
#AutoIt3Wrapper_Res_Description=Смена раскладки
#AutoIt3Wrapper_Res_Fileversion=0.1.1.3
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
#AutoIt3Wrapper_Res_LegalCopyright=@mef-t
#AutoIt3Wrapper_Tidy_Stop_OnError=n
#AutoIt3Wrapper_AU3Check_Stop_OnWarning=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

#include <ModernMenuRaw.au3>
#include <Clipboard.au3>
#include <WinAPI.au3>
#include <WinAPIEx.au3>
#include <Misc.au3>


Const $tagDROPFILES = "dword pFiles; long ptX; long ptY; bool fNC; bool fWide; "

#NoTrayIcon
Opt("GUIOnEventMode", 1)
Opt("TrayMenuMode", 7)

_SetFlashTimeOut(250)
$nTrayIcon = _TrayIconCreate("keyboard switcher", "ico\ico2.ico")

_TrayCreateContextMenu() ; контекстное меню иконки в трее
$bUseAdvTrayMenu = False

$nExit = _TrayCreateItem('Выход')
GUICtrlSetOnEvent($nExit, "_exit")

_TrayIconSetState()

$kKeySelectConvert = '^`'
$kKeyLastConvert = '{PAUSE}'

_HotKeyDisabled()

While 1
	Sleep(200)
WEnd

Func _exit()
	Exit
EndFunc

Func _Key_Switche()
	_HotKeyDisabled(False)
	_bClip(@HotKeyPressed)
	_HotKeyDisabled()
EndFunc

Func _HotKeyDisabled($bType = True)
	If $bType Then
		HotKeySet($kKeySelectConvert, '_Key_Switche') ; конвертирование выделенного текста
		;~ HotKeySet('^ё', '_Key_Switche') ; конвертирование выделенного текста
		HotKeySet($kKeyLastConvert, '_Key_Switche') ; конвертирование последнего слова
		;~ HotKeySet('{ESC}', '_exit') ; выход из скрипта по ESC
	Else
		HotKeySet($kKeySelectConvert) ; конвертирование выделенного текста
		;~ HotKeySet('^ё') ; конвертирование выделенного текста
		HotKeySet($kKeyLastConvert) ; конвертирование последнего слова
		;~ HotKeySet('{ESC}') ; выход из скрипта по ESC
	EndIf
EndFunc

Func _bClip($Key)

	Select
		Case _ClipBoard_IsFormatAvailable($CF_TEXT) Or _ClipBoard_IsFormatAvailable($CF_OEMTEXT) Or _ClipBoard_IsFormatAvailable($CF_UNICODETEXT)
			$hText = ClipGet()
			ClipPut("")
			; =====================================
			ConvertProc($Key)
			; =====================================
			ClipPut("")
			ClipPut($hText)

		Case _ClipBoard_IsFormatAvailable($CF_BITMAP)
			_ClipBoard_Open(0)
			$hBitmap = _ClipBoard_GetDataEx($CF_BITMAP)
			$hBitmap = _WinAPI_CopyImage( $hBitmap, 0, 0, 0, BitOr( 0x0008, 0x0004 ))
			_ClipBoard_Empty()
			_ClipBoard_Close()
			; =====================================
			ConvertProc($Key)
			; =====================================
			_ClipBoard_Open(0)
			_ClipBoard_Empty()
			_ClipBoard_SetDataEx($hBitmap, $CF_BITMAP)
			_ClipBoard_Close()

		Case _ClipBoard_IsFormatAvailable($CF_HDROP)
			_ClipBoard_Open(0)
			$pDROPFILES = _ClipBoard_GetDataEx( $CF_HDROP )
			$tDROPFILES = DllStructCreate( $tagDROPFILES, $pDROPFILES )
				$pFiles = DllStructGetData( $tDROPFILES, "pFiles" )
				$ptX 	= DllStructGetData( $tDROPFILES, "ptX" )
				$ptY 	= DllStructGetData( $tDROPFILES, "ptY" )
				$fNC 	= DllStructGetData( $tDROPFILES, "fNC" )
				$fWide 	= DllStructGetData( $tDROPFILES, "fWide" )
			Local $aFileList[999] = [0], $pCurFile = $pDROPFILES + $pFiles
			While True
				$tFILELIST		= DllStructCreate( "wchar[260]", $pCurFile )
				$sCurFile		= DllStructGetData( $tFILELIST, 1 )
				$iCurFileLen 	= StringLen( $sCurFile )

				If $iCurFileLen Then
					$aFileList[0] += 1
					$aFileList[$aFileList[0]] = $sCurFile
;~ 					ConsoleWrite( $sCurFile & @CRLF )
					; *
					$pCurFile += ( $iCurFileLen * 2 ) + 0x02
				Else
					ExitLoop
				EndIf
			WEnd
			_ClipBoard_Empty()
			_ClipBoard_Close()
			; =====================================
			ConvertProc($Key)
			; =====================================
			_ClipBoard_Open(0)
			_ClipBoard_Empty()
			$iUnicodeArray_TotalLen = 0x01
			$sUnicodeArray_TagStrings = ""
			$sUnicodeArray_TagStrings = ""
			For $Idx = 1 To $aFileList[0] Step 1
				$iLen = StringLen( $aFileList[$Idx] )

				$iUnicodeArray_TotalLen 	+= ( $iLen * 2 ) + 0x01
				$sUnicodeArray_TagStrings 	&= "wchar[" & $iLen & "]; byte[1]; "
			Next
			$sUnicodeArray_TagStrings &= "byte[1];"
			; ---
			$hMemory = _MemGlobalAlloc( $pFiles + $iUnicodeArray_TotalLen, $GHND )
			If $hMemory <> 0 Then
				$hLock = _MemGlobalLock($hMemory)
				If $hLock <> 0 Then
					$tDROPFILES = 	DllStructCreate( $tagDROPFILES & $sUnicodeArray_TagStrings, $hLock )
									DllStructSetData( $tDROPFILES, "pFiles", $pFiles )
									DllStructSetData( $tDROPFILES, "ptX", $ptX )
									DllStructSetData( $tDROPFILES, "ptY", $ptY )
									DllStructSetData( $tDROPFILES, "fNC", $fNC )
									DllStructSetData( $tDROPFILES, "fWide", $fWide )

					For $Idx = 1 To $aFileList[0] Step 1
									DllStructSetData( $tDROPFILES, 6 + ( ( $Idx - 1 ) * 2 ), $aFileList[$Idx] )
					Next

					_MemGlobalUnlock( $hMemory )
					_ClipBoard_SetDataEx( $hMemory, $CF_HDROP )
				EndIf
			EndIf
			_ClipBoard_Close()

		Case _ClipBoard_CountFormats() = 0
			_ClipBoard_Open(0)
			_ClipBoard_Empty()
			_ClipBoard_Close()
			; =====================================
			ConvertProc($Key)
			; =====================================
		Case Else
			MsgBox(64, 'Ошибка', 'Буфер обмена скопировать не удалось')
	EndSelect

EndFunc


Func ConvertProc($Key)

	if $Key = $kKeyLastConvert Then
		_SendEx("^+{LEFT}")
	EndIf

    _SendEx("^{INS}")
    Local $SelectedText = ClipGet()
	If $SelectedText = "" Then
		Return
	EndIf

    Local $NewClip = ConvertText($SelectedText)

    ClipPut($NewClip)
    _SendEx("+{INS}")
	Local $hWnd = WinGetHandle('[ACTIVE]')
	If Not $hWnd Then
		Return
	EndIf

	If Not StringInStr(_WinAPI_GetClassName($hWnd), 'AutoIt') Then
		_WinAPI_SetKeyboardLayout(_GetOwnerWindow($hWnd), 0, 0x0002)
	Else
		_AutoItSetKeyboardLayout($hWnd)
	EndIf

EndFunc

Func _SendEx($sSend_Data)
    Local $hUser32DllOpen = DllOpen("User32.dll")

    While _IsPressed("10", $hUser32DllOpen) Or _IsPressed("11", $hUser32DllOpen) Or _IsPressed("12", $hUser32DllOpen)
        Sleep(10)
    WEnd

    Send($sSend_Data)

    DllClose($hUser32DllOpen)
EndFunc

;If $Mode = 0 Then Russian language used
;If $Mode = 1 Then English language used
;If $Mode = -1 Then String Inverted
Func ConvertText($Text, $Mode=-1)

	Local $AnsiStr		= "ёйцукенгшщзхъфывапролджэячсмитьбю.,/№;%:?ХЪБЮЖЁ" & '"Э'
    Local $AsciiStr		= "`qwertyuiop[]asdfghjkl;'zxcvbnm,./?|#$%^&{}<>:~" & '@"'

	Local $sCharStr		= $AnsiStr & $AsciiStr
	Local $iLenChars	= StringLen($sCharStr)
	Local $sCharStrUP	= StringRegExp ($sCharStr, "[А-ЯЁ]" , 3)
	$sCharStrUP			= _ArrayToString($sCharStrUP, "")

	$sTextR = StringLower($Text)
	$sTextR = StringRegExpReplace ($sTextR, "[^a-zа-яё\x22-\x27\x2c\x2e\x2f\x3a-\x3c\x3e-\x40\x5b\x5d\x5e\x60\x7b-\x7e]", "" )
	Local $iSearch  = (StringIsASCII($sTextR) * (-2)) + 1


    For $i = 1 To StringLen($Text)
		Local $StringIsUpper = 0, $iNewChar = '', $sChar = '', $iPosition = 0, $iNewCharPosition = 0 ; обновление переменных
		$sChar = StringMid($Text, $i, 1) ; извлечение исмвола из переводимой строки
        If StringIsUpper($sChar) And StringInStr($sCharStrUP, $sChar, 1) = 0 Then
			$StringIsUpper = 1
		EndIf
		$iRegistr = $StringIsUpper*-1+1
		$iPosition = StringInStr($sCharStr, $sChar, $iRegistr, $iSearch)
		If $iPosition > 0 Then
			$iNewCharPosition = $iPosition + ($iLenChars / 2)
			If $iNewCharPosition > $iLenChars Then $iNewCharPosition -= $iLenChars
			$iNewChar = StringMid($sCharStr, $iNewCharPosition, 1)
			If $StringIsUpper = 1 Then $iNewChar = StringUpper($iNewChar)
			$Text = StringReplace($Text, $i, $iNewChar)
		EndIf
    Next
    Return $Text
EndFunc

;~ --------------------------------------------------------------------------------------

Func _AutoItSetKeyboardLayout($hWnd)

	Local $List = _WinAPI_EnumProcessWindows(WinGetProcess($hWnd), 0)

	If Not IsArray($List) Then
		Return SetError(1, 0, 0)
	EndIf

	For $i = 1 To $List[0][0]
		If (Not BitAND(WinGetState($List[$i][0]), 2)) And (StringInStr($List[$i][1], 'AutoIt')) Then
			_WinAPI_SetKeyboardLayout($List[$i][0], 0, 0x0002)
		EndIf
	Next
EndFunc   ;==>_AutoItSetKeyboardLayout

Func _GetOwnerWindow($hWnd)

	Local $hOwner = _WinAPI_GetAncestor($hWnd, 3)

	If _WinAPI_GetClassName($hOwner) = 'Shell_TrayWnd' Then
		Return $hWnd
	EndIf
	Return $hOwner
EndFunc   ;==>_GetOwnerWindow

Func _ArrayToString(Const ByRef $avArray, $sDelim = "|", $iStart = 0, $iEnd = 0)
	If Not IsArray($avArray) Then Return SetError(1, 0, "")
	If UBound($avArray, 0) <> 1 Then Return SetError(3, 0, "")

	Local $sResult, $iUBound = UBound($avArray) - 1

	; Bounds checking
	If $iEnd < 1 Or $iEnd > $iUBound Then $iEnd = $iUBound
	If $iStart < 0 Then $iStart = 0
	If $iStart > $iEnd Then Return SetError(2, 0, "")

	; Combine
	For $i = $iStart To $iEnd
		$sResult &= $avArray[$i] & $sDelim
	Next

	Return StringTrimRight($sResult, StringLen($sDelim))
EndFunc   ;==>_ArrayToString

Файл: keyboard switcher

Снимок: N/A

История версий:
0.1.1.3 - * Первый релиз (трей с отдельным меню, конвертация раскладки, копирование памяти с текстом, растровым изображением и файлами)

Источник: autoit-script.ru
Автор: mef-t

Отдельное спасибо:
Yashied - позаимствовал код для переключения раскладки после конвертации из программы http://autoit-script.ru/index.php/topic,2212.0.html
firex - помог с копированием буфера обмена, содержащего растровый рисунок и список файлов
InnI - ткнул носом в темы с проблемой залипания клавиш
ViSiToR a.k.a CreatoR - программа a.k.a SwitchIt; за основу была взята данная программа, но со временем многое переделалось, на текущий момент в приведенном коде осталось мало общего и исходным

Первостепенные доработки:
  • исправить редактирование последнего слова, не всегда верно определяется
  • добавить сохранение буфера обмена для видео, аудио потоков и других типов соддержимого
  • добавить конвертацию из маленький в большие символы и обратно

P.S.: Буду рад Вашим комментариям, критике, предложениям и отзывам.
 

erlik

Продвинутый
Сообщения
317
Репутация
84
Re: [Compiled] keyboard switcher - смена раскладки текста

1. Смена по Break - попробуй использовать любое слово с 'ю'.
2. Смена по Ctrl +` - у меня вообще не работает. Возможно хоткей занят какой-то прогой, но я без понятия какой. Для проверки Break отменил этот хоткей в Punto.
3. Наверно стоит разрешать запускать только одну копию программы.
4. Наверно стоит дать пользователю возможность назначать хоткеи.
 
Автор
mef-t

mef-t

Осваивающий
Сообщения
306
Репутация
30
Re: [Compiled] keyboard switcher - смена раскладки текста

Да, все верно.
1. Доработку по данному пункту указывал в пункте "первостепенные доработки". Сама проблема известна и требуется особая обработка.
2. Одно из двух: или реально сторонняя программа, или баг. Буду искать. На домашнем, кажется, смог воспроизвести. Буду искать решение.
3. Это, наверно, не первостепенная задача, но в будущем так же сделаю.
4. Так же в будущем при разработке гуи с настройкой обязательно сделаю. Пока что это все можно сделать или в скрипте, или можно попробовать вынести в ini файл.

Спасибо
 

asocil

Новичок
Сообщения
1
Репутация
0
Re: [Compiled] keyboard switcher - смена раскладки текста

Подтверждаю не работает

2. Смена по Ctrl +` - у меня вообще не работает.
 

InnaS

Новичок
Сообщения
5
Репутация
0
Re: [Compiled] keyboard switcher - смена раскладки текста

Так же подтверждаю
 

iostream

Новичок
Сообщения
1
Репутация
0
Re: [Compiled] keyboard switcher - смена раскладки текста

Пробуйте это

Код:
#include <WinAPISys.au3> ; -библиотека для переключения
run('notepad.exe')
Sleep(500)
MsgBox(0,'','Switch RU',1)
WinActivate('Безымянный')
_WinAPI_SetKeyboardLayout(WinGetHandle("Безымянный"),0x0419) ;переключаемся на английский , (можно на любой код языка)
Sleep(3000)
MsgBox(0,'','Switch EN',1)
WinActivate('Безымянный')
Send('{enter}')
_WinAPI_SetKeyboardLayout(WinGetHandle("Безымянный"),0x0409) ;переключаемся на английский , (можно на любой код языка)
Sleep(3000)
ProcessClose('notepad.exe')
 

IrreVersibler

Новичок
Сообщения
1
Репутация
0
Отличный скрипт, но не получилось переделать под себя. У меня не стандартная русская раскладка, а интуитивная транслитерация, т.е. "S"="С", "G"="Г" и т.д. Хотел просто поменять раскладку в строке 221 скрипта, но это не спасло ситуацию, потому как при выведении скрипта у меня выкидывается ошибка намного выше по тексту (в строке 14). Экзешник выводится без ошибок, но его я не могу уже переписать. Не подкинете идеек?
 
Автор
mef-t

mef-t

Осваивающий
Сообщения
306
Репутация
30
IrreVersibler сказал(а):
Отличный скрипт, но не получилось переделать под себя. У меня не стандартная русская раскладка, а интуитивная транслитерация, т.е. "S"="С", "G"="Г" и т.д. Хотел просто поменять раскладку в строке 221 скрипта, но это не спасло ситуацию, потому как при выведении скрипта у меня выкидывается ошибка намного выше по тексту (в строке 14). Экзешник выводится без ошибок, но его я не могу уже переписать. Не подкинете идеек?

14 строка - #include <ModernMenuRaw.au3>
Полагаю, у Вас отсутствует файл ModernMenuRaw.au3
Скачать его можно тут http://autoit-script.ru/index.php/topic,12136.0.html
 
Верх