DirectInput Вопросы и обсуждение.

Доброго всем дня или ночи.
На днях появился у меня пад Logitech F510 (надоело в хоккей на клаве играть *warning!* ) И вот по своей специфике, акрамя игровых баталий, решил я покодить его DirectInput'ум.
Но вопрос не по паду Wacko

Столкнулся я просто с вопросом по обработке клавиатуры. Сразу скажу, что сама мелкософт советует обрабатывать лучше WM_KEYDOWN и т.д., чем юзать для этих целей DI, а для казуалок всяких достаточно WM'ки обрабатывать с головой. Думаю, что многие с этим согласятся. Хотя все зависит от задачи...
Но я хочу кое в чем разобраться, ради своего интереса.
В обработке WM_KEYDOWN wParam == vk, а lParam - флаговый параметр. Так вот в 30 бите lParam'а можно узнать, была ли уже нажата данная клавиша до прихода этого сообщения в стек. Круто Smile можно обрабатывать различные вариации типа: IsKeyDown(key), IsKeyPressed(key).
С DI обычно используют непосредственный опрос клавиатуры. Так вот значения по нажатию в массив клавиш приходит 128 для any key -> 0x80, то бишь мы и проверяем (buf[key] & 0x80) != 0. А как узнать аля 30 бит в WM_KEYDOWN? Не уж то надо обрабатывать это вручную, запоминать все состояния? Так как, когда я физический нажал клавишу и быстро отпустил, прошли кажется мгновения, но так как опрос происходит довольно быстро (~ ваш FPS), то соответственно посчиталось, что клавиша нажата была ~ == FPS. Не катит =)

Буферизированный опрос пока еще "не курил", хотя когда-то давно и "курил" Smile но все забыл.

Последняя правка: пн, 29/08/2011 - 22:04
Submitted by MaxImuS on

Комментарии

Для клавы таки лучше юзать WM_KEYDOWN/WM_KEYUP, поллить такие вещи чревато потерей событий, особенно без буферизованного ввода -- действительно будут терятся события.

Но если уж поллить, то придётся запоминать состояния и на ручной тяге аккуратно генерить "евенты" (up/down) самому.

Для is-key-pressed можно просто GetAsyncKeyState() юзать и не морочится с директ-инпутом.

Submitted by BLK Dragon on
>> Но если уж поллить, то придётся запоминать состояния и на ручной тяге аккуратно генерить "евенты" (up/down) самому.

Все таки мои предположения подтверждаются =(
А что скажешь по поводу шутеров? Для них вполне хватит GetAsyncKeyState() без DI?

Вычитал еще, что для DI приемлемый опрос с частотой 30-40 и выше, а иначе возможны потери событий, как раз то, про что ты и упомянул. И из этого у меня вытекают такие мысли, что если кто-то упорно заюзает DI, то fps должен держать не ниже 30...

Submitted by MaxImuS on

Нет, вот чего точно нельзя делать, так это просто обновлять текущие состояния кнопок каждый кадр -- легко потерять нажатие/отпускание, особенно во время FPS drop'а. Когда-то очень давно (ещё в ДОСе) я пытался так делать и мне очень не понравились результаты Smile

Можно юзать DI, но нужно при этом юзать буферизованный ввод чтоб ничего не терялось -- я так делаю для мыши и геймпада и всё ок. На PSP/PS3, кстати, такая же точно модель получения данных от геймпада/клавы/мыши -- вытягиваешь буфер с обновлениями состояний со времени последнего опроса и аккуратно это обрабатываешь.

Так что смирись и делай как все Smile

Хотя именно для клавы и именно для получения событий нажатия/отпускания достаточно WM_KEYDOWN/WM_KEYUP, для получения состояния -- GetAsyncKeyState. Но НЕ нужно пытаться получать состояния путём запоминания в массивчике внутри проги с обновлением по WM_KEYDOWN/WM_KEYUP и НЕ нужно пытаться ловить переходы нажато/отпущено через GetAsyncKeyState -- получится фигня.

Submitted by BLK Dragon on
>> Нет, вот чего точно нельзя делать, так это просто обновлять текущие состояния кнопок каждый кадр -- легко потерять нажатие/отпускание, особенно во время FPS drop'а. Когда-то очень давно (ещё в ДОСе) я пытался так делать и мне очень не понравились результаты
спасибо за совет, только я не совсем понял про опрос, если не каждый кадр, то как?

>> Можно юзать DI, но нужно при этом юзать буферизованный ввод чтоб ничего не терялось -- я так делаю для мыши и геймпада и всё ок. На PSP/PS3, кстати, такая же точно модель получения данных от геймпада/клавы/мыши -- вытягиваешь буфер с обновлениями состояний со времени последнего
да, для мыши я юзаю буферизацию. GetDeviceData() я так понял вытягивает последние данные из буфера DI, а DI в свою очередь набивает буфер сам после захвата устройства. так ли это?

>> Так что смирись и делай как все
не смирюсь, ибо революцию я не делаю... шутка =), не собираюсь ни в одном проекте юзать клаву через DI. все это ради утоления интереса что может данный интерфейс, уточняю то, чего я пока не знаю толком. всегда мною ввод с клавы обрабатывался через WM и GetAsyncKeyState

>> Но НЕ нужно пытаться получать состояния путём запоминания в массивчике внутри проги с обновлением по WM_KEYDOWN/WM_KEYUP и НЕ нужно пытаться ловить переходы нажато/отпущено через GetAsyncKeyState -- получится фигня.

простыми словами Smile - не стоит делать с точностью да на оборот. но я уже себе такое не позволю или можно завязывать с карьерой Wink

Submitted by MaxImuS on
Что я хотел сказать про опрос.

Если читать каждый кадр (1/60 или даже 1/100) состояние кнопок, то это ни фига не гарантирует что мы не пропустим событие перехода нажато/отпущено, в лёгком случае мы рискуем тупо получить лаг на кадр (в каком нибудь файтинге это фатально), в худшем -- вообще потерять нажатие/отпускание кнопки.

Девайсы обычно опрашивают состояние с довольно большой частотой и передают наружу (в систему) путём набивания буфера, а ты уже через DI или местный аналог выгребаешь и обрабатываешь весь этот поток данных. Ну или вот операционка обрабатывает и выдаёт тебе евенты и последнее актуальное состояние кнопки.

В виндовсе начина я ХР кстати есть т.н. Raw Input -- можно грести "настоящие" данные до того как они проходят через систему, так можно например несколько мышек обрабатывать; у меня как то была версия прототипа драконошутера, где можно было играть вдвоём на одном компе с разных мышек Smile

Submitted by BLK Dragon on
>> В виндовсе начина я ХР кстати есть т.н. Raw Input -- можно грести "настоящие" данные до того как они проходят через систему, так можно например несколько мышек обрабатывать; у меня как то была версия прототипа драконошутера, где можно было играть вдвоём на одном компе с разных мышек
это наверное забавно получилось =), знаю конечно что не ось, не DI мне не позволят обработать две мыши либо клавы

>> Девайсы обычно опрашивают состояние с довольно большой частотой и передают наружу (в систему) путём набивания буфера, а ты уже через DI или местный аналог выгребаешь и обрабатываешь весь этот поток данных. Ну или вот операционка обрабатывает и выдаёт тебе евенты и последнее актуальное состояние кнопки.
ну это собственно я и имел ввиду

>> Если читать каждый кадр (1/60 или даже 1/100) состояние кнопок, то это ни фига не гарантирует что мы не пропустим событие перехода нажато/отпущено, в лёгком случае мы рискуем тупо получить лаг на кадр (в каком нибудь файтинге это фатально), в худшем -- вообще потерять нажатие/отпускание кнопки.
а здесь извиняюсь заранее Smile так как немного под пивом Russian и немного не улавливаю мысль твою
имелось ввиду, что если я буду опрашивать устройство с частотой 60 либо даже 100, то это не дает мне гарантии, что я сохраню все события в целостности (ну типа не потеряю)?

тогда у меня возникает вопрос: в случае обработки WM мне ясно - я вешаю, к примеру, на WM_KEYDOWN какую-то обработку и она дернется, как только я заставлю обработать стек моих сообщений окна; а вот с собственным вытягиванием при помощи DI последних действительных состояний кнопок из буфера я так и не соображу, с какой мне частотой производить это, раз ты сказал, что каждый кадр тянуть это не обязательно?

Submitted by MaxImuS on

Если опрашивать _текущее_состояние_ -- то можно легко потерять переходы между сосчтояниями.

Если вытягивать забуферизованный ввод -- ничего не теряется. Но делать это всё одно каждый кадр нужно.

Submitted by BLK Dragon on
>> Если опрашивать _текущее_состояние_ -- то можно легко потерять переходы между сосчтояниями.
>> Если вытягивать забуферизованный ввод -- ничего не теряется. Но делать это всё одно каждый кадр нужно.

спасибо, уловил

Submitted by MaxImuS on

У меня еще один вопрос возник Smile А можно ли одновременно клаву опрашивать GetDeviceData и GetDeviceState? Или это ересь Smile и возможен опрос только с одним форматом?

Submitted by MaxImuS on
Quote:
MaxImuS писал(а):
У меня еще один вопрос возник Smile А можно ли одновременно клаву опрашивать GetDeviceData и GetDeviceState? Или это ересь Smile и возможен опрос только с одним форматом?
Одно другому не мешает.
Submitted by BLK Dragon on

спасибо. но наверное никто так в жизни не делает, да? на ум приходит система типа (абстрактный пример): двигаем человечком в платформере - опрашиваем GetDeviceState(); перешли в экран ввода имени профиля - опрашиваем GetDeviceData(); и т.д.

Submitted by MaxImuS on
Quote:
MaxImuS писал(а):
спасибо. но наверное никто так в жизни не делает, да? на ум приходит система типа (абстрактный пример): двигаем человечком в платформере - опрашиваем GetDeviceState(); перешли в экран ввода имени профиля - опрашиваем GetDeviceData(); и т.д.
Почему же, как раз прыжок человечка в платформере логично делать по WM_KEYDOWN, а движение по GetAsyncKeyState.
Submitted by BLK Dragon on
Quote:
BLK Dragon писал(а):
Почему же, как раз прыжок человечка в платформере логично делать по WM_KEYDOWN, а движение по GetAsyncKeyState.
Да, согласен. На кнопку для прыжка можно повесить в системе input'а "слушателя". Получается, я в начале цикла считал буфер данных контрола (это я всЕ про DI Lol для нужд всей системы, а перед непосредственным передвижением можно снять состояние GetAsyncKeyState и узнать интересующие меня клавиши, так?
Submitted by MaxImuS on

В случае когда ты сам вычитываешь буферизованный ввод через DI или местный аналог, то сам генеришь евенты (key-up/key-down) и сам обновляешь некое текущее состояние кнопок (которое хранится в движке и потом из кода игры запрашивается по is-key-pressed) -- это на уровне "движка"; на уровне приложения реагируешь на события ввода (генереруемые движком) и спрашиваешь текущие состояния кнопок.

Submitted by BLK Dragon on
Блин Smile даже не знаю как вопрос поставить...
Вообщем обработчик клавы написан и делает все что нужно (но пока не все!). Вот как раз вопрос про это "не все". Есть в окнах замечательное событие WM_CHAR. Так вот и у меня стала задача как из полученных скан-кодов выдирать чары... смотрел библиотечку ios (пока скопил от туда реализацию транслейта). Не хотелось бы заниматься плагиатом и попросту воровать чужой код. Я понимаю, что функции апи у всех одинаковые и порой алгоритмы совпадают, но все же...

GetKeyboardLayout(); GetKeyboardState(); MapVirtualKeyEx(); sc, vk - с этим мне все понятно (достаточно msdn, что бы понять что это все делает)
Трабла у меня начинается с ToUnicodeEx(). Все бы ничего, но тут меня в тупик ставит DeadKey - на словах я вроде бы разобрался что это есть такое (все зависит от текущей локали). В реализации я немного не понимаю как все таки это обрабатывать Sad Может кто-нибудь попробует мне немного объяснить про это, как на практике это работает? Так как
switch(buff[0]){case 0x5E: // Circumflex accent: в deadKey = 0x302; break;case 0x60: // Grave accent: а deadKey = 0x300; break;case 0xA8: // Diaeresis: ь deadKey = 0x308; break;case 0xB4: // Acute accent: й deadKey = 0x301; break;case 0xB8: // Cedilla: з deadKey = 0x327; break;default: deadKey = buff[0]; break;}

для меня еще загадка.

Submitted by MaxImuS on

К слову говоря, текстовый ввод (ну то что юзер набирает буковками, имя там или ещё что-то такое) лучше делать через WM_CHAR, и либо программу собрать в уникоде либо окно создавать CreateWindowW/CreateWindowExW. Тогда будут приходить настоящие уникодные символы (UTF16 строго говоря) и цирк с локалями и сканкодами не нужен.

Submitted by BLK Dragon on
Quote:
BLK Dragon писал(а):
и цирк с локалями и сканкодами не нужен.
А все же? =)

p.s. кстати, ситуация немного прояснилась с набором в командной строке charmap

Submitted by MaxImuS on

Я не занимался сканкодами и локалями в винде, тока в досе. Считаю, что "локали" нужно забыть как страшный сон, UTF8 для хранения строчек в файлах и UTF16 для ввода/отображения текста.

Submitted by BLK Dragon on
Я бы застрелился, если строковые ресурсы хранил бы не в utf8 *suicide*
Все что я пытаюсь сделать, так это заменить ::TranslateMessage()

Заменяю я это все дела тем же winapi. Интересно сделать своими руками велик Smile Помнишь журнал "Сделай сам!"? Smile

Submitted by MaxImuS on

"Сделай Сам!", конечно, замечательный был журнал, но я не уверен, что на DirectInput можно реализовать функционал TranslateMessage, т.е. возможность вводить текст на нескольких языках.

Submitted by BLK Dragon on
Нет конечно же Smile DI это вообще никак не сделает. От него я только беру скан-коды и уже винапишными методами транслирую в чары. Причем используется текущая локаль в системе (те самые несколько языков) - ::GetKeyboardLayout(). Трансляция происходит только в момент формирования эвента KeyDown и сам чар уже рассылается всем "подписчикам". TranslateMessage() изымается из цикла WM_CHAR отпадает. Моя трабла состояла в непонимании термина DeadKey, но уже вроде все уяснилось =).

p.s. Подсмотрено это было все дело в ois

Submitted by MaxImuS on

GameDev.by