Самой сложной частью 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 = True
End Sub
Теперь,
как Вы уже догадались, напишем функцию InitDI.
Public Function InitDI() As Boolean
On 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_KEYBOARD
diDev.SetCooperativeLevel Me.hWnd, DISCL_NONEXCLUSIVE Or DISCL_BACKGROUND
diDev.Acquire
InitDI = True
End 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.Unacquire
Set diDev = Nothing
Set di = Nothing
End 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 If
Next
End 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 String
Dim 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 track
aKeys(&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 home
aKeys(&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" ' Home
aKeys(&HC8) = "DIK_UP" ' стрелка вверх
aKeys(&HC9) = "DIK_PRIOR" ' PgUp
aKeys(&HCB) = "DIK_LEFT" ' стрелка влево
aKeys(&HCD) = "DIK_RIGHT" ' стрелка вправо
aKeys(&HCF) = "DIK_END" ' End
aKeys(&HD0) = "DIK_DOWN" ' стрелка вниз
aKeys(&HD1) = "DIK_NEXT" ' PgDn
aKeys(&HD2) = "DIK_INSERT" ' Insert
aKeys(&HD3) = "DIK_DELETE" ' Delete
aKeys(&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 Кб).
В следующей части учебника мы будем работать с мышью.