Directx input что это
Предметная область
Задача – получить данные от игрового руля. В первую очередь необходимо изучить предметную область. Где используются игровые рули? Очевидно, в играх. Множество игр разрабатывается с помощью технологии DirectX. Почитав википедию, можно узнать, что DirectX подразделяется на множество интерфейсов. Интерес для нас представляет интерфейс DirectInput.
Используемые игровые контроллеры
Для реализации проекта в мое распоряжение был предоставлен игровой руль Defender Forsage GTR.
Также я не упустил возможности поэкспериментировать со своим игровым джойстиком Logitech Rumblepad 2.
Managed DirectX
Необходимые инструменты
Начало работы
Добавим к проекту новый файл app.config со следующим содержимым:
Теперь все готово, можно начинать работать с игровыми контроллерами.
Получение состояния игрового руля
Очевидно, что первым делом необходимо узнать обо всех подключенных игровых контроллерах:
Далее необходимо инициализировать игровое устройство. Для наглядности подразумеваю, что оно у меня одно:
В характеристиках руля сказано, что угол поворота рулевого колеса составляет 180 градусов, поэтому в InputRange я указал значение угла отклонения влево и вправо в 90 градусов.
К сожалению, мы не сможем подписаться на какие-либо события от руля или джойстика вроде KeyDown\KeyUp, и состояние игрового контроллера придется опрашивать вручную:
Для наглядности можно вывести на экран структуру JoystickState и увидеть, какие поля меняются в зависимости от состояния игрового руля. Все это справедливо также и для джойстика.
Выводы
Оказывается, запрограммировать игровой контроллер под свои нужды не так уж и сложно, большинство всевозможных джойстиков\рулей и т.п. подчиняются интерфейсу DirectInput, теперь в свои проекты\игры вы с легкостью сможете добавить их поддержку. Что касается игр, то остается только реализовать функционал, дающий пользователю возможность самому «навешивать» на кнопки действия, предусмотренные логикой игры.
Любая программа без пользовательского ввода превращается в статическую картинку, а то и в слайд шоу или кино. Но ведь мы смотрим не телевизор - даешь интерактивность! Именно эту проблему мы и будем сегодня обсуждать. Для нашего обсуждения я не стал сочинять чего-нибудь необычного - я воспользовался примерами из DirectX 7 SDK. Они достаточно хорошо иллюстрируют то, с чем мы сегодня столкнемся. Для начала обговорим условия компиляции и линковки приложений - кроме используемой нами DINPUT.LIB, при линковке тебе нужно будет включить в проект DXGUID.LIB для приложений, у которых не определена INITGUID (Использование INITGUID - старый стиль включения GUID номеров в приложение, использующее COM модель).
Ну, а для начала немного теории. Для чего нужны функции DirectInput, ты уже знаешь. Чем же DirectInput API лучше, чем стандартные возможности, предоставляемые приложению ядром? Ну, конечно своей скоростью и своими возможностями:
Рассмотрим схему инициализации для DirectInput. Поскольку DirectInput как и практически все компоненты DirectX построен на основе модели COM от Microsoft, общая структура работы с API ничем не будет отличаться от работы с другими компонентами DirectX API. Первое, что должно сделать приложение, использующее DirectInput API, это получить доступ к объекту DirectInput через соответствующий интерфейс. Сделать это можно вызовом DirectInputCreate() или DirectinputCreateEx(). Во всех примерах MS кроме одного используется первый вариант. Вариант два появился в версии DirectX 7.0. Рассмотрим параметры этих функций. Для этого ты можешь воспользоваться документацией.
hInst - идентификатор экземпляра самого приложения получаемый в WinMain().
dwVer - версия объекта DirectInput. Обычно подставляется макроопределение DIRECTINPUT_VERSION заранее определенное в DINPUT.H для установленной версии DirectX SDK.
lplpDI - указатель на указатель интерфейса, который примет в себя информацию.
pU - указатель наследования или агрегирования COM. Нас он не интересует - достаточно передать NULL.
hInst - то же, что и для варианта DirectInputCreate()
dwVer - то же, что и для варианта DirectInputCreate()
ri - идентификатор требуемого интерфейса. Может принимать значения IID_IDirectInput,IID_IDirectInput2,IID_IDirectInput7.
ppO - указатель на указатель интерфейса, который примет в себя информацию. Аналогичен с последним параметром предыдущей функции.
pU - указатель наследования или агрегирования COM. Аналогичен с последним параметром предыдущей функции.
Как ты видишь — все достаточно просто. После получения указателя на интерфейс, нужно "создать" устройство от которого ты хочешь получать данные. Под устройством подразумевается все, что поддерживает DirectInput, например клавиатура, мышь, джойстики и т.п. Для создания устройств также существуют две функции - CreateDevice() и ее -Ex вариант (появился в 7 версии DirectX):
CreateDevice(REFGUID rg,LPDIRECTINPUTDEVICE *lplpDI,LPUNKNOWN pU);
rg - уникальный идентификатор устройства. Если ты еще не привык, что вся работа идет с некими Global Unique IDentifer'ами, советую поскорее привыкнуть ;). Для стандартных устройств заранее определены значения: GUID_SysKeyboard для клавиатуры; GUID_SysMouse для мыши. Остальные идентификаторы устройств (например джойстики) можно получить вызовом EnumDevices().
lplpDI - указатель на указатель интерфейса, с помощью которого мы будем впоследствии работать с устройством.
pU - все то же агрегирование.
CreateDeviceEx(REFGUID rg,REFIID ri,LPVIOD *ppO,LPUNKNOWN pU);
rg - то же, что и в первом случае.
ri - идентификатор требуемого интерфейса. Может принимать значения IID_IDirectInput,IID_IDirectInput2,IID_IDirectInput7.
ppO - указатель на указатель интерфейса, который примет в себя информацию. Аналогичен параметру lplpDI предыдущей функции.
pU - указатель наследования или агрегирования COM. Аналогичен с последним параметром предыдущей функции.
После того, как мы получили указатель на интерфейс устройства, воспользуемся им для установки формата данных для этого устройства. Функция SetDataFormat() получает всего один параметр - указатель на структуру описывающую формат данных для устройства. Для стандартных устройств заранее определены глобальные переменные: c_dfDIKeyboard, c_dfDIMouse, c_dfDIMouse2, c_dfDIJoystick, c_dfDIJoystick2. Итак - формат данных установлен - DirectInput знает тип устройства. Что же теперь? А теперь мы должны установить уровень доступа. Довольно важно определиться заранее (как и с форматом принимаемых данных) - какой доступ необходим.
* Эксклюзивный (exclusive)/Совместный (non-exclusive) - первое чем хорош эксклюзивный режим, это то, что он "подавляет" большинство системных комбинаций (кроме Alt+TAB и Alt+Ctrl+Del, кстати говоря - есть и отдельный флажок при установке уровня кооперации запрещающий системные комбинации Windows), позволяя обработать нажатие, скажем, Ctrl+Esc. Следует помнить, что ни одно приложение не сможет получить эксклюзивного доступа к устройству, если такой доступ уже был получен другим приложением, однако сможет получить совместный.
Активный (foreground)/Фоновый (background) - при фоновом доступе приложение сможет читать данные с устройства даже когда окно приложения не активно. В случае же активного доступа приложение сможет читать данные, только если его окно обладает "фокусом" (активно).
* Уровень доступа устройства устанавливается вызовом SetCooperativeLevel(). У функции два параметра: первый из них это идентификатор окна приложения, второй - комбинации флагов. И последнее - как и в случае с DirectDraw, когда приложение могло "потерять" память поверхностей - приложение DirectInput перед чтением данных с устройства должно "захватить"(Acquire) его. При чтении данных обязательно проверь результат - приложение может "уступить" (Unacquire) устройство, например, при потере фокуса приложением (Кстати, это происходит автоматически, если приложение имеет "активный" доступ к устройству). Для захвата и освобождения устройств существуют функции Acquire() и Unacquire() соответственно.
Что еще полезно знать:
* По умолчанию клавиатура использует непосредственные (не буферизированные) данные - для того, чтобы прочитать состояние клавиатуры нужно воспользоваться функцией GetDeviceState(). Параметрами для этой функции в случае непосредственных данных будет являться размер массива (равный 256) и указатель на массив из 256 байт для данных о всех клавишах. Для удобства работы для каждого индекса массива определено макроопределение с именем клавиши. Например, строка:
char cDummy = cBuff[DIK_ESCAPE];
занесет в сDummy байт данных по клавише Esc. Для определения нажата ли клавиша, достаточно проверить последний бит этого байта:
Для того, что бы установить буферизированный ввод с клавиатуры, после установки уровня кооперации нужно установить размер буфера:
По умолчанию мышь возвращает относительные координаты, а джойстик абсолютные.
По завершении приложения ты должен "убрать за собой" - "уступить" все устройства, и удалить объекты DirectInput вызовом Release().
Это был лишь небольшой обзор, и в нем много чего было опущено (например, те же устройства с обратной связью (Force Feedback)). Не смотря на это, он должен был дать тебе достаточно информации для дальнейшего глубокого изучения.
Вот думаю менять свой геймпад OKLICK GP-310M на что-нибудь по-новее,чтоб поддерживал вибрацию во ВСЕХ играх. желательно,чтоб работал без драйвера (чтоб конфликтов не было).
Ну и вообще,чтоб по-мимо вибрации работал и он сам во всех играх (новых и старых),включая Mortal Kombat Kollection,в котором мой "оклик" просто наотрез отказывается работать и просто делает вид,что его там нет).
А зайдя в DMC геймпад как-то странно начал себя вести - если включаешь аналог - постоянная "прокрутка" вниз в меню (ну т.е. как-будто я зажал кнопку вниз),а если выключаешь аналог - вниз и вверх вообще не работают,а работают только вправо и влево.
И ещё - лучше даже,чтоб геймпад эмулировал не назначенные кнопки,а не использовал существующие (да,да,отличная статья про клавиатуру,где говорилось,что. порядка 50 кнопок что-ли ещё свободные в винде (или железе,блин,забыл) которые могли-бы использовать геймпады,мышки,клавы и т.д.
И вот после всякой подобной хрени я подумал о его замене. у меня мой - Direct Input,но вот сказать - лучше он или хуже XInput - я не могу,потому-что одна из статей есть на вике,но на английском,а второй - тупо нету.
Потому-что я подумал,что все эти мелкие косяки,если и устранимы,то только некоторые из них и\или частично,но вот,что брать - тот-же D Input только смотреть,чтоб поддерживал Win 8 (x64) (кстати да,у меня Windows 8 x64,а драйвера для моего геймпада есть только для. блин,не помню уже какой винды - Win XP что-ли. ведь только там он у меня почти без нареканий работал.
Ну кроме проблемы с вибрацией,которая была не во всех играх,хотя и на сайте написано поддержка Win 7,но не сказано - x64 или нет,но я точно помню,что когда я покупал геймпад - ещё и не "пахло" Windows 7,да и драйверов на оф.сайте я что-то вообще не нашёл. так-что пользуюсь теми,что в комплекте шли,через "совместимость" их ставлю.
Ну дык вот,какой геймпад лучше всего купить в 2013ом году,чтоб не прогадать ?
И что лучше брать - DInput ,только с поддержкой Win 8 x64 или всё-таки - XInput ?
Ещё пару слов,как я себе его представляю - поддерживает все игры и везде работает вибрация,выглядит как геймпад от "соньки" (ну т.е. как мой или типо того). очень желательно,чтоб даже кнопки - auto,turbo и analog (ну и clear само собой) остались,т.к. реально полезные кнопки,чёрный цвет. ну и пожалуй всё,в остальном он был просто идеален и стоил своих. 500 что-ли рублей.
По-поводу цены нового. ну. ну готов потратить 500-2000 рублей. думаю будет достаточно.
Не понимаю почему люди не могу пользоваться поиском. Для того и придумали Google Search. Ну да ладно.
Что же касается геймпада, то советую брать Logitech F710. Это лучший геймпад. Если интересует проводная модель то присмотрись к Logitech F510 или Logitech F310. Все эти геймпады удобны, приятны на ощупь, поддерживают стандарты ввода XInput и DirectInput и ПОЛНОСТЬЮ стоят своих цен.
По поводу стандартов ввода, то тут дела следующие.
DirectInput - это стандарт ввода, при котором ты теоретически(если производитель предоставил тебе программу, хотя есть и универсальные программы) можешь изменить назначение любой кнопки.
XInput - это стандарт ввода, разработанный специально для геймпада от Xbox 360, а тут Microsoft позаботилась чтобы всё было отлично. Назначение кнопок фиксированное (только в самой игре можно их сменить). Если геймпад поддерживает этот стандарт ввода, то он точно (100% гарантированно) будет определяться игрой (игра тоже должна поддерживать этот стандарт, но игр, не поддерживающих этот стандарт не выпускают уже лет 7) как надо (все кнопки выполняю свои функции и работает вибрация).
Предметная область
Задача – получить данные от игрового руля. В первую очередь необходимо изучить предметную область. Где используются игровые рули? Очевидно, в играх. Множество игр разрабатывается с помощью технологии DirectX. Почитав википедию, можно узнать, что DirectX подразделяется на множество интерфейсов. Интерес для нас представляет интерфейс DirectInput.
Используемые игровые контроллеры
Для реализации проекта в мое распоряжение был предоставлен игровой руль Defender Forsage GTR.
Также я не упустил возможности поэкспериментировать со своим игровым джойстиком Logitech Rumblepad 2.
Managed DirectX
Необходимые инструменты
Начало работы
Добавим к проекту новый файл app.config со следующим содержимым:
Теперь все готово, можно начинать работать с игровыми контроллерами.
Получение состояния игрового руля
Очевидно, что первым делом необходимо узнать обо всех подключенных игровых контроллерах:
Далее необходимо инициализировать игровое устройство. Для наглядности подразумеваю, что оно у меня одно:
В характеристиках руля сказано, что угол поворота рулевого колеса составляет 180 градусов, поэтому в InputRange я указал значение угла отклонения влево и вправо в 90 градусов.
К сожалению, мы не сможем подписаться на какие-либо события от руля или джойстика вроде KeyDown\KeyUp, и состояние игрового контроллера придется опрашивать вручную:
Для наглядности можно вывести на экран структуру JoystickState и увидеть, какие поля меняются в зависимости от состояния игрового руля. Все это справедливо также и для джойстика.
Выводы
Оказывается, запрограммировать игровой контроллер под свои нужды не так уж и сложно, большинство всевозможных джойстиков\рулей и т.п. подчиняются интерфейсу DirectInput, теперь в свои проекты\игры вы с легкостью сможете добавить их поддержку. Что касается игр, то остается только реализовать функционал, дающий пользователю возможность самому «навешивать» на кнопки действия, предусмотренные логикой игры.
Читайте также: