I've read everywhere that using windows messages is preferable to DirectInput. Despite this, there are many DirectInput tutorials and barely any for dealing with keyboard in Windows messaging. After not finding any good sources, I began to try it on my own.
I made two 256 member bool arrays to hold if keys were pressed. I want to make it so that I can look at m_bKeyDown[256] to see if a key was pressed this frame, and m_bKeyDown to see if it is being held down, but not pressed this frame. My MsgProc switch statement is as follows:
LRESULT D3DApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch(msg){
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_KEYDOWN:
if(m_bKeyPressed[wParam])
m_bKeyDown[wParam] = false;
else
m_bKeyDown[wParam] = true;
break;
m_bKeyPressed[wParam] = true;
case WM_KEYUP:
m_bKeyDown[wParam] = false;
m_bKeyPressed[wParam] = false;
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
I tested it by having it make a sound when I held down the F1 key. Ideally the sound should not repeat until I release the button and press it again:
if(m_bKeyDown[VK_F1])
m_fMod.FPlaySound(testSound);
There seems to be no difference though, the sound repeats when I hold down the button. How do I fix the loop or set up Windows messaging to do this? Am I on the right track or should I go a completely different direction?
Edit: I used iedoc's below example and now it does better, but the sound still plays three times before stopping, like there is a delay for some reason. Any idea how to avoid this?
try this:
LRESULT D3DApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch(msg){
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_KEYDOWN:
if(!m_bKeyPressed[wParam])
{
m_bKeyDown[wParam] = true;
m_bKeyPressed[wParam] = true;
}
else
m_bKeyDown[wParam] = false;
break;
case WM_KEYUP:
m_bKeyDown[wParam] = false;
m_bKeyPressed[wParam] = false;
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
Related
I am making an program and would like to have my program restarted when a person tries to resize the screen.
So far from searching the internet i've found that it's not possible to ''re-run your application'' as with code.
Everyone refers to just close and rerun it, but that's not what i want, i want the code to be doing that.
So i was thinking, can i not re-run winmain? and ' kill ' the current winmain instance in my code, but keep the ''shell (application?)'' active?
this is what i am trying to do:
LRESULT CALLBACK Proc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_SIZE: //Check if the window has been resized
WinMain(this, this, this, NULL);
// or restart application code.
break;
case WM_PAINT: // we need to paint? lets paint!
if (DrawUI)
Render(true);
else
Render(false);
break;
case WM_CREATE:
return DwmExtendFrameIntoClientArea(hWnd, &pMargin); // extension of window frame into client area
break;
case WM_DESTROY:
PostQuitMessage(0); // We need to use this to exit a message loop
break;
default:
return DefWindowProc(hWnd, Message, wParam, lParam); // Making sure all messages are processed
break;
}
}
please see the code under WM_SIZE: that's what im trying to do, but i don't know how to do this correctly, and how to close the previous winmain.
I am trying to write a windowprocedure that would call the animation of a rectangle in the window only when the start button is clicked and stop when the stop button is clicked.
I tried doing this like this:
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
switch (wParam)
{
case BUTTON_START:
stopClicked = false;
DestroyWindow(hStartButton);
CreateStopButton(hWnd);
Animate(hWnd);
return 0;
case BUTTON_STOP:
stopClicked = true;
DestroyWindow(hStopButton);
CreateStartButton(hWnd);
return 0;
}
case WM_CREATE:
AddMenus(hWnd);
CreateStartButton(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
return 0;
}
the Animate function:
void Animate(HWND hWnd)
{
HDC hdcWnd = GetDC(hWnd);
while(!stopClicked)
{
//drawing code
}
ReleaseDC(hWnd, hdcWnd);
DeleteDC(hdcWnd);
}
The program crashes as it never exist the while(!stopClicked) loop.
My question is how to make that possible that the animation would stop on a button click?
Your application hanged, bucause you are waiting for a flag to change and there is no way it will change.
WindowProcedure is called on an event, and until you leave it, any other event won't be processed.
What you need to do is to perform steps of animation on timer.
You need to setup a timer which will send you an event which you have to handle and there you can draw next frame of your animation.
How do I get my mousehook to callback from a seperate thread, to avoid it from interfering with my mainthread, and causing mouselag?
HHOOK Mousehook;
int trial=0; //paintflag for testing
LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case WM_LBUTTONDOWN:
trial = 1; //set paintflag
InvalidateRect(hWnd, NULL, TRUE);
break;
case WM_RBUTTONDOWN:
PostQuitMessage(0);
break;
default:
break;
}
return CallNextHookEx(Mousehook, nCode, wParam, lParam);
}
this is the function I have, and it is called with
Mousehook = SetWindowsHookEx(WH_MOUSE_LL, HookCallback, NULL, 0);
But I have no idea how to make all that into a seperate thread and single call.
Anyone know a good way? Any help would be much appreciated, is it even possible like this?
I found out how to do it. Atleast for now, this is how I made a designated thread for my mousehook, so that it can run in the background:
declaring my hook and the callback routine
HHOOK Mousehook;
LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case WM_LBUTTONDOWN: //incase lmb down
//
break;
case WM_RBUTTONDOWN: //incase of rmb down
//
break;
default:
break;
}
return CallNextHookEx(Mousehook, nCode, wParam, lParam);
}
This is old news however, so whats the trick? First off add threading
#include <thread>
using std::thread //for convenience
then we make the function that the thread runs:
void mhook()
{
MSG msg;
Mousehook = SetWindowsHookEx(WH_MOUSE_LL, HookCallback, NULL, 0);
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
this will keep the thread waiting for msg'es. Now all we need to do is create the thread like so:
thread listen(mhook);
this will make a thread that hooks and listens for mouseactions, without disturbing your main thread.
I am trying to catch ENTER and ESC key press in singleline edit control.
When user presses ENTER or ESC I want to take away keyboard focus from edit control and set it to listview control. Listview control is edit control's sibling.
My goal is to write single subclass procedure that can be used for subclassing edit controls in both main window and dialog box.
I have found this MSDN article that I found useful because of its second solution. Below is my adaptation of the code.
// subclass procedure for edit control
LRESULT CALLBACK InPlaceEditControl_SubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (message)
{
case WM_GETDLGCODE:
return (DLGC_WANTALLKEYS | DefSubclassProc(hwnd, message, wParam, lParam));
case WM_CHAR:
//Process this message to avoid message beeps.
switch (wParam)
{
case VK_RETURN:
// change focus to listview
SetFocus(hwndListView);
return 0L;
case VK_ESCAPE:
// change focus to listview
SetFocus(hwndListView);
return 0L;
default:
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_RETURN:
// change focus to listview
SetFocus(hwndListView);
return 0L;
case VK_ESCAPE:
// change focus to listview
SetFocus(hwndListView);
return 0L;
default:
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
break;
case WM_NCDESTROY:
::RemoveWindowSubclass(hwnd, InPlaceEditControl_SubclassProc, uIdSubclass);
return DefSubclassProc(hwnd, message, wParam, lParam);
}
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
QUESTION:
Is my adaptation correct or am I missing something (maybe instead of SetFocus I should use WM_NEXTDLGCTL like Raymond Chen pointed out)?
I am trying to Subclass the Listbox and the Edit Control of a Combobox for some customasing reasons. Below is the code work . Subclassing for Edit Control is working perfect but Listbox is not getting the messeage of MouseDown.
void Subclass(HWND hComboBox)
{
HWND hEdit=FindWindowEx(hComboBox, NULL, WC_EDIT, NULL);
HWND hCombo=FindWindowEx(hComboBox, NULL, WC_LISTBOX, NULL);
SetProp(hEdit, TEXT("Wprc"), (HANDLE)GetWindowLongPtr(hEdit, GWL_WNDPROC));
SubclassWindow(hEdit, ComboBox_Proc);
SetProp(hCombo, TEXT("Wprc1"), (HANDLE)GetWindowLongPtr(hCombo, GWL_WNDPROC));
SubclassWindow(hCombo, ComboBox_Proc1);
}
static LRESULT CALLBACK ComboBox_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CHAR:
break;
case WM_KEYDOWN:
break;
case WM_DESTROY:
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (DWORD)GetProp(hwnd, TEXT("Wprc")));
RemoveProp(hwnd, TEXT("Wprc"));
break;
default:
return CallWindowProc((WNDPROC)GetProp(hwnd, TEXT("Wprc")), hwnd, msg, wParam, lParam);
}
return FALSE;
}
static LRESULT CALLBACK ComboBox_Proc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
//PROBLEM IS HERE
break;
case WM_DESTROY:
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (DWORD)GetProp(hwnd, TEXT("Wprc1")));
RemoveProp(hwnd, TEXT("Wprc1"));
break;
default:
return CallWindowProc((WNDPROC)GetProp(hwnd, TEXT("Wprc1")), hwnd, msg, wParam, lParam);
}
return FALSE;
}
The ListBox part of a ComboBox is of type COMBOLBOX (with L).
The ComboLBox window is not a child of the ComboBox window.
The only way I found to subclass the COMBOLBOX control is as follows.
Windows sends the WM_CTLCOLORLISTBOX message to the COMBOBOX (no L) before the listbox is drawn. The lParam of this message contains the handle of the listbox.
case WM_CTLCOLORLISTBOX:
{
if ( !hSubclassedListBox )
{
hSubclassedListBox = (HWND)lParam;
SubclassWindow(hSubclassedListBox , MyLBProc);
}
}
Alsoo see this link for more information
For those who are using Visual Studio with WINVER set to 0500 or higher (Windows XP or later), you can use the GetComboBoxInfo function (passing the handle to the ComboBox), which will return (in a COMBOBOXINFO structure) the handles to both the Edit box and the ComboLBox (ListBox). The handles can then be used to get the CWnd-derived objects they represent.