|
|
@@ -581,9 +581,22 @@ namespace DuiLib
|
|
|
void CPaintManagerUI::OnTouchInput(WPARAM wParam, LPARAM lParam)
|
|
|
{
|
|
|
// 对照 NIM Duilib 的 Window::HandleMessage case WM_TOUCH(Window.cpp:1139-1199):
|
|
|
- // 解析触点 -> 换算坐标 -> FindControl -> 向控件派发真正的触摸事件。
|
|
|
- // 这里不合成任何鼠标消息:点击由控件自己吃到 TOUCHDOWN/TOUCHUP 后 Activate() 产生,
|
|
|
+ // 解析触点 -> 换算坐标 -> FindControl -> 向控件派发真正的鼠标语义事件。
|
|
|
+ // 这里不合成任何鼠标消息:点击由控件自己吃到 BUTTONDOWN/BUTTONUP 后 Activate() 产生,
|
|
|
// 不经 Windows 消息队列,因此主窗口与模态弹框行为完全一致。
|
|
|
+ //
|
|
|
+ // ★ 关键:触摸的 DOWN/UP 必须 1:1 复用 DuiLib 既有的“鼠标点击状态机”
|
|
|
+ // (CPaintManagerUI::SetCapture / m_pEventClick / ReleaseCapture),
|
|
|
+ // 绝不能用 raw ::SetCapture + 私有 m_pTouchTarget 另搞一套。原因:
|
|
|
+ // 所有控件(CButtonUI/COptionUI/...)的 BUTTONUP 都依赖“当初 BUTTONDOWN 时
|
|
|
+ // 已被 SetCapture 且 m_pEventClick 指向自己”这一前提,才能在抬手时正确 Activate(),
|
|
|
+ // 并把 m_pEventClick 清空、m_bMouseCapture 复位,使下一拍干净。
|
|
|
+ // 之前用 raw ::SetCapture + 私有 m_pTouchTarget,与鼠标状态机失配,导致:
|
|
|
+ // (1) 按下去有 PUSHED 悬浮态、抬起来 BUTTONUP 丢拍 -> 不触发点击;
|
|
|
+ // (2) 下一拍点别的控件时,上一拍残留的按下态才被结算 -> 点击延迟一拍;
|
|
|
+ // (3) 多窗口(主窗 + 模态弹框)下 raw ::SetCapture 的 HWND 归属与 m_pEventClick
|
|
|
+ // 两套状态互相打架,弹框按钮始终收不到完整的 DOWN/UP 周期 -> 全无响应。
|
|
|
+ // 所以这里直接走与 WM_LBUTTONDOWN / WM_LBUTTONUP 完全一致的代码路径。
|
|
|
TouchApi::PFN_GetTouchInputInfo pfnGetInfo = TouchApi::GetGetTouchInputInfo();
|
|
|
if (pfnGetInfo == NULL) return;
|
|
|
|
|
|
@@ -605,6 +618,7 @@ namespace DuiLib
|
|
|
if (ti.dwFlags & TouchApi::TOUCHEVTFLAG_DOWN)
|
|
|
{
|
|
|
m_bTouchDown = true;
|
|
|
+ m_ptTouchDownPos = pt;
|
|
|
m_ptLastTouchPos = pt;
|
|
|
m_ptLastMousePos = pt;
|
|
|
m_moveDistSq = 0;
|
|
|
@@ -614,10 +628,13 @@ namespace DuiLib
|
|
|
if (m_pTouchTarget != NULL && m_pTouchTarget->GetManager() != this)
|
|
|
m_pTouchTarget = NULL;
|
|
|
|
|
|
- ::SetCapture(m_hWndPaint);
|
|
|
-
|
|
|
if (m_pTouchTarget != NULL)
|
|
|
{
|
|
|
+ // —— 复用鼠标点击状态机(与 WM_LBUTTONDOWN 完全一致)——
|
|
|
+ SetCapture(); // mgr:m_bMouseCapture=true + ::SetCapture(hWndPaint)
|
|
|
+ m_pEventClick = m_pTouchTarget; // 点击目标槽,UP 时据此派发 BUTTONUP
|
|
|
+ m_pTouchTarget->SetFocus();
|
|
|
+
|
|
|
TEventUI event = { 0 };
|
|
|
// 归一化:直接派发等价鼠标按下事件,使重写了 DoEvent 的控件(CButtonUI 等)也能原生响应手指。
|
|
|
event.Type = UIEVENT_BUTTONDOWN;
|
|
|
@@ -637,7 +654,11 @@ namespace DuiLib
|
|
|
m_ptLastTouchPos = pt;
|
|
|
m_ptLastMousePos = pt;
|
|
|
|
|
|
- m_moveDistSq += (std::int64_t)dx * dx + (std::int64_t)dy * dy;
|
|
|
+ // tap/drag 判定用“距按下点的净位移平方”,而非逐包位移累加:
|
|
|
+ // 触屏抖动手指会来回小幅移动,累加会让净位移≈0 的轻触被误判成滑动。
|
|
|
+ LONG netDx = pt.x - m_ptTouchDownPos.x;
|
|
|
+ LONG netDy = pt.y - m_ptTouchDownPos.y;
|
|
|
+ m_moveDistSq = (std::int64_t)netDx * netDx + (std::int64_t)netDy * netDy;
|
|
|
if (m_moveDistSq > (std::int64_t)TOUCH_TAP_SLOP * TOUCH_TAP_SLOP)
|
|
|
m_bTouchMoved = true;
|
|
|
|
|
|
@@ -667,31 +688,35 @@ namespace DuiLib
|
|
|
{
|
|
|
if (!m_bTouchDown) continue;
|
|
|
|
|
|
- if (::GetCapture() == m_hWndPaint) ::ReleaseCapture();
|
|
|
-
|
|
|
- // 抬起仍派发给按下时命中的同一个控件(NIM 语义)。
|
|
|
- // 一旦判定为滑动手势,就把触点坐标挪到控件之外的 (-1,-1):
|
|
|
- // 按钮的 UIEVENT_BUTTONUP 分支只在 PtInRect 通过时才 Activate(),
|
|
|
- // 这样既能正常清除 PUSHED/CAPTURED 态,又不会误触发 click。
|
|
|
- POINT ptUp = pt;
|
|
|
- if (m_bTouchMoved)
|
|
|
+ // —— 复用鼠标点击状态机(与 WM_LBUTTONUP 完全一致)——
|
|
|
+ if (m_pEventClick != NULL)
|
|
|
{
|
|
|
- ptUp.x = -1;
|
|
|
- ptUp.y = -1;
|
|
|
- }
|
|
|
+ // 一旦判定为滑动手势,就把触点坐标挪到控件之外的 (-1,-1):
|
|
|
+ // 按钮的 UIEVENT_BUTTONUP 分支只在 PtInRect 通过时才 Activate(),
|
|
|
+ // 这样既能正常清除 PUSHED/CAPTURED 态,又不会误触发 click。
|
|
|
+ POINT ptUp = pt;
|
|
|
+ if (m_bTouchMoved)
|
|
|
+ {
|
|
|
+ ptUp.x = -1;
|
|
|
+ ptUp.y = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ReleaseCapture(); // mgr:m_bMouseCapture=false + ::ReleaseCapture
|
|
|
|
|
|
- if (m_pTouchTarget != NULL)
|
|
|
- {
|
|
|
TEventUI event = { 0 };
|
|
|
// 归一化:直接派发等价鼠标抬起事件(MOVE 仍保持 UIEVENT_TOUCHMOVE 留给 CContainerUI 滚动)。
|
|
|
event.Type = UIEVENT_BUTTONUP;
|
|
|
- event.pSender = m_pTouchTarget;
|
|
|
+ event.pSender = m_pEventClick;
|
|
|
event.ptMouse = ptUp;
|
|
|
event.dwTimestamp = ::GetTickCount();
|
|
|
event.wKeyState = MapKeyState();
|
|
|
- m_pTouchTarget->Event(event);
|
|
|
+
|
|
|
+ CControlUI* pClick = m_pEventClick;
|
|
|
+ m_pEventClick = NULL; // 抬手即清空,保证下一拍干净(消除“点击延迟一拍”)
|
|
|
+ pClick->Event(event);
|
|
|
}
|
|
|
|
|
|
+ // 无论如何复位触摸手势态,避免状态泄漏(如手势被系统取消、未收到 UP 等)
|
|
|
m_bTouchDown = false;
|
|
|
m_pTouchTarget = NULL;
|
|
|
m_moveDistSq = 0;
|