Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Visual C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 15.04.2016, 17:25   #1
Arigato
Высокая репутация
СуперМодератор
 
Аватар для Arigato
 
Регистрация: 27.07.2008
Сообщений: 15,544
По умолчанию Клавиатурный хук

Казалось бы, такая простая задача и в поиске тысячи примеров реализации. Но ни один, что я находил, нормально не работает.

Первый способ.

Код:
hMsgHook= ::SetWindowsHookEx (WH_KEYBOARD_LL, KeyboardMsgProc1, hInstance, 0); // этот хук не понимает русские буквы

// Эта функция не понимает русских букв
LRESULT CALLBACK KeyboardMsgProc1 (int nCode, WPARAM wParam, LPARAM lParam)
{
	if (nCode == HC_ACTION)
	{
		if (wParam==WM_KEYDOWN){
			KBDLLHOOKSTRUCT *hookkeyboard = (KBDLLHOOKSTRUCT*)lParam;
			char key=hookkeyboard->vkCode; // получаем код клавиши
			if(key>='0' && key<='9' || key>='A' && key<='Z' || key==' '){ // символ
				// Отправляем сообщение в приложение
				PostMessage (hParentWnd, KBoardMessage, key, 0 );
			}
		}
	}


	return CallNextHookEx (hMsgHook, nCode ,wParam , lParam);
};
Работает нормально, в смысле надежно реагирует на нажатия, но не определяет код символа, а только код клавиши. Мне же надо знать, введена ли русская или английская буква, в каком регистре и т.д.

Второй способ.

Код:
hMsgHook= ::SetWindowsHookEx (WH_KEYBOARD, KeyboardMsgProc2, hInstance, 0); // этот понимает русские, но не всегда корректно

// переводит код нажатой клавиши в символ
short GetSymbolFromVK(WPARAM wParam)
{
    BYTE btKeyState[256];
    WORD Symbol;
	HKL hklLayout = GetKeyboardLayout(GetCurrentThreadId()); // узнаем язык клавиатуры
    if((ToAsciiEx(wParam, 0, btKeyState, &Symbol, 0, hklLayout) == 1) && // сам перевод
                 GetKeyState(VK_CONTROL) >= 0 && GetKeyState(VK_MENU) >= 0) // проверяем CTRL и ALT
        return Symbol;
     return -1;
}

// Эта функция читает русские буквы, но не всегда
LRESULT CALLBACK KeyboardMsgProc2 (int nCode, WPARAM wParam, LPARAM lParam)
{
	if (nCode == HC_ACTION)
	{
		if (lParam>0){
			WORD wc;
			if((wc=GetSymbolFromVK(wParam))!=-1) // переводим нажатие в текст
				if(iswprint(wc)) {// проверяем или знак текстовой
					// Отправляем сообщение в приложение
					PostMessage (hParentWnd, KBoardMessage, wc, 0 );
				}
		}
	}


	return CallNextHookEx (hMsgHook, nCode, wParam, lParam);
};
Этот вариант работает непойми как. Иногда привильно, иногда вместо русских воспринимает английские или наоборот, часто путает регистр букв, некоторые буквы вообще проглатывает и пропускает.

Есть ли у кого пример полностью рабочего хука без подобных косяков?
Arigato вне форума Ответить с цитированием
Старый 15.04.2016, 17:42   #2
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

http://www.codeproject.com/Articles/...M-CHAR-Message
waleri вне форума Ответить с цитированием
Старый 15.04.2016, 18:07   #3
Arigato
Высокая репутация
СуперМодератор
 
Аватар для Arigato
 
Регистрация: 27.07.2008
Сообщений: 15,544
По умолчанию

Сначала подумал, что за индусский код такой:

Код:
if(nCode >=0 && nCode == HC_ACTION)
А потом внизу увидел автора кода: sridhar vattam, India



А хук не работает как надо, русские буквы превращаются биллеберду, а английские дублируются раз по 5. Вот вывод:

Цитата:
ddddffffffffgggggggg@@@@@@@@888 888882222222255555555BBBBBBBB!!!!!! !!
Я набрал "dfgПривет!". Но есть ощущение, что как-то можно его до ума довести, только пока не ясно как...
Arigato вне форума Ответить с цитированием
Старый 15.04.2016, 19:49   #4
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

Надо отслеживать нажатие клавиши или нет, если символ сконвертирован, то не надо передавать в систему. А если НЕ сконвертирован, то обязательно передавать дальше - система должна следить например за состоянием SHIFT.

А зачем это надо - не проще будет свою раскладку сделать?
waleri вне форума Ответить с цитированием
Старый 15.04.2016, 20:18   #5
Arigato
Высокая репутация
СуперМодератор
 
Аватар для Arigato
 
Регистрация: 27.07.2008
Сообщений: 15,544
По умолчанию

От повторов удалось избавиться, работает отлично с ASCII-кодами, воспринимает регистр букв, значки. Но вместо русских все еще белиберда:

Код:
hMsgHook= ::SetWindowsHookEx (WH_GETMESSAGE, procCharMsg, hInstance, 0);

LRESULT CALLBACK procCharMsg(int nCode, WPARAM wParam, LPARAM lParam)
{
	if(nCode == HC_ACTION){
		MSG *msg;
		WPARAM charCode;
		msg=(MSG *)lParam;
		if(msg->message == WM_CHAR && wParam == PM_REMOVE){
			charCode = msg->wParam;
			PostMessage (hParentWnd, KBoardMessage, charCode, 0);
		}
	}
	return CallNextHookEx(hMsgHook, nCode, wParam, lParam);
}
Остается понять, что не так с русскими буквами и как с этим разобраться?

Ввод "dfgПривет!" теперь приводит к "dfg@825B!".

P.S. Вариант с WM_CHAR никуда не годится. Если набирать текст в Word, он отлавливается (с проблемой с русскими буквами), а в Блокноте - нет. Вернулись к началу, пока ни одного нормального варианта хука нет, который бы работал везде вне зависимости от активного приложения, от раскладки клавиатуры, от регистра символов...

Последний раз редактировалось Arigato; 15.04.2016 в 20:37.
Arigato вне форума Ответить с цитированием
Старый 15.04.2016, 21:08   #6
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,770
По умолчанию

Цитата:
Сообщение от Arigato Посмотреть сообщение
есть ощущение, что как-то можно его до ума довести, только пока не ясно как...
Пить/курить то же, что и автор кода.
Vapaamies вне форума Ответить с цитированием
Старый 15.04.2016, 22:08   #7
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

Можно попробовать посылать WM_UNICHAR.

Сделайте свою раскладку и проблем не будет...
waleri вне форума Ответить с цитированием
Старый 15.04.2016, 23:04   #8
Arigato
Высокая репутация
СуперМодератор
 
Аватар для Arigato
 
Регистрация: 27.07.2008
Сообщений: 15,544
По умолчанию

Не совсем понимаю, зачем посылать и что значит свою раскладку? Мне не посылать надо, а перехватывать.
Arigato вне форума Ответить с цитированием
Старый 16.04.2016, 00:50   #9
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,770
По умолчанию

Мне кажется, что это случай для MapVirtualCodeEx.
Vapaamies вне форума Ответить с цитированием
Старый 16.04.2016, 00:50   #10
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

А, понятно...
А что содержит wParam когда перехватывается notepad и когда word?
Тут похоже, что в одном случае Юникод а в другом нет.
Проверяйте получателя WM_CHAR с помощью IsWindowUnicode()
waleri вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Клавиатурный хук, вывод клавиши два раза. Winexcel Общие вопросы Delphi 3 14.07.2014 07:18
Клавиатурный тренажер на с++ S@M@N Помощь студентам 1 28.01.2013 20:21
Клавиатурный шпион okda Общие вопросы C/C++ 0 12.02.2012 13:39
Клавиатурный обработчик. Shub_Niggurath Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 1 16.06.2010 22:47
Клавиатурный хук. Гляньте код.... Levmetall Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 1 26.02.2010 18:44