I'm using a game engine library (AppGameKit) and Qt (5.12.3) in Visual Studio 2017. Normally using the default project template of this engine will build an executable that launches it's own window and handles key and mouse input.
Now I'm trying to tweak this to be used in Qt (embedded in a QWidget
). For now I've managed to do so by passing the HWND
of the QWidget
(QWidget::winId()
) to the game engine initialization function.
My only problem now, is that Qt is handling all input (mouse and keyboard), and I need the game engine to get access to it.
By inspecting the game engine's core code, I see the following WndProc
function:
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;
}
The code in the game engine that normally creates the Win32 window does the following (which is not called in my case since I embed it in a Widget instead):
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);
And at some point creates the window:
HWND hWnd = CreateWindowW(L"OPENGLWINDOW", L"AGK", dwStyle, x, y,
WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top, NULL, NULL, hInstance, NULL);
So I can see what happens to the WndProc
function, but I'm not sure what to do with it to "connect" it to the Qt widget.
Some googling points me too QApplication::installNativeEvent() but it's not really clear how to use it in my case.
EDIT
I tried with installNativeEvent
. So I implemented my own QAbstractNativeEventFilter
as:
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;
}
};
where WndProc
handles keys and mouse input in the game engine.
And in main.cpp
:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
AGK_QT w;
w.show();
a.installNativeEventFilter(new MyEventFilter());
return a.exec();
}
But I'm still not getting any response from keyboard or mouse in the game engine.
The EDIT section in the question is the actual correct answer. It was not working at first, but that was because of a different issue.
So a QAbstractNativeEventFilter
is needed:
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;
}
};
where WndProc
handles keys and mouse input in the game engine.
In the main.cpp
set the event filter to the application:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
AGK_QT w;
w.show();
a.installNativeEventFilter(new MyEventFilter());
return a.exec();
}
As the game engine has it's own loop, I need to call:
qApp->processEvents()
My mistake was that I called qApp->processEvents()
before updating the game engine update function. Switching the order they were called fixed it for me.