DirectX & Visual Basic

Учебник DirectInput: часть 1

Работа с клавиатурой

Самой сложной частью 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 Кб).

В следующей части учебника мы будем работать с мышью.

Следующая часть>>
Hosted by uCoz