张洋 4 weeks ago
parent
commit
9215c606bb
2 changed files with 22 additions and 17 deletions
  1. 14 12
      DuiLib/Core/UIManager.cpp
  2. 8 5
      DuiLib/Core/UIManager.h

+ 14 - 12
DuiLib/Core/UIManager.cpp

@@ -623,6 +623,8 @@ namespace DuiLib
 				if (pControl->GetManager() != this) break;
 
 				m_pEventTouch = pControl;
+				m_bTouchMoved = false;
+				m_ptTouchStart = pt;
 				pControl->SetFocus();
 				SetCapture();                              // mgr 级:m_bMouseCapture=true + ::SetCapture
 
@@ -644,6 +646,11 @@ namespace DuiLib
 				LONG dx = pt.x - m_ptLastTouchPos.x;
 				LONG dy = pt.y - m_ptLastTouchPos.y;
 				m_ptLastTouchPos = pt;
+				// 相对手势起点的累计位移超过阈值 -> 判定为拖拽(用于松开时抑制点击)
+				LONG ox = pt.x - m_ptTouchStart.x;
+				LONG oy = pt.y - m_ptTouchStart.y;
+				if (ox > 5 || ox < -5 || oy > 5 || oy < -5)
+					m_bTouchMoved = true;
 				if (m_pEventTouch == NULL) break;
 
 				TEventUI event = { 0 };
@@ -1238,10 +1245,10 @@ namespace DuiLib
 		if (m_hWndPaint == NULL) return false;
 
 		// [触屏兼容] 不再过滤 Windows 为触摸模拟的鼠标消息(MOUSEEVENTF_FROMTOUCH)。
-		// 100% 照搬 NIM Duilib:触摸的“点击”正来自这些模拟的 WM_LBUTTONDOWN/UP,
-		// 由 MessageHandler 原生鼠标路径交给 CButtonUI 等控件 Activate() 触发。
-		// 为防止一次手指手势既滚动又点击,仅在 WM_LBUTTON*/WM_MOUSEMOVE 分支加了
-		// `if (m_pEventTouch != NULL) return;` 守卫(手势进行中 m_pEventTouch 非空)。
+		// 触摸的“点击”正来自这些模拟的 WM_LBUTTONDOWN/UP,由原生鼠标路径交给 CButtonUI 等控件
+		// Activate() 触发——而 DuiLib 的点击状态机依赖 WM_LBUTTONDOWN 设置 m_pEventClick,故绝不能
+		// 在鼠标分支吞掉这些模拟消息(之前那样做会导致触摸与鼠标点击全失效)。
+		// 为避免“拖拽=滚动”又“误点按钮”,改用 m_bTouchMoved:若本次手势发生位移,在 WM_LBUTTONUP 抑制点击。
 
 		// Cycle through listeners
 		for (int i = 0; i < m_aMessageFilters.GetSize(); i++)
@@ -1838,8 +1845,6 @@ namespace DuiLib
 			break;
 			case WM_MOUSEMOVE:
 			{
-				// 触屏手势进行中 -> 忽略模拟鼠标移动(NIM 同款守卫)
-				if (m_pEventTouch != NULL) { lRes = 0; return true; }
 				// Start tracking this entire window again...
 				if (!m_bMouseTracking)
 				{
@@ -1979,8 +1984,6 @@ namespace DuiLib
 			break;
 			case WM_LBUTTONDOWN:
 			{
-				// 触屏手势进行中 -> 忽略模拟鼠标,避免“既滚动又点击”双触发(NIM 同款守卫)
-				if (m_pEventTouch != NULL) { lRes = 0; return true; }
 				// We alway set focus back to our app (this helps
 				// when Win32 child windows are placed on the dialog
 				// and we need to remove them on focus change).
@@ -2024,8 +2027,6 @@ namespace DuiLib
 			break;
 			case WM_LBUTTONDBLCLK:
 			{
-				// 触屏手势进行中 -> 忽略模拟鼠标(NIM 同款守卫)
-				if (m_pEventTouch != NULL) { lRes = 0; return true; }
 				if (!m_bNoActivate) ::SetFocus(m_hWndPaint);
 
 				POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
@@ -2048,8 +2049,9 @@ namespace DuiLib
 			break;
 			case WM_LBUTTONUP:
 			{
-				// 触屏手势进行中 -> 忽略模拟鼠标(NIM 同款守卫)
-				if (m_pEventTouch != NULL) { lRes = 0; return true; }
+				// 触屏拖拽手势(已发生位移)-> 松开不触发点击,仅滚动(避免“拖拽又误点”)
+				if (m_bTouchMoved) m_pEventClick = NULL;
+				m_bTouchMoved = false;  // 用完即清,绝不影响后续真实鼠标点击
 				POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
 				m_ptLastMousePos = pt;
 				if (m_pEventClick == NULL) break;

+ 8 - 5
DuiLib/Core/UIManager.h

@@ -516,12 +516,15 @@ namespace DuiLib {
 		bool m_bShowUpdateRect;
 
 		// 触屏状态(库级统一接管后,每个窗口的 CPaintManagerUI 各持一份)
-		// 100% 照搬 NIM Duilib(Window.cpp:1139-1199):用独立成员 m_pEventTouch 追踪“本次触摸命中控件”,
-		// DOWN 时设定、UP 时清空;绝不复用 m_pEventClick(那是鼠标点击状态机专用)。
-		// 按钮点击不在此合成,而是来自 Windows 为触摸自动模拟的 WM_LBUTTONDOWN/UP(见 MessageHandler 的
-		// WM_LBUTTON* 分支)——NIM 从不过滤这些模拟鼠标,仅在鼠标分支加了 m_pEventTouch!=NULL 守卫防止双触发。
-		CControlUI* m_pEventTouch = NULL;   // 本次触摸命中的控件(对应 NIM 的 m_pEventTouch)
+		// 旧 DuiLib 点击状态机依赖:WM_LBUTTONDOWN 设置 m_pEventClick,WM_LBUTTONUP 据此触发点击
+		// (CButtonUI::Activate)。因此【绝不能】在鼠标分支里用 m_pEventTouch 守卫吞掉 Windows 为触摸
+		// 模拟的 WM_LBUTTONDOWN/UP——否则 m_pEventClick 永不被设置,触摸与鼠标点击全失效。
+		// 正确做法:放开模拟鼠标(FROMTOUCH 不过滤),点击自然走原生路径;仅用 m_bTouchMoved 标记
+		// “本次手势是否发生位移”,若位移则松开时不触发点击(避免拖拽=滚动 又 误点按钮)。
+		CControlUI* m_pEventTouch = NULL;   // 本次触摸命中的控件(用于派发 UIEVENT_TOUCHMOVE 做跟手滚动)
 		POINT m_ptLastTouchPos = { 0, 0 };  // 上一包触点:用于去重 + 计算跟手滚动的位移增量
+		POINT m_ptTouchStart = { 0, 0 };    // 本次手势起点:用于判断是否发生位移(拖拽 vs 轻点)
+		bool m_bTouchMoved = false;         // 本次触摸是否发生位移(>阈值视为拖拽),松开时抑制点击
 
 		//
 		CControlUI* m_pRoot;