处理自定义 Qt 小部件中的输入事件
Handle input events in custom Qt widget
我在 Visual Studio 2017 年使用游戏引擎库 (AppGameKit) 和 Qt (5.12.3)。通常使用该引擎的默认项目模板将构建一个可执行文件,该文件启动它自己的 window 并处理键和鼠标输入。
现在我正在尝试调整它以便在 Qt 中使用(嵌入在 QWidget
中)。现在,我已经通过将 QWidget
(QWidget::winId()
) 的 HWND
传递给游戏引擎初始化函数来做到这一点。
我现在唯一的问题是 Qt 正在处理所有输入(鼠标和键盘),我需要游戏引擎才能访问它。
通过检查游戏引擎的核心代码,我看到以下WndProc
函数:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
//Lots of input handling
default:
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
return 0;
}
游戏引擎中通常创建 Win32 window 的代码执行以下操作(在我的例子中没有调用,因为我将它嵌入到 Widget 中):
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = hIcon ? (HICON)hIcon : LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"OPENGLWINDOW";
wcex.hIconSm = NULL;
RegisterClassExW(&wcex);
并在某个时候创建 window:
HWND hWnd = CreateWindowW(L"OPENGLWINDOW", L"AGK", dwStyle, x, y,
WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top, NULL, NULL, hInstance, NULL);
所以我可以看到 WndProc
函数发生了什么,但我不确定如何使用它 "connect" 它到 Qt 小部件。
一些谷歌搜索也指向我 QApplication::installNativeEvent() 但我不太清楚如何使用它。
编辑
我试过 installNativeEvent
。所以我将自己的 QAbstractNativeEventFilter
实现为:
class MyEventFilter : public QAbstractNativeEventFilter
{
public:
MyEventFilter(){}
bool nativeEventFilter(const QByteArray &eventType, void *message, long* res) override
{
if (eventType == "windows_generic_MSG") {
res = (long*)WndProc(((MSG*)message)->hwnd, ((MSG*)message)->message, ((MSG*)message)->wParam, ((MSG*)message)->lParam);
}
return false;
}
};
其中 WndProc
处理游戏引擎中的键和鼠标输入。
并且在 main.cpp
中:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
AGK_QT w;
w.show();
a.installNativeEventFilter(new MyEventFilter());
return a.exec();
}
但是我在游戏引擎中仍然没有收到键盘或鼠标的任何响应。
问题中的 EDIT 部分是实际的正确答案。起初它不起作用,但那是因为另一个问题。
所以需要 QAbstractNativeEventFilter
:
class MyEventFilter : public QAbstractNativeEventFilter
{
public:
MyEventFilter(){}
bool nativeEventFilter(const QByteArray &eventType, void *message, long* res) override
{
if (eventType == "windows_generic_MSG") {
res = (long*)WndProc(((MSG*)message)->hwnd, ((MSG*)message)->message, ((MSG*)message)->wParam, ((MSG*)message)->lParam);
}
return false;
}
};
其中 WndProc
处理游戏引擎中的键和鼠标输入。
在 main.cpp
中将事件过滤器设置为应用程序:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
AGK_QT w;
w.show();
a.installNativeEventFilter(new MyEventFilter());
return a.exec();
}
由于游戏引擎有自己的循环,我需要调用:
qApp->processEvents()
我的错误是我在更新游戏引擎更新功能之前调用了qApp->processEvents()
。切换他们被调用的顺序对我来说是固定的。
我在 Visual Studio 2017 年使用游戏引擎库 (AppGameKit) 和 Qt (5.12.3)。通常使用该引擎的默认项目模板将构建一个可执行文件,该文件启动它自己的 window 并处理键和鼠标输入。
现在我正在尝试调整它以便在 Qt 中使用(嵌入在 QWidget
中)。现在,我已经通过将 QWidget
(QWidget::winId()
) 的 HWND
传递给游戏引擎初始化函数来做到这一点。
我现在唯一的问题是 Qt 正在处理所有输入(鼠标和键盘),我需要游戏引擎才能访问它。
通过检查游戏引擎的核心代码,我看到以下WndProc
函数:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
//Lots of input handling
default:
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
return 0;
}
游戏引擎中通常创建 Win32 window 的代码执行以下操作(在我的例子中没有调用,因为我将它嵌入到 Widget 中):
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = hIcon ? (HICON)hIcon : LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"OPENGLWINDOW";
wcex.hIconSm = NULL;
RegisterClassExW(&wcex);
并在某个时候创建 window:
HWND hWnd = CreateWindowW(L"OPENGLWINDOW", L"AGK", dwStyle, x, y,
WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top, NULL, NULL, hInstance, NULL);
所以我可以看到 WndProc
函数发生了什么,但我不确定如何使用它 "connect" 它到 Qt 小部件。
一些谷歌搜索也指向我 QApplication::installNativeEvent() 但我不太清楚如何使用它。
编辑
我试过 installNativeEvent
。所以我将自己的 QAbstractNativeEventFilter
实现为:
class MyEventFilter : public QAbstractNativeEventFilter
{
public:
MyEventFilter(){}
bool nativeEventFilter(const QByteArray &eventType, void *message, long* res) override
{
if (eventType == "windows_generic_MSG") {
res = (long*)WndProc(((MSG*)message)->hwnd, ((MSG*)message)->message, ((MSG*)message)->wParam, ((MSG*)message)->lParam);
}
return false;
}
};
其中 WndProc
处理游戏引擎中的键和鼠标输入。
并且在 main.cpp
中:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
AGK_QT w;
w.show();
a.installNativeEventFilter(new MyEventFilter());
return a.exec();
}
但是我在游戏引擎中仍然没有收到键盘或鼠标的任何响应。
问题中的 EDIT 部分是实际的正确答案。起初它不起作用,但那是因为另一个问题。
所以需要 QAbstractNativeEventFilter
:
class MyEventFilter : public QAbstractNativeEventFilter
{
public:
MyEventFilter(){}
bool nativeEventFilter(const QByteArray &eventType, void *message, long* res) override
{
if (eventType == "windows_generic_MSG") {
res = (long*)WndProc(((MSG*)message)->hwnd, ((MSG*)message)->message, ((MSG*)message)->wParam, ((MSG*)message)->lParam);
}
return false;
}
};
其中 WndProc
处理游戏引擎中的键和鼠标输入。
在 main.cpp
中将事件过滤器设置为应用程序:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
AGK_QT w;
w.show();
a.installNativeEventFilter(new MyEventFilter());
return a.exec();
}
由于游戏引擎有自己的循环,我需要调用:
qApp->processEvents()
我的错误是我在更新游戏引擎更新功能之前调用了qApp->processEvents()
。切换他们被调用的顺序对我来说是固定的。