|
|
@@ -34,6 +34,17 @@ void CTouchWindowBase::AddTouchSample(LONG y)
|
|
|
m_samples.pop_front();
|
|
|
}
|
|
|
|
|
|
+void CTouchWindowBase::SynthesizeTap(HWND target, POINT pt)
|
|
|
+{
|
|
|
+ if (!target || !::IsWindow(target))
|
|
|
+ return;
|
|
|
+ LPARAM lParamPos = MAKELPARAM(pt.x, pt.y);
|
|
|
+ // 模拟一次完整的“轻触点击”。注意:这两条消息由 PostMessage 发出,ExtraInfo=0,
|
|
|
+ // 不带 MOUSEEVENTF_FROMTOUCH,因此会被 DuiLib 当作真实鼠标点击正常处理。
|
|
|
+ ::PostMessage(target, WM_LBUTTONDOWN, MK_LBUTTON, lParamPos);
|
|
|
+ ::PostMessage(target, WM_LBUTTONUP, 0, lParamPos);
|
|
|
+}
|
|
|
+
|
|
|
void CTouchWindowBase::StartInertia(float velocityPxPerMs)
|
|
|
{
|
|
|
if (m_inertiaActive)
|
|
|
@@ -68,8 +79,19 @@ LRESULT CTouchWindowBase::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
switch (uMsg)
|
|
|
{
|
|
|
case WM_CREATE:
|
|
|
- // 注册接收触摸(移除:由外部窗口统一注册,避免重复注册)
|
|
|
- // ::RegisterTouchWindow(m_hWnd, 0);
|
|
|
+ // 注册接收 WM_TOUCH。所有继承本类的窗口(主窗口、各种模态框)都会自动生效,
|
|
|
+ // 避免“主窗口能滑、弹框不能滑”的不一致。
|
|
|
+ ::RegisterTouchWindow(m_hWnd, 0);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case WM_LBUTTONDOWN:
|
|
|
+ case WM_LBUTTONUP:
|
|
|
+ case WM_LBUTTONDBLCLK:
|
|
|
+ // 关键修复:过滤 Windows 为触屏“模拟”出来的鼠标消息(带 MOUSEEVENTF_FROMTOUCH)。
|
|
|
+ // 否则手指在列表上滑动/轻触都会被当成真实鼠标点击 —— 这正是“滑动误触加入购物车”的根因。
|
|
|
+ // 真实鼠标的 ExtraInfo 不带该标记,因此不影响鼠标操作(含调试鼠标)。
|
|
|
+ if ((::GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH)
|
|
|
+ return 0;
|
|
|
break;
|
|
|
|
|
|
case WM_TOUCH:
|
|
|
@@ -96,11 +118,18 @@ LRESULT CTouchWindowBase::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
StopInertia();
|
|
|
|
|
|
m_touchDown = true;
|
|
|
+ m_lastX = pt.x;
|
|
|
m_lastY = pt.y;
|
|
|
m_accumWheel = 0;
|
|
|
m_samples.clear();
|
|
|
AddTouchSample(pt.y);
|
|
|
|
|
|
+ // 轻触/滑动判定初始化
|
|
|
+ m_touchStartPt = pt;
|
|
|
+ m_touchStartTime = NowMs();
|
|
|
+ m_bTouchMoved = false;
|
|
|
+ m_moveDistSq = 0;
|
|
|
+
|
|
|
// 保存最后触摸点(用于惯性期间发送位置)
|
|
|
m_lastTouchPt = pt;
|
|
|
|
|
|
@@ -112,9 +141,16 @@ LRESULT CTouchWindowBase::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
{
|
|
|
if (m_touchDown)
|
|
|
{
|
|
|
+ LONG dx = pt.x - m_lastX;
|
|
|
LONG dy = pt.y - m_lastY; // 按手机习惯:手指上滑(坐标减小) -> 负增量
|
|
|
+ m_lastX = pt.x;
|
|
|
m_lastY = pt.y;
|
|
|
|
|
|
+ // 累计移动距离平方,用于“轻触 vs 滑动”判定
|
|
|
+ m_moveDistSq += (std::int64_t)dx * dx + (std::int64_t)dy * dy;
|
|
|
+ if (m_moveDistSq > (std::int64_t)TAP_MOVE_THRESHOLD * TAP_MOVE_THRESHOLD)
|
|
|
+ m_bTouchMoved = true;
|
|
|
+
|
|
|
AddTouchSample(pt.y);
|
|
|
|
|
|
int wheelUnits = static_cast<int>(dy * PIXEL_TO_WHEEL);
|
|
|
@@ -160,6 +196,7 @@ LRESULT CTouchWindowBase::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
m_touchDown = false;
|
|
|
// 保存最后触摸点(确保惯性期间有位置可用)
|
|
|
m_lastTouchPt = pt;
|
|
|
+ m_lastX = 0;
|
|
|
m_lastY = 0;
|
|
|
m_accumWheel = 0;
|
|
|
m_samples.clear();
|
|
|
@@ -167,6 +204,14 @@ LRESULT CTouchWindowBase::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
//::PostMessage(target, WM_LBUTTONUP, 0, MAKELPARAM(pt.x, pt.y));
|
|
|
::ReleaseCapture();
|
|
|
|
|
|
+ // 关键修复(误触):本次触摸没有发生“滑动”才视为“轻触点击”,
|
|
|
+ // 模拟一次 down+up,让 DuiLib 正常触发 click(如点商品加入购物车)。
|
|
|
+ // 若发生过滑动,则只滚动、绝不触发点击,从而彻底避免误触。
|
|
|
+ if (!m_bTouchMoved)
|
|
|
+ {
|
|
|
+ SynthesizeTap(target, m_touchStartPt);
|
|
|
+ }
|
|
|
+
|
|
|
// 启动惯性滚动(如果速度足够大)
|
|
|
StartInertia(velocityPxPerMs);
|
|
|
}
|