mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[idd] input: preserve reports under backpressure
Move named pipe writes off the LGMP input worker so a stalled LGInput endpoint cannot block queue draining or lease maintenance. Coalesce motion only under queue pressure while preserving mode, button, wheel, and keyboard transitions. Reset HID state after discontinuities and carry all 32 mouse button bits through the pipe and HID reports.
This commit is contained in:
@@ -28,39 +28,191 @@
|
||||
|
||||
CInputPipeServer g_inputPipeServer;
|
||||
|
||||
static constexpr int32_t MAX_SPLIT_REPORTS = 4;
|
||||
static constexpr int32_t MAX_MOUSE_DELTA =
|
||||
INT16_MAX * MAX_SPLIT_REPORTS;
|
||||
static constexpr int32_t MIN_MOUSE_DELTA =
|
||||
INT16_MIN * MAX_SPLIT_REPORTS;
|
||||
static constexpr int32_t MAX_MOUSE_WHEEL =
|
||||
INT8_MAX * MAX_SPLIT_REPORTS;
|
||||
static constexpr int32_t MIN_MOUSE_WHEEL =
|
||||
LG_INPUT_MOUSE_WHEEL_MIN * MAX_SPLIT_REPORTS;
|
||||
static constexpr DWORD WAIT_FIRST_OBJECT_VALUE = 0;
|
||||
|
||||
bool CInputPipeServer::Init()
|
||||
{
|
||||
DeInit();
|
||||
|
||||
m_state.store(0, std::memory_order_release);
|
||||
m_stopEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
||||
m_queueEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr);
|
||||
if (!m_stopEvent || !m_queueEvent)
|
||||
{
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
m_sequence = 0;
|
||||
m_mouseMode = MouseMode::NONE;
|
||||
m_absoluteValid = false;
|
||||
m_absoluteX = 0;
|
||||
m_absoluteY = 0;
|
||||
DEBUG_ERROR_HR(GetLastError(),
|
||||
"Failed to create LGInput sender resources");
|
||||
DeInit();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_thread = CreateThread(nullptr, 0, ThreadProc, this, 0, nullptr);
|
||||
if (!m_thread)
|
||||
{
|
||||
DEBUG_ERROR_HR(GetLastError(), "Failed to create LGInput sender");
|
||||
DeInit();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_endpoint.SetHandler(this);
|
||||
return m_endpoint.Start(
|
||||
LG_INPUT_PIPE_NAME,
|
||||
CPipeEndpoint::Mode::Server,
|
||||
sizeof(LGInputPipeMessage));
|
||||
if (!m_endpoint.Start(
|
||||
LG_INPUT_PIPE_NAME,
|
||||
CPipeEndpoint::Mode::Server,
|
||||
sizeof(LGInputPipeMessage)))
|
||||
{
|
||||
DeInit();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CInputPipeServer::DeInit()
|
||||
{
|
||||
Invalidate();
|
||||
Invalidate(0, false);
|
||||
if (m_stopEvent)
|
||||
SetEvent(m_stopEvent);
|
||||
|
||||
m_endpoint.Stop();
|
||||
|
||||
if (m_thread)
|
||||
{
|
||||
WaitForSingleObject(m_thread, INFINITE);
|
||||
CloseHandle(m_thread);
|
||||
m_thread = nullptr;
|
||||
}
|
||||
|
||||
if (m_queueEvent)
|
||||
{
|
||||
CloseHandle(m_queueEvent);
|
||||
m_queueEvent = nullptr;
|
||||
}
|
||||
if (m_stopEvent)
|
||||
{
|
||||
CloseHandle(m_stopEvent);
|
||||
m_stopEvent = nullptr;
|
||||
}
|
||||
|
||||
CSRWExclusiveLock lock(&m_queueLock);
|
||||
m_queueHead = 0;
|
||||
m_queueCount = 0;
|
||||
m_mouseMode = MouseMode::NONE;
|
||||
m_absoluteValid = false;
|
||||
m_relativeButtons = 0;
|
||||
m_absoluteButtons = 0;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::QueueLocked(
|
||||
LGInputPipeMessageType type,
|
||||
const KVMFRInputPayload& payload,
|
||||
bool pureMotion)
|
||||
{
|
||||
if (m_queueCount)
|
||||
{
|
||||
const size_t tailIndex =
|
||||
(m_queueHead + m_queueCount - 1) % QUEUE_LENGTH;
|
||||
QueueItem& tail = m_queue[tailIndex];
|
||||
if (tail.type == type)
|
||||
{
|
||||
if (type == LG_INPUT_PIPE_MESSAGE_MOUSE_RELATIVE &&
|
||||
m_queueCount >= MOTION_COALESCE_THRESHOLD &&
|
||||
tail.pureMotion && pureMotion &&
|
||||
tail.payload.mouseRelative.wheel == 0 &&
|
||||
payload.mouseRelative.wheel == 0 &&
|
||||
tail.payload.mouseRelative.buttons ==
|
||||
payload.mouseRelative.buttons)
|
||||
{
|
||||
const int64_t x = static_cast<int64_t>(
|
||||
tail.payload.mouseRelative.deltaX) +
|
||||
payload.mouseRelative.deltaX;
|
||||
const int64_t y = static_cast<int64_t>(
|
||||
tail.payload.mouseRelative.deltaY) +
|
||||
payload.mouseRelative.deltaY;
|
||||
if (x >= LG_INPUT_MOUSE_DELTA_MIN &&
|
||||
x <= LG_INPUT_MOUSE_DELTA_MAX &&
|
||||
y >= LG_INPUT_MOUSE_DELTA_MIN &&
|
||||
y <= LG_INPUT_MOUSE_DELTA_MAX)
|
||||
{
|
||||
tail.payload.mouseRelative.deltaX = static_cast<int32_t>(x);
|
||||
tail.payload.mouseRelative.deltaY = static_cast<int32_t>(y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (type == LG_INPUT_PIPE_MESSAGE_MOUSE_ABSOLUTE &&
|
||||
tail.pureMotion && pureMotion &&
|
||||
tail.payload.mouseAbsolute.wheel == 0 &&
|
||||
payload.mouseAbsolute.wheel == 0 &&
|
||||
tail.payload.mouseAbsolute.buttons ==
|
||||
payload.mouseAbsolute.buttons)
|
||||
{
|
||||
tail.payload.mouseAbsolute.x = payload.mouseAbsolute.x;
|
||||
tail.payload.mouseAbsolute.y = payload.mouseAbsolute.y;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QueueRawLocked(type, payload, pureMotion);
|
||||
}
|
||||
|
||||
bool CInputPipeServer::QueueRawLocked(
|
||||
LGInputPipeMessageType type,
|
||||
const KVMFRInputPayload& payload,
|
||||
bool pureMotion)
|
||||
{
|
||||
if (m_queueCount == QUEUE_LENGTH)
|
||||
return false;
|
||||
|
||||
const size_t index =
|
||||
(m_queueHead + m_queueCount) % QUEUE_LENGTH;
|
||||
m_queue[index].type = type;
|
||||
m_queue[index].state =
|
||||
m_state.load(std::memory_order_relaxed);
|
||||
m_queue[index].payload = payload;
|
||||
m_queue[index].pureMotion = pureMotion;
|
||||
++m_queueCount;
|
||||
SetEvent(m_queueEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::QueueResetLocked()
|
||||
{
|
||||
KVMFRInputPayload payload = {};
|
||||
if (!QueueRawLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_RELATIVE, payload, false))
|
||||
return false;
|
||||
|
||||
if (m_absoluteValid)
|
||||
{
|
||||
payload.mouseAbsolute.x = m_absoluteX;
|
||||
payload.mouseAbsolute.y = m_absoluteY;
|
||||
if (!QueueRawLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_ABSOLUTE, payload, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
payload = {};
|
||||
if (!QueueRawLocked(LG_INPUT_PIPE_MESSAGE_KEYBOARD, payload, false))
|
||||
return false;
|
||||
|
||||
m_mouseMode = MouseMode::NONE;
|
||||
m_relativeButtons = 0;
|
||||
m_absoluteButtons = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CInputPipeServer::ResyncLocked()
|
||||
{
|
||||
m_queueHead = 0;
|
||||
m_queueCount = 0;
|
||||
uint64_t state = m_state.load(std::memory_order_relaxed);
|
||||
while (state & 1)
|
||||
{
|
||||
if (m_state.compare_exchange_weak(
|
||||
state, state + 2, std::memory_order_acq_rel))
|
||||
{
|
||||
QueueResetLocked();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CInputPipeServer::SendMouseRelative(
|
||||
@@ -69,66 +221,47 @@ bool CInputPipeServer::SendMouseRelative(
|
||||
int32_t wheel,
|
||||
uint32_t buttons)
|
||||
{
|
||||
if (deltaX < MIN_MOUSE_DELTA || deltaX > MAX_MOUSE_DELTA ||
|
||||
deltaY < MIN_MOUSE_DELTA || deltaY > MAX_MOUSE_DELTA ||
|
||||
wheel < MIN_MOUSE_WHEEL || wheel > MAX_MOUSE_WHEEL ||
|
||||
(buttons & ~static_cast<uint32_t>(LG_INPUT_MOUSE_BUTTON_MASK)))
|
||||
if (deltaX < LG_INPUT_MOUSE_DELTA_MIN ||
|
||||
deltaX > LG_INPUT_MOUSE_DELTA_MAX ||
|
||||
deltaY < LG_INPUT_MOUSE_DELTA_MIN ||
|
||||
deltaY > LG_INPUT_MOUSE_DELTA_MAX ||
|
||||
wheel < LG_INPUT_MOUSE_WHEEL_MIN_TOTAL ||
|
||||
wheel > LG_INPUT_MOUSE_WHEEL_MAX ||
|
||||
!(m_state.load(std::memory_order_acquire) & 1))
|
||||
return false;
|
||||
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
if (!IsAvailable())
|
||||
return false;
|
||||
KVMFRInputPayload payload = {};
|
||||
payload.mouseRelative.buttons = buttons;
|
||||
payload.mouseRelative.deltaX = deltaX;
|
||||
payload.mouseRelative.deltaY = deltaY;
|
||||
payload.mouseRelative.wheel = wheel;
|
||||
|
||||
if (m_mouseMode == MouseMode::ABSOLUTE)
|
||||
CSRWExclusiveLock lock(&m_queueLock);
|
||||
const bool pureMotion = wheel == 0 && buttons == m_relativeButtons;
|
||||
const bool switching = m_mouseMode == MouseMode::ABSOLUTE_INPUT;
|
||||
bool queued = (m_state.load(std::memory_order_relaxed) & 1) != 0;
|
||||
if (queued && switching)
|
||||
{
|
||||
const LGInputPipeMouseAbsolute neutral = {
|
||||
0,
|
||||
m_absoluteX,
|
||||
m_absoluteY,
|
||||
0,
|
||||
};
|
||||
if (!SendMessageLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_ABSOLUTE,
|
||||
&neutral,
|
||||
sizeof(neutral)))
|
||||
{
|
||||
Invalidate();
|
||||
return false;
|
||||
}
|
||||
m_mouseMode = MouseMode::NONE;
|
||||
KVMFRInputPayload neutral = {};
|
||||
neutral.mouseAbsolute.x = m_absoluteX;
|
||||
neutral.mouseAbsolute.y = m_absoluteY;
|
||||
queued = QueueRawLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_ABSOLUTE, neutral, false);
|
||||
}
|
||||
if (queued)
|
||||
queued = QueueLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_RELATIVE, payload, pureMotion);
|
||||
|
||||
do
|
||||
if (!queued)
|
||||
ResyncLocked();
|
||||
else
|
||||
{
|
||||
const int16_t x = deltaX > INT16_MAX ? INT16_MAX :
|
||||
deltaX < INT16_MIN ? INT16_MIN : static_cast<int16_t>(deltaX);
|
||||
const int16_t y = deltaY > INT16_MAX ? INT16_MAX :
|
||||
deltaY < INT16_MIN ? INT16_MIN : static_cast<int16_t>(deltaY);
|
||||
const int8_t wheelDelta = wheel > INT8_MAX ? INT8_MAX :
|
||||
wheel < LG_INPUT_MOUSE_WHEEL_MIN ? LG_INPUT_MOUSE_WHEEL_MIN :
|
||||
static_cast<int8_t>(wheel);
|
||||
|
||||
const LGInputPipeMouseRelative payload = {
|
||||
static_cast<uint8_t>(buttons),
|
||||
x,
|
||||
y,
|
||||
wheelDelta,
|
||||
};
|
||||
if (!SendMessageLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_RELATIVE, &payload, sizeof(payload)))
|
||||
{
|
||||
Invalidate();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_mouseMode = MouseMode::RELATIVE;
|
||||
deltaX -= x;
|
||||
deltaY -= y;
|
||||
wheel -= wheelDelta;
|
||||
if (switching)
|
||||
m_absoluteButtons = 0;
|
||||
m_mouseMode = MouseMode::RELATIVE_INPUT;
|
||||
m_relativeButtons = buttons;
|
||||
}
|
||||
while (deltaX || deltaY || wheel);
|
||||
|
||||
return true;
|
||||
return queued;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::SendMouseAbsolute(
|
||||
@@ -139,170 +272,206 @@ bool CInputPipeServer::SendMouseAbsolute(
|
||||
{
|
||||
if (x > LG_INPUT_MOUSE_ABSOLUTE_MAX ||
|
||||
y > LG_INPUT_MOUSE_ABSOLUTE_MAX ||
|
||||
wheel < MIN_MOUSE_WHEEL || wheel > MAX_MOUSE_WHEEL ||
|
||||
(buttons & ~static_cast<uint32_t>(LG_INPUT_MOUSE_BUTTON_MASK)))
|
||||
wheel < LG_INPUT_MOUSE_WHEEL_MIN_TOTAL ||
|
||||
wheel > LG_INPUT_MOUSE_WHEEL_MAX ||
|
||||
!(m_state.load(std::memory_order_acquire) & 1))
|
||||
return false;
|
||||
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
if (!IsAvailable())
|
||||
return false;
|
||||
KVMFRInputPayload payload = {};
|
||||
payload.mouseAbsolute.buttons = buttons;
|
||||
payload.mouseAbsolute.x = x;
|
||||
payload.mouseAbsolute.y = y;
|
||||
payload.mouseAbsolute.wheel = wheel;
|
||||
|
||||
if (m_mouseMode == MouseMode::RELATIVE)
|
||||
CSRWExclusiveLock lock(&m_queueLock);
|
||||
const bool pureMotion = wheel == 0 && buttons == m_absoluteButtons;
|
||||
const bool switching = m_mouseMode == MouseMode::RELATIVE_INPUT;
|
||||
bool queued = (m_state.load(std::memory_order_relaxed) & 1) != 0;
|
||||
if (queued && switching)
|
||||
{
|
||||
const LGInputPipeMouseRelative neutral = {};
|
||||
if (!SendMessageLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_RELATIVE,
|
||||
&neutral,
|
||||
sizeof(neutral)))
|
||||
{
|
||||
Invalidate();
|
||||
return false;
|
||||
}
|
||||
m_mouseMode = MouseMode::NONE;
|
||||
const KVMFRInputPayload neutral = {};
|
||||
queued = QueueRawLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_RELATIVE, neutral, false);
|
||||
}
|
||||
if (queued)
|
||||
queued = QueueLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_ABSOLUTE, payload, pureMotion);
|
||||
|
||||
do
|
||||
if (!queued)
|
||||
ResyncLocked();
|
||||
else
|
||||
{
|
||||
const int8_t wheelDelta = wheel > INT8_MAX ? INT8_MAX :
|
||||
wheel < LG_INPUT_MOUSE_WHEEL_MIN ? LG_INPUT_MOUSE_WHEEL_MIN :
|
||||
static_cast<int8_t>(wheel);
|
||||
const LGInputPipeMouseAbsolute payload = {
|
||||
static_cast<uint8_t>(buttons),
|
||||
x,
|
||||
y,
|
||||
wheelDelta,
|
||||
};
|
||||
if (!SendMessageLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_ABSOLUTE, &payload, sizeof(payload)))
|
||||
{
|
||||
Invalidate();
|
||||
return false;
|
||||
}
|
||||
m_mouseMode = MouseMode::ABSOLUTE;
|
||||
m_absoluteValid = true;
|
||||
m_absoluteX = x;
|
||||
m_absoluteY = y;
|
||||
wheel -= wheelDelta;
|
||||
if (switching)
|
||||
m_relativeButtons = 0;
|
||||
m_mouseMode = MouseMode::ABSOLUTE_INPUT;
|
||||
m_absoluteValid = true;
|
||||
m_absoluteX = x;
|
||||
m_absoluteY = y;
|
||||
m_absoluteButtons = buttons;
|
||||
}
|
||||
while (wheel);
|
||||
|
||||
return true;
|
||||
return queued;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::SendKeyboard(
|
||||
uint8_t modifiers,
|
||||
const uint8_t * keys)
|
||||
{
|
||||
if (!keys)
|
||||
if (!keys || !(m_state.load(std::memory_order_acquire) & 1))
|
||||
return false;
|
||||
|
||||
LGInputPipeKeyboard payload = {};
|
||||
payload.modifiers = modifiers;
|
||||
KVMFRInputPayload payload = {};
|
||||
payload.keyboard.modifiers = modifiers;
|
||||
for (size_t i = 0; i < LG_INPUT_KEYBOARD_KEY_COUNT; ++i)
|
||||
{
|
||||
if (keys[i] > LG_INPUT_KEYBOARD_USAGE_MAX)
|
||||
return false;
|
||||
payload.keys[i] = keys[i];
|
||||
payload.keyboard.keys[i] = keys[i];
|
||||
}
|
||||
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
const bool sent = IsAvailable() &&
|
||||
SendMessageLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_KEYBOARD,
|
||||
&payload,
|
||||
sizeof(payload));
|
||||
if (!sent)
|
||||
Invalidate();
|
||||
return sent;
|
||||
CSRWExclusiveLock lock(&m_queueLock);
|
||||
const bool queued = (m_state.load(std::memory_order_relaxed) & 1) &&
|
||||
QueueLocked(LG_INPUT_PIPE_MESSAGE_KEYBOARD, payload, false);
|
||||
if (!queued)
|
||||
ResyncLocked();
|
||||
return queued;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::Reset()
|
||||
{
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
const bool reset = IsAvailable() &&
|
||||
ResetLocked();
|
||||
if (!reset)
|
||||
Invalidate();
|
||||
return reset;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::ResetLocked()
|
||||
{
|
||||
const LGInputPipeMouseRelative relative = {};
|
||||
const LGInputPipeMouseAbsolute absolute = {
|
||||
0,
|
||||
m_absoluteX,
|
||||
m_absoluteY,
|
||||
0,
|
||||
};
|
||||
const LGInputPipeKeyboard keyboard = {};
|
||||
|
||||
if (!SendMessageLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_RELATIVE,
|
||||
&relative,
|
||||
sizeof(relative)) ||
|
||||
(m_absoluteValid &&
|
||||
!SendMessageLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_ABSOLUTE,
|
||||
&absolute,
|
||||
sizeof(absolute))) ||
|
||||
!SendMessageLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_KEYBOARD,
|
||||
&keyboard,
|
||||
sizeof(keyboard)))
|
||||
if (!(m_state.load(std::memory_order_acquire) & 1))
|
||||
return false;
|
||||
|
||||
m_mouseMode = MouseMode::NONE;
|
||||
CSRWExclusiveLock lock(&m_queueLock);
|
||||
bool queued = (m_state.load(std::memory_order_relaxed) & 1) != 0;
|
||||
if (queued)
|
||||
queued = QueueResetLocked();
|
||||
if (!queued)
|
||||
ResyncLocked();
|
||||
return queued;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::Pop(QueueItem& item)
|
||||
{
|
||||
CSRWExclusiveLock lock(&m_queueLock);
|
||||
if (!m_queueCount)
|
||||
return false;
|
||||
|
||||
item = m_queue[m_queueHead];
|
||||
m_queueHead = (m_queueHead + 1) % QUEUE_LENGTH;
|
||||
--m_queueCount;
|
||||
if (m_queueCount)
|
||||
SetEvent(m_queueEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::SendMessageLocked(
|
||||
LGInputPipeMessageType type,
|
||||
const void * payload,
|
||||
size_t size)
|
||||
bool CInputPipeServer::Send(const QueueItem& item)
|
||||
{
|
||||
if (!payload || !size || size > LG_INPUT_PIPE_MAX_PAYLOAD_SIZE)
|
||||
return false;
|
||||
|
||||
LGInputPipeMessage message = {};
|
||||
message.magic = LG_INPUT_PIPE_MAGIC;
|
||||
message.version = LG_INPUT_PIPE_VERSION;
|
||||
message.type = type;
|
||||
message.payloadSize = static_cast<uint32_t>(size);
|
||||
memcpy(message.payload, payload, size);
|
||||
message.magic = LG_INPUT_PIPE_MAGIC;
|
||||
message.version = LG_INPUT_PIPE_VERSION;
|
||||
message.type = item.type;
|
||||
message.payloadSize = sizeof(KVMFRInputPayload);
|
||||
memcpy(message.payload, &item.payload, sizeof(item.payload));
|
||||
|
||||
message.sequence = ++m_sequence;
|
||||
const bool sent = m_endpoint.Send(&message, sizeof(message));
|
||||
return sent;
|
||||
bool current;
|
||||
bool sent = true;
|
||||
{
|
||||
CSRWSharedLock lock(&m_connectionLock);
|
||||
const uint64_t state = m_state.load(std::memory_order_acquire);
|
||||
current = (state & 1) && item.state == state;
|
||||
if (current)
|
||||
{
|
||||
message.sequence = ++m_sequence;
|
||||
sent = m_endpoint.Send(&message, sizeof(message));
|
||||
}
|
||||
}
|
||||
|
||||
if (!sent)
|
||||
{
|
||||
Invalidate(item.state, true);
|
||||
return false;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
void CInputPipeServer::Invalidate()
|
||||
void CInputPipeServer::Invalidate(uint64_t state, bool requireMatch)
|
||||
{
|
||||
uint64_t state = m_state.load(std::memory_order_acquire);
|
||||
while ((state & 1) && !m_state.compare_exchange_weak(
|
||||
state, state + 1, std::memory_order_acq_rel))
|
||||
CSRWExclusiveLock connectionLock(&m_connectionLock);
|
||||
uint64_t current = m_state.load(std::memory_order_relaxed);
|
||||
for (;;)
|
||||
{
|
||||
if (!(current & 1) || (requireMatch && state != current))
|
||||
return;
|
||||
if (m_state.compare_exchange_weak(
|
||||
current, current + 1, std::memory_order_acq_rel))
|
||||
break;
|
||||
}
|
||||
|
||||
CSRWExclusiveLock queueLock(&m_queueLock);
|
||||
m_queueHead = 0;
|
||||
m_queueCount = 0;
|
||||
}
|
||||
|
||||
DWORD WINAPI CInputPipeServer::ThreadProc(void * context)
|
||||
{
|
||||
static_cast<CInputPipeServer *>(context)->Thread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CInputPipeServer::Thread()
|
||||
{
|
||||
const HANDLE handles[] = { m_stopEvent, m_queueEvent };
|
||||
for (;;)
|
||||
{
|
||||
const DWORD wait = WaitForMultipleObjects(
|
||||
_countof(handles), handles, FALSE, INFINITE);
|
||||
if (wait == WAIT_FIRST_OBJECT_VALUE)
|
||||
break;
|
||||
if (wait != WAIT_FIRST_OBJECT_VALUE + 1)
|
||||
{
|
||||
DEBUG_ERROR_HR(GetLastError(), "LGInput sender wait failed");
|
||||
break;
|
||||
}
|
||||
|
||||
QueueItem item = {};
|
||||
while (Pop(item))
|
||||
if (!Send(item))
|
||||
break;
|
||||
}
|
||||
|
||||
Invalidate(0, false);
|
||||
}
|
||||
|
||||
void CInputPipeServer::OnPipeConnected()
|
||||
{
|
||||
Invalidate();
|
||||
CSRWExclusiveLock connectionLock(&m_connectionLock);
|
||||
CSRWExclusiveLock queueLock(&m_queueLock);
|
||||
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
const bool ready = ResetLocked();
|
||||
if (!ready)
|
||||
uint64_t state = m_state.load(std::memory_order_relaxed);
|
||||
if (state & 1)
|
||||
++state;
|
||||
++state;
|
||||
m_sequence = 0;
|
||||
|
||||
m_queueHead = 0;
|
||||
m_queueCount = 0;
|
||||
m_mouseMode = MouseMode::NONE;
|
||||
const bool reset = QueueResetLocked();
|
||||
for (size_t i = 0; i < m_queueCount; ++i)
|
||||
{
|
||||
DEBUG_WARN("Failed to neutralize the LGInput endpoint");
|
||||
return;
|
||||
const size_t index = (m_queueHead + i) % QUEUE_LENGTH;
|
||||
m_queue[index].state = state;
|
||||
}
|
||||
if (reset)
|
||||
m_state.store(state, std::memory_order_release);
|
||||
|
||||
m_state.fetch_add(1, std::memory_order_acq_rel);
|
||||
if (!reset)
|
||||
DEBUG_WARN("Failed to queue LGInput endpoint neutralization");
|
||||
}
|
||||
|
||||
void CInputPipeServer::OnPipeDisconnected()
|
||||
{
|
||||
Invalidate();
|
||||
Invalidate(0, false);
|
||||
}
|
||||
|
||||
bool CInputPipeServer::OnPipeMessage(
|
||||
|
||||
Reference in New Issue
Block a user