Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник
Коллекция курьезных вопросов из форумов
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

Странное поведение хука [D7]


Dimaxx ©   (15.01.21 17:45

Доброго времени. Столкнулся с сабжем. Код:

var
 LastStatus: TKeyboardState;

function KeyboardProc(nCode: integer; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
var
 Code: word;
 State: integer;
 CurStatus: TKeyboardState;
begin
 // определим - хук поймал нажатие (=0) или отжатие (=1) клавиш?
 State:=(LParam shr 31) and 1;
 // отсеем автоповтор
 if (nCode=HC_ACTION) and (State xor ((LParam shr 30) and 1)=0) then
   begin
     Code:=WParam;
     // получим текущее состояние клавиш
     GetKeyboardState(CurStatus);
     // проверим сначала клавиши Shift, Control, Alt
     case Code of
       VK_SHIFT: if State=0 then
                   begin // если нажата
                     // выставим код клавиши
                     if CurStatus[VK_LSHIFT]>1 then Code:=VK_LSHIFT else
                       if CurStatus[VK_RSHIFT]>1 then Code:=VK_RSHIFT;
                   end
                 else
                   begin // если отжата
                     if LastStatus[VK_LSHIFT]<>CurStatus[VK_LSHIFT] then Code:=VK_LSHIFT else
                       if LastStatus[VK_RSHIFT]<>CurStatus[VK_RSHIFT] then Code:=VK_RSHIFT;
                   end;
       VK_CONTROL: if State=0 then
                     begin // если нажата
                       // выставим код клавиши
                       if CurStatus[VK_LCONTROL]>1 then Code:=VK_LCONTROL else
                         if CurStatus[VK_RCONTROL]>1 then Code:=VK_RCONTROL;
                     end
                   else
                     begin // если отжата
                       if LastStatus[VK_LCONTROL]<>CurStatus[VK_LCONTROL] then Code:=VK_LCONTROL else
                         if LastStatus[VK_RCONTROL]<>CurStatus[VK_RCONTROL] then Code:=VK_RCONTROL;
                     end;
       VK_MENU: if State=0 then
                  begin // если нажата
                    // выставим код клавиши
                    if CurStatus[VK_LMENU]>1 then Code:=VK_LMENU else
                      if CurStatus[VK_RMENU]>1 then Code:=VK_RMENU;
                  end
                else
                  begin // если отжата
                    if LastStatus[VK_LMENU]<>CurStatus[VK_LMENU] then Code:=VK_LMENU else
                      if LastStatus[VK_RMENU]<>CurStatus[VK_RMENU] then Code:=VK_RMENU;
                  end;
     end;
     LastStatus:=CurStatus;
     case State of
       0: Form1.ListBox1.Items.Add('Нажато '+IntToStr(Code));
       1: Form1.ListBox1.Items.Add('Отжато '+IntToStr(Code));
     end;
   end;
 Result:=CallNextHookEx(0,nCode,WParam,LParam);
end;


При нажатии одной или двух клавиш поведение нормальное - все ловится. Странность состоит в том, что при нажатии трех клавиш происходят чудеса. К примеру: нажимаем последовательно клавиши "1","2","3", не отпуская предыдущие. Коды прилетают. Последовательно отпускаем "1","2","3" - коды также прилетают. Вроде все нормально. Но! Нажимаем "1","2","3", отпускаем "2", затем "3" и продолжаем удерживать "1". Прилетают коды "2" и "3", а через несколько секунд прилетает отжатие "1", хотя клавиша все еще удерживается. То же самое происходит, если отжимать клавиши в обратном порядке - прилетают "3" и "2", а затем также через несколько секунд "1", хотя ее не отпускали. И в тоже время отпустив "1", "2" и удерживая "3" отжатие "3" не прилетает, пока не отпустим "3". Такое происходит с любыми 3-мя и более клавишами.

Как побороть?


Styx ©   (15.01.21 18:11[1]

Это может быть и аппаратной проблемой...
https://gaming.stackexchange.com/questions/6669/how-do-i-remove-the-limit-on-pc-keyboard-button-presses


Dimaxx ©   (15.01.21 19:40[2]

Хм, возможно. Но в играх 3 клавиши нормально распознаются.


dmk ©   (15.01.21 23:57[3]

Вот так распознается до 6 клавиш одновременно:
procedure TRenderForm.CheckSystemKeys;
var
 K: TKeyboardState;
 i: Integer;
 B: Byte;
 S: string;

begin
 GetKeyboardState(K);
 S := '';

 for i := Low(K) to High(K) do
 begin
   B := K[i] shr 7;
   if (B <> 0) then
     S := S + IntToStr(i) + '/';
 end;

 Caption := S;
end;


Я делаю выборку так:
function KeyState(K: Word): Boolean;
begin
 Result := Boolean(Word(GetAsyncKeyState(K)) shr 15); //Значащий бит 16 передвигаем в начало
end;


Потом присваиваю состояние логическим переменным:
   // Системные клавиши + клавиши мыши
   SK.Alt := KeyState(VK_MENU);
   SK.Ctrl := KeyState(VK_CONTROL);
   SK.Shift := KeyState(VK_SHIFT);
   SK.Left := KeyState(VK_LBUTTON);
   SK.Middle := KeyState(VK_MBUTTON);
   SK.Right := KeyState(VK_RBUTTON);


Через GetKeyboardState иногда получаются двойные скан-коды, которые требуют дополнительной обработки. Например левый Ctrl имеет скан-код 17/162, а правый Ctrl имеет код: 17/163. Ну и т.д. и т.п.

Через GetAsyncState получается корректней, т.к. система обрабатывает дополнительные скан-коды (возможно через драйвер). Клавиатуры то разные бывают.


Dimaxx ©   (16.01.21 00:35[4]

У меня тоже распознаются все без проблем. Затык не в распознавании, а в странном поведении при отжатии клавиш не в порядке их нажатия.


dmk ©   (16.01.21 10:33[5]

>в странном поведении
Сдвигайте значимый бит в начало:
B := K[i] shr 7;
Будет корректное поведение.


Павиа   (17.01.21 13:33[6]

У меня все нормально работает
https://yadi.sk/d/SbRb-RXxq6jdsw


Dimaxx ©   (18.01.21 10:54[7]

2 Павиа: Точно такое же поведение, что я описал:

> Нажимаем "1","2","3", отпускаем "2", затем "3" и продолжаем
> удерживать "1". Прилетают коды "2" и "3", а через несколько
> секунд прилетает отжатие "1", хотя клавиша все еще удерживается.


Pavia ©   (18.01.21 15:21[8]


> > секунд прилетает отжатие "1", хотя клавиша все еще удерживается

Тогда это аппаратная проблема.


Dimaxx ©   (18.01.21 17:08[9]

Возможно, но почему тогда все отлично работает, если отпускать клавиши в том же порядке, что и нажимали? Тут на аппаратку не спишешь.


dmk ©   (18.01.21 20:05[10]

GetKeyboardState делает выборку из очереди сообщений,
а здесь прямо через драйвер.

Простейший сканер:
https://yadi.sk/d/Tz_awJEf81IIBg


Dimaxx ©   (18.01.21 21:02[11]

GetKeyboardState тут совершенно не причем. Он использован для распознавания нажатия левого/правого Shift/Ctrl/Alt. Если его убрать и просто выводить коды прилетающих в хук клавиш ничего не изменится, поведение тоже самое. Фиктивное отпускание клавиши прилетает в хук и прилетает скорее всего потому, что переполнен буфер нажатых клавиш.

Кстати, и на работе, и дома у меня клавы HP. Возможно это они себя так ведут. Попробую взять другую клаву и проверю.


Dimaxx ©   (20.01.21 14:20[12]

Проверил.

1) Клава HP (USB): при убирании GetKeyboardState из хука пропадает вышеописанный "глюк".
2) Клава HP (PS/2): "глюк" сохраняется даже без использования GetKeyboardState.
3) Клава Genius (USB): "глюка" нет в любом случае.

Выходит, виноват контроллер клавы.


Dimaxx ©   (20.01.21 14:30[13]

Еще один момент: Клава HP (PS/2) автоматом отпускает даже 1 клавишу Shift/Ctrl/Alt, если не нажимаются другие клавиши. Т.е. зажимаем Shift и нажимаем алфавитно-цифровые клавиши (переключили регистр ввода). Прилетают коды клавиш в соответствии с нажатыми. Как только перестаем нажимать клавиши, но удерживаем шифт, то через несколько секунд прилетает отжатие Shift.


Rouse_ ©   (23.01.21 23:51[14]


> то через несколько секунд прилетает отжатие Shift.

а если после этого продолжить нажимать кнопки?


Dimaxx ©   (25.01.21 09:52[15]

Если удерживать Shift после "прилета" отжатия, то при нажатии на алфавитно-цифровые сначала прилетает нажатие Shift, а потом коды нажатых клавиш.


Rouse_ ©   (25.01.21 10:07[16]

Хитро :)))) Ну это точно аппаратное что-то.


Dimaxx ©   (25.01.21 17:29[17]

Короче, переделал я без GetKeyboardState, чтобы избежать глюка.


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо