我找不到如何在 windows phone 8 应用程序中处理多点触控的示例(在 c++ 和 directx 上的游戏中)。可能有人可以帮助我吗?谢谢!
2 回答
我想出了怎么做。我是一个 C++ 新手,所以可能有更好的方法来做到这一点,但我的方法有效。
(仅供参考 - 我在诺基亚的开发者网站上写了一篇关于此的文章:http: //developer.nokia.com/Community/Wiki/Multi-touch_handling_using_DirectX_C%2B%2B#PointerPoint)
您需要跟踪 PointerPoint 内的 PointerId。我将 PointerId 存储在 std::unordered_map 中的 OnPointerPressed 事件中。键(无符号整数)是 PointerId。然后,当您收到 OnPointerReleased 事件时,您将它们从地图中删除。PointerId 将匹配。事实证明,对于每一个新手指,您都会获得一个新的 PointerId……即使您松开第一根手指并再次放下它。
然后,当您到达 OnPointerMoved 事件处理程序时,您只需调用 unordered_map 上的 size() 函数即可了解您当前在屏幕上进行了多少次触摸。
我使用 unordered_map 的原因是因为我需要跟踪以前的点位置。我意识到您可能可以使用 GetIntermediatePoints 方法获得旧职位,但我不想对新事物进行故障排除......
无论如何,希望这会有所帮助。下面的代码:
编辑:更新代码以处理您从每帧的每次触摸中获得的 x 移动事件。就像我说的,这不是最好的,但它有效。
#include <unordered_map>
std::unordered_map<unsigned int, Windows::UI::Input::PointerPoint^> m_pointerIds;
std::unordered_map<unsigned int, Windows::UI::Input::PointerPoint^> m_oldPoints;
void Direct3DBackground::OnPointerPressed(DrawingSurfaceManipulationHost^ sender, PointerEventArgs^ args)
{
m_pointerIds.emplace(args->CurrentPoint->PointerId, args->CurrentPoint);
m_oldPoints.emplace(args->CurrentPoint->PointerId, args->CurrentPoint);
}
void Direct3DBackground::OnPointerMoved(DrawingSurfaceManipulationHost^ sender, PointerEventArgs^ args)
{
if (m_pointerIds.size() == 1)
{
DoSomethingForOneTouch(args);
}
else if (m_pointerIds.size() == 2)
{
UINT changedPointId = args->CurrentPoint->PointerId;
UINT frameId = args->CurrentPoint->FrameId;
UINT otherPointId;
for (auto it = m_pointerIds.begin(); it != m_pointerIds.end(); ++it)
{
if (it->first != changedPointId)
{
otherPointId = it->first;
break;
}
}
m_oldPoints[changedPointId] = m_pointerIds[changedPointId];
m_pointerIds[changedPointId] = args->CurrentPoint;
if (m_pointerIds[otherPointId]->FrameId == frameId)
{
//DO YOUR CALCULATION using new points and old points
//as both touches have been updated for the current frame.
}
}
}
void Direct3DBackground::OnPointerReleased(DrawingSurfaceManipulationHost^ sender, PointerEventArgs^ args)
{
m_pointerIds.erase(args->CurrentPoint->PointerId);
m_oldPoints.erase(args->CurrentPoint->PointerId);
}
上面的代码很好地展示了这个想法,但是即使在实践中也看不到背后的一些关键细节。OnPointerPressed
事件来自由 UI 线程处理的消息队列。而 OnPointerMoved
从另一个线程调用事件NPCtrl.dll!CDirectManipulationServer::ServerThreadStatic
。从 VS 中的本机调试器可以很容易地看出这一点。这是两个线程之间的竞争条件的开放领域,正如我的测试所示,在这种特殊情况下实际上确实发生了这种情况。所以很明显,这段代码需要用同步模式来改进,比如
void Direct3DBackground::OnPointerPressed(DrawingSurfaceManipulationHost^ sender, PointerEventArgs^ args)
{
std::unique_lock<std::mutex> l(eventLock);
m_pointerIds.emplace(args->CurrentPoint->PointerId, args->CurrentPoint);
m_oldPoints.emplace(args->CurrentPoint->PointerId, args->CurrentPoint);
}
eventLock
在哪里std::mutex
。应该为所有三个事件添加相同的锁。另一种方法更复杂,并且会涉及一个并发队列,每当触发新事件时都会添加该队列。