Unity, setWindowsHook и многопоточность для независимой от кадров системы ввода в Windows - PullRequest
2 голосов
/ 24 апреля 2019

Я хочу создать независимую от фреймов систему сенсорного ввода, чтобы в Unity можно было получать события касаний непосредственно из Windows.

То, что я сделал, это:

=> Введите код C ++ для настройки Windows Hook на глобальное сообщение WM-Touch . (Используя SetWindowsHookEx с идентификатором потока = 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 );
}


=> Создать DLL_Interface Singleton класс, используя C # для инкапсуляции функций из 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 # , инициализация Hook in loop_thread с использованием функций из скомпилированной ранее библиотеки DLL (функция инициализации 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 извлекает событие касания на частоте 250 Гц из DLL (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 и потянул сенсорный вход с частотой 250 Гц в качестве частоты, скорость сенсорного ввода по-прежнему ограничена частотой обновления кадров Unity .

Частота обновления Unity составляет 30 Гц, сенсорный ввод также ограничен частотой 30 Гц

Частота обновления Unity составляет 60 Гц, сенсорный ввод также ограничен частотой 60 Гц

Почему хук, инициализированный в loop_thread, ограничен частотой кадров основного потока Unity?

У меня есть несколько подозреваемых:

=> RegisterTouchWindow функция ожидает ответа основного потока Unity перед отправкой сообщения WM-Touch, поэтому я не могу обойти частоту обновления кадров Unity с помощью этой функции.

=> Функция SetWindowHookEx каким-то образом внедряет код для фильтрации сообщений в основной поток Unity, поэтому она ограничена частотой кадров основного потока Unity. (In документация указано, что: "система выполняет перехват в контексте перехватывающего приложения; в частности, в потоке, который вызвал SetWindowsHookEx")

=> Вызов функции инициализации ловушки из DLL в loop_thread устанавливает ловушку не на loop_thread, а на основной поток вызывающего (в данном случае основной поток Unity?).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...