mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-01-20 16:41:02 +00:00
- Fix legacy input state getting out of sync when raw mouse input grabs or releases the events
- Remove the need to center the mouse by specifying RIDEV_INPUTSINK (RIDEV_CAPTUREMOUSE does not take effect unless it is also an input sink)
This commit is contained in:
parent
43eb262571
commit
b4424b2d4d
1 changed files with 117 additions and 27 deletions
|
@ -78,6 +78,15 @@ public:
|
||||||
protected:
|
protected:
|
||||||
bool Grabbed;
|
bool Grabbed;
|
||||||
POINT UngrabbedPointerPos;
|
POINT UngrabbedPointerPos;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RegisterRawInput();
|
||||||
|
void UnregisterRawInput();
|
||||||
|
void CheckDelayedUnregister(RAWINPUT* raw);
|
||||||
|
void ReleaseLegacyInput();
|
||||||
|
|
||||||
|
bool mDelayUnregister = false;
|
||||||
|
int mButtonsDown = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FDInputMouse : public FMouse
|
class FDInputMouse : public FMouse
|
||||||
|
@ -569,22 +578,21 @@ void FRawMouse::Grab()
|
||||||
{
|
{
|
||||||
if (!Grabbed)
|
if (!Grabbed)
|
||||||
{
|
{
|
||||||
RAWINPUTDEVICE rid;
|
if (!mDelayUnregister)
|
||||||
|
|
||||||
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
|
||||||
rid.usUsage = HID_GDP_MOUSE;
|
|
||||||
rid.dwFlags = RIDEV_CAPTUREMOUSE | RIDEV_NOLEGACY;
|
|
||||||
rid.hwndTarget = Window;
|
|
||||||
if (RegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
|
||||||
{
|
{
|
||||||
|
ReleaseLegacyInput();
|
||||||
|
RegisterRawInput();
|
||||||
|
mButtonsDown = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mDelayUnregister = false;
|
||||||
|
}
|
||||||
|
|
||||||
GetCursorPos(&UngrabbedPointerPos);
|
GetCursorPos(&UngrabbedPointerPos);
|
||||||
|
while (ShowCursor(FALSE) >= 0);
|
||||||
Grabbed = true;
|
Grabbed = true;
|
||||||
SetCursorState(false);
|
SetCursorState(false);
|
||||||
// By setting the cursor position, we force the pointer image
|
|
||||||
// to change right away instead of having it delayed until
|
|
||||||
// some time in the future.
|
|
||||||
CenterMouse(-1, -1, NULL, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,19 +606,104 @@ void FRawMouse::Ungrab()
|
||||||
{
|
{
|
||||||
if (Grabbed)
|
if (Grabbed)
|
||||||
{
|
{
|
||||||
RAWINPUTDEVICE rid;
|
// This is to prevent WM_RBUTTONUP from falling through to the application under the cursor when we release capture.
|
||||||
|
if (mButtonsDown == 0)
|
||||||
|
{
|
||||||
|
UnregisterRawInput();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mDelayUnregister = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grabbed = false;
|
||||||
|
ClearButtonState();
|
||||||
|
SetCursorState(true);
|
||||||
|
SetCursorPos(UngrabbedPointerPos.x, UngrabbedPointerPos.y);
|
||||||
|
while (ShowCursor(TRUE) < 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FRawMouse :: RegisterRawInput
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FRawMouse::RegisterRawInput()
|
||||||
|
{
|
||||||
|
RAWINPUTDEVICE rid;
|
||||||
|
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
||||||
|
rid.usUsage = HID_GDP_MOUSE;
|
||||||
|
rid.dwFlags = RIDEV_CAPTUREMOUSE | RIDEV_NOLEGACY | RIDEV_INPUTSINK;
|
||||||
|
rid.hwndTarget = Window;
|
||||||
|
RegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FRawMouse :: UnregisterRawInput
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FRawMouse::UnregisterRawInput()
|
||||||
|
{
|
||||||
|
RAWINPUTDEVICE rid;
|
||||||
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
||||||
rid.usUsage = HID_GDP_MOUSE;
|
rid.usUsage = HID_GDP_MOUSE;
|
||||||
rid.dwFlags = RIDEV_REMOVE;
|
rid.dwFlags = RIDEV_REMOVE;
|
||||||
rid.hwndTarget = NULL;
|
rid.hwndTarget = NULL;
|
||||||
if (RegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
RegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||||
{
|
|
||||||
Grabbed = false;
|
|
||||||
ClearButtonState();
|
|
||||||
}
|
}
|
||||||
SetCursorState(true);
|
|
||||||
SetCursorPos(UngrabbedPointerPos.x, UngrabbedPointerPos.y);
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FRawMouse :: ReleaseLegacyMouseDown
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FRawMouse::ReleaseLegacyInput()
|
||||||
|
{
|
||||||
|
// Send release of all pressed mouse buttons to the Windows legacy input system.
|
||||||
|
// If this isn't done the legacy input system may think the buttons are still down when we release the capture of input events.
|
||||||
|
|
||||||
|
const int vkeys[] = { VK_LBUTTON, VK_RBUTTON, VK_MBUTTON, VK_XBUTTON1, VK_XBUTTON2 };
|
||||||
|
const DWORD keyflags[] = { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_XUP, MOUSEEVENTF_XUP };
|
||||||
|
const DWORD mousedata[] = { 0, 0, 0, XBUTTON1, XBUTTON2 };
|
||||||
|
std::vector<INPUT> inputs;
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
bool keydown = GetKeyState(vkeys[i]) < 0;
|
||||||
|
if (keydown)
|
||||||
|
{
|
||||||
|
INPUT input = {};
|
||||||
|
input.type = INPUT_MOUSE;
|
||||||
|
input.mi.dwExtraInfo = GetMessageExtraInfo();
|
||||||
|
input.mi.dwFlags = keyflags[i];
|
||||||
|
input.mi.mouseData = mousedata[i];
|
||||||
|
inputs.push_back(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SendInput((UINT)inputs.size(), inputs.data(), sizeof(INPUT));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FRawMouse::CheckDelayedUnregister(RAWINPUT* raw)
|
||||||
|
{
|
||||||
|
// Track button state
|
||||||
|
for (DWORD i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
DWORD down = 1 << (i * 2);
|
||||||
|
DWORD up = down << 1;
|
||||||
|
if (raw->data.mouse.usButtonFlags & down)
|
||||||
|
mButtonsDown |= (1 << i);
|
||||||
|
else if (raw->data.mouse.usButtonFlags & up)
|
||||||
|
mButtonsDown &= ~(1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDelayUnregister && mButtonsDown == 0)
|
||||||
|
{
|
||||||
|
UnregisterRawInput();
|
||||||
|
mDelayUnregister = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,10 +748,7 @@ bool FRawMouse::ProcessRawInput(RAWINPUT *raw, int code)
|
||||||
int x = m_noprescale ? raw->data.mouse.lLastX : raw->data.mouse.lLastX << 2;
|
int x = m_noprescale ? raw->data.mouse.lLastX : raw->data.mouse.lLastX << 2;
|
||||||
int y = -raw->data.mouse.lLastY;
|
int y = -raw->data.mouse.lLastY;
|
||||||
PostMouseMove(x, y);
|
PostMouseMove(x, y);
|
||||||
if (x | y)
|
CheckDelayedUnregister(raw);
|
||||||
{
|
|
||||||
CenterMouse(-1, -1, NULL, NULL);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue