Что нового

Запрет передачи программе нажатия некоторых клавиш

alexingor

Новичок
Сообщения
10
Репутация
0
Во втором посте ныне закрытого сообщения http://autoit-script.ru/index.php/topic,143.msg925 , код #2 CreatoR :king: привел замечательный скрипт перехвата нажатия клавиш. Я хотел использовать его для создания своего скрипта, который будет отлавливать нажатия клавиш, и при некотором сочетании будет выдавать в поток другие символы. Так вот, мне нужно сделать так, чтобы во время ввода определенной трехсимвольной последовательности коды нажимаемых клавиш не передавались в поток, а только накапливались в переменной, и по окончании ее накопления скрипт сам передал в поток сформированный им код одного определенного символа. В скрипте есть глобальный флажок $bCharOut, значение которого устанавливается фрагментом, анализирующим код каждой нажатой клавиши (он добавлен в конец процедуры _EvaluateKey_Proc). Теперь вопрос. Как обеспечить блокировку вывода в поток кода нажатой клавиши, когда этот флажок установлен в 0, и разрешить, когда он 1?
 
Автор
A

alexingor

Новичок
Сообщения
10
Репутация
0
madmasles [?]
и при некотором сочетании будет выдавать в поток другие символы.
Зачем?
Скрипт облегчает ввод символов с диакритическими знаками. Напрмер, если пользователь нажимает три клавиши "`:a", в поток пойдет символ "ä", а если "`~n" - то "ñ".
Мне и моим сотрудникам приходится много работать с иностранными языками, вот я и взялся облегчить эту практически не реализованную в системе операцию.
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
alexingor
В справке _WinAPI_SetWindowsHookEx
Ещё может это
 
Автор
A

alexingor

Новичок
Сообщения
10
Репутация
0
AZJIO [?]
Для меня это слишком абстрактно. Можно конкретнее? Я обещаю разобраться со всеми этими хуками, но не сейчас, когда подобными вещами приходится ночами заниматься.
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
alexingor
Может проще использовать что-то вроде виртуальной клавиатуры?
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
alexingor
Конкретно мне тоже приходится в своё личное время заниматься. Конкретно по коду: хук ловит нажатие клавиши и буферизирует в переменную. Размер буфера можно указать любой, 3, 5, 10 символов, хоть сколько. Справа добавляется символ, слева отрезается символ оставшаяся комбинация из 3-х символов сравнивается с вашими комбинациями. При совпадении выполняется Send или вставка через буфер обмена отвравкой ^{INS}.
Естествено тема не для новичка. Тогда вам в "стол заказов".
 
Автор
A

alexingor

Новичок
Сообщения
10
Репутация
0
WSWR [?]
Может проще использовать что-то вроде виртуальной клавиатуры?
Виртуальная клавиатура заставляет переносить руку с клавиатуры на мышь. Вся задумка в том, чтобы мышь не задействовать.


Добавлено:
Сообщение автоматически объединено:

AZJIO [?]
Справа добавляется символ, слева отрезается символ оставшаяся комбинация из 3-х символов сравнивается с вашими комбинациями. При совпадении выполняется Send или вставка через буфер обмена отвравкой ^{INS}.
Я, наверно, слишком мало понимаю, если это - ответ на вопрос, как сделать так, чтобы некоторые символы НЕ отправлялись приложению. Мне кажется, этот фрагмент поясняет, как ОТПРАВИТЬ нужные, а это я и сам научился делать. Мне нужна помощь именно в блокировании передачи приложению ненужных символов.
Тогда вам в "стол заказов".
Я не против оплатить работу знатоков, но в данном случае мне кажется, что масштаб проблемы вполне решаемый в рамках форума. Или это дилетантское заблуждение?


Добавлено:
Сообщение автоматически объединено:

AZJIO [?]
Конкретно мне тоже приходится в своё личное время заниматься.
Я восхищаюсь и преклоняюсь перед той работой, которую вы, знатоки и гуру, выполняете здесь на форуме, помогая чайникам вроде меня, и тем самым продвигая идею внедрения действительно отличного и полезного инструмента - AitoIt. Огромное спасибо :beer:
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
alexingor

Возможный вариант:
два кода - один блокирует ввод в окно указанного класса (в данном случае, блокнот) на основе BlockInputEx.au3 http://autoit-script.ru/index.php?topic=162.0 Т.о., ввод с клавиатуры символов в эти окна не пойдет, что позволяет его подменить.
Запускать лучше первым.
Код:
#include <BlockInputEx.au3> 

HotKeySet('{ESC}', '_Quit')

$hNotepad_Wnd = WinGetHandle('[REGEXPCLASS:Notepad]') ;
_BlockInputEx(3, '', '[:ALPHA:]|[~`;$]|[:NUMBER:]', $hNotepad_Wnd)


While 1
	Sleep(1000)
	If WinGetHandle('[REGEXPCLASS:Notepad]') <> $hNotepad_Wnd Then
		$hNotepad_Wnd = WinGetHandle('[REGEXPCLASS:Notepad]')
		_BlockInputEx(3, '', '[:ALPHA:]|[~`;$]|[:NUMBER:]', $hNotepad_Wnd)
	EndIf
WEnd

Func _Quit()
	Exit
EndFunc   ;==>_Quit
Блокирование еще можно понастраивать, например, цифры можно вывести из под него(это потребует изменений и во втором коде).

Второй код - немного измененный от CreatoR-ра, куда я добавил простейшее определение последовательностей символов. При активном окне блокнота ввод осуществляется через ControlSend.
Если последовательно нажаты "`~любой символ", в активное окно блокнота будет послано слово "Autoit", если нажаты "`;любой символ", в окно будет послано "Ї". Естественно, это только пример, и он не без недостатков.
Код:
#include <Misc.au3>

HotKeySet('^e', 'OnAutoItExit')

Global Const $WH_KEYBOARD_LL = 13
Global $hStub_KeyProc = DllCallbackRegister("_Key_Proc", "int", "int;ptr;ptr")
Global $hMod = DllCall("kernel32.dll", "hwnd", "GetModuleHandle", "ptr", 0)
Global $hHook = DllCall("user32.dll", "hwnd", "SetWindowsHookEx", "int", $WH_KEYBOARD_LL, _
		"ptr", DllCallbackGetPtr($hStub_KeyProc), "hwnd", $hMod[0], "dword", 0)
Global $sTring = '', $flag0 = 0, $flag1 = 0, $flag2 = 0

While 1
	Sleep(30)
WEnd

Func _EvaluateKey_Proc($nKeyCode)
	Local $sCapt_Codes, $sEng_Codes, $sEngShift_Codes, $sRus_Codes, $sRusShift_Codes
	Local $sUkr_Codes, $sUkrShift_Codes

	Local $aCapture_Codes, $aEng_Codes, $aEngShift_Codes, $aRus_Codes, $aRusShift_Codes, $aUkr_Codes, $aUkrShift_Codes

	Local $sSound
	Local $sChar

	Switch $nKeyCode
		; проверяться будут только нажатия на буквы и цифры и еще клавиши минус и плюс, что после клавиши 0.
		Case 65 To 90, 48 To 57, 186 To 192, 219, 221, 222
			$sCapt_Codes = _
					"АQWERTYUIOPЫЭASDFGHJKLєЮZXCVBNMјѕї" & _
					"1234567890Ѕ»"

			$sEng_Codes = _
					"`qwertyuiop[]asdfghjkl;'zxcvbnm,./" & _
					"1234567890-="

			$sEngShift_Codes = _
					'~QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?' & _
					'!@#$%^&*()_+'

			$sRus_Codes = _
					"ёйцукенгшщзхъфывапролджэячсмитьбю." & _
					"1234567890-="

			$sRusShift_Codes = _
					'ЁЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,' & _
					'!"№;%:?*()_+'

			$sUkr_Codes = _
					"'йцукеягшщзхЇфівапролджєнчсмитьбю." & _
					"1234567890-="

			$sUkrShift_Codes = _
					"’ЙЦУКЕЯГШЩЗХЇФІВАПРОЛДЖЄНЧСМИТЬБЮ," & _
					'!"№;%:?*()_+'

			$aCapture_Codes = StringSplit($sCapt_Codes, "")

			$aEng_Codes = StringSplit($sEng_Codes, "")
			$aEngShift_Codes = StringSplit($sEngShift_Codes, "")

			$aRus_Codes = StringSplit($sRus_Codes, "")
			$aRusShift_Codes = StringSplit($sRusShift_Codes, "")

			$aUkr_Codes = StringSplit($sUkr_Codes, "")
			$aUkrShift_Codes = StringSplit($sUkrShift_Codes, "")

			Switch _WinGetKeyboardLayout(WinGetHandle("[ACTIVE]"))
				Case 0409 ;Если раскладка английская
					If _IsPressed(10) Then ; если нажата клавиша Shift
						$sChar = _ReplaceKeyCode_Proc($nKeyCode, $aCapture_Codes, $aEngShift_Codes)
					Else ; если не нажата клавиша Shift
						$sChar = _ReplaceKeyCode_Proc($nKeyCode, $aCapture_Codes, $aEng_Codes)
					EndIf

					$sSound = "en.wav"
				Case 0419 ;Если расскладка русская
					If _IsPressed(10) Then ; если нажата клавиша Shift
						$sChar = _ReplaceKeyCode_Proc($nKeyCode, $aCapture_Codes, $aRusShift_Codes)
					Else ; если не нажата клавиша Shift
						$sChar = _ReplaceKeyCode_Proc($nKeyCode, $aCapture_Codes, $aRus_Codes)
					EndIf

					$sSound = "ru.wav"
				Case 0422 ;Если расскладка украинская
					If _IsPressed(10) Then ; если нажата клавиша Shift
						$sChar = _ReplaceKeyCode_Proc($nKeyCode, $aCapture_Codes, $aUkrShift_Codes)
					Else ; если не нажата клавиша Shift
						$sChar = _ReplaceKeyCode_Proc($nKeyCode, $aCapture_Codes, $aUkr_Codes)
					EndIf

					$sSound = "ukr.wav"
			EndSwitch

			;ToolTip($sChar & " - " & Asc($sChar), 0, 80)
			
			If WinActive('[REGEXPCLASS:Notepad]', '') Then
				$sTring = $sTring & $sChar
				ToolTip($sTring, 0, 0)
				
				If Not StringInStr($sTring, '`') Then
					ControlSend('', '', '', $sChar)
					$sTring = ''
				Else
					
					If StringLen($sTring) = 3 Then
						
						; действия - блок замены
						
						If StringInStr($sTring, '`;') Then ControlSend('', '', '', 'Ї', 1)
						If StringInStr($sTring, '`~') Then ControlSend('', '', '', 'Autoit', 1)
						
						
						$sTring = ''
					EndIf
					
				EndIf
			EndIf
			;SoundPlay($sSound)
		Case Else ; если была нажата не буква и не цыфра, то выход из функции
			Return
	EndSwitch
EndFunc   ;==>_EvaluateKey_Proc

Func _Key_Proc($nCode, $wParam, $lParam)
	Local $aRet, $KEYHOOKSTRUCT

	If $nCode < 0 Then
		$aRet = DllCall("user32.dll", "long", "CallNextHookEx", "hwnd", $hHook[0], "int", $nCode, "ptr", $wParam, "ptr", $lParam)
		Return $aRet[0]
	EndIf

	If $wParam = 256 Then
		$KEYHOOKSTRUCT = DllStructCreate("dword;dword;dword;dword;ptr", $lParam)
		_EvaluateKey_Proc(DllStructGetData($KEYHOOKSTRUCT, 1))
	EndIf

	$aRet = DllCall("user32.dll", "long", "CallNextHookEx", "hwnd", $hHook[0], "int", $nCode, "ptr", $wParam, "ptr", $lParam)
	Return $aRet[0]
EndFunc   ;==>_Key_Proc

;Функция для замены кодов нажатых клавиш с массива
Func _ReplaceKeyCode_Proc($nKeyCode, $aSearch_Array, $aReplace_Array)
	For $i = 1 To $aSearch_Array[0]
		If $nKeyCode == Asc($aSearch_Array[$i]) Then
			$nKeyCode = Asc($aReplace_Array[$i])
			Return Chr($nKeyCode)
		EndIf
	Next
EndFunc   ;==>_ReplaceKeyCode_Proc

;функция позволяет узнать язык текущей расскладки клавиатуры
Func _WinGetKeyboardLayout($hWnd)
	Local $aRet = DllCall("user32.dll", "long", "GetWindowThreadProcessId", "hwnd", $hWnd, "ptr", 0)
	$aRet = DllCall("user32.dll", "long", "GetKeyboardLayout", "long", $aRet[0])

	Return "0000" & Hex($aRet[0], 4)
EndFunc   ;==>_WinGetKeyboardLayout

Func OnAutoItExit()
	If $hStub_KeyProc Then DllCallbackFree($hStub_KeyProc)
	$hStub_KeyProc = 0
	DllCall("user32.dll", "int", "UnhookWindowsHookEx", "hwnd", $hHook[0])
	If @HotKeyPressed <> "" Then Exit
EndFunc   ;==>OnAutoItExit

Вообще, если идет работа с какой-то конкретной программой, у которой нормальные контролы, то, возможно, проще отслеживать последовательности символов в самом контроле, вроде автозамены: символы вводятся, код читает последние три символа прямо из контрола, при наличии специальных символов заменяет их на нужные. По крайней мере, в этом случае не нужно фильтровать весь ввод символов сложными и неудобными конструкциями...
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
Альтернативный вариант:
"`" выступает здесь как горячая клавиша, которая переводит фокус ввода с активного текущего окна на скрытое GUI скрипта с элементом Edit, т.е. после нажатия этой клавиши ввод перехватывается, в Edit отсчитывается два символа(управляющий, например, тильда, и произвольная буква), делаются нужные действия, и активность возвращается исходному рабочему окну, и через Send/ControlSend в это окно посылается замененный символ. Естественно, и здесь есть недостатки...
Код:
Global $hWnd
$Form = GUICreate('Form1', 100, 30, 0, 0)
$edit1 = GUICtrlCreateEdit('', 5, 5, 90, 20)
GUISetState(@SW_HIDE, $Form)

HotKeySet('{ё}', '_Out')
HotKeySet('{ESC}', '_Quit')

While 1
	Sleep(30)

	$sTring = GUICtrlRead($edit1)
	If StringLen($sTring) = 2 Then		
		GUICtrlSetData($edit1, '')
		WinActivate($hWnd, '')
		Sleep(300)
		If StringInStr($sTring, '~') Then ; действия 
			ControlSend('', '', '', 'Autoit') ;	Send('Autoit') 
		EndIf
	EndIf

WEnd

Func _Out()
	$hWnd = WinGetHandle('[ACTIVE]', '')	
	$sLayout = _WinGetKeyboardLayout($hWnd)
	_SetKeyboardLayout($sLayout)	
	WinActivate($Form, '')
EndFunc   ;==>_Out

Func _SetKeyboardLayout($sLayout)
	$sLayout = '0000' & $sLayout
	$ret = DllCall("user32.dll", "long", "LoadKeyboardLayout", "str", $sLayout, "int", 0)
	DllCall("user32.dll", "ptr", "SendMessage", "hwnd", GUICtrlGetHandle($edit1), "int", "0x50", "int", 1, "int", $ret[0])
EndFunc   ;==>_SetKeyboardLayout

Func _WinGetKeyboardLayout($hWn)
	Local $aRet = DllCall("user32.dll", "long", "GetWindowThreadProcessId", "hwnd", $hWn, "ptr", 0)
	$aRet = DllCall("user32.dll", "long", "GetKeyboardLayout", "long", $aRet[0])
	Return "0000" & Hex($aRet[0], 4)
EndFunc   ;==>_WinGetKeyboardLayout

Func _Quit()
	Exit
EndFunc   ;==>_Quit
 
Автор
A

alexingor

Новичок
Сообщения
10
Репутация
0
WSWR, большое спасибо за ПОДРОБНЕЙШИЕ ответы. Обещаю все проработать и рассказать результат. Просто сейчас возникла небольшая запарка. Проблему я решил третьим способом :rofl:. То есть, обнаружил, что в Word диакритику можно вводить с помощью клавиатурных сокращений. Если кому интересно - то вот здесь последний столбец. Но приведенные примеры все равно проработаю - они ценны теоретически, наверняка пригодятся :IL_AutoIt_1:. Отпишусь еще, тему пока не закрываю.
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
alexingor
Если речь о работе с Word, то есть библиотека Word.au3, а там - полезные функции, например,
Код:
_WordDocFindReplace

Может, пригодится
 
Верх