Обработка многократных нажатий клавиш

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Обработка многократных нажатий клавиш

Сообщение shade »

В движке для реализации перемещений с помощью клавиш нужна поддержка многократных нажатий.
Например, клавиша W - движение в перед
клавиша D - движение вправо
клавиша A - движение влево
игрок нажимает и удерживает W, при этом он по перемено нажимает A и D, - и герой в игре двигается змейкой.

Как реализовать такое в Lazarus? Может можно как-то опрашивать клавиатуру? Под Windows это можно сделать с помощью GetKeyState/GetAsyncKeyState), может есть кроссплатформный аналог?

Или прийдется на OnKeyDown/OnKeyUp/OnTimer заполнять массив нажатий - как сейчас и реализовал - но частота таймера слишком маленькая... (вообще в данном движке таймер и не нужен, по крайней мере пока - все реакции по событиям)
SAK
постоялец
Сообщения: 158
Зарегистрирован: 17.02.2006 23:45:14
Откуда: Тим
Контактная информация:

Сообщение SAK »

А зачем таймер? OnKeyDown устанавливает флаг нажатия, OnKeyUp - снимает его. Или я что-то не понимаю.
haword
постоялец
Сообщения: 301
Зарегистрирован: 02.03.2006 10:34:40

Сообщение haword »

shade писал(а):В движке для реализации перемещений с помощью клавиш нужна поддержка многократных нажатий.
Например, клавиша W - движение в перед
клавиша D - движение вправо
клавиша A - движение влево
игрок нажимает и удерживает W, при этом он по перемено нажимает A и D, - и герой в игре двигается змейкой.

Как реализовать такое в Lazarus? Может можно как-то опрашивать клавиатуру? Под Windows это можно сделать с помощью GetKeyState/GetAsyncKeyState), может есть кроссплатформный аналог?

Или прийдется на OnKeyDown/OnKeyUp/OnTimer заполнять массив нажатий - как сейчас и реализовал - но частота таймера слишком маленькая... (вообще в данном движке таймер и не нужен, по крайней мере пока - все реакции по событиям)

попробуй так!
создаешь буфер нажатых клавиш, вешаешь обработчик на кейап и кейдаун, при нажатии заносишь в буфер полученный код и увеличиваешь счетчик на единицу, при отпускании клавиши удаляешь код с буфера и уменьшаешь счетчик. Должно сработать.
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

SAK писал(а):А зачем таймер? OnKeyDown устанавливает флаг нажатия, OnKeyUp - снимает его. Или я что-то не понимаю.

Нажимаем и держим W - идут OnKeyDown с W
нажимаем и держим A - идут OnKeyDown с A
отпускаем A - более ни каких OnKeyDown не будет даже не смотря на то, что W мы не отпускали

haword писал(а):попробуй так!

Я так и сделал. Не понял только за чем счетчик?
Я вот и говорю, что частоты таймера мне не хватает - движение рывками
Yogrik
постоялец
Сообщения: 116
Зарегистрирован: 22.03.2006 23:41:48

Сообщение Yogrik »

А таймер имеется в виду TTimer???
Если да, то может попробывать реализовать "таймер" через поток...
Ну там типо: потоку задаются какие кнопки зажаты, а он перерисовывает то что нужно
Тогда задержки-то и не будет, но может появится мерцание, хотя и с ним можно бороться не перерисовывая лишний раз...
haword
постоялец
Сообщения: 301
Зарегистрирован: 02.03.2006 10:34:40

Сообщение haword »

shade писал(а):
SAK писал(а):А зачем таймер? OnKeyDown устанавливает флаг нажатия, OnKeyUp - снимает его. Или я что-то не понимаю.

Нажимаем и держим W - идут OnKeyDown с W
нажимаем и держим A - идут OnKeyDown с A
отпускаем A - более ни каких OnKeyDown не будет даже не смотря на то, что W мы не отпускали

haword писал(а):попробуй так!

Я так и сделал. Не понял только за чем счетчик?
Я вот и говорю, что частоты таймера мне не хватает - движение рывками

Я пробывал, после отпускания любой клавиши идет ОнКейАп с кодом! Для этого и счетчик чтобы знать количество одновременно нажатых клавишь. И странно таймер под виндой кажись до 1 милисекунды может срабатывать, этого чтоли не хватает времени?
SAK
постоялец
Сообщения: 158
Зарегистрирован: 17.02.2006 23:45:14
Откуда: Тим
Контактная информация:

Сообщение SAK »

Всё же не понимаю.
Делаем флаги: flagA, flagW. При OnKeyDown с A устанавливаем flagA:=true; OnKeyDown с W - flagW:=true; Для OnKeyUp соответственно каждой клавише сбрасываем флаги в false. Теперь не имеет значение идут события OnKeyDown после первого нажатия или нет, анализируем только соответствующий флаг который будет сброшен только после отпускания соответствующей ему клавиши. Событие OnKeyDown фиксируется только для нажатия клавиши автоповторы отбрасываются. Зачем надо знать количество одновременно нажатых клавиш?

PS. Или частота автоповтора задаёт скорость игры? Но для этого всё же таймер лучше.
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

Yogrik писал(а):А таймер имеется в виду TTimer???

Именно TTimer... Есть альтернативы?

SAK писал(а):PS. Или частота автоповтора задаёт скорость игры? Но для этого всё же таймер лучше.

Движок не игровой, поэтому понятия скорости нет. И таймера пока не нужно, только вот ради обработки нажатий и сделал таймер.

SAK писал(а):Событие OnKeyDown фиксируется только для нажатия клавиши автоповторы отбрасываются.

В случае однократных нажатий использовал автоповторы и все работало нормально. А при использования многократных нажатий, автоповтор работает только для последней нажатой клавиши и если она отпускается, то автоповторы прекращаются.

haword писал(а):Я пробывал, после отпускания любой клавиши идет ОнКейАп с кодом! Для этого и счетчик чтобы знать количество одновременно нажатых клавишь.

ОнКейАпом никаких проблем небыло и нет.
Мне не нужно знать сколько клавиш нажато, мне нужно знать только какие. Для этого я использую TKeyState = set of byte;
при OnKeyDown: KeyState := KeyState + [Key]
при OnKeyUp: KeyState := KeyState - [Key]
В таймере просто проверка:
if VK_W in KeyState then shift_camera_forward(step_len);
и т.п.

haword писал(а):И странно таймер под виндой кажись до 1 милисекунды может срабатывать, этого чтоли не хватает времени?

Задать кончено можно до 1мс, но не факт что события будут идти с такой скростью.
На новых тачках может быть, а вот на мой с пустым таймером где-то до 30мс можно отсчитывать, точно не помню раньше замерял, а тут еще нужно сцену рендерить.

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

Впрочем ладно, многократные нажатия работают.
А дискретизация/сглаживание движений это другая тема..

PS: Просто интересно (но в данной ситуации бесполезно), можно ли в Lazarus определить нажата некоторая клавиша или нет - без обработки OnKeyDown/OnKeyUp? и не используя платформно зависимые юниты типа windows.
Yogrik
постоялец
Сообщения: 116
Зарегистрирован: 22.03.2006 23:41:48

Сообщение Yogrik »

shade писал(а):Именно TTimer... Есть альтернативы?

Альтернатив нет, но есть TIdleTime......;)
haword
постоялец
Сообщения: 301
Зарегистрирован: 02.03.2006 10:34:40

Сообщение haword »

SAK писал(а):Всё же не понимаю.
Делаем флаги: flagA, flagW. При OnKeyDown с A устанавливаем flagA:=true; OnKeyDown с W - flagW:=true; Для OnKeyUp соответственно каждой клавише сбрасываем флаги в false. Теперь не имеет значение идут события OnKeyDown после первого нажатия или нет, анализируем только соответствующий флаг который будет сброшен только после отпускания соответствующей ему клавиши. Событие OnKeyDown фиксируется только для нажатия клавиши автоповторы отбрасываются. Зачем надо знать количество одновременно нажатых клавиш?

А если одновременно три клавиши нажмешь? или четыре? или все 10? Мое решение было бы буфер с нажатыми клавишами. Счетчик можно использовать к примеру при нажатии более 4 клавиш ни на что не реагировать. Хотя можно и считать количество цифр в буфере. Кому как удобнее.
haword
постоялец
Сообщения: 301
Зарегистрирован: 02.03.2006 10:34:40

Сообщение haword »

если кейап и кейдаун отрабатывают то и таймер не зачем
Ответить