Commit d14dac18 authored by Clark Lin's avatar Clark Lin
Browse files

add mouse event handle

parent ac85e129
...@@ -38,7 +38,7 @@ public: ...@@ -38,7 +38,7 @@ public:
Type type; Type type;
unsigned char code; unsigned char code;
public: public:
Event() Event() noexcept
: :
type( Type::Invalid ), type( Type::Invalid ),
code( 0u ) code( 0u )
......
/******************************************************************************************
* Chili DirectX Framework Version 16.07.20 *
* Mouse.cpp *
* Copyright 2016 PlanetChili <http://www.planetchili.net> *
* *
* This file is part of The Chili DirectX Framework. *
* *
* The Chili DirectX Framework 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 DirectX Framework 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 DirectX Framework. If not, see <http://www.gnu.org/licenses/>. *
******************************************************************************************/
#include "Mouse.h"
#include "Window.h"
std::pair<int,int> Mouse::GetPos() const noexcept
{
return { x,y };
}
int Mouse::GetPosX() const noexcept
{
return x;
}
int Mouse::GetPosY() const noexcept
{
return y;
}
bool Mouse::IsInWindow() const noexcept
{
return isInWindow;
}
bool Mouse::LeftIsPressed() const noexcept
{
return leftIsPressed;
}
bool Mouse::RightIsPressed() const noexcept
{
return rightIsPressed;
}
Mouse::Event Mouse::Read() noexcept
{
if( buffer.size() > 0u )
{
Mouse::Event e = buffer.front();
buffer.pop();
return e;
}
else
{
return Mouse::Event();
}
}
void Mouse::Flush() noexcept
{
buffer = std::queue<Event>();
}
void Mouse::OnMouseMove( int newx,int newy ) noexcept
{
x = newx;
y = newy;
buffer.push( Mouse::Event( Mouse::Event::Type::Move,*this ) );
TrimBuffer();
}
void Mouse::OnMouseEnter() noexcept
{
isInWindow = true;
buffer.push(Mouse::Event(Mouse::Event::Type::Enter, *this));
TrimBuffer();
}
void Mouse::OnMouseLeave() noexcept
{
isInWindow = false;
buffer.push(Mouse::Event(Mouse::Event::Type::Leave, *this));
TrimBuffer();
}
void Mouse::OnLeftPressed( int x,int y ) noexcept
{
leftIsPressed = true;
buffer.push( Mouse::Event( Mouse::Event::Type::LPress,*this ) );
TrimBuffer();
}
void Mouse::OnLeftReleased( int x,int y ) noexcept
{
leftIsPressed = false;
buffer.push( Mouse::Event( Mouse::Event::Type::LRelease,*this ) );
TrimBuffer();
}
void Mouse::OnRightPressed( int x,int y ) noexcept
{
rightIsPressed = true;
buffer.push( Mouse::Event( Mouse::Event::Type::RPress,*this ) );
TrimBuffer();
}
void Mouse::OnRightReleased( int x,int y ) noexcept
{
rightIsPressed = false;
buffer.push( Mouse::Event( Mouse::Event::Type::RRelease,*this ) );
TrimBuffer();
}
void Mouse::OnWheelUp( int x,int y ) noexcept
{
buffer.push( Mouse::Event( Mouse::Event::Type::WheelUp,*this ) );
TrimBuffer();
}
void Mouse::OnWheelDown( int x,int y ) noexcept
{
buffer.push( Mouse::Event( Mouse::Event::Type::WheelDown,*this ) );
TrimBuffer();
}
void Mouse::TrimBuffer() noexcept
{
while( buffer.size() > bufferSize )
{
buffer.pop();
}
}
void Mouse::OnWheelDelta(int x, int y, int delta) noexcept
{
wheelDeltaCarry += delta;
// generate events for every 120
// 默认每次达到120,执行一次滚轮事件。如果数字够大,可以执行复数次
while (wheelDeltaCarry >= WHEEL_DELTA)
{
wheelDeltaCarry -= WHEEL_DELTA;
OnWheelUp(x, y);
}
while (wheelDeltaCarry <= -WHEEL_DELTA)
{
wheelDeltaCarry += WHEEL_DELTA;
OnWheelDown(x, y);
}
}
\ No newline at end of file
/******************************************************************************************
* Chili DirectX Framework Version 16.07.20 *
* Mouse.h *
* Copyright 2016 PlanetChili <http://www.planetchili.net> *
* *
* This file is part of The Chili DirectX Framework. *
* *
* The Chili DirectX Framework 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 DirectX Framework 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 DirectX Framework. If not, see <http://www.gnu.org/licenses/>. *
******************************************************************************************/
#pragma once
#include <queue>
class Mouse
{
friend class Window;
public:
class Event
{
public:
enum class Type
{
LPress,
LRelease,
RPress,
RRelease,
WheelUp,
WheelDown,
Move,
Enter,
Leave,
Invalid
};
private:
Type type;
bool leftIsPressed;
bool rightIsPressed;
int x;
int y;
public:
Event() noexcept
:
type( Type::Invalid ),
leftIsPressed( false ),
rightIsPressed( false ),
x( 0 ),
y( 0 )
{}
Event( Type type,const Mouse& parent ) noexcept
:
type( type ),
leftIsPressed( parent.leftIsPressed ),
rightIsPressed( parent.rightIsPressed ),
x( parent.x ),
y( parent.y )
{}
bool IsValid() const noexcept
{
return type != Type::Invalid;
}
Type GetType() const noexcept
{
return type;
}
std::pair<int,int> GetPos() const noexcept
{
return{ x,y };
}
int GetPosX() const noexcept
{
return x;
}
int GetPosY() const noexcept
{
return y;
}
bool LeftIsPressed() const noexcept
{
return leftIsPressed;
}
bool RightIsPressed() const noexcept
{
return rightIsPressed;
}
};
public:
Mouse() = default;
Mouse( const Mouse& ) = delete;
Mouse& operator=( const Mouse& ) = delete;
std::pair<int,int> GetPos() const noexcept;
int GetPosX() const noexcept;
int GetPosY() const noexcept;
bool IsInWindow() const noexcept;
bool LeftIsPressed() const noexcept;
bool RightIsPressed() const noexcept;
Mouse::Event Read() noexcept;
bool IsEmpty() const noexcept
{
return buffer.empty();
}
void Flush() noexcept;
private:
void OnMouseMove( int x,int y ) noexcept;
void OnMouseEnter() noexcept;
void OnMouseLeave() noexcept;
void OnLeftPressed( int x,int y ) noexcept;
void OnLeftReleased( int x,int y ) noexcept;
void OnRightPressed( int x,int y ) noexcept;
void OnRightReleased( int x,int y ) noexcept;
void OnWheelUp( int x,int y ) noexcept;
void OnWheelDown( int x,int y ) noexcept;
void OnWheelDelta(int x, int y, int delta) noexcept;
void TrimBuffer() noexcept;
private:
static constexpr unsigned int bufferSize = 16u;
int x;
int y;
bool leftIsPressed = false;
bool rightIsPressed = false;
bool isInWindow = false;
// 执行滚轮事件的次数,正数表示向上滚动,负数表示向下滚动
int wheelDeltaCarry = 0;
std::queue<Event> buffer;
};
\ No newline at end of file
...@@ -139,6 +139,7 @@ ...@@ -139,6 +139,7 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="ChiliException.cpp" /> <ClCompile Include="ChiliException.cpp" />
<ClCompile Include="Keyboard.cpp" /> <ClCompile Include="Keyboard.cpp" />
<ClCompile Include="Mouse.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" />
...@@ -147,6 +148,7 @@ ...@@ -147,6 +148,7 @@
<ClInclude Include="ChiliException.h" /> <ClInclude Include="ChiliException.h" />
<ClInclude Include="ChiliWin.h" /> <ClInclude Include="ChiliWin.h" />
<ClInclude Include="Keyboard.h" /> <ClInclude Include="Keyboard.h" />
<ClInclude Include="Mouse.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" />
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* along with The Chili Direct3D Engine. If not, see <http://www.gnu.org/licenses/>. * * along with The Chili Direct3D Engine. If not, see <http://www.gnu.org/licenses/>. *
******************************************************************************************/ ******************************************************************************************/
#include "Window.h" #include "Window.h"
#include <sstream>
int CALLBACK WinMain( int CALLBACK WinMain(
HINSTANCE hInstance, HINSTANCE hInstance,
...@@ -38,9 +38,41 @@ int CALLBACK WinMain( ...@@ -38,9 +38,41 @@ int CALLBACK WinMain(
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
if (wnd.kbd.KeyIsPressed(VK_SPACE) || wnd.kbd.KeyIsPressed(VK_MENU)) // if (wnd.kbd.KeyIsPressed(VK_SPACE) || wnd.kbd.KeyIsPressed(VK_MENU))
// {
// MessageBox(nullptr, "Something happens!", "Space key was pressed", MB_OK | MB_ICONEXCLAMATION);
// }
while (!wnd.mouse.IsEmpty())
{ {
MessageBox(nullptr, "Something happens!", "Space key was pressed", MB_OK | MB_ICONEXCLAMATION); const auto e = wnd.mouse.Read();
static int i = 0;
switch (e.GetType())
{
case Mouse::Event::Type::Move:
{
std::ostringstream oss;
oss << "Mouse Position: (" << e.GetPosX() << "," << e.GetPosY() << "), " << "Mouse Press Status: (" << wnd.mouse.LeftIsPressed() << "," << wnd.mouse.RightIsPressed() << ")";
wnd.SetTitle(oss.str());
break;
}
case Mouse::Event::Type::WheelUp:
{
i++;
std::ostringstream oss;
oss << "Up: " << i;
wnd.SetTitle(oss.str());
break;
}
case Mouse::Event::Type::WheelDown:
{
i--;
std::ostringstream oss;
oss << "Down: " << i;
wnd.SetTitle(oss.str());
break;
}
}
} }
} }
......
...@@ -85,6 +85,9 @@ HINSTANCE Window::WindowClass::GetInstance() noexcept ...@@ -85,6 +85,9 @@ HINSTANCE Window::WindowClass::GetInstance() noexcept
// Window Stuff // Window Stuff
Window::Window( int width,int height,const char* name ) Window::Window( int width,int height,const char* name )
:
width(width),
height(height)
{ {
// calculate window size based on desired client region size // calculate window size based on desired client region size
RECT wr; RECT wr;
...@@ -92,10 +95,10 @@ Window::Window( int width,int height,const char* name ) ...@@ -92,10 +95,10 @@ Window::Window( int width,int height,const char* name )
wr.right = width + wr.left; wr.right = width + wr.left;
wr.top = 100; wr.top = 100;
wr.bottom = height + wr.top; wr.bottom = height + wr.top;
if (FAILED(AdjustWindowRect(&wr, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, FALSE))) if (AdjustWindowRect(&wr, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, FALSE) == 0)
{ {
throw CHWND_LAST_EXCEPT(); throw CHWND_LAST_EXCEPT();
}; }
// create window & get hWnd // create window & get hWnd
hWnd = CreateWindow( hWnd = CreateWindow(
...@@ -118,6 +121,14 @@ Window::~Window() ...@@ -118,6 +121,14 @@ Window::~Window()
DestroyWindow( hWnd ); DestroyWindow( hWnd );
} }
void Window::SetTitle(const std::string& title)
{
if (SetWindowText(hWnd, title.c_str()) == 0)
{
throw CHWND_LAST_EXCEPT();
}
}
LRESULT CALLBACK Window::HandleMsgSetup( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noexcept LRESULT CALLBACK Window::HandleMsgSetup( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noexcept
{ {
// use create parameter passed in from CreateWindow() to store window class pointer at WinAPI side // use create parameter passed in from CreateWindow() to store window class pointer at WinAPI side
...@@ -161,6 +172,11 @@ LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noex ...@@ -161,6 +172,11 @@ LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noex
PostQuitMessage( 0 ); PostQuitMessage( 0 );
return 0; return 0;
// 如果窗口失去焦点,立刻清空所有队列中的成员
case WM_KILLFOCUS:
kbd.ClearState();
break;
// 记录Key被按下 // 记录Key被按下
case WM_KEYDOWN: case WM_KEYDOWN:
// Bipset的第28,29,30位固定是0,30位代表前一次按键状态,1代表按下。 // Bipset的第28,29,30位固定是0,30位代表前一次按键状态,1代表按下。
...@@ -173,6 +189,7 @@ LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noex ...@@ -173,6 +189,7 @@ LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noex
} }
break; break;
// 记录SysKey被按下
case WM_SYSKEYDOWN: case WM_SYSKEYDOWN:
// 同上 // 同上
if (!(lParam & 0x40000000) || kbd.AutorepeatIsEnabled()) // filter autorepeat if (!(lParam & 0x40000000) || kbd.AutorepeatIsEnabled()) // filter autorepeat
...@@ -181,6 +198,8 @@ LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noex ...@@ -181,6 +198,8 @@ LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noex
} }
break; break;
// 记录SysKey被释放
case WM_SYSKEYUP:
// 记录Key释放 // 记录Key释放
case WM_KEYUP: case WM_KEYUP:
kbd.OnKeyReleased(static_cast<unsigned char>(wParam)); kbd.OnKeyReleased(static_cast<unsigned char>(wParam));
...@@ -191,12 +210,86 @@ LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noex ...@@ -191,12 +210,86 @@ LRESULT Window::HandleMsg( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam ) noex
kbd.OnChar(static_cast<unsigned char>(wParam)); kbd.OnChar(static_cast<unsigned char>(wParam));
break; break;
// 如果窗口失去焦点,立刻清空所有队列中的成员 // 鼠标移动
case WM_KILLFOCUS: case WM_MOUSEMOVE:
kbd.ClearState(); {
const POINTS pt = MAKEPOINTS(lParam);
mouse.OnMouseMove(pt.x, pt.y);
// in client region -> log move, and log enter + capture mouse (if not previously in window)
// 判断是否在窗口内
if (pt.x >= 0 && pt.x <= width && pt.y >= 0 and pt.y <= height) {
// 如果鼠标在窗口内,那么一定会记录鼠标的移动
mouse.OnMouseMove(pt.x, pt.y);
// 判断之前的鼠标状态。如果之前不在窗口内,那么说明现在是从外面移动进入窗口内
if (!mouse.IsInWindow())
{
SetCapture(hWnd);
mouse.OnMouseEnter();
}
}
else
{
// 当鼠标移动到了窗口外,如果之前左键或者右键是按住的状态,那么被识别为拖拽
if (mouse.LeftIsPressed() || mouse.RightIsPressed())
{
// 拖拽过程中,依然会记录鼠标的移动
mouse.OnMouseMove(pt.x, pt.y);
}
else
{
// 否则的话,释放对鼠标的捕获
ReleaseCapture();
mouse.OnMouseLeave();
}
}
break;
}
// 点击左键
case WM_LBUTTONDOWN:
{
const POINTS pt = MAKEPOINTS(lParam);
mouse.OnLeftPressed(pt.x, pt.y);
break;
}
// 点击右键
case WM_RBUTTONDOWN:
{
const POINTS pt = MAKEPOINTS(lParam);
mouse.OnRightPressed(pt.x, pt.y);
break;
}
// 释放左键
case WM_LBUTTONUP:
{
const POINTS pt = MAKEPOINTS(lParam);
mouse.OnLeftReleased(pt.x, pt.y);
break; break;
} }
// 释放右键
{
case WM_RBUTTONUP:
const POINTS pt = MAKEPOINTS(lParam);
mouse.OnRightReleased(pt.x, pt.y);
break;
}
// 鼠标滚轮
case WM_MOUSEWHEEL:
{
const POINTS pt = MAKEPOINTS(lParam);
const int delta = GET_WHEEL_DELTA_WPARAM(wParam);
mouse.OnWheelDelta(pt.x, pt.y, delta);
break;
}
}
return DefWindowProc( hWnd,msg,wParam,lParam ); return DefWindowProc( hWnd,msg,wParam,lParam );
} }
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "ChiliWin.h" #include "ChiliWin.h"
#include "ChiliException.h" #include "ChiliException.h"
#include "Keyboard.h" #include "Keyboard.h"
#include "Mouse.h"
class Window class Window
...@@ -59,12 +60,14 @@ public: ...@@ -59,12 +60,14 @@ public:
~Window(); ~Window();
Window(const Window&) = delete; Window(const Window&) = delete;
Window& operator=(const Window&) = delete; Window& operator=(const Window&) = delete;
void SetTitle(const std::string& title);
private: 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: public:
Keyboard kbd; Keyboard kbd;
Mouse mouse;
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