Skip to content

Commit

Permalink
feat: 增加鼠标扩展键的检测 (#237)
Browse files Browse the repository at this point in the history
* feat: 增加鼠标扩展键的检测
* refactor: 优化鼠标消息处理部分的代码
* fix: 修复 WM_MOUSEWHEEL 提供的屏幕坐标经由 ScreenToClient 计算后与其它消息提供的客户区坐标不一致的问题
  • Loading branch information
yixy-only authored Nov 23, 2024
1 parent 2c481a9 commit a808a97
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 169 deletions.
22 changes: 16 additions & 6 deletions include/ege.h
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,8 @@ enum key_code_e
key_mouse_l = 0x01,
key_mouse_r = 0x02,
key_mouse_m = 0x04,
key_mouse_x1 = 0x05,
key_mouse_x2 = 0x06,
key_back = 0x08,
key_tab = 0x09,
key_enter = 0x0d,
Expand Down Expand Up @@ -722,9 +724,11 @@ enum mouse_msg_e

enum mouse_flag_e
{
mouse_flag_left = 1,
mouse_flag_right = 2,
mouse_flag_mid = 4,
mouse_flag_left = 0x001,
mouse_flag_right = 0x002,
mouse_flag_mid = 0x004,
mouse_flag_x1 = 0x008,
mouse_flag_x2 = 0x010,
mouse_flag_shift = 0x100,
mouse_flag_ctrl = 0x200
};
Expand All @@ -736,12 +740,16 @@ struct mouse_msg
mouse_msg_e msg;
unsigned int flags;
int wheel;

bool is_left() const {return (flags & mouse_flag_left) != 0;}
bool is_right() const {return (flags & mouse_flag_right) != 0;}
bool is_mid() const {return (flags & mouse_flag_mid) != 0;}
bool is_down() const {return msg == mouse_msg_down;}
bool is_up() const {return msg == mouse_msg_up;}
bool is_move() const {return msg == mouse_msg_move;}
bool is_x1() const {return (flags & mouse_flag_x1) != 0;}
bool is_x2() const {return (flags & mouse_flag_x2) != 0;}

bool is_down() const {return msg == mouse_msg_down; }
bool is_up() const {return msg == mouse_msg_up; }
bool is_move() const {return msg == mouse_msg_move; }
bool is_wheel() const {return msg == mouse_msg_wheel;}
};

Expand All @@ -753,6 +761,8 @@ struct MOUSEMSG
bool mkLButton;
bool mkMButton;
bool mkRButton;
bool mkXButton1;
bool mkXButton2;
short x;
short y;
short wheel;
Expand Down
9 changes: 4 additions & 5 deletions src/ege_head.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@
#define DEFAULT_CHARSET ANSI_CHARSET
#endif

#include "types.h"


namespace ege
{
Expand Down Expand Up @@ -200,10 +202,7 @@ struct _graph_setting
HANDLE threadui_handle;

/* 鼠标状态记录 */
int mouse_state_l, mouse_state_m, mouse_state_r;
int mouse_last_x, mouse_last_y;
int mouse_lastclick_x, mouse_lastclick_y;
int mouse_lastup_x, mouse_lastup_y;
Point mouse_pos;
int mouse_show;

LPMSG_KEY_PROC callback_key;
Expand All @@ -212,7 +211,7 @@ struct _graph_setting
void* callback_mouse_param;
LPCALLBACK_PROC callback_close;

/* 键盘状态记录 */
/* 按键状态记录 */
int keystatemap[MAX_KEY_VCODE];

/* egeControlBase */
Expand Down
4 changes: 2 additions & 2 deletions src/egegapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ int showmouse(int bShow)
int mousepos(int* x, int* y)
{
struct _graph_setting* pg = &graph_setting;
*x = pg->mouse_last_x;
*y = pg->mouse_last_y;
*x = pg->mouse_pos.x;
*y = pg->mouse_pos.y;
return 0;
}

Expand Down
168 changes: 75 additions & 93 deletions src/graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
#include <stdio.h>
#include <stdlib.h>

#include <windowsx.h>

#include "ege_head.h"
#include "ege_common.h"
#include "ege_extension.h"
Expand Down Expand Up @@ -435,18 +437,79 @@ static void on_key(struct _graph_setting* pg, UINT message, unsigned long keycod
}

/*private function*/
static void push_mouse_msg(struct _graph_setting* pg, UINT message, WPARAM wparam, LPARAM lparam)
static void push_mouse_msg(struct _graph_setting* pg, UINT message, WPARAM wparam, LPARAM lparam, int time)
{
EGEMSG msg = {0};
msg.hwnd = pg->hwnd;
msg.message = message;
msg.wParam = wparam;
msg.lParam = lparam;
msg.mousekey = (pg->mouse_state_m << 2) | (pg->mouse_state_r << 1) | (pg->mouse_state_l << 0);
msg.time = ::GetTickCount();

msg.mousekey |= pg->keystatemap[VK_LBUTTON] ? mouse_flag_left : 0;
msg.mousekey |= pg->keystatemap[VK_RBUTTON] ? mouse_flag_right : 0;
msg.mousekey |= pg->keystatemap[VK_MBUTTON] ? mouse_flag_mid : 0;
msg.mousekey |= pg->keystatemap[VK_XBUTTON1] ? mouse_flag_x1 : 0;
msg.mousekey |= pg->keystatemap[VK_XBUTTON2] ? mouse_flag_x2 : 0;

msg.time = time;
pg->msgmouse_queue->push(msg);
}

static void mouseProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
/* up 消息会后紧跟一条 move 消息,标记并将其忽略 */
static bool skipNextMoveMessage = false;
if ((message < WM_MOUSEFIRST) || (message > WM_MOUSELAST))
return;

_graph_setting* pg = &graph_setting;

bool curMsgIsNeedToPush = true;

int key = 0;

/* WINAPI bug: WM_MOUSEWHEEL 提供的是屏幕坐标,DPI 不等于 100% 时 ScreenToClient 的计算
* 结果与其它鼠标消息提供的坐标不一致,故忽略 lParam 提供的值,直接使用之前记录的客户区坐标
*/
if (message == WM_MOUSEWHEEL) {
lParam = MAKELPARAM(pg->mouse_pos.x, pg->mouse_pos.y);
}

mouse_msg msg = mouseMessageConvert(message, wParam, lParam, &key);
Point curPos(msg.x, msg.y);

if (msg.is_up()) {
skipNextMoveMessage = true;
} else if (msg.is_move()) {
/* 忽略 up 消息后伴随的同位置 move 消息 */
if (skipNextMoveMessage && (curPos == pg->mouse_pos)) {
curMsgIsNeedToPush = false;
skipNextMoveMessage = false;
}
}

/* 鼠标按键动作 */
if (key != 0) {
pg->keystatemap[key] = msg.is_down();

/* 设置鼠标消息捕获 */
if (msg.is_down()) {
SetCapture(hWnd);
} else {
const int keyStateMask = MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2;
if ((wParam & keyStateMask) == 0) {
ReleaseCapture();
}
}
}

if (curMsgIsNeedToPush && (hWnd == pg->hwnd)) {
push_mouse_msg(pg, message, wParam, lParam, GetMessageTime());
}

pg->mouse_pos = curPos;
}

/*private function*/
static LRESULT CALLBACK wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
Expand Down Expand Up @@ -526,95 +589,15 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l
}
}
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
pg->mouse_lastclick_x = (short int)((UINT)lParam & 0xFFFF);
pg->mouse_lastclick_y = (short int)((UINT)lParam >> 16);
pg->keystatemap[VK_LBUTTON] = 1;
SetCapture(hWnd);
pg->mouse_state_l = 1;
if (hWnd == pg->hwnd) {
push_mouse_msg(pg, message, wParam, lParam);
}
break;
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
pg->mouse_lastclick_x = (short int)((UINT)lParam & 0xFFFF);
pg->mouse_lastclick_y = (short int)((UINT)lParam >> 16);
pg->keystatemap[VK_MBUTTON] = 1;
SetCapture(hWnd);
pg->mouse_state_m = 1;
if (hWnd == pg->hwnd) {
push_mouse_msg(pg, message, wParam, lParam);
}
break;
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
pg->mouse_lastclick_x = (short int)((UINT)lParam & 0xFFFF);
pg->mouse_lastclick_y = (short int)((UINT)lParam >> 16);
pg->keystatemap[VK_RBUTTON] = 1;
SetCapture(hWnd);
pg->mouse_state_r = 1;
if (hWnd == pg->hwnd) {
push_mouse_msg(pg, message, wParam, lParam);
}
break;
case WM_LBUTTONUP:
pg->mouse_lastup_x = (short int)((UINT)lParam & 0xFFFF);
pg->mouse_lastup_y = (short int)((UINT)lParam >> 16);
pg->mouse_state_l = 0;
pg->keystatemap[VK_LBUTTON] = 0;
if (pg->mouse_state_l == 0 && pg->mouse_state_m == 0 && pg->mouse_state_r == 0) {
ReleaseCapture();
}
if (hWnd == pg->hwnd) {
push_mouse_msg(pg, message, wParam, lParam);
}
break;
case WM_MBUTTONUP:
pg->mouse_lastup_x = (short int)((UINT)lParam & 0xFFFF);
pg->mouse_lastup_y = (short int)((UINT)lParam >> 16);
pg->mouse_state_m = 0;
pg->keystatemap[VK_MBUTTON] = 0;
if (pg->mouse_state_l == 0 && pg->mouse_state_m == 0 && pg->mouse_state_r == 0) {
ReleaseCapture();
}
if (hWnd == pg->hwnd) {
push_mouse_msg(pg, message, wParam, lParam);
}
break;
case WM_RBUTTONUP:
pg->mouse_lastup_x = (short int)((UINT)lParam & 0xFFFF);
pg->mouse_lastup_y = (short int)((UINT)lParam >> 16);
pg->mouse_state_r = 0;
pg->keystatemap[VK_RBUTTON] = 0;
if (pg->mouse_state_l == 0 && pg->mouse_state_m == 0 && pg->mouse_state_r == 0) {
ReleaseCapture();
}
if (hWnd == pg->hwnd) {
push_mouse_msg(pg, message, wParam, lParam);
}
break;
case WM_MOUSEMOVE:
pg->mouse_last_x = (short int)((UINT)lParam & 0xFFFF);
pg->mouse_last_y = (short int)((UINT)lParam >> 16);
if (hWnd == pg->hwnd && (pg->mouse_lastup_x != pg->mouse_last_x || pg->mouse_lastup_y != pg->mouse_last_y)) {
push_mouse_msg(pg, message, wParam, lParam);
}
break;
case WM_MOUSEWHEEL: {
POINT pt;
pt.x = (short int)((UINT)lParam & 0xFFFF);
pt.y = (short int)((UINT)lParam >> 16);
ScreenToClient(pg->hwnd, &pt);
pg->mouse_last_x = pt.x;
pg->mouse_last_y = pt.y;
lParam = ((unsigned short)(short int)pg->mouse_last_y << 16) | (unsigned short)(short int)pg->mouse_last_x;
}
if (hWnd == pg->hwnd) {
push_mouse_msg(pg, message, wParam, lParam);
}

case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_LBUTTONDBLCLK:
case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDBLCLK:
case WM_RBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDBLCLK:
case WM_XBUTTONDOWN: case WM_XBUTTONUP: case WM_XBUTTONDBLCLK:
case WM_MOUSEMOVE: case WM_MOUSEWHEEL:
mouseProc(hWnd, message, wParam, lParam);
break;

case WM_SETCURSOR:
if (pg == pg_w) {
on_setcursor(pg, hWnd);
Expand Down Expand Up @@ -850,8 +833,7 @@ void initgraph(int* gdriver, int* gmode, const char* path)
POINT pt;
GetCursorPos(&pt);
ScreenToClient(pg->hwnd, &pt);
pg->mouse_last_x = pt.x;
pg->mouse_last_y = pt.y;
pg->mouse_pos = Point(pt.x, pt.y);

static egeControlBase _egeControlBase;

Expand Down
Loading

0 comments on commit a808a97

Please sign in to comment.