Hi,
Just to follow this up, I implemented (copy/pasted :),thanks Paul) the code to do the mouse manipulation and it worked very well 99.999% of the time. However I was experiencing stutters in the mouse movement, noticing massive jumps in the MouseEvent x,y position as received by my mouse event handlers, from cinder. This seemed to occur when the code performed the win32 ::SetMousePos() method, but only sometimes. I can only assume this means that Windows 10 may have a similar issue to the one described in the commented MacOS version in constrainCursor(), and maybe the mouse coordinates are not delivered seamlessly to the application after the ::SetMousePos() call. It may be my application logic, however when I swapped out this method with another I got good results. Who knows.
So I then discovered that I could use the raw input mode of Windows which has 2 benefits. It allows the mouse to report relative movements of the mouse indefinitely, and then the application can track the virtual cursor based on that info. It also allows the application to respond to subpixel mouse movements generated by higher-DPI mice, which is nice. It also removes any ballistics on the position reporting, which can be an advantage or disadvantage depending on the application. In this case, for camera movement, I think its a pro. I can add my own mouse ballistics code driving my virtual cursor if I need to later.
By some giggery pokery (adding a mMouseRelativeX and mMouseRelativeY field to the MouseEvent class and adding a new MouseDragRel application event etc) and by adding code to manage the WM_INPUT message in the cinder message loop:
// AppImplMsw.cpp
// LAJ mod - raw mouse input
case WM_INPUT:
{
UINT dwSize;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
LPBYTE lpb = new BYTE[dwSize];
if (lpb == NULL)
{
return 0;
}
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize)
console() << "ERROR: GetRawInputData does not return correct size" << std::endl;
RAWINPUT* raw = (RAWINPUT*)lpb;
TCHAR szTempOutput[300];
if (raw->header.dwType == RIM_TYPEKEYBOARD)
{
/* Keyboard data - dont need this but it is available */
raw->data.keyboard.MakeCode,
raw->data.keyboard.Flags,
raw->data.keyboard.Reserved,
raw->data.keyboard.ExtraInformation,
raw->data.keyboard.Message,
raw->data.keyboard.VKey);*/
}
else if (raw->header.dwType == RIM_TYPEMOUSE)
{
/* Mouse data */
impl->mMouseRelativeX = raw->data.mouse.lLastX;
impl->mMouseRelativeY = raw->data.mouse.lLastY;
if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN)
impl->leftDown = true;
if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN)
impl->middleDown = true;
if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
impl->rightDown = true;
if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP)
impl->leftDown = false;
if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP)
impl->middleDown = false;
if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP)
impl->rightDown = false;
// TODO: pass on control/alt etc keyflags also
unsigned int cinderEventFlags = 0;
if (impl->leftDown)
cinderEventFlags |= MouseEvent::LEFT_DOWN;
if (impl->middleDown)
cinderEventFlags |= MouseEvent::MIDDLE_DOWN;
if (impl->rightDown)
cinderEventFlags |= MouseEvent::RIGHT_DOWN;
if (impl->mIsDragging &&
cinderEventFlags != 0) // and a button is pressed
{
MouseEvent event(impl->getWindow(), 0, 0, 0,
impl->mMouseRelativeX, impl->mMouseRelativeY,
cinderEventFlags, 0.0f, static_cast<unsigned int>(wParam));
impl->getWindow()->emitMouseDragRel(&event);
}
}
delete[] lpb;
return 0;
}
and the following code to register the applications interest in the WM_INPUT message (in the WindowImplMsw class constructor):
// AppImplMsw.cpp
// LAJ mod - Raw mouse input
RAWINPUTDEVICE mouseDev;
mouseDev.usUsagePage = 1; // 1 = HID_USAGE_PAGE_GENERIC
mouseDev.usUsage = 2; // 2 = HID_USAGE_GENERIC_MOUSE
mouseDev.dwFlags = RIDEV_INPUTSINK;
mouseDev.hwndTarget = mWnd;
RegisterRawInputDevices(&mouseDev, 1, sizeof(mouseDev));
Now, all I do is I handlke camera rotation and panning in the MouseDragRel event handler, where I can also maintain a virtually infinite mouse cursor, and this results in very smooth unlimited camera movements.
I wondered by the by, why Cinder does not offer a relative mouse input independent of operating system? I would have thought it a common problem for camera movements etc?
Cheers!
Laythe