I'm using C++ and DirectD3D9 to draw a menu.
I wish to navigate the menu with the mouse.
I can get the mouse position, however, checking if the left button is clicked is proving tricky.
I am able to check if it is being held down, but not clicked.
bool LBUTTONDOWN = false;
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION && (wParam == WM_LBUTTONUP || wParam == WM_LBUTTONDOWN)) {
LBUTTONDOWN = wParam == WM_LBUTTONDOWN;
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
How can I add a check to see if I clicked the left button?
You need to use a timing trick. Create a variable named something like 'nTime',
Set the zero for it when the LButton is up. Increase the variable value using a '+=' operator when the LButton is down and check the variable against a value something like that -
bool LBUTTONDOWN = false;
int nTime = 0;
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION && (wParam == WM_LBUTTONUP || wParam == WM_LBUTTONDOWN))
{
LBUTTONDOWN = wParam == WM_LBUTTONDOWN;
if ( LBUTTONDOWN )
{
nTime += 1;
if ( nTime > 1000 /*( this value depends on you )*/ )
{
nTime = 0;
// Here is your hold event code.
}
}
else
nTime = 0;
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
There is no DoubleClick message for LowLevelMouseProc. However, I suppose you can have a work around:
Record the time interval between LBUTTONDOWN and LBUTTONUP, then to check whether it is quick enough to be a click event. And because the mouse acts very fast, it is better to set a timer for the mouse capturing.
For the mouse capturing, you can still call LowLevelMouseProc. However, the DirectInput is more convenient for processing mouse movements.
In DirectX SDK samples, there is a DirectInput sample named "CustomFormat". It shows how to set up a timer to capture mouse input.
I hope this helps.
Related
I've got C++ application (used for share application's window via network). I need to update application's area on client side when it's size was changed on server side. For this purpose once in a period of time I call GetWindowPos to check if the window was resized. But I don't want to send the info when the window is in resizing state and send the info only when resizing is completed. I noticed that on Windows 8.1 and Windows 10 GetWindowPos returns same values when the window is in resizing state, however on Windows 7 it returns different values when the window is in resizing state. So the question is how to understand if window is in resizing state?
UPD: Implementation of WM_ENTERSIZEMOVE - WM_EXITSIZEMOVE variant
void WindowsDisplayHelperMasterWindow::SetMsgHook()
{
m_pThis = this;
m_msgHook = SetWindowsHookEx(WH_GETMESSAGE, MsgPoc, NULL, 0);
}
Static function that call non-static method of the class:
LRESULT CALLBACK WindowsDisplayHelperMasterWindow::MsgPoc(int code, WPARAM wParam, LPARAM lParam)
{
if (m_pThis != nullptr)
{
return m_pThis->GetMsgProcHook(code, wParam, lParam);
}
return CallNextHookEx(0, code, wParam, lParam);
}
Hook function:
LRESULT CALLBACK WindowsDisplayHelperMasterWindow::GetMsgProcHook(int code, WPARAM wParam, LPARAM lParam)
{
if (code < 0)
{
return CallNextHookEx(0, code, wParam, lParam);
}
MSG* lpmsg = (MSG*)lParam;
if (lpmsg->hwnd != m_windowHandle)
{
return CallNextHookEx(0, code, wParam, lParam);
}
if (lpmsg->message == WM_ENTERSIZEMOVE && !m_isWindowResizing)
{
m_isWindowResizing = true;
}
else if (lpmsg->message == WM_EXITSIZEMOVE && m_isWindowResizing)
{
m_isWindowResizing = false;
}
return CallNextHookEx(0, code, wParam, lParam);
}
m_pThis and m_msgHook are static class members:
WindowsDisplayHelperMasterWindow* WindowsDisplayHelperMasterWindow::m_pThis = nullptr;
HHOOK WindowsDisplayHelperMasterWindow::m_msgHook = NULL;
And here is the check itself:
if (!m_displayMode.IsEqualGeometry(displayMode) && !m_isWindowResizing)
{
DUMPER_DEBUG("DS_ERROR_MODE_CHANGED");
return DS_ERROR_MODE_CHANGED; // depending on this value server asks client to update application's window area
}
Thanks.
A window receives a WM_ENTERSIZEMOVE message, after it has entered the moving and sizing modal loop. A window receives a WM_EXITSIZEMOVE message, after it has exited the moving or sizing modal loop.
If you monitor those two messages, you know when a window is in moving and sizing state.
I have a procedure that when a user press Ctrl button and right click it will show a message box to screen. But it has a loop, I only press Ctrl button and right click once time but it shows a sequence of message box. How to fix this?
https://youtu.be/LzI9M_zEEKQ
This is my MouseProc procedure
#define EXPORT __declspec(dllexport)
unsigned char KeyState[256];
LRESULT EXPORT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(hHook, nCode, wParam, lParam);
GetKeyboardState(KeyState);
if (nCode == HC_ACTION)
{
if ((wParam == WM_RBUTTONUP) && (KeyState[VK_CONTROL] & 0x80))
{
MessageBox(NULL, L"Ctrl + Right Click", L"Mouse hook", MB_OK);
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
Thanks for reading.
You shall not use MessageBox() in message hooks as it breaks normal message hook flow - MessageBox() runs its own modal loop.
If you need exactly MessageBox there then you should use PostMessage with custom message and handler. In this case MessageBox will be invoked after CallNextHookEx(hHook, nCode, wParam, lParam);
I have a USB HID touchpad that collects input. By default, when I press on the touchpad it generates carriage return (Enter) and when I try to use it as a mouse it actually enters a dragging state.
What I want to do is to convert the carriage return into a mouse click event and the dragging state into a cursor move without the initial clicking part.
I found the raw input alternative. However, I don't know how to convert it into mouse click and cursor move.
Here is the code responsible with the mouse 'reading':
LRESULT CALLBACK mouseProc (int nCode, WPARAM wParam, LPARAM lParam)
{
MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lParam;
if (pMouseStruct != NULL)
{
if(wParam == WM_LBUTTONDOWN)
{
cout<<"clicked"<<endl;
}
printf("Mouse position X = %d Mouse Position Y = %d\n", pMouseStruct->pt.x,pMouseStruct->pt.y);
stringstream sx, sy;
sx << (int) pMouseStruct->pt.x << endl;
sy << (int) pMouseStruct->pt.y << endl;
}
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
then the keyboard part:
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(NULL, nCode, wParam, lParam);
tagKBDLLHOOKSTRUCT *str = (tagKBDLLHOOKSTRUCT *)lParam;
cout<<str->vkCode<<endl;
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
then the logging part:
DWORD WINAPI MyLogger(LPVOID lpParm)
{
HINSTANCE hInstance = GetModuleHandle(NULL);
hMouseHook = SetWindowsHookEx( WH_MOUSE_LL, mouseProc, hInstance, NULL );
hKeyHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, NULL );
MSG message;
while (GetMessage(&message,NULL,0,0))
{
TranslateMessage( &message );
DispatchMessage( &message );
}
UnhookWindowsHookEx(hMouseHook);
return 0;
}
Note: I don't know if this is relevant, but I want to use the HID to play in a Chromium instance on a windows system.
When you register the hook with WH_MOUSE_LL, the possible values of wparam are: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_RBUTTONDOWN, or WM_RBUTTONUP.
I'm expecting that once the WM_LBUTTONDOWN is issued, a corresponding WM_LBUTTONUP has to be issued to prevent the cursor from entering dragging state.
I don't have the device to test this but I would try the call below to prevent entering dragging state.
CallNextHookEx(hMouseHook, nCode, WM_LBUTTONUP, lParam);
or use mouse_event with MOUSEEVENTF_LEFTUP to inject the release of the left button.
I don't think that the raw input alternative is a good idea. I see it as a measure of last resort.
The touchpad is just a mouse like any other. It generates standard mouse events. Use a global WH_MOUSE hook via SetWindowsHookEx() to capture mouse events globally. To replay them, use mouse_event(). Alternatively, use WH_JOURNALRECORD and WH_JOURNALPLAYBACK hooks instead for capture and playback, respectively.
For mouse click and mouse move - when you handle the input from the HID use the SendInput method.
The click is easy, for the mouse move try to get the scaled drag coordinates and convert them to the current screen scale coordinates and also use the SendInput method.
Also you can track the displacement in x, y and make appropriate calibration to translate them to screen x, y
Ello All,
I'm pretty new to c++ and I've been trying to get this to work for longer than I care to admit. So I've gone off of the following refs and gotten the controller to work in a console app.
xbox360 controller input with c using x input
Code proj article
MSDN
Here is the result
xbox360Controller.h
xbox360Controller.cpp
From there I'm trying to get it to work with cocos2d-x using steve tranby's post at the bottom of this thread (he adds to the )and adapting that to the 360 gamepad.
While I've gotten the keypad events to work
(it was standard windows input so not too bad)
LRESULT CCEGLView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
BOOL bProcessed = FALSE;
CCLog("Message sent = %d",message);
//note* only showing relavant sections of code for brevity
switch (message)
{
case WM_KEYDOWN:
if (wParam == VK_F1 || wParam == VK_F2)
{
CCDirector* pDirector = CCDirector::sharedDirector();
if (GetKeyState(VK_LSHIFT) getKeypadDispatcher()->dispatchKeypadMSG(wParam == VK_F1 ? kTypeBackClicked : kTypeMenuClicked);
}
}
else if (wParam == VK_ESCAPE)
{
CCDirector::sharedDirector()->getKeypadDispatcher()->dispatchKeypadMSG(kTypeBackClicked);
}
else
{
CCDirector::sharedDirector()->getKeypadDispatcher()->dispatchKeypadDown(wParam);
}
if ( m_lpfnAccelerometerKeyHook!=NULL )
{
(*m_lpfnAccelerometerKeyHook)( message,wParam,lParam );
}
break;
default:
if (m_wndproc)
{
m_wndproc(message, wParam, lParam, &bProcessed);
if (bProcessed) break;
}
return DefWindowProc(m_hWnd, message, wParam, lParam);
}
if (m_wndproc && !bProcessed)
{
m_wndproc(message, wParam, lParam, &bProcessed);
}
return 0;
}
I can't figure out where to put the controller logic. I've tried
in the WindowProc method and realized that didnt work as it only
fires as a callback to WindowProc events(I probably don't have the correct lingo for it, sorry)
The closest I've gotten it to something that fires often enough to check is at the point
static LRESULT CALLBACK _WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CCDirector* pDirector = CCDirector::sharedDirector();
XboxController* player1 = new XboxController(GamePadIndex_One);
if(player1->IsConnected())
{
player1->Update();
for(int i =0;iState._buttons[i]==true)
{
//CCApplication::sharedApplication()->getKe
pDirector->getKeypadDispatcher()->dispatchKeypadDown(i);
}
}
}
delete player1;
if (s_pMainWindow && s_pMainWindow->getHWnd() == hWnd)
{
return s_pMainWindow->WindowProc(uMsg, wParam, lParam);
}
else
{
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
The full code is here
and the source is at github Here.
Anyone know the right place to put the XboxController instance in order for it to respond to KeypadDown properly?
First of, WindowProc is a callback function that is called after there's an message sent to the window from Windows.
So, if there's no message, this function would not get called.
XInput api is not message-based api, it does not generate messages. It requires the app to read its state as frequent as possible. Usually it's read in every game loop, just before the game logic is processed. Alternatively, you could have a separated thread to poll the state every 33ms or so.
I'd to recommend you to take a look at how XInput work, the concept of Windows programming, and the basic concept of game engine architecture.
I have a program with several custom controls. One of these custom controls is a text input control. Since a window does not automatically receive keyboard focus when you click on it, i've created a mouse hook in my program that calls SetFocus() on a window when the user clicks in that window. However, there is a problem.
If another program has focus when you click on my program's window (or any of the controls in that window) SetFocus() fails. I then have to click again for it to succeed. Here's the code:
LRESULT CALLBACK kbfProc(int nCode, WPARAM wParam, LPARAM lParam) // Keyboard focus switching procedure
{
switch(nCode)
{
case HC_ACTION:
{
if(wParam == WM_LBUTTONDOWN || wParam == WM_NCLBUTTONDOWN)
{
MOUSEHOOKSTRUCT * mhs = (MOUSEHOOKSTRUCT*) lParam;
if(SetFocus(mhs->hwnd) == NULL)
{
printf("SetFocus(Hwnd = %.8x) failed. Error code: %lu\n", mhs->hwnd, GetLastError());
} else {
printf("SetFocus(Hwnd = %.8x) returned success.\n", mhs->hwnd);
}
}
}
break;
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
And the output of those printf calls is this:
SetFocus(Hwnd = 00410c06) failed. Error code: 87
SetFocus(Hwnd = 00410c06) returned success.
SetFocus(Hwnd = 01740fc8) failed. Error code: 87
SetFocus(Hwnd = 01740fc8) returned success.
Error code 87 is ERROR_INVALID_PARAMETER, but i'm obviously passing a valid window handle to the function, so why is it failing?
Whenever you're calling SetFocus, the window must be attached to the calling thread's message queue or SetFocus will return invalid if it's not. To workaround this, use SetForegroundWindow first when the mouse moves over your window before calling SetFocus.
I know I'm couple of days late, but since I just spent a whole day trying to fix this, I'll add my fix here as well, just in case it helps someone.
Basically it was the AttachThreadInput thing mentioned above in a comment. GetActiveWindow() was always returning NULL as well. Which window you need to attach to might vary case by case, but I needed the root window, so I used GetAncestor. If you know the window handle you want, then you can just use it instead. So this is the code that fixed it for me:
AttachThreadInput(GetCurrentThreadId(), GetWindowThreadProcessId(GetAncestor(hWnd, GA_ROOT), NULL), TRUE);
I've found a solution. After a lot of googling and trial & error I eventually came across this webpage (backup link). It goes over the behavior of window focus and activation in detail.
I ended up adding some code to the WM_ACTIVATE handler of my main window that searches for the child window that was clicked when the window is activated. Here's all the code:
Here's the hook procedure:
LRESULT CALLBACK kbfProc(int nCode, WPARAM wParam, LPARAM lParam)
{
switch(nCode)
{
case HC_ACTION:
{
if(wParam == WM_LBUTTONDOWN || wParam == WM_NCLBUTTONDOWN)
{
MOUSEHOOKSTRUCT * mhs = (MOUSEHOOKSTRUCT*) lParam;
BringWindowToTop(MainWindow->t_hwnd);
SetFocus(mhs->hwnd);
}
}
break;
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
Here's the code i put in the WM_ACTIVATE handler:
case WM_ACTIVATE:
{
unsigned long state = (unsigned long) wParam & 0x0000FFFF;
unsigned long mState = (unsigned long) wParam & 0xFFFF0000;
if(state != 0)
{
...[some code here]...
FocusChildWindow(hwnd);
}
...[some code here]...
}
break;
And here's the FocusChildWindow() function:
void FocusChildWindow(HWND hwnd)
{
POINT mpos;
GetCursorPos(&mpos);
RECT wr;
GetWindowRect(hwnd, &wr);
mpos.x -= wr.left;
mpos.y -= wr.top;
HWND cw = ChildWindowFromPoint(hwnd, mpos);
if(cw == NULL || cw == hwnd)
{
SetFocus(hwnd);
} else {
GetCursorPos(&mpos);
HWND cw2;
while(1)
{
POINT sc = mpos;
MapWindowPoints(HWND_DESKTOP, cw, &sc, 1);
cw2 = ChildWindowFromPoint(cw, sc);
if(cw2 == NULL || cw2 == cw)
{
SetFocus(cw);
break;
} else {
cw = cw2;
}
}
}
}
The following worked for me when SetFocus() had no effect setting the keyboard focus to a child control window on a property sheet page window:
::SendMessage(m_hPropPageWnd, WM_UPDATEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);