枚举区分键盘状态:
1.Press,按下
2.Release,松开
3.Invaild,无效
记录按键的char值;
定义键盘事件Event;
使用bites表存所有key的状态,使用bites原因一共键位个数不超过256个,所以足够了;
使用两个队列Queue分别记录键盘事件和char值;
检测到VM_KEYDOWN的系统消息时,调用按下的回调事件,将keystate更改为true,push事件;
检测到VM_KEYUP和VM_CHAR抬起一样;
tips:在窗口不为焦点窗口时需要清空两个队列;
在WindowsProc函数下拦截消息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 case WM_KILLFOCUS: kbd.ClearState (); break ; case WM_KEYDOWN: case WM_SYSKEYDOWN: if (!(lParam & 0x40000000 ) || kbd.AutorepeatIsEnabled ()) { kbd.OnKeyPressed (static_cast <unsigned char >(wParam)); } break ; case WM_KEYUP: case WM_SYSKEYUP: kbd.OnKeyReleased (static_cast <unsigned char >(wParam)); break ; case WM_CHAR: kbd.OnChar (static_cast <unsigned char >(wParam)); break ;
完整代码:
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 class Keyboard { friend class Window ; public : class Event { public : enum class Type { Press, Release, Invaild }; private : Type type; unsigned char code; public : Event () noexcept : type ( Type::Invaild), code ( 0u ) {} Event (Type type, unsigned char code) noexcept : type ( type ), code ( code ) {} bool IsPress () const noexcept { return type == Type::Press; } bool IsRelease () const noexcept { return type == Type::Release; } bool IsInvaild () const noexcept { return type != Type::Invaild; } unsigned char GetCode () const noexcept { return code; } }; public : Keyboard () = default ; Keyboard ( const Keyboard& ) = delete ; Keyboard& operator =( const Keyboard& ) = delete ; bool KeyIsPressed ( unsigned char keycode ) const noexcept ; std::optional<Event> ReadKey () noexcept ; bool KeyIsEmpty () const noexcept ; void FlushKey () noexcept ; std::optional<char > ReadChar () noexcept ; bool CharIsEmpty () const noexcept ; void FlushChar () noexcept ; void Flush () noexcept ; void EnableAutorepeat () noexcept ; void DisableAutorepeat () noexcept ; bool AutorepeatIsEnabled () const noexcept ; private : void OnKeyPressed ( unsigned char keycode ) noexcept ; void OnKeyReleased ( unsigned char keycode ) noexcept ; void OnChar ( char character ) noexcept ; void ClearState () noexcept ; template <typename T> static void TrimBuffer ( std::queue<T>& buffer ) noexcept ;private : static constexpr unsigned int nKeys = 256u ; static constexpr unsigned int bufferSize = 16u ; bool autorepeatEnabled = false ; std::bitset<nKeys> keystates; std::queue<Event> keybuffer; std::queue<char > charbuffer; };
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 bool Keyboard::KeyIsPressed ( unsigned char keycode ) const noexcept { return keystates[keycode]; } std::optional<Keyboard::Event> Keyboard::ReadKey () noexcept { if ( keybuffer.size () > 0u ) { Keyboard::Event e = keybuffer.front (); keybuffer.pop (); return e; } return Keyboard::Event (); } bool Keyboard::KeyIsEmpty () const noexcept { return keybuffer.empty (); } std::optional<char > Keyboard::ReadChar () noexcept { if ( charbuffer.size () > 0u ) { unsigned char charcode = charbuffer.front (); charbuffer.pop (); return charcode; } return 0 ; } bool Keyboard::CharIsEmpty () const noexcept { return charbuffer.empty (); } void Keyboard::FlushKey () noexcept { keybuffer = std::queue <Event>(); } void Keyboard::FlushChar () noexcept { charbuffer = std::queue <char >(); } void Keyboard::Flush () noexcept { FlushKey (); FlushChar (); } void Keyboard::EnableAutorepeat () noexcept { autorepeatEnabled = true ; } void Keyboard::DisableAutorepeat () noexcept { autorepeatEnabled = false ; } bool Keyboard::AutorepeatIsEnabled () const noexcept { return autorepeatEnabled; } void Keyboard::OnKeyPressed ( unsigned char keycode ) noexcept { keystates[keycode] = true ; keybuffer.push ( Keyboard::Event ( Keyboard::Event::Type::Press,keycode ) ); TrimBuffer ( keybuffer ); } void Keyboard::OnKeyReleased ( unsigned char keycode ) noexcept { keystates[keycode] = false ; keybuffer.push ( Keyboard::Event ( Keyboard::Event::Type::Release,keycode ) ); TrimBuffer ( keybuffer ); } void Keyboard::OnChar ( char character ) noexcept { charbuffer.push ( character ); TrimBuffer ( charbuffer ); } void Keyboard::ClearState () noexcept { keystates.reset (); } template <typename T>void Keyboard::TrimBuffer ( std::queue<T>& buffer ) noexcept { while ( buffer.size () > bufferSize ) { buffer.pop (); } }