Related
I have a program (not a DLL) that creates a thread, and in this thread I create a hook using SetWindowsHookExW() to get keyboard events. I also have a global variable that I can use to turn off this thread.
The thing is that I don't know how to release the hooks and continue the function/thread, because it also does some cleanup. When I use UnhookWindowsHookEx() and place breakpoints in the following lines, the breakpoints are never reached.
The example on MSDN is "broken", because it needs an app.h; Also, every tutorial on the Internet, either input systems, keylogger, etc, they talk about DLLs, that I'm not using, and some of them implement a wrapper Unhook function but they never use it.
What I've been trying:
#include <Windows.h>
bool bContinue;
wchar_t vkTecla;
LRESULT CALLBACK KeyboardCallBack(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
vkTecla = ((KBDLLHOOKSTRUCT*)lParam)->vkCode;
if (wParam == WM_KEYDOWN)
{
// Do stuff here
}
// ...
}
if (bContinue)
{
UnhookWindowsHookEx(hHook);
return 0;
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
void MainThread(HANDLE hfile)
{
hHook = SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardCallBack, 0, 0);
MSG msg;
// I tested these 3 cases
/*************/
while(GetMessageW(&msg, 0, 0, 0));
// Or
GetMessageW(&msg, 0, 0, 0);
/*************/
while(GetMessageW(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/*************/
while (bContinue)
{
// PeekMessage(...);
GetMessageW(&msg, 0, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// In this example I would remove the other Unhook function
UnhookWindowsHookEx(hHook);
/*************/
CloseHandle(hfile);
}
If I do the first example, the:
while(GetMessageW(&msg, 0, 0, 0));
and check bContinue inside of the callback function;
or use the third one:
while (bContinue)
{
GetMessageW(&msg, 0, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hHook);
And place a breakpoint in CloseHandle(hArquivo);, when I make the bContinue = false, this line never gets executed.
So the question is:
Where do I place UnhookWindowsHookEx()? Is it inside the Callback function, or somewhere else?
When I release the hook, will the thread continue? Because at the moment, I don't get the program to stop at breakpoints past the unhooking that have some cleanup.
GetMessage() is a blocking function. It will not exit until the message queue of the calling thread has a message available for the caller to process.
But, you are running this code in a worker thread that has no UI of its own. And, although hooks do use messaging internally, they are private to the hook implementation and the caller of (Peek|Get)Message() will never see them. So, unless the other threads in your app are posting messages to this worker thread via PostThreadMessage(), there are simply no messages for GetMessage() to return to your code. That is why your loop doesn't break.
So, you need to either:
use PeekMessage() instead of GetMessage() so you can monitor your bContinue variable in between polls of the message queue:
#include <Windows.h>
bool bContinue = TRUE;
LRESULT CALLBACK KeyboardCallBack(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
wchar_t vkTecla = ((KBDLLHOOKSTRUCT*)lParam)->vkCode;
if (wParam == WM_KEYDOWN)
{
// Do stuff here
}
// ...
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
void MainThread(HANDLE hfile)
{
HHOOK hHook = SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardCallBack, 0, 0);
MSG msg;
while (bContinue)
{
if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
Sleep(10);
}
UnhookWindowsHookEx(hHook);
CloseHandle(hfile);
}
...
// to stop the thread:
bContinue = FALSE;
change bContinue to be a HANDLE returned by CreateEvent(), and then use MsgWaitForMultipleObjects() in a loop to monitor that event and the message queue at the same time, calling (Get|Peek)Message() only when it reports the message queue has messages to process. Then you can use SetEvent() when you want to trigger the loop to end.
#include <Windows.h>
HANDLE hStop = CreateEvent(NULL, TRUE, FALSE, NULL);
LRESULT CALLBACK KeyboardCallBack(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
wchar_t vkTecla = ((KBDLLHOOKSTRUCT*)lParam)->vkCode;
if (wParam == WM_KEYDOWN)
{
// Do stuff here
}
// ...
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
void MainThread(HANDLE hfile)
{
HHOOK hHook = SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardCallBack, 0, 0);
MSG msg;
while (MsgWaitForMultipleObjects(1, &hStop, FALSE, INFINITE, QS_ALLINPUT) == (WAIT_OBJECT_0 + 1))
{
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
UnhookWindowsHookEx(hHook);
CloseHandle(hfile);
}
...
// to stop the thread:
SetEvent(hStop);
I create a window and message loop in the child thread.
When I sent a custom message through PostMessage, when I called DestroyWindow in the thread, DestroyWindow blocked and did not trigger WM_DESTORY, so the message loop thread cannot exit normally.
I tried PostThreadMessage, In addition, I tried to use closewindow. But the problem is that WM_DESTORY is not triggered after calling DestroyWindow, not the PostMessage.
Message loop thread is still running and window handle is valid, why? I worked hard for a few days and couldn't find the reason, thank you very much.
Destroy window:
#define WM_QUIT_MSG_LOOP (WM_USER+8600)
mfxStatus CD3D11Device::DeleteRenderChildWindow()
{
LOG(LS_INFO) << "Intel D3D11Render, Enter DeleteRenderChildWindow, HWND:" << m_hChildHwnd;
//SetParent(m_hChildHwnd, NULL);
if (m_hChildHwnd){
LOG(LS_WARNING) << "Intel D3D11Render, DeleteRenderChildWindow, HWND:" << m_hChildHwnd;
PostMessage(m_hChildHwnd, WM_QUIT_MSG_LOOP, NULL, NULL);
}
if(m_pChildWindowMsgThread)
m_pChildWindowMsgThread->Wait();
MSDK_SAFE_DELETE(m_pChildWindowMsgThread);
MSDK_SAFE_DELETE(m_pCreateFinishEvent);
LOG(LS_INFO) << "Intel D3D11Render, Leave DeleteRenderChildWindow, HWND:" << m_hChildHwnd;
return MFX_ERR_NONE;
}
Create window:
LRESULT CALLBACK CD3D11Device::ChildRenderMsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
LRESULT lResult = 0;
switch (uMsg) {
case WM_DESTROY: {
LOG(LS_WARNING) << "Intel D3D11Render ChildRenderMsgProc, PostQuitMessage, HWND:" << hwnd;
PostQuitMessage(0);
break;
}
case WM_SETCURSOR: {
break;
}
default:
lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
break;
}
return lResult;
}
HWND CD3D11Device::ThreadCreateChildWindow(){
HMODULE hInstance = nullptr;
BOOL result =
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<char*>(&DefWindowProc), &hInstance);
if (!result) {
LOG(LS_ERROR) << "[ThreadCreateChildWindow]GetModuleHandleExA failed.";
return 0;
}
// Register the host window class. See the MSDN documentation of the
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = &ChildRenderMsgProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.lpszClassName = _T("Render Window Class");
//wcex.style |= CS_HREDRAW | CS_VREDRAW &~WS_CAPTION &~WS_SYSMENU;
// Ignore the error which may happen when the class is already registered.
RegisterClassExW(&wcex);
RECT rcClient = { 0 };
GetWindowRect(m_HandleWindow, &rcClient);
// Create the host window.
HWND hChildWindow =
CreateWindowW(_T("Render Window Class"), _T("MiniRender"), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 0,
0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, m_HandleWindow, nullptr, hInstance, nullptr);
if (!hChildWindow) {
LOG(LS_ERROR) << "[ThreadCreateChildWindow]Create child window failed.";
return 0;
}
ShowWindow(hChildWindow, SW_SHOW);
SetRenderChildHwnd(hChildWindow);
m_pCreateFinishEvent->Signal();
LOG(LS_WARNING) << "Intel D3D11Render, ThreadCreateChildWindow, HWND:" << hChildWindow;
return hChildWindow;
}
Message loop thread:
unsigned int CD3D11Device::ChildWindowMsgThread(void* ctx){
CD3D11Device* pD3D11Device = static_cast<CD3D11Device*>(ctx);
HWND hChildWindow = NULL;
if (pD3D11Device) {
hChildWindow = pD3D11Device->ThreadCreateChildWindow();
}
if (hChildWindow == NULL){
return 0;
}
MSG msg;
BOOL result;
while ((result = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (result == -1) {
LOG(LS_ERROR) << "Intel D3D11Render, ChildWindowMsgThread, GetMessage failed, HWND:" << hChildWindow;
continue;
}
if (msg.message == WM_QUIT_MSG_LOOP) {
LOG(LS_WARNING) << "Intel D3D11Render, ChildWindowMsgThread, recv WM_QUIT_MSG_LOOP, HWND:" << hChildWindow;
//It's blocking up here
DestroyWindow(hChildWindow);
}
else {
PostMessage(pD3D11Device->GetParentHwnd(), msg.message, msg.wParam, msg.lParam);
}
LOG(LS_WARNING) << "Intel D3D11Render, ChildWindowMsgThread, GetMessageing, HWND:" << hChildWindow;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
A window has a thread affinity. Only the thread that created the window can destroy the window (and receive and dispatch messages for the window). This is clearly stated in the documentation:
A thread cannot use DestroyWindow to destroy a window created by a different thread.
I am using win32 API to develop an Application.I am using WM_LBUTTONDOWN message to handle two operation .
If a click on button X I want to perform operation A.
a)If a double click occur on button X I want to perform operation C as well
that is operation A
followed by operation C.
But while implementing I can either perform operation Aor operation C.
case WM_LBUTTONDOWN:
{
overallClicks++;
left1.x = LOWORD(lParam);
left1.y = HIWORD(lParam);
wsprintf(waCoord, _T("my coordinates are (%i,%i)"), left1.x, left1.y);
if (click_count == 0)
{
SetTimer(hWnd, TIMER_ID, GetDoubleClickTime(), NULL);
}
click_count++;
if (fun()) {
//do something
}
else {
MessageBox(NULL, _T("yo"), _T("yo"), MB_OK);
}
return 0;
// dwLastClickTime= GetMessageTime();
//SetTimer(hWnd,0,GetDoubleClickTime(),0);
//break;
// handleDoubleClicks(hWnd, message, wParam, lParam, ptLastClickPos, dwLastClickTime);
}
case WM_TIMER:
{
HandleTimer(hWnd, message, wParam, lParam);
}
LRESULT HandleTimer(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
BOOL i = KillTimer(hWnd, TIMER_ID);
if (click_count == 1)
{
// wchar_t* ptr = ;
MessageBox(hWnd, waCoord, _T("Left mouse button click"), MB_OK);
}
else if (click_count == 2)
{
MessageBox(hWnd, waCoord, TEXT("I appear when double clicked"), MB_OKCANCEL);
}
else if (click_count == 3)
{
MessageBox(hWnd, waCoord, TEXT("I appear when triple clicked"), MB_OKCANCEL);
}
else if (click_count > 3) {
MessageBox(hWnd, waCoord, TEXT("I appear when rage clicked"), MB_OKCANCEL);
}
click_count = 0;
return 0;
}
I would like elaborate for example I am double clicking on disabled button I want to show pop up that I have double clicked as well as that button is disabled.
With the help of an answer from your previous case.
Because your code logic uses if...else... conditional statements. The way I can think of is to add an additional timer in the case of double-click to complete the action when clicked.
void CALLBACK f(HWND hwnd, UINT uMsg, UINT timerId, DWORD dwTime)
{
EnableWindow(hwndButton, 0);
}
...
LRESULT CALLBACK OwnerDrawButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_TIMER:
{
KillTimer(hWnd, TIMER_ID);
if (click_count == 1)
{
wchar_t waCoord[20];
wsprintf(waCoord, _T("(%i,%i)"), point.x, point.y);
MessageBox(hWnd, waCoord, _T("Left mouse button click"), MB_OK);
SetTimer(NULL, 0, 100, (TIMERPROC)&f);
}
else if (click_count == 2)
{
SetTimer(NULL, 0, 100, (TIMERPROC)&f);
MessageBox(hWnd, TEXT("Double click"), TEXT("I appear when double clicked"), MB_OKCANCEL);
}
click_count = 0;
return 0;
}
break;
case WM_LBUTTONDOWN:
{
if (click_count == 0)
{
SetTimer(hWnd, TIMER_ID, GetDoubleClickTime(), NULL);
}
click_count++;
return 0;
}
break;
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, &OwnerDrawButtonProc, 1);
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
Remove the CS_DBLCLKS style when using the button control.
Updated:
Because the button is disabled, I'm sorry I didn't see this. In this way, the message of the parent window can only be used to determine whether the mouse coordinates are within the range of the button. If it is, double-click to perform operation C.
Only need to modify part of the code of the parent window:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static RECT rc;
static POINT pt = { 0 };
rc.left = 10;
rc.top = 10;
rc.right = 110;
rc.bottom = 110;
switch (message)
{
case WM_CREATE:
{
hwndButton = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"OK", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON , // Styles
10, // x position
10, // y position
100, // Button width
100, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
NULL); // Pointer not needed.
DWORD class_style = GetClassLongPtr(hwndButton, GCL_STYLE);
SetClassLongPtr(hwndButton, GCL_STYLE, class_style & (~CS_DBLCLKS));
SetWindowSubclass(hwndButton, &OwnerDrawButtonProc, IDC_OWNERDRAWBUTTON, 0);
return TRUE;
}
case WM_TIMER:
{
KillTimer(hWnd, TIMER_ID);
if (click_count == 2)
{
MessageBox(hWnd, TEXT("Double click"), TEXT("I appear when double clicked"), MB_OKCANCEL);
}
click_count = 0;
return 0;
}
case WM_LBUTTONDOWN:
{
POINT p;
p.x = GET_X_LPARAM(lParam);
p.y = GET_Y_LPARAM(lParam);
if (PtInRect(&rc, p))
{
pt = p;
if (click_count == 0)
{
SetTimer(hWnd, TIMER_ID, GetDoubleClickTime(), NULL);
}
click_count++;
}
return 0;
}
...
Debug:
So basically I have this program that makes a transparent overlay for a game so I can make a kill counter. However, when I click on the game with the overlay on, nothing happens. I managed to make it so when you click on it then it sends a message to the game telling it to shoot, however, when I tried the same for moving my characters head it was just laggy and snappy. When I would move my head quickly, my cursor would also fly out of the game window. How can I fix this so when I play the game it would be like its not even there.
I have tried sending the message and setting the window active AND using setcapture. However, none of these worked. I have tried looking at other places but they didn't work either.
/* This is my while(true) loop: */
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
break;
}
TranslateMessage(&msg); // translates virtual-key messages into character messages
DispatchMessage(&msg); // dispatches a message to WindowProc
}
if (gameProcId == 0)
{
gameProcId = GetProcId(L"ac_client.exe");
}
if (gameWnd == NULL)
{
gameWnd = FindWindow(NULL, L"AssaultCube");
}
if ((gameProc == NULL) && (gameProcId != 0))
{
gameProc = OpenProcess(PROCESS_VM_READ, false, gameProcId); // opens an existing local process and returns a handle to it
}
if (gameProc != NULL)
{
if ((!init_ok) || ((loops % 20) == 0))
{
RECT client_rect;
#pragma warning (suppress: 6387)
GetClientRect(gameWnd, &client_rect); // gets a windows coordinates, upper-left corner is (0,0)
w_res.X = client_rect.right;
w_res.Y = client_rect.bottom;
RECT bounding_rect;
#pragma warning (suppress: 6387)
GetWindowRect(gameWnd, &bounding_rect); // gets dimensions of a window
if (!init_ok)
{
if ((w_pos.X != bounding_rect.left) || (w_pos.Y != bounding_rect.top))
{
MoveWindow(hWnd, bounding_rect.left, bounding_rect.top,
client_rect.right, client_rect.bottom, false);
w_pos.X = bounding_rect.left;
w_pos.Y = bounding_rect.top;
}
//SetCursorPos(w_pos.X * 4, w_pos.Y * 4);
//ClipCursor(&gameRect);
}
else
{
if ((bounding_rect.left == 0) && (bounding_rect.top == 0))
{
MoveWindow(hWnd, bounding_rect.left, bounding_rect.top, // changes both the position and dimension of a window
client_rect.right, client_rect.bottom, false);
}
MoveWindow(hWnd, bounding_rect.left, bounding_rect.top, client_rect.right,
client_rect.bottom, false);
}
init_ok = true;
}
}
if (loops % 10 == 0)
{
if (FindWindow(NULL, L"AssaultCube") == NULL)
{
SendMessage(hWnd, WM_CLOSE, NULL, NULL); // calls WindowProc() and sends the message to a window
}
}
loops++;
if (loops > 100) loops = 0;
Render();
}
}
/* This is my WindowProc() function: */
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}break;
case WM_LBUTTONDOWN:
{
PostMessage(gameWnd, message, wParam, lParam);
return 0;
}
case WM_MOUSEMOVE:
{
SendMessage(gameWnd, message, wParam, lParam);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
You didn't post enough code to attempt to solve this problem, we don't see your call to CreateWindowEx().
Here is a working solution for a win32 overlay:
#include <iostream>
#include <windows.h>
using namespace std;
//global forward declerations
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void cleanUpObjects(HPEN pen);
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
RECT overlayWindowRect;
RECT gameWindowRect;
HWND gameWindowHandle;
gameWindowHandle = FindWindowA(0, "AssaultCube");
GetWindowRect(gameWindowHandle, &gameWindowRect);
WNDCLASSEX w;
w.cbSize = sizeof(WNDCLASSEX);
w.style = CS_HREDRAW | CS_VREDRAW;
w.lpfnWndProc = WndProc;
w.cbClsExtra = 0;
w.cbWndExtra = 0;
w.hInstance = hInstance;
w.hIcon = NULL;
w.hCursor = NULL;
w.hbrBackground = (HBRUSH)0;
w.lpszMenuName = NULL;
w.lpszClassName = "ClassName";
w.hIconSm = NULL;
if (!RegisterClassEx(&w))
{
MessageBox(NULL, "Could not Register Class", "Window Title", NULL);
return -1;
}
HWND hWnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT, "ClassName", "Window",
WS_CAPTION,
gameWindowRect.left, //x
gameWindowRect.top, // y
gameWindowRect.right - gameWindowRect.left, // width
gameWindowRect.bottom - gameWindowRect.top, // height
NULL, NULL,
hInstance, NULL);
if (!hWnd)
{
MessageBox(NULL, "Call to create window failed", "Win32 Guided tour", NULL);
return -1;
}
else
{
GetWindowRect(hWnd, &overlayWindowRect);
}
// Remove Borders around window
SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~(WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_BORDER));
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) & ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
// Make the Background Transparent
SetLayeredWindowAttributes(hWnd, RGB(255, 255, 255), 255, LWA_COLORKEY); // Replaces color white with transparancey
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
HDC myHDC = GetDC(hWnd);
// Drawing Stuff
HPEN myPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
HPEN originalPen;
originalPen = (HPEN)SelectObject(myHDC, myPen);
//main loop waits for messages
MSG msg;
while (true)
{
//peekmessage allows for program to do multiple things at once. faster than getmessage()
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
// if msg is quit, quit
if (msg.message == WM_QUIT)
break;
}
else
{
Rectangle(myHDC, 200, 200, 300, 400);
ZeroMemory(&gameWindowRect, sizeof(gameWindowRect)); //clear out the struct
GetWindowRect(gameWindowHandle, &gameWindowRect); // retrieves the games xy and height width and stores in gamewindowrect
if (gameWindowRect.right != overlayWindowRect.right) // checks if the x coordinates are the same
{
ZeroMemory(&gameWindowRect, sizeof(gameWindowRect)); // clear out struct once again
GetWindowRect(gameWindowHandle, &gameWindowRect); // get the dimensions of the game window again
MoveWindow(hWnd, gameWindowRect.left, gameWindowRect.top, gameWindowRect.right - gameWindowRect.left, gameWindowRect.bottom - gameWindowRect.top, TRUE);
// moves window to specific spot
}
}
Sleep(5);
}
cleanUpObjects(myPen);
cleanUpObjects(originalPen);
return msg.wParam;
}
LRESULT CALLBACK WndProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
PAINTSTRUCT ps;
HDC hdc;
switch (uMsg)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
DestroyWindow(hWnd);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
break;
}
return 0;
}
//cleans up objects
void cleanUpObjects(HPEN pen)
{
DeleteObject(pen);
}
I have created WinAPI windows for my rendering application. I am using raw input for keyboard and mouse.
The problem is, I have added 3rd party GUI to get inputs from user (like load models etc.). Mouse is working (I can click on buttons etc.), but keyboard not. If I put focus on edit box and start writing, nothing appears and key strokes are lost in focused GUI. However, the main window is still processing them and e.g. camera is moving around.
If I click into some other window, like web browser, all is behaving as it should.
My WinAPI window is inited like this:
bool Form::InitWnd(HINSTANCE instance){
WNDCLASS window_class;
window_class.style = CS_OWNDC;
window_class.cbClsExtra = 0;
window_class.cbWndExtra = 0;
window_class.hInstance = instance;
window_class.hIcon = LoadIcon(NULL,IDI_APPLICATION);
window_class.hCursor = LoadCursor(NULL,IDC_ARROW);
window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
window_class.lpszMenuName = NULL;
window_class.lpszClassName = this->name.c_str();
window_class.lpfnWndProc = &Form::MainWndProc;
if (!RegisterClass(&window_class)) return false;
this->mainWindowHandle = CreateWindow(this->name.c_str(),
L"Caption", //caption
this->style, //style flags
this->positionX, //x pos
this->positionY, //y pos
this->width,
this->height,
NULL, //parent window
NULL, //menu
this->instance,
this); //pointer to window creation data
if (this->mainWindowHandle == 0) return false;
this->engineCore->InitWindow(this->mainWindowHandle);
return true;
}
LRESULT CALLBACK Form::MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
static Form* me = 0;
switch ( msg ){
case WM_CREATE:
me = (Form*)((CREATESTRUCT*)lParam)->lpCreateParams;
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_INPUT:
if (me) me->engineCore->UpdateInput(lParam);
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int Form::Run(int cmd){
ShowWindow(this->mainWindowHandle, cmd);
UpdateWindow(this->mainWindowHandle);
MSG msg = {0};
while ( true ){
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){
if (msg.message == WM_QUIT) break;
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else {
engineCore->RunMainEngineLoop();
}
}
return (int)msg.wParam;
}
And keyboard is processed:
//Register
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = 0x01;
Rid[0].usUsage = DEVICE_KEYBOARD;
Rid[0].dwFlags = RIDEV_NOLEGACY;
Rid[0].hwndTarget = windowHandle;
if (RegisterRawInputDevices(Rid, count, sizeof(Rid[0])) == FALSE){
MY_LOG_ERROR("Failed to register device");
}
//Update loop
UINT dwSize;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
BYTE * lpb = new BYTE[dwSize];
if (lpb == NULL){
return 0;
}
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize){
SAFE_DELETE_ARRAY(lpb);
return 0;
}
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEKEYBOARD){
//process keys
}
SAFE_DELETE_ARRAY(lpb);
Similar code is used for mouse