13 апреля 2010 в 16:46
Direct3D Урок 06: Использование DirectInput
До этого момента в наших программах для ввода мы пользовалить возможностями WinAPI. Да, с его помощью очень просто реализовать поддержку клавиатуры (и даже мышки). Но он не предназначен для игр. Сегодня мы поговорим о том, как использовать в наших программах возможности DirectInput. Это более продвинутый интерфейс для ввода, разработанный Microsoft специально для использования в играх! Вот... итак начнем...
За основу для данного урока я взял Урок #3.
Так как код этого урока будет не очень маленьким:), то для него рекомендуется завести отдельный исходной файл (*.CPP) , а также потребуется использовать файл заголовка (*.H). Я назвал их Input.cpp и Input.h соответственно. Добавляйте такие файлы в свой проект и приступаем к делу.
Сначала разберемся с файлом заголовка (хедером) Input.h:
Первым делом добавте в него следующую строку:
// Заголовочный файл для DirectInput #include "dinput.h"
Он нам понадобится для доступа ко всем функциям DirectInput'а
А теперь создадим удобный для нас класс для работы с ним:
//----------------------------------------------------------------------------- // Name: class CInput // Desc: Класс для использования DirectInput-устройств //----------------------------------------------------------------------------- class CInput { public: bool Init(HWND hwnd); // Инициализация DirectInput void Shutdown(void); // Удаление DirectInput void Update(void); // Обновление состояний устройств ввода bool isKey(BYTE in_kb); // Проверка кнопки на клавиатуре на нажатость bool isKeyNew(BYTE in_kb); // Проверка кнопки на клавиатуре на новое нажатие bool isMBut(BYTE in_mb); // Проверка кнопки мыши на нажатость bool isMButNew(BYTE in_mb); // Проверка кнопки мыши на новое нажатие float GetMouseSpeedX(void); // Получаем скорость мыши по оси X float GetMouseSpeedY(void); // Получаем скорость мыши по оси Y float GetMouseSpeedZ(void); // Получаем скорость мыши по оси Z (колесико) private: HWND hwnd; LPDIRECTINPUT8 lpDI; // DDX8Input Объект LPDIRECTINPUTDEVICE8 lpDIKeyboard, // Интерфейс клавиатуры lpDIMouse; // Интерфейс мыши BYTE DIks[256]; // Кнопки кла-вы bool kNew[256]; // Новое нажатие DIMOUSESTATE2 DIms; // Состояние мышки bool mbNew[8]; // Новое нажатие };
Вот и все! С Input.h закончили. Переходим к главной части нашей программы - Input.cpp
В начале файла добавляем:
#include "Input.h"
Таким образом, мы включаем текст нашего хедера в текущий файл.
Далее мы определяем все методы для нашего класса CInput. Здесь их разбирать не имеет смысла, т.к. все они просты и понятны - просто скачайте исходник!
Сейчас же я рассмотрю только главные...
Первый метод - функция инициализации CInput::Init(HWND hwnd).
При ее вызове мы просто передаем экземпляр нашего окна. Здесь создается DirectInput, а также интерфейсы клавиатуры и мыши. Далее и идет функция, Update. Она вызывается каждый кадр и обновляет состояние клавиатуры и мыши.
//----------------------------------------------------------------------------- // Name: bool CInput::Update(void) // Desc: Обновление состояния клавиатуры и мыши //----------------------------------------------------------------------------- void CInput::Update(void) { HRESULT hr; // Опрашиваем клавиатуру hr = lpDIKeyboard->GetDeviceState(sizeof(BYTE)*256, &DIks); // Данные с кла-вы if(FAILED(hr)) // Если мы потеряли устройство { do{ hr = lpDIKeyboard->Acquire(); // Пытаемся захватить } while(hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED); } // Опрашиваем мышь hr = lpDIMouse->GetDeviceState(sizeof(DIMOUSESTATE2), &DIms); // Данные с мыши if(FAILED(hr)) // Если мы потеряли устройство { do{ hr = lpDIMouse->Acquire(); // Пытаемся захватить } while(hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED); } }
Далее мы определяем функции, с помощью которых мы можем получить относительную (относительно предыдущего кадра) скорость мыши:
//----------------------------------------------------------------------------- // Name: float CInput::GetMouseSpeedX(void) // Desc: Возвращает относительную скорость мыши по оси X //----------------------------------------------------------------------------- float CInput::GetMouseSpeedX(void) { return (float)DIms.lX; } //----------------------------------------------------------------------------- // Name: float CInput::GetMouseSpeedY(void) // Desc: Возвращает относительную скорость мыши по оси Y //----------------------------------------------------------------------------- float CInput::GetMouseSpeedY(void) { return (float)DIms.lY; } //----------------------------------------------------------------------------- // Name: float CInput::GetMouseSpeedZ(void) // Desc: Возвращает относительную скорость мыши по оси Z (колесико) //----------------------------------------------------------------------------- float CInput::GetMouseSpeedZ(void) { return (float)DIms.lZ; }
А как же нам добраться до наших кнопочек? Вот как:
//----------------------------------------------------------------------------- // Name: bool CInput::isKey(BYTE in_kb) // Desc: Проверка на нажатие кнопок клавиатуры //----------------------------------------------------------------------------- bool CInput::isKey(BYTE in_kb) { if(DIks[in_kb] & 0x80) return true; else return false; } //----------------------------------------------------------------------------- // Name: bool CInput::isKeyNew(BYTE in_kb) // Desc: Проверка кнопок кла-вы на новое нажатие //----------------------------------------------------------------------------- bool CInput::isKeyNew(BYTE in_kb) { if(DIks[in_kb] & 0x80) { if(kNew[in_kb]){ kNew[in_kb] = false; return true; } } else kNew[in_kb] = true; return false; } //----------------------------------------------------------------------------- // Name: bool CInput::isMBut(BYTE in_mb) // Desc: Проверка на нажатие кнопок мышки //----------------------------------------------------------------------------- bool CInput::isMBut(BYTE in_mb) { if(DIms.rgbButtons[in_mb] & 0x80) return true; else return false; } //----------------------------------------------------------------------------- // Name: bool CInput::isMButNew(BYTE in_mb) // Desc: Проверка кнопок мыши на новое нажатие //----------------------------------------------------------------------------- bool CInput::isMButNew(BYTE in_mb) { if(DIms.rgbButtons[in_mb] & 0x80) { if(mbNew[in_mb]){ mbNew[in_mb] = false; return true; } } else mbNew[in_mb] = true; return false; }
И теперь нам осталось лишь освободить память из-под DirectInput:
//----------------------------------------------------------------------------- // Name: bool CInput::Shutdown(void) // Desc: Освобождаем память из-под интерфейса ввода //----------------------------------------------------------------------------- void CInput::Shutdown(void) { if(lpDIKeyboard) lpDIKeyboard->Unacquire(); if(lpDIMouse) lpDIMouse->Unacquire(); if(lpDIKeyboard) lpDIKeyboard->Release(); if(lpDIMouse) lpDIMouse->Release(); if(lpDI) lpDI->Release(); }
Дааа... теперь как нам все это использовать?
открываем наш родной Main.cpp.
В начале файла, к списку библиотек добавим
#pragma comment(lib, "dinput8.lib" ) // Ссылка на dinput8.lib #pragma comment(lib, "dxguid.lib" ) // ССылка на dxguid.lib
И после всех заголовков добавим:
#include "Input.h" // Заголовок для использования класса CInput
теперь, когда мы стали такими крутыми ;) нам больше не нужен старый массив:
bool keys[256]; // Массив для работы с клавиатурой
Просто удалите эту строку. И вместо нее напишите:
CInput Input; // наш класс для работы с кла-вой и мышой через DirectInput
Теперь переходим в функцию AllInit()
// Инициируем интерфейс ввода if(!Input.Init(hWnd)) return false; // Если возникла ошибка - выйдем
А в AllShutdown() освободим его:
Input.Shutdown(); // Освобождаем интерфейс ввода
Теперь MsgProc удаляем следующие строки - они нам больше ни к чему:
case WM_KEYDOWN: // Если нажата клавиша { keys[wParam] = TRUE; return 0; } case WM_KEYUP: // Если клавиша отпущена { keys[wParam] = FALSE; return 0; }
И сейчас в WinMain вместо
if(keys[VK_ESCAPE]) isProcess=false; if(keys[VK_F1]) { fullscreen=!fullscreen; //переключаемся в Оконный/полноэкранный режим ResetWindow(Width, Height, fullscreen); }
Запишим
Input.Update(); // Обновляем состояние клавиатуры и мышки // Если нажали ESCAPE выходим из цикла if(Input.isKey(DIK_ESCAPE)) isProcess=false; if(Input.isKey(DIK_F1)) // А если F1 { fullscreen=!fullscreen; //переключаемся в Оконный/полноэкранный режим ResetWindow(Width, Height, fullscreen); }
У нас появилась полная поддержка DirectInput!
25 декабря 2017 в 01:14
Всё?
5 октября 2018 в 15:12
Доброго времени суток. Не совсем понятно как получить информацию о повторе нажатии клавиши. Я пробовал на простом примере перемещения некоего объекта по экрану и если ты нажал и держишь клавишу, то объект продолжает постоянно двигаться, а хотелось бы чтобы он двигался только после того как клавиша отпущена и затем нажата снова.
авторизуйтесь
или войдите через