todo : remplacer les scancodes par les virtual codes
Intro :
A l’inverse de l’utilisation du composant DirectInput de DirectX, nous pouvons directement utiliser les réponses de la boucle de message WndProc en tant qu’entrées clavier-souris.
Cet article fournira la classe InputManager utilisée dans d’autres articles.
Explications :
Voici le code pour le fichier InputManager.h
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
#ifndef INPUT_MANAGER_H #define INPUT_MANAGER_H #include <windows.h> #include <map> #include <vector> #include <sstream> #include <iostream> #define BIT(x) 1 << x #include "Singleton.h" // Objet d'entrée clavier qui sera envoyé au KeyListener enregistré // dans la classe InputManager class KeyEvent { public: KeyEvent(int kc, wchar_t txt) : keyCode(kc), text(txt) {} virtual ~KeyEvent() {} // L'ID de la touche const int keyCode; // La caractère correspondant de la touche const wchar_t text; }; // Classe KeyListener qui permet à n'importe quel objet héritant de // cette classe de recevoir les entrées clavier class KeyListener { public: virtual ~KeyListener() {} virtual void OnKeyPressed(const KeyEvent &arg) = 0; virtual void OnKeyReleased(const KeyEvent &arg) = 0; }; class InputManager : public Singleton<InputManager> { public: // Touches spéciales enum KeyModifier { SHIFT = BIT(0), CTRL = BIT(1), ALT = BIT(2) }; // Bouttons de la souris enum MouseButton { MouseButtonLeft, MouseButtonRight, MouseButtonMiddle, MouseButtoNone }; InputManager(); virtual ~InputManager(); // Méthodes d'enregistrements des entrées clavier de la boucle // de message Win32 WndProc void InjectKeyDown(unsigned int iVirtualKeyCode, unsigned int iScanCode); void InjectKeyUp(unsigned int iVirtualKeyCode, unsigned int iScanCode); void InjectKeyModifierDown(KeyModifier modifier); void InjectKeyModifierUp(KeyModifier modifier); // Méthodes d'enregistrements des entrées souris de la boucle // de message Win32 WndProc void InjectMousePosition(int iMouseX, int iMouseY); void InjectMouseButtonDown(MouseButton button); void InjectMouseButtonUp(); // Méthodes de récupérations de la position de la souris void GetMouseAbsoluteLocation(int& iMouseX, int& iMouseY); void GetMouseRelativePosition(float& fX, float& fY); // Méthodes de récupérations des entrées clavier bool IsKeyDown(unsigned int key); bool IsKeyUp(unsigned int key); bool IsMouseButtonDown(unsigned int button); bool IsKeyModifierDown(KeyModifier modifier); // Enregistre le receveur de touches clavier void SetKeyListener(KeyListener* pKeyListener); // Renvoie le caractère wchar_t correspondant à la clé spécifié wchar_t GetKeyCodeAsWChar(char key); // Renvoie une chaîne de caractère correspondant à la clé spécifié std::string GetKeyCodeAsString(char key); // Met le curseur au centre de la fenêtre void CenterMouseCursor(); // Je place cette fonction utilitaire au sein même // de la classe, mais sa place serait plus juste ailleurs std::string Formater(const std::wstring& src) { char outString[512]; CharToOemW(src.c_str(), outString); return std::string(outString); } private: // Coordonnées de la souris int m_iMouseX; int m_iMouseY; // Variable représentant les combinaison de touches // de modification unsigned int m_iModifiers; // Touches préssées std::map<unsigned int, bool> m_pressedKeys; // L'écouteur d'entrée clavier KeyListener* m_pKeyListener; // Le boutton de la souris^^ MouseButton m_iMouseButton; // variable ppour gérer les accents comme : // û, ì, ò, ô, etc... wchar_t m_deadKey; }; #endif |
Voici le code pour le fichier InputManager.cpp :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
#include "InputManager.h" #include "System.h" #include <sstream> template<> InputManager* Singleton<InputManager>::ms_instance = nullptr; InputManager::InputManager() : m_iMouseX(0), m_iMouseY(0), m_iModifiers(0), m_pKeyListener(nullptr), m_iMouseButton(MouseButton::MouseButtoNone), m_deadKey('\0') { } InputManager::~InputManager() { } void InputManager::SetKeyListener(KeyListener* pKeyListener) { assert(pKeyListener); m_pKeyListener = pKeyListener; } bool InputManager::IsKeyModifierDown(KeyModifier modifier) { return m_iModifiers & modifier; } void InputManager::InjectKeyModifierDown(KeyModifier modifier) { m_iModifiers |= modifier; } void InputManager::InjectKeyModifierUp(KeyModifier modifier) { m_iModifiers &= ~(modifier); } void InputManager::InjectKeyDown(unsigned int iVirtualKeyCode, unsigned int iScanCode) { m_pressedKeys[iVirtualKeyCode] = true; if (m_pKeyListener != nullptr) { wchar_t c = GetKeyCodeAsWChar(iScanCode); KeyEvent keyEvent(iScanCode, c); m_pKeyListener->OnKeyPressed(keyEvent); } } void InputManager::InjectKeyUp(unsigned int iVirtualKeyCode, unsigned int iScanCode) { m_pressedKeys[iVirtualKeyCode] = false; if (m_pKeyListener != nullptr) { wchar_t c = GetKeyCodeAsWChar(iScanCode); KeyEvent keyEvent(iScanCode, c); m_pKeyListener->OnKeyReleased(keyEvent); } } void InputManager::InjectMousePosition(int iMouseX, int iMouseY) { m_iMouseX = iMouseX; m_iMouseY = iMouseY; } void InputManager::GetMouseAbsoluteLocation(int& mouseX, int& mouseY) { mouseX = m_iMouseX; mouseY = m_iMouseY; } // todo : essayer avec les m_iMouseX et m_iMouseY void InputManager::GetMouseRelativePosition(float& fX, float& fY) { POINT p; if (!GetCursorPos(&p)) { DWORD xy = GetMessagePos(); p.x = LOWORD(xy); p.y = HIWORD(xy); } int borderX = GetSystemMetrics(SM_CXSIZEFRAME); int borderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME); RECT rect; GetWindowRect(SYSTEM->GetHwnd(), &rect); float x = p.x - rect.left - borderX; float y = p.y - rect.top - borderY; fX = ((float) x / (float) SYSTEM->GetWindowWidth()) - 0.5f; fY = ((float) y / (float) SYSTEM->GetWindowHeight()) - 0.5f; } bool InputManager::IsKeyDown(unsigned int key) { return m_pressedKeys[key] == true; } bool InputManager::IsKeyUp(unsigned int key) { return m_pressedKeys[key] == false; } void InputManager::InjectMouseButtonDown(MouseButton button) { m_iMouseButton = button; } void InputManager::InjectMouseButtonUp() { m_iMouseButton = MouseButtoNone; } bool InputManager::IsMouseButtonDown(unsigned int button) { return m_iMouseButton == button; } std::string InputManager::GetKeyCodeAsString(char key) { wchar_t w = GetKeyCodeAsWChar(key); std::wstring wStr; wStr.push_back( w ); std::string str = Formater(wStr); return str; } wchar_t InputManager::GetKeyCodeAsWChar(char key) { BYTE keyState[256]; HKL layout = GetKeyboardLayout(0); if (GetKeyboardState(keyState) == 0) { return 0; } unsigned int vk = MapVirtualKeyEx(key, 3, layout); if (vk == 0) { return 0; } WCHAR buff[3] = {0}; int ascii = ToUnicodeEx(vk, key, keyState, buff, 3, 0, layout); if (ascii == 1 && m_deadKey != '\0') { WCHAR wcBuff[3] = {buff[0], m_deadKey, '\0'}; WCHAR out[3]; if (FoldStringW(MAP_PRECOMPOSED, (LPWSTR)wcBuff, 3, (LPWSTR)out, 3)) { return out[0]; } } else if (ascii == -1) { return buff[0]; } else if (ascii == 2) { switch (buff[0]) { case 0x5E: // Circumflex accent: â m_deadKey = 0x302; break; case 0x60: // Grave accent: à m_deadKey = 0x300; break; case 0xA8: // Diaeresis: ü m_deadKey = 0x308; break; case 0xB4: // Acute accent: é m_deadKey = 0x301; break; case 0xB8: // Cedilla: ç m_deadKey = 0x327; break; default: m_deadKey = buff[0]; break; } } else if (ascii == 1) { m_deadKey = '\0'; return buff[0]; } return 0; } void InputManager::CenterMouseCursor() { int borderX = GetSystemMetrics(SM_CXSIZEFRAME); int borderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME); RECT rect; HWND hwnd = SYSTEM->GetHwnd(); GetWindowRect(hwnd, &rect); unsigned int iWindowWidth = SYSTEM->GetWindowWidth(); unsigned int iWindowHeight = SYSTEM->GetWindowHeight(); SetCursorPos(0.5f * iWindowWidth + rect.left + borderX, 0.5f * iWindowHeight + rect.top + borderY); } |
Voici la fonction WndProc utilisée pour obtenir les entrées afin de les passer à la classe InputManager :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if (!InputManager::IsCreated()) { return DefWindowProc(hWnd, message, wParam, lParam); } switch (message) { case WM_DESTROY: PostQuitMessage(0); break; case WM_KEYDOWN: { INPUT_MANAGER->InjectKeyDown(wParam, HIWORD(lParam)); if (wParam == VK_SHIFT) { INPUT_MANAGER->InjectKeyModifierDown(InputManager::KeyModifier::SHIFT); } if (wParam == VK_CONTROL) { INPUT_MANAGER->InjectKeyModifierDown(InputManager::KeyModifier::CTRL); } if (wParam == VK_MENU) { INPUT_MANAGER->InjectKeyModifierDown(InputManager::KeyModifier::ALT); } } break; case WM_KEYUP: { INPUT_MANAGER->InjectKeyUp(wParam, HIWORD(lParam)); if (wParam == VK_SHIFT) { INPUT_MANAGER->InjectKeyModifierUp(InputManager::KeyModifier::SHIFT); } if (wParam == VK_CONTROL) { INPUT_MANAGER->InjectKeyModifierUp(InputManager::KeyModifier::CTRL); } if (wParam == VK_MENU) { INPUT_MANAGER->InjectKeyModifierUp(InputManager::KeyModifier::ALT); } break; } case WM_MOUSEMOVE: { int iMouseX = (int) LOWORD(lParam); int iMouseY = (int) HIWORD(lParam); INPUT_MANAGER->InjectMousePosition(iMouseX, iMouseY); break; } case WM_LBUTTONDOWN: { INPUT_MANAGER->InjectMouseButtonDown(InputManager::MouseButton::MouseButtonLeft); break; } case WM_RBUTTONDOWN: { INPUT_MANAGER->InjectMouseButtonDown(InputManager::MouseButton::MouseButtonRight); break; } case WM_MBUTTONDOWN: { INPUT_MANAGER->InjectMouseButtonDown(InputManager::MouseButton::MouseButtonMiddle); break; } case WM_MBUTTONUP: case WM_LBUTTONUP: case WM_RBUTTONUP: { INPUT_MANAGER->InjectMouseButtonUp(); break; } default: { return DefWindowProc(hWnd, message, wParam, lParam); } } return 0; } |
Résumé :
Nous avons présenter une manière de récupérer les entrées clavier de votre jeu ou application.
Voici l’archive du code complet pour cet RawInputManager.zip
Références :


