Synchronize Wintab and Win32 time.

Time is synchronized by the difference between the WT_PACKET receive
time and the last received PACKET's pkTime. This is used to prevent
Wintab packets from being prematurely expired.
This commit is contained in:
Nicholas Rishel
2020-12-16 15:32:18 -08:00
parent 9f588432e9
commit 3a1d1aaa86
3 changed files with 55 additions and 30 deletions

View File

@@ -1614,7 +1614,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
break;
}
case WT_PACKET:
window->updatePendingWintabEvents();
window->updateWintabEventsSyncTime();
break;
////////////////////////////////////////////////////////////////////////
// Pointer events, processed

View File

@@ -1292,7 +1292,7 @@ GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin3
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
updatePendingWintabEvents();
updateWintabEvents();
auto &pendingEvents = m_wintab.pendingEvents;
size_t pendingEventSize = pendingEvents.size();
@@ -1388,6 +1388,44 @@ GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin3
return GHOST_kSuccess;
}
void GHOST_WindowWin32::updateWintabEvents()
{
readWintabEvents();
// When a Wintab device is used to leave window focus, some of it's packets are periodically not
// queued in time to be flushed. Reading packets needs to occur before expiring packets to clear
// these from the queue.
expireWintabEvents();
}
void GHOST_WindowWin32::updateWintabEventsSyncTime()
{
readWintabEvents();
if (!m_wintab.pendingEvents.empty()) {
auto lastEvent = m_wintab.pendingEvents.back();
m_wintab.sysTimeOffset = ::GetTickCount() - lastEvent.pkTime;
}
expireWintabEvents();
}
void GHOST_WindowWin32::readWintabEvents()
{
if (!(m_wintab.packetsGet && m_wintab.context)) {
return;
}
auto &pendingEvents = m_wintab.pendingEvents;
/* Get new packets. */
const int numPackets = m_wintab.packetsGet(
m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data());
for (int i = 0; i < numPackets; i++) {
pendingEvents.push(m_wintab.pkts[i]);
}
}
/* Wintab (per documentation but may vary with implementation) does not update when its event
* buffer is full. This is an issue because we need some synchronization point between Wintab
* events and Win32 events, so we can't drain and process the queue immediately. We need to
@@ -1396,17 +1434,12 @@ GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin3
* mode from the Wintab API alone. There is no guaranteed ordering between Wintab and Win32 mouse
* events and no documented time stamp shared between the two, so we synchronize on mouse button
* events. */
void GHOST_WindowWin32::updatePendingWintabEvents()
void GHOST_WindowWin32::expireWintabEvents()
{
if (!(m_wintab.packetsGet && m_wintab.context)) {
return;
}
auto &pendingEvents = m_wintab.pendingEvents;
/* Clear outdated events from queue. */
DWORD currTime = ::GetTickCount();
DWORD millisTimeout = 500;
DWORD currTime = ::GetTickCount() - m_wintab.sysTimeOffset;
DWORD millisTimeout = 300;
while (!pendingEvents.empty()) {
DWORD pkTime = pendingEvents.front().pkTime;
@@ -1417,24 +1450,6 @@ void GHOST_WindowWin32::updatePendingWintabEvents()
break;
}
}
/* Get new packets. */
const int numPackets = m_wintab.packetsGet(
m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data());
int i = 0;
/* Don't queue outdated packets, such events can include packets that occurred before the current
* window lost and regained focus. */
for (; i < numPackets; i++) {
DWORD pkTime = m_wintab.pkts[i].pkTime;
if (currTime < pkTime + millisTimeout) {
break;
}
}
for (; i < numPackets; i++) {
pendingEvents.push(m_wintab.pkts[i]);
}
}
GHOST_TUns16 GHOST_WindowWin32::getDPIHint()

View File

@@ -486,9 +486,14 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TSuccess getWintabInfo(std::vector<GHOST_WintabInfoWin32> &outWintabInfo);
/**
* Updates stored pending Wintab events.
* Updates pending Wintab events and syncs Wintab time with OS time.
*/
void updatePendingWintabEvents();
void updateWintabEventsSyncTime();
/**
* Updates pending Wintab events.
*/
void updateWintabEvents();
GHOST_TSuccess beginFullScreen() const
{
@@ -629,6 +634,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TUns8 numSysButtons = 0;
/** Cursors currently in contact mapped to system buttons */
DWORD sysButtonsPressed = 0;
DWORD sysTimeOffset = 0;
LONG maxPressure = 0;
LONG maxAzimuth = 0, maxAltitude = 0;
/** Reusable buffer to read in Wintab Packets. */
@@ -642,6 +648,10 @@ class GHOST_WindowWin32 : public GHOST_Window {
*/
void initializeWintab();
void readWintabEvents();
void expireWintabEvents();
/**
* Convert Wintab system mapped (mouse) buttons into Ghost button mask.
* \param cursor: The Wintab cursor associated to the button.