Самой сложной частью DirectX является, несомненно, Direct3d. DirectInput, конечно, тоже имеет свои тонкости, но, как правило, при написании программы от него требуется только работа с клавиатурой. Помимо этого, с помощью DirectInput Вы можете работать с мышью, джойстиком и другими устройствам. В отличии от известных вам событий элементов управления KeyPress, KeyDown и т. д., DirectInput работает непосредственно с драйверами устройств ввода. За счёт этого достигается, например, возможность контроля над нажатием нескольких клавиш одновременно, что неосуществимо обычными средствами. Так что, если Вы решили писать игру на Visual Basic, без DirectInput не обойтись.
В этой части учебника показано, как работать с клавиатурой посреством DirectInput. Для этого необходимо создать объект DirectInput, устройство DirectInput, настроить это устройство соответствующим образом, получить текущее состояние клавиатуры и, в конце, уничтожить созданные объекты.
Итак, начнём. Подключите к проекту библиотеку DirectX 8 for Visual Basic Type Library. Создайте ListBox с именем List1 и Timer с именем Timer1, свойство Interval которого установите в 100, а Enabled - False. В коде модуля формы сделайте следующие объявления:
Dim dx As New DirectX8 'объект DirectX
Dim di As DirectInput8 'объект DirectInput
Dim diDev As DirectInputDevice8 'устройство DirectInput
Dim diState As DIKEYBOARDSTATE 'структура, содержащая состояние клавиатуры
В поцедуру Form_Load добавьте следующий код:
Private Sub Form_Load()Me.Show If Not InitDI() Then MsgBox "Невозможно инициализировать DirectInput."End
End If Timer1.Enabled = TrueEnd Sub
Теперь,
как Вы уже догадались, напишем функцию InitDI.
Public Function InitDI() As BooleanOn Local Error Resume Next Set di = dx.DirectInputCreate()If di Is Nothing Then Exit Function Set diDev = di.CreateDevice("GUID_SysKeyboard")If diDev Is Nothing Then Exit Function diDev.SetCommonDataFormat DIFORMAT_KEYBOARDdiDev.SetCooperativeLevel Me.hWnd, DISCL_NONEXCLUSIVE Or DISCL_BACKGROUNDdiDev.Acquire InitDI = TrueEnd Function
Сначала эта функция создаёт объект DirectInput с помощью метода DirectInputCreate объекта DirectX. Затем с помощью метода CreateDevice объекта DirectInput создаётся устройство diDev. Единственным параметром метода CreateDevice является строка GUID. Значение этого метода "GUID_SysKeyboard" соответствует системной клавиатуре, "GUID_SysMouse" - системной мыши. В нашем примере устройство diDev будет работать с системной клавиатурой.
Затем с помощью метода SetCommonDataFormat для устройства diDev задаётся формат данных. Так как мы работаем с клавиатурой, нами используется константа DIFORMAT_KEYBOARD.
Метод SetCooperativeLevel ассоциирует окно с устройством diDev, а также устанавливает параметры этого устройства с помощью набора флагов CONST_DISCLFLAGS. Здесь приведены краткие описания некоторых флагов: DISCL_BACKGROUND - если используется этот флаг, Вы можете работать с устройством в любое время, даже когда окно, ассоциированное с ним неактивно; DISCL_FOREGROUND - в противоположность предыдущему флагу, Вы можете работать с устройством только тогда, когода ассоциированное с ним окно активно; DISCL_EXCLUSIVE - приложение получает эксклюзивный доступ к устройству ввода (заметьте, что одновременно только одно приложение может иметь эксклюзивный доступ к устройству ввода); DISCL_NONEXCLUSIVE - при использовании этого флага приложение не конфликтует с другими приложениями, использующими это же устройство ввода.
Для того, чтобы получить доступ к устройству ввода, используется метод Acquire объекта diDev.
Напишем сразу и процедуру CleanUp, уничтожающую созданные объекты и с помощью метода Unacquire объекта diDev разрывающую связь этого объекта с устройством ввода.
Public Sub CleanUp()diDev.UnacquireSet diDev = NothingSet di = NothingEnd Sub
Код, вызывающий процедуру CleanUp вставьте в обработчик события Unload формы.
Теперь пришло время получить текущее состояние клавиатуры и вывести информацию о нём в список List1. Делаться это будет в процедуре Timer1_Timer. Вот её код:
Private Sub Timer1_Timer()Dim iKeyCounter As Integer diDev.GetDeviceStateKeyboard diState List1.Clear For iKeyCounter = 0 To 255 If diState.Key(iKeyCounter) <> 0 Then List1.AddItem KeyNames(iKeyCounter) End IfNextEnd Sub
Для получения текущего состояния клавиатуры используется метод GetDeviceStateKeyboard объекта diDev. Единственный его параметр имеет тип DIKEYBOARDSTATE, просто содержащий массив из 256 байтов. Каждый элемент буффера diState соответствует одной клавише. Если в момент получения состояния клавиатуры она была нажата, то значение этого элемента устанавливается равным 1.
Затем, после очистки списка List1, происходит проверка значений всех элементов буффера diState. Если значение данного элемента отлично от нуля, то есть нажата соответствующая ему клавиша, в список List1 функцией KeyNames выводится имя соответствующей этой клавише константы из набора CONST_DIKEYFLAGS. Каждая из костант в этом наборе соответствует определённой клавише на клавиатуре. Клавише со стрелкой, направленной влево, например, соответствует константа DIK_LEFT. Нажатие этой клавиши Вы можете проверить использовав следующий код:
If state.Key(DIK_LEFT) <> 0 Then' нажата клавиша со стрелкой, направленной влево
End If
Осталось
только привести код функции KeyNames. Вот
он:
Function KeyNames(iNum As Integer) As StringDim aKeys(255) As String aKeys(&H1) = "DIK_ESCAPE" aKeys(&H2) = "DIK_1" aKeys(&H3) = "DIK_2" aKeys(&H4) = "DIK_3" aKeys(&H5) = "DIK_4" aKeys(&H6) = "DIK_5" aKeys(&H7) = "DIK_6" aKeys(&H8) = "DIK_7" aKeys(&H9) = "DIK_8" aKeys(&HA) = "DIK_9" aKeys(&HB) = "DIK_0"aKeys(&HC) = "DIK_MINUS" ' минус на главной клавиатуре
aKeys(&HD) = "DIK_EQUALS"
aKeys(&HE) = "DIK_BACK" ' backspace aKeys(&HF) = "DIK_TAB" aKeys(&H10) = "DIK_Q" aKeys(&H11) = "DIK_W" aKeys(&H12) = "DIK_E" aKeys(&H13) = "DIK_R" aKeys(&H14) = "DIK_T" aKeys(&H15) = "DIK_Y" aKeys(&H16) = "DIK_U" aKeys(&H17) = "DIK_I" aKeys(&H18) = "DIK_O" aKeys(&H19) = "DIK_P" aKeys(&H1A) = "DIK_LBRACKET" aKeys(&H1B) = "DIK_RBRACKET"aKeys(&H1C) = "DIK_RETURN" ' Enter на главной клавиатуре
aKeys(&H1D) = "DIK_LCONTROL"
aKeys(&H1E) = "DIK_A" aKeys(&H1F) = "DIK_S" aKeys(&H20) = "DIK_D" aKeys(&H21) = "DIK_F" aKeys(&H22) = "DIK_G" aKeys(&H23) = "DIK_H" aKeys(&H24) = "DIK_J" aKeys(&H25) = "DIK_K" aKeys(&H26) = "DIK_L" aKeys(&H27) = "DIK_SEMICOLON" aKeys(&H28) = "DIK_APOSTROPHE" aKeys(&H29) = "DIK_GRAVE" aKeys(&H2A) = "DIK_LSHIFT" aKeys(&H2B) = "DIK_BACKSLASH" aKeys(&H2C) = "DIK_Z" aKeys(&H2D) = "DIK_X" aKeys(&H2E) = "DIK_C" aKeys(&H2F) = "DIK_V" aKeys(&H30) = "DIK_B" aKeys(&H31) = "DIK_N" aKeys(&H32) = "DIK_M" aKeys(&H33) = "DIK_COMMA"aKeys(&H34) = "DIK_PERIOD" ' . на главной клавиатуре
aKeys(&H35) = "DIK_SLASH" ' / на главной клавиатуре
aKeys(&H36) = "DIK_RSHIFT"
aKeys(&H37) = "DIK_MULTIPLY" ' * на вспомогательной клавиатуре
aKeys(&H38) = "DIK_LMENU" ' левый Alt
aKeys(&H39) = "DIK_SPACE" aKeys(&H3A) = "DIK_CAPITAL" aKeys(&H3B) = "DIK_F1" aKeys(&H3C) = "DIK_F2" aKeys(&H3D) = "DIK_F3" aKeys(&H3E) = "DIK_F4" aKeys(&H3F) = "DIK_F5" aKeys(&H40) = "DIK_F6" aKeys(&H41) = "DIK_F7" aKeys(&H42) = "DIK_F8" aKeys(&H43) = "DIK_F9" aKeys(&H44) = "DIK_F10" aKeys(&H45) = "DIK_NUMLOCK" aKeys(&H46) = "DIK_SCROLL" ' Scroll Lock aKeys(&H47) = "DIK_NUMPAD7" aKeys(&H48) = "DIK_NUMPAD8" aKeys(&H49) = "DIK_NUMPAD9"aKeys(&H4A) = "DIK_SUBTRACT" ' минус на вспомогательной клавиатуре
aKeys(&H4B) = "DIK_NUMPAD4"
aKeys(&H4C) = "DIK_NUMPAD5" aKeys(&H4D) = "DIK_NUMPAD6"aKeys(&H4E) = "DIK_ADD" ' + на вспомогательной клавиатуре
aKeys(&H4F) = "DIK_NUMPAD1"
aKeys(&H50) = "DIK_NUMPAD2" aKeys(&H51) = "DIK_NUMPAD3" aKeys(&H52) = "DIK_NUMPAD0"aKeys(&H53) = "DIK_DECIMAL" ' . на вспомогательной клавиатуре
aKeys(&H56) = "DIK_OEM_102 < > | on UK/Germany keyboards"
aKeys(&H57) = "DIK_F11" aKeys(&H58) = "DIK_F12" aKeys(&H64) = "DIK_F13 on (NEC PC98) " aKeys(&H65) = "DIK_F14 on (NEC PC98) " aKeys(&H66) = "DIK_F15 on (NEC PC98) " aKeys(&H70) = "DIK_KANA on (Japanese keyboard)" aKeys(&H73) = "DIK_ABNT_C1 / ? on Portugese (Brazilian) keyboards " aKeys(&H79) = "DIK_CONVERT on (Japanese keyboard)" aKeys(&H7B) = "DIK_NOCONVERT on (Japanese keyboard)" aKeys(&H7D) = "DIK_YEN on (Japanese keyboard)" aKeys(&H7E) = "DIK_ABNT_C2 on Numpad . on Portugese (Brazilian) keyboards " aKeys(&H8D) = "DIK_NUMPADEQUALS = on numeric keypad (NEC PC98) " aKeys(&H90) = "DIK_PREVTRACK on Previous Track (DIK_CIRCUMFLEX on Japanese keyboard) " aKeys(&H91) = "DIK_AT (NEC PC98) " aKeys(&H92) = "DIK_COLON (NEC PC98) " aKeys(&H93) = "DIK_UNDERLINE (NEC PC98) " aKeys(&H94) = "DIK_KANJI on (Japanese keyboard)" aKeys(&H95) = "DIK_STOP (NEC PC98) " aKeys(&H96) = "DIK_AX (Japan AX) " aKeys(&H97) = "DIK_UNLABELED (J3100) " aKeys(&H99) = "DIK_NEXTTRACK" ' next trackaKeys(&H9C) = "DIK_NUMPADENTER" ' Enter на вспомогательной клавиатуре
aKeys(&H9D) = "DIK_RCONTROL"
aKeys(&HA0) = "DIK_MUTE" ' Mute aKeys(&HA1) = "DIK_CALCULATOR" ' calculator aKeys(&HA2) = "DIK_PLAYPAUSE" ' Play / Pause aKeys(&HA4) = "DIK_MEDIASTOP" ' Media Stop aKeys(&HAE) = "DIK_VOLUMEDOWN" ' Volume - aKeys(&HB0) = "DIK_VOLUMEUP" ' Volume + aKeys(&HB2) = "DIK_WEBHOME" ' Web homeaKeys(&HB3) = "DIK_NUMPADCOMMA" ' , на вспомогательной клавиатуре (NEC PC98)
aKeys(&HB5) = "DIK_DIVIDE" ' / на вспомогательной клавиатуре
aKeys(&HB7) = "DIK_SYSRQ"
aKeys(&HB8) = "DIK_RMENU" ' правый Alt
aKeys(&HC5) = "DIK_PAUSE" ' Pause aKeys(&HC7) = "DIK_HOME" ' HomeaKeys(&HC8) = "DIK_UP" ' стрелка вверх
aKeys(&HC9) = "DIK_PRIOR" ' PgUpaKeys(&HCB) = "DIK_LEFT" ' стрелка влево
aKeys(&HCD) = "DIK_RIGHT" ' стрелка вправо
aKeys(&HCF) = "DIK_END" ' EndaKeys(&HD0) = "DIK_DOWN" ' стрелка вниз
aKeys(&HD1) = "DIK_NEXT" ' PgDn aKeys(&HD2) = "DIK_INSERT" ' Insert aKeys(&HD3) = "DIK_DELETE" ' DeleteaKeys(&HDB) = "DIK_LWIN" ' левая Windows клавиша
aKeys(&HDC) = "DIK_RWIN" ' правая Windows клавиша
aKeys(&HDD) = "DIK_APPS" ' клавиша вызова контекстно-зависимого меню
aKeys(&HDE) = "DIK_POWER" ' клавиша Power
aKeys(&HDF) = "DIK_SLEEP" ' клавиша Sleep
aKeys(&HE3) = "DIK_WAKE" ' клавиша Wake
aKeys(&HE5) = "DIK_WEBSEARCH" ' Web Search aKeys(&HE6) = "DIK_WEBFAVORITES" ' Web Favorites aKeys(&HE7) = "DIK_WEBREFRESH" ' Web Refresh aKeys(&HE8) = "DIK_WEBSTOP" ' Web Stop aKeys(&HE9) = "DIK_WEBFORWARD" ' Web Forward aKeys(&HEA) = "DIK_WEBBACK" ' Web Back aKeys(&HEB) = "DIK_MYCOMPUTER" ' My Computer aKeys(&HEC) = "DIK_MAIL" ' Mail aKeys(&HED) = "DIK_MEDIASELECT" ' Media Select KeyNames = aKeys(iNum) End Function
Далеко не все клавиши из тех, которым соответствуют константы из набора CONST_DIKEYFLAGS, существуют на Вашей клавиатуре (попробуйте, например нажать клавишу F15...).
Программа же, которую мы создавали, готова. Запустив её на выполнение и нажимая клавиши на клавиатуре, Вы можете видеть имена констант из набора CONST_DIKEYFLAGS, соответствующих нажатым в данный момент клавишам.
Вы можете скачать архив RAR с готовым проектом (4 Кб).
В следующей части учебника мы будем работать с мышью.