![]() |
![]() ![]() ![]() | |
|
Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|| Форумы Здесь вы можете задать свой вопрос и наверняка получите ответ |
ЧАТ |
Место для общения :)
Орешник
Коллекция курьезных вопросов из форумов
| ||
![]() | ||
|
Чтобы не потерять эту дискуссию, сделайте закладку
« предыдущая ветвь | форум | следующая ветвь »
Странное поведение хука [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, чтобы избежать глюка.
Разрешается использование тегов форматирования текста:
версия для печати
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)
|
![]() ![]() ![]() |