Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.02.26;
Скачать: CL | DM;

Вниз

Как правильно обработать WH_KEYBOARD?   Найти похожие ветки 

 
kami ©   (2005-12-04 14:59) [0]

Все поиски в интернете привели к нахождению нескольких примеров. Одни из них даже не компилировались, другие - определяли все нажатые клавиши, как заглавные английские.
Пришлось порыться в MSDN и написать такой вот код:
var
 MyHook:HHook;
 KeyFile:TFileStream;
function KeyboardProcLL(code: integer; W: WParam; L: LParam): LResult;
var
 kbd:KBDLLHOOKSTRUCT;
 keyState:TKeyboardState;
 p:PChar;
 RetChars:integer;
 ProcessID:DWORD;
begin
 if code<0 then
   begin
     Result:=CallNextHookEx(MyHook,code,W,L);
     Exit;
   end;
 if (W=WM_KEYUP) then
   begin
     kbd:=KBDLLHOOKSTRUCT(Pointer(L)^); // получили структуру KBDLLHOOKSTRUCT
     GetKeyboardState(KeyState);
     GetMem(p,3);
     ProcessID:=1;// без узнавания активного потока почему-то не работает
     RetChars:=ToASCIIEx( // если использовать просто vkCode, то выдает заглавные английские буквы
       kbd.vkCode,
       kbd.scanCode,
       keyState,
       p,
       0,
       GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow,@ProcessID)));
     // в p - нажатые символы kbd - не изменялся
     if RetChars>0 then
       KeyFile.WriteBuffer(p[0],RetChars);
     FreeMem(p);
   end;
 Result:=CallNextHookEx(MyHook,code,W,L);
end;


Но он неправильно обрабатывает нажатия символов на цифровых клавишах (типа " № # % ?) :(
В общем, что-то я опять перенамудрил :(
Как все-таки правильно получить нажатый символ (с учетом раскладки клавиатуры для активного потока) ?


 
kami ©   (2005-12-04 18:27) [1]

Неужели никто не знает? Не может быть, чтобы нельзя было сделать, PuntoSwitcher прекрасно с этим справляется
Up, в смысле :)


 
kami ©   (2005-12-06 22:03) [2]

Up еще раз :)


 
KADAN ©   (2005-12-07 07:58) [3]

> другие - определяли все нажатые клавиши, как заглавные английские.
а я всю жизнь думал что ловится код клавиши а не символ... а пунтосвитчер просто клавиатуру "выучил" и следит за состоянием всяческих "шифтов", капсов и раскладкой


 
kami ©   (2005-12-07 16:43) [4]

KADAN ©   (07.12.05 7:58) [3]
а пунтосвитчер просто клавиатуру "выучил"
На чем основывается это утверждение?
ловится код клавиши
Вообще-то ловится (вернее, посылается в процедуру хука) виртуальный код клавиши и её hardware скан-код (основные параметры KBDLLHOOKSTRUCT). Вот я и хочу узнать, как из них определить, какой символ отобразится в программе. Мой вариант кода работает некорректно на цифровых клавишах, а заводить полную таблицу раскладки клавиатуры во всех режимах, с учетом нажатых шифтов, капслоков и иже с ними, имхо, совсем неверное решение.


 
Lamer@fools.ua ©   (2005-12-07 20:50) [5]

Функция MapVirtualKey/MapVirtualKeyEx не спасёт отца русской демократии?


 
kami ©   (2005-12-07 21:40) [6]

Lamer@fools.ua ©   (07.12.05 20:50) [5]
MapVirtualKeyEx

Пока она меня не спасает :)
Пытался ее использовать с самого начала, сейчас попробовал еще раз - возвращает только заглавные английские буквы, и в MSDN написано : uCode is a virtual-key code and is translated into an unshifted character value (пробовал использовать ее с параметром 2 (VCode>Char)).
Может, что-то я не так делаю?


 
Lamer@fools.ua ©   (2005-12-07 22:18) [7]

>>kami ©

В тестовом приложении без хуков всё отлично работает (и текущая раскладка учитывается и состояние Shift и Caps Lock):

procedure TForm1.Timer1Timer(Sender: TObject);
var
 KS: TKeyboardState;
 I: Low(KS) .. High(KS);
 S: String;
 C: UINT;
 C1: Integer;
 Ch: packed array [0 .. 1] of Char;
begin
 if not GetKeyboardState(KS) then
   RaiseLastOSError;

 Memo1.Lines.BeginUpdate;
 try
   Memo1.Lines.Clear;

   for I := Low(KS) to High(KS) do
   begin
     if KS[I] and $80 <> 0 then
     begin
       S := Format("%.2xh", [I]);

       C := MapVirtualKey(I, 2);
       if C <> 0 then
         S := S + Format(": ""%s""", [Char(C)])
       else
         S := S + ": ?";

       C := MapVirtualKey(I, 0);
       if C <> 0 then
       begin
         C1 := ToAscii(I, C, KS, Ch, 0);
         case C1 of
           1:  S := S + Format(": ""%s"" -- #%d", [Ch[0], Byte(Ch[0])]);
           2:  S := S + Format(": ""%s%s"" -- #%d#%d", [Ch[0], Ch[1], Byte(Ch[0]), Byte(Ch[1])]);
         else
           S := S + ": ?";
         end;
       end;

       Memo1.Lines.Add(S);
     end;
   end;
 finally
   Memo1.Lines.EndUpdate;
 end;
end;


На форме:
Memo1: TMemo;
Timer1: TTimer;


У таймера Interval = 100.


 
kami ©   (2005-12-07 22:48) [8]

Lamer@fools.ua ©   (07.12.05 22:18) [7]
Посмотрел, в принципе - то же самое: получение vkCode и ScanCode, затем - преобразование в ASCII.
Перенес в хук - точно такая же картина (только, ко всему прочему, определяет все нажатия клавиш в раскладке моего приложения. Оно и понятно - ToASCII работает с раскладкой своего потока ).
В своем приложении, к стати,определяет все правильно, а вот с другими :(


 
kami ©   (2005-12-07 23:27) [9]

Lamer@fools.ua ©   (07.12.05 22:18)
Сейчас поекспериментил, выяснил, что в чужом приложении не определяются нажатия шифтов из моего хука.
Посему вставил следующую строчку :
GetKeyboardState(KeyState);
KeyState[VK_SHIFT]:=GetKeyState(VK_SHIFT);

Вроде, все заработало.
Спасибо.



Страницы: 1 вся ветка

Текущий архив: 2006.02.26;
Скачать: CL | DM;

Наверх




Память: 0.49 MB
Время: 0.092 c
4-1134078315
spyrytus
2005-12-09 00:45
2006.02.26
Как отследить "Завершение работы".


15-1139233884
PARUS
2006-02-06 16:51
2006.02.26
Нету спама!(Дуратский вопрос)


15-1138963953
Некто
2006-02-03 13:52
2006.02.26
Купил новый корпус


4-1133978876
swan
2005-12-07 21:07
2006.02.26
Робота с Com-портом.ВАЖНО!


3-1135669029
DELORAC
2005-12-27 10:37
2006.02.26
Как получить из базы Oracle тексты создания таблиц?