我想在Unity中实现独立于框架的触摸输入系统,以直接从Windows获取触摸事件。
我所做的是:
=>编写 C ++ 代码以在全局WM-Touch消息上设置Windows Hook。 (使用SetWindowsHookEx,并将线程ID = 0用于全局消息),将其编译为 DLL 。
void DLL_initialize_hook(IntPtr window_handler)
{
// <g_hInst> is the DLL handler
// <HookProcPosted> and <HookProcCalled> are the functions
// to filter and manage touch messages
SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)HookProcPosted, g_hInst, 0);
SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)HookProcCalled, g_hInst, 0);
//register touch window to receive touch data as WM-Touch
int fine_touch = 1;
RegisterTouchWindow(window_handler, fine_touch );
}
=>使用 C# 创建 DLL_Interface Singleton 类以封装DLL中的函数。
void StartHook(IntPtr unity_window_handler )
{
DLL_initialize_hook(unity_window_handler );
}
Touch[] getAllTouchData()
{
//Actually there are more steps than just calling 2 function
//that's why i wraped it
TouchData[] data = DLL_getTouchData()
return ConvertAllData(data );
}
=>在 中创建 新线程 (将其命名为 loop_thread ) Unity 使用 C# , 使用DLL中的函数初始化Hook in loop_thread 以前编译过的(DLL初始化函数需要Unity窗口处理程序将其注册为触摸窗口:RegisterTouchWindow)
//the function to run in the thread
void Thread_run()
{
Thread_Initialize();
Thread_Loop();
}
void Thread_Initialize()
{
DLL_Interface.StarHook(unity_window_handler);
}
=> loop_thread从DLL以250Hz的频率拉动触摸事件(DLL仅输出新数据)
void Thread_Loop()
{
while(running)
{
//Get the Touche data using a function from singleton interface
List<Touch> touches = DLL_Interface.Instance.getAllTouchData();
//Conversion and put the data available for Unity in a thread safe way
ManageTheTouches(touches);
//Wait next pull
Thread.sleep(sleep_time)
}
}
我想要的是 接收触摸输入,而不受Unity框架更新速率的限制 。
即使我 为 loop_thread 上的触摸消息初始化了一个全局钩子 ,并使用250Hz作为频率, 触摸输入速率仍然受到Unity帧更新速率的限制 。
Unity update rate is 30 Hz, touch input also limited at 30 Hz
Unity update rate is 60 Hz, touch input also limited at 60 Hz
为什么在loop_thread上初始化的Hook受Unity主线程的帧速率限制?
我有几个嫌疑犯:
=> RegisterTouchWindow 函数在发送WM-Touch消息之前正在等待Unity主线程的响应,这就是为什么我不能使用此函数绕过Unity的帧更新速率。
=> SetWindowHookEx 函数以某种方式注入代码以将消息过滤到Unity的主线程中,因此受Unity的主线程的帧速率限制。(在 文档 指出:“系统在挂钩应用程序的上下文中执行挂钩;特别是在名为SetWindowsHookEx的线程上执行)”
=>从loop_thread中的DLL调用钩子初始化函数不会将钩子安装在loop_thread上,而是安装在调用者的主线程(在本例中是Unity主线程?)上。