Commit ac85e129 authored by Administrator's avatar Administrator
Browse files

add keyboard event handle

parent 8ea2f717
/******************************************************************************************
* Chili Direct3D Engine *
* Copyright 2018 PlanetChili <http://www.planetchili.net> *
* *
* This file is part of Chili Direct3D Engine. *
* *
* Chili Direct3D Engine is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* The Chili Direct3D Engine is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with The Chili Direct3D Engine. If not, see <http://www.gnu.org/licenses/>. *
******************************************************************************************/
#include "Keyboard.h"
bool Keyboard::KeyIsPressed( unsigned char keycode ) const noexcept
{
return keystates[keycode];
}
Keyboard::Event Keyboard::ReadKey() noexcept
{
if( keybuffer.size() > 0u )
{
Keyboard::Event e = keybuffer.front();
keybuffer.pop();
return e;
}
else
{
return Keyboard::Event();
}
}
bool Keyboard::KeyIsEmpty() const noexcept
{
return keybuffer.empty();
}
char Keyboard::ReadChar() noexcept
{
if( charbuffer.size() > 0u )
{
unsigned char charcode = charbuffer.front();
charbuffer.pop();
return charcode;
}
else
{
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();
}
}
/******************************************************************************************
* Chili Direct3D Engine *
* Copyright 2018 PlanetChili <http://www.planetchili.net> *
* *
* This file is part of Chili Direct3D Engine. *
* *
* Chili Direct3D Engine is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* The Chili Direct3D Engine is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with The Chili Direct3D Engine. If not, see <http://www.gnu.org/licenses/>. *
******************************************************************************************/
#pragma once
#include <queue>
#include <bitset>
class Keyboard
{
friend class Window;
public:
class Event
{
public:
enum class Type
{
Press,
Release,
Invalid
};
private:
Type type;
unsigned char code;
public:
Event()
:
type( Type::Invalid ),
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 IsValid() const noexcept
{
return type != Type::Invalid;
}
unsigned char GetCode() const noexcept
{
return code;
}
};
public:
Keyboard() = default;
// 单例设计
Keyboard( const Keyboard& ) = delete;
// 单例设计
Keyboard& operator=( const Keyboard& ) = delete;
// key event stuff
// 根据bitset keystates中指定Key的状态
bool KeyIsPressed( unsigned char keycode ) const noexcept;
// 从keyBuffer队列中找到最前面的Event,取出并移出队列
Event ReadKey() noexcept;
// 检查keyBuffer队列是否为空
bool KeyIsEmpty() const noexcept;
// 重置keyBuffer队列
void FlushKey() noexcept;
// char event stuff
// 从charBuff队列中找到最前面的Event,取出并移出队列
char ReadChar() noexcept;
// 检查charBuffer队列是否为空
bool CharIsEmpty() const noexcept;
// 重置charBuffer队列
void FlushChar() noexcept;
// 重置keyBuffer和charBuffer队列
void Flush() noexcept;
// autorepeat control
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:
// Key的数量,Unsigned 256足够对应所有的Key
static constexpr unsigned int nKeys = 256u;
// 队列长度
static constexpr unsigned int bufferSize = 16u;
// Todo
bool autorepeatEnabled = false;
// 用于存放每个Key的状态,每个bit的值对应一个Key的状态
std::bitset<nKeys> keystates;
// 用于存放Key事件的队列
std::queue<Event> keybuffer;
// 用于存放Char的队列
std::queue<char> charbuffer;
};
\ No newline at end of file
...@@ -138,6 +138,7 @@ ...@@ -138,6 +138,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="ChiliException.cpp" /> <ClCompile Include="ChiliException.cpp" />
<ClCompile Include="Keyboard.cpp" />
<ClCompile Include="Window.cpp" /> <ClCompile Include="Window.cpp" />
<ClCompile Include="WindowsMessageMap.cpp" /> <ClCompile Include="WindowsMessageMap.cpp" />
<ClCompile Include="WinMain.cpp" /> <ClCompile Include="WinMain.cpp" />
...@@ -145,6 +146,7 @@ ...@@ -145,6 +146,7 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="ChiliException.h" /> <ClInclude Include="ChiliException.h" />
<ClInclude Include="ChiliWin.h" /> <ClInclude Include="ChiliWin.h" />
<ClInclude Include="Keyboard.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="Window.h" /> <ClInclude Include="Window.h" />
<ClInclude Include="WindowsMessageMap.h" /> <ClInclude Include="WindowsMessageMap.h" />
......
...@@ -37,6 +37,11 @@ int CALLBACK WinMain( ...@@ -37,6 +37,11 @@ int CALLBACK WinMain(
// TranslateMessage will post auxilliary WM_CHAR messages from key msgs // TranslateMessage will post auxilliary WM_CHAR messages from key msgs
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
if (wnd.kbd.KeyIsPressed(VK_SPACE) || wnd.kbd.KeyIsPressed(VK_MENU))
{
MessageBox(nullptr, "Something happens!", "Space key was pressed", MB_OK | MB_ICONEXCLAMATION);
}
} }
// check if GetMessage call itself borked // check if GetMessage call itself borked
......
...@@ -160,6 +160,41 @@ LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noex ...@@ -160,6 +160,41 @@ LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noex
case WM_CLOSE: case WM_CLOSE:
PostQuitMessage( 0 ); PostQuitMessage( 0 );
return 0; return 0;
// 记录Key被按下
case WM_KEYDOWN:
// Bipset的第28,29,30位固定是0,30位代表前一次按键状态,1代表按下。
// 因此28-31的16进制值如果是4的话,表示前一次是按下的状态,这次是持续按键
// 如果Key被持续按下,第一个条件不成立,不执行操作
// 在以上的基础上,提供Autorepeat的选项。如果启用Autorepeat,那么即使持续按键,也执行操作
if (!(lParam & 0x40000000) || kbd.AutorepeatIsEnabled()) // filter autorepeat
{
kbd.OnKeyPressed(static_cast<unsigned char>(wParam));
}
break;
case WM_SYSKEYDOWN:
// 同上
if (!(lParam & 0x40000000) || kbd.AutorepeatIsEnabled()) // filter autorepeat
{
kbd.OnKeyPressed(static_cast<unsigned char>(wParam));
}
break;
// 记录Key释放
case WM_KEYUP:
kbd.OnKeyReleased(static_cast<unsigned char>(wParam));
break;
// 记录文字输入
case WM_CHAR:
kbd.OnChar(static_cast<unsigned char>(wParam));
break;
// 如果窗口失去焦点,立刻清空所有队列中的成员
case WM_KILLFOCUS:
kbd.ClearState();
break;
} }
return DefWindowProc( hWnd,msg,wParam,lParam ); return DefWindowProc( hWnd,msg,wParam,lParam );
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#pragma once #pragma once
#include "ChiliWin.h" #include "ChiliWin.h"
#include "ChiliException.h" #include "ChiliException.h"
#include "Keyboard.h"
class Window class Window
...@@ -62,6 +63,8 @@ private: ...@@ -62,6 +63,8 @@ private:
static LRESULT CALLBACK HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept; static LRESULT CALLBACK HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept;
static LRESULT CALLBACK HandleMsgThunk(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept; static LRESULT CALLBACK HandleMsgThunk(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept;
LRESULT HandleMsg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept; LRESULT HandleMsg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept;
public:
Keyboard kbd;
private: private:
int width; int width;
int height; int height;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment