Detecting Enter/Return on Keydown event in C++ - c++

I am trying to detect in my application, if the Enter/Return buttons are pressed. My problem is that the LVN_KEYDOWN event (Indicates that a key has been pressed) does not detect the Enter/Return key.
I have seen similar questions for other languages, but can not find a solution for C++.
My event to read the key press is:
void ListOption::OnLvnKeydownList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLVKEYDOWN pLVKeyDow = reinterpret_cast<LPNMLVKEYDOWN>(pNMHDR);
// TODO: Add your control notification handler code here
if(pLVKeyDow->wVKey == VK_RETURN)
{
OnItemActivateList1(pNMHDR, pResult);
*pResult = 1;
}
*pResult = 0;
}
This code works for almost any key, execept for the Enter key.
My dialog has only one button, and it's "Default Button" value is FALSE. How is it possible to detect the keypress?
Update: My application uses modal dialogs.. It contains a CImageSheet that contains CImagePages(tabs). Here is an image to explain better (I have placed grey blocks to hide some private data).
When I press Enter, I wish to open a new dialog to change the option. Currently this is done with the LVN_ITEMCTIVATE event (when the user double clicks an item):

You can override PreTranslateMessage in the window which owns the ListView. In this case it seems to be a CPropertyPage.
BOOL CMyPropertyPage::PreTranslateMessage(MSG* pMsg)
{
//optional: you can handle keys only when ListView has focus
if (GetFocus() == &List)
if (pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_RETURN)
{
//return 1 to eat the message, or allow for default processing
int sel = List.GetNextItem(-1, LVNI_SELECTED);
if (sel >= 0)
{
MessageBox("VK_RETURN");
TRACE("ListView_GetNextItem %d\n", sel);
return 1;
}
else
TRACE("ListView_GetNextItem not-selected, %d\n", sel);
}
if (pMsg->wParam == VK_ESCAPE)
{
//do nothing!
}
}
return CPropertyPage::PreTranslateMessage(pMsg);
}

Related

How to get left click notification on an edit control?

I want to track event of single left-click on edit control.
I override PretranslateMessage function as below:
BOOL CMyClass::PreTranslateMessage(Msg* pMsg)
{
switch(pMsg->message)
case WM_LBUTTONDOWN:
{
CWnd* pWnd = GetFocus();
if (pWnd->GetDlgCtrlID == MY_EDIT_CTRL_ID)
{
//Do some thing
}
break;
}
}
The problem is that when I click on the edit control, all other control become disabled (for example buttons don't respond to clicks etc.)
How can I fix this problem? Or how can I track click notificationN on edit box?
You need this:
BOOL CMyClass::PreTranslateMessage(MSG* pMsg)
{
switch(pMsg->message)
{
case WM_LBUTTONDOWN:
{
CWnd* pWnd = GetFocus();
if (pWnd->GetDlgCtrlID() == MY_EDIT_CTRL_ID) // << typo corrected here
{
//Do some thing
}
break;
}
}
return __super::PreTranslateMessage(pMsg); //<< added
}
BTW its a bit awkword to use a switch statement here. Following code is cleaner IMO, unless you want to add morecases than only WM_LBUTTONDOWN:
BOOL CMyClass::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_LBUTTONDOWN)
{
CWnd* pWnd = GetFocus();
if (pWnd->GetDlgCtrlID() == MY_EDIT_CTRL_ID)
{
//Do some thing
}
}
return __super::PreTranslateMessage(pMsg); //<< added
}

CInvalidArgumentException when checking class in PreTranslateMessage

The case: I'd like to make shortcuts with numpad so users can use my application fast. I implemented this in PreTranslateMessage and this worked.
But the case is that I have an Edit Control where the user should enter some number. So at the time the user has focus on a Edit Control (CEdit), the shortcuts should be disabled.
To cover this, I added
CWnd* pControl;
pControl = this->GetFocus();
if(!(pControl->IsKindOf(RUNTIME_CLASS(CEdit)))){
But now whenever my application dialog loses focus, it closes (see video) and I get the following exeption:
This is the full code:
// Handles keypresses for fast acces of functions
BOOL COpenFilesDlg::PreTranslateMessage(MSG *pMsg){
CWnd* pControl;
pControl = this->GetFocus();
if(!(pControl->IsKindOf(RUNTIME_CLASS(CEdit)))){ //when this statement is commented the program doesn't crash
if(pMsg->message == WM_KEYDOWN)
{
if((pMsg->wParam == 0x31 || pMsg->wParam == VK_NUMPAD1))
someFunction();
else if((pMsg->wParam == 0x33 || pMsg->wParam == VK_NUMPAD3)){
someOtherFunction();
}
}
}
return CDialog::PreTranslateMessage(pMsg);
}
Now is my question: Why does my program crash when it is not in focus and how do I check if the focus is on a Edit Control in a proper way?
CWnd::GetFocus returns a pointer to the window that has the current focus, or NULL if there is no focus window.
pControl = this->GetFocus();
if ( pControl != NULL )
{
if(!(pControl->IsKindOf(RUNTIME_CLASS(CEdit))))
...
}
Another way is to compare pControl value with pointer to CEdit class member (or members) of the dialog class. For example, if CEdit m_edit is edit box class member, test:
if ( pControl == (CWnd*)&m_edit )
{
// focus is on m_edit control
}

Change CDialog controls focus from another dialog

I am trying to change the focus of a CDialog controls from a CFormView by using PostMessage:
[CHelpView is inherited from CFormView.
And m_wndDlg is a CSampleDlg(inherited from CDialog) object]
void CHelpView::OnEnterbutton()
{
pSplitterFrame->m_dlgPane->m_wndDlg->PostMessage(WM_KEYDOWN, 'r', 2);
}
BOOL CSampleDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message >= WM_KEYFIRST && // for performance
pMsg->message <= WM_KEYLAST)
{
if (pMsg->wParam=='r' && pMsg->lParam==2){
NextDlgCtrl();
return TRUE;
}
}
}
The dialog receives the message but the NextDlgCtrl method doesn't change the focus. I realized that if I change the PreTranslateMessage method so that if the Return key is pressed, within the dialog, this NextDlgCtrl method properly changes the focus each time the user hit the return key(from the dialog). Yet this I couldn't achieve through another dialog.
Does anyone possibly know the reason behind it or any hints or workaround ?
Thanks.
EDIT:
Here's (part of)the log file for the dialog from SPY++.
<01128> 0016013E R WM_GETDLGCODE fuDlgCode:0000
<01129> 0016013E P WM_KEYDOWN nVirtKey:00726574 cRepeat:2 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<01130> 0016013E S WM_NEXTDLGCTL wCtlFocus:(null) (next control receives focus) fHandle:False
<01131> 0016013E R WM_NEXTDLGCTL
<01132> 0016013E S WM_GETDLGCODE
Your PreTranslateMessage handler, as written, will never work. This line,
if (pMsg->wParam=='r' && pMsg->wParam==2){
NextDlgCtrl();
return TRUE;
can never be true. How can pMsg->wParam equate to two values at the same time? I think you meant to check for lParam?
You are posting a lParam value of 2, but checking for '2' -- they are not the same!
Try
if (pMsg->wParam == 'r' && pMsg->wParam == 2)
EDIT: realised after rrirower's answer: it should of course be
if (pMsg->wParam == 'r' && pMsg->lParam == 2)

Translating WM_MOUSEWHEEL Delphi code to C++ Builder

I have these links with code:
WMMouseWheel not working in Delphi
How to disable MouseWheel if mouse is not over VirtualTreeView (TVirtualStringTree)
Translated it to C++ Builder but it doesn't work:
UPDATE: After narrowing the problem down it appears that WM_MOUSEWHEEL messages don't work over unfocused TVirtualStringTree control only, they work over other controls. When focus is on e.g. TMemo control, other TMemo control scrolls on wheel but not TVirtualStringTree control. When focus is on TVirtualStringTree it scrolls TVirtualStringTree but not other controls. So the problem is now specific to TVirtualStringTree only.
void __fastcall TForm1::ApplicationEventsMessage(tagMSG &Msg, bool &Handled)
{
TPoint Pt;
HWND Wnd;
if (Msg.message == WM_MOUSEWHEEL ||
Msg.message == WM_VSCROLL ||
Msg.message == WM_HSCROLL)
{
if (GetCursorPos(&Pt))
{
Wnd = WindowFromPoint(Pt);
// It must be a VCL control otherwise we could get access violations
if (IsWindowEnabled(Wnd) && FindControl(Wnd) != NULL)
{
Msg.hwnd = Wnd; // change the message receiver to the control under the cursor
}
}
}
}
Different version of the similar code, also doesn't work:
TPoint pnt;
TWinControl *ctrl;
if ((Msg.message == WM_MOUSEWHEEL ||
Msg.message == WM_VSCROLL ||
Msg.message == WM_HSCROLL) &&
GetCursorPos(&pnt))
{
ctrl = FindVCLWindow(pnt);
if (ctrl != NULL)
{
SendMessage(ctrl->Handle, Msg.message, Msg.wParam, Msg.lParam); // No effect
// SendMessage(ctrl->Handle, WM_VSCROLL, 1, 0); // This is the only thing that actually moves scrollbars but this is not exactly the same message like above
// Msg.hwnd = ctrl->Handle; // No effect
this->Caption=ctrl->Name; // This shows correct control name so the message IS GETTING THROUGH!
Handled = true;
}
}
It should work but it doesn't. Tried other code as well. No effect - mouse wheel does not operate on unfocused control. As you can see, I checked for all 3 variants of wheel messages, it gets correct control under the mouse, it shows that control name but the control doesn't receive wheel messages.
Any ideas what piece of the puzzle am I missing to get it to work?
As nobody offered any proper solution, I am posting my own. The solution is not perfect but at least it does what it needs to do - mouse wheel scrolls all controls under it, including the VirtualTreeView controls. The code in solution is in C++ but Delphi version is very similar (it only needs to be translated).
My current solution is to grab WM_MOUSEWHEEL events and translate them into WM_VSCROLL or WM_HSCROLL to which VirtualTreeView reacts and scrolls the content. Additionally, it needs to take into account high-precision mouse wheels which can have smaller value than WHEEL_DELTA (which is set to 120). Finally, it needs to take into account user setting for number of lines to scroll (set in Control Panel in Windows). So here goes:
Put a TApplicationEvents to a form and in the OnMessage event do this:
void __fastcall TFormMain::ApplicationEventsMessage(tagMSG &Msg, bool &Handled)
{
// Check these 3 messages because some mouse drivers may use VSCROLL instead of MOUSESWHEEL message
if (Msg.message == WM_MOUSEWHEEL || Msg.message == WM_VSCROLL || Msg.message == WM_HSCROLL)
{
TPoint pnt;
TWinControl *ctrl;
if (!GetCursorPos(&pnt)) return;
ctrl = FindVCLWindow(pnt);
if (ctrl != NULL)
{
// ToDo: implement if user needs wheel-click - then we also need KEYSTATE but for this example it is not needed
// int fwKeys = GET_KEYSTATE_WPARAM(Msg.wParam);
int zDelta = GET_WHEEL_DELTA_WPARAM(Msg.wParam),
pvParam = 3; // Windows default value
unsigned MyMsg = WM_VSCROLL;
// ToDo: extract SystemParametersInfo somewhere else so it is not extracted for each WM_MOUSEWHEEL message which may not be needed
switch (Msg.message)
{
// This will translate WM_MOUSEWHEEL into WM_VSCROLL
case WM_MOUSEWHEEL:
case WM_VSCROLL:
// Windows setting which determines how many lines to scroll - we'll send that many WM_VSCROLL or WM_HSCROLL messages
SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &pvParam, 0);
MyMsg = WM_VSCROLL;
break;
case WM_HSCROLL:
// Same as above but for WM_HSCROLL (horizontal wheel)
SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &pvParam, 0);
MyMsg = WM_HSCROLL;
break;
}
// This calculation takes into account high-precision wheels with delta smaller than 120
// Possible TODO: Round up values smaller than 1 (e.g. 0.75 * pvParam) if pvParam is 1
int ScrollBy = ((double)zDelta / (double)WHEEL_DELTA) * pvParam;
// Send multiple messages based on how much the zDelta value was
if (zDelta > 0)
{
do
{
SendMessage(ctrl->Handle, MyMsg, SB_LINEUP, 0);
}
while (--ScrollBy > 0);
}
else
{
do
{
SendMessage(ctrl->Handle, MyMsg, SB_LINEDOWN, 0);
}
while (++ScrollBy < 0);
}
Handled = true;
}
}
}

Prevent to show default windows context menu in winEvent in Qt

I want to to get word under mouse cursor but when user right click in any window, default windows context menu appear, how can i prevent showing default windows context menu in winEvent in Qt?
bool EventReceiverWindow::winEvent (MSG *message,long *result )
{
if( message->message == WM_RBUTTONUP ) {
// *result = ? (What's value should i passed to *result to prevent showing defualt context menu)
return true;
}
}
What you are attempting to do is not practical. You'd need to hook into the message queue of all running apps. That's just not a realistic proposition. I can't guess what's driving this question but I wonder if a system wide hot key might serve your needs.
Just pass TRUE to the *result and return true;
bool EventReceiverWindow::winEvent (MSG *message,long *result )
{
if( message->message == WM_RBUTTONUP ) {
*result = true;
return true;
}
}