mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[idd] input: receive LGMP input reports
Add an optional input transport and a dedicated LGMP receiver that validates source ownership, generations, ordered sequences, and leases. Poll input outside the 10 ms control timer. Forward mouse and keyboard state through the LGInput pipe, and neutralize the endpoint before ownership changes or transport failures can leave input held.
This commit is contained in:
@@ -21,17 +21,34 @@
|
||||
#include "ipc/CInputPipeServer.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
#include "CSRWLock.h"
|
||||
#include "InputPipeProtocol.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
|
||||
bool CInputPipeServer::Init()
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_sendLock);
|
||||
m_sequence = 0;
|
||||
ReleaseSRWLockExclusive(&m_sendLock);
|
||||
m_state.store(0, std::memory_order_release);
|
||||
{
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
m_sequence = 0;
|
||||
m_mouseMode = MouseMode::NONE;
|
||||
m_absoluteValid = false;
|
||||
m_absoluteX = 0;
|
||||
m_absoluteY = 0;
|
||||
}
|
||||
|
||||
m_endpoint.SetHandler(this);
|
||||
return m_endpoint.Start(
|
||||
@@ -42,53 +59,134 @@ bool CInputPipeServer::Init()
|
||||
|
||||
void CInputPipeServer::DeInit()
|
||||
{
|
||||
Invalidate();
|
||||
m_endpoint.Stop();
|
||||
}
|
||||
|
||||
bool CInputPipeServer::SendMouseRelative(
|
||||
int16_t deltaX,
|
||||
int16_t deltaY,
|
||||
int8_t wheel,
|
||||
uint8_t buttons)
|
||||
int32_t deltaX,
|
||||
int32_t deltaY,
|
||||
int32_t wheel,
|
||||
uint32_t buttons)
|
||||
{
|
||||
if (wheel < LG_INPUT_MOUSE_WHEEL_MIN ||
|
||||
(buttons & ~LG_INPUT_MOUSE_BUTTON_MASK))
|
||||
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)))
|
||||
return false;
|
||||
|
||||
const LGInputPipeMouseRelative payload = {
|
||||
buttons,
|
||||
deltaX,
|
||||
deltaY,
|
||||
wheel,
|
||||
};
|
||||
return SendMessage(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_RELATIVE,
|
||||
&payload,
|
||||
sizeof(payload));
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
if (!IsAvailable())
|
||||
return false;
|
||||
|
||||
if (m_mouseMode == MouseMode::ABSOLUTE)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
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;
|
||||
}
|
||||
while (deltaX || deltaY || wheel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::SendMouseAbsolute(
|
||||
uint16_t x,
|
||||
uint16_t y,
|
||||
int8_t wheel,
|
||||
uint8_t buttons)
|
||||
int32_t wheel,
|
||||
uint32_t buttons)
|
||||
{
|
||||
if (x > LG_INPUT_MOUSE_ABSOLUTE_MAX ||
|
||||
y > LG_INPUT_MOUSE_ABSOLUTE_MAX ||
|
||||
wheel < LG_INPUT_MOUSE_WHEEL_MIN ||
|
||||
(buttons & ~LG_INPUT_MOUSE_BUTTON_MASK))
|
||||
wheel < MIN_MOUSE_WHEEL || wheel > MAX_MOUSE_WHEEL ||
|
||||
(buttons & ~static_cast<uint32_t>(LG_INPUT_MOUSE_BUTTON_MASK)))
|
||||
return false;
|
||||
|
||||
const LGInputPipeMouseAbsolute payload = {
|
||||
buttons,
|
||||
x,
|
||||
y,
|
||||
wheel,
|
||||
};
|
||||
return SendMessage(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_ABSOLUTE,
|
||||
&payload,
|
||||
sizeof(payload));
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
if (!IsAvailable())
|
||||
return false;
|
||||
|
||||
if (m_mouseMode == MouseMode::RELATIVE)
|
||||
{
|
||||
const LGInputPipeMouseRelative neutral = {};
|
||||
if (!SendMessageLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_MOUSE_RELATIVE,
|
||||
&neutral,
|
||||
sizeof(neutral)))
|
||||
{
|
||||
Invalidate();
|
||||
return false;
|
||||
}
|
||||
m_mouseMode = MouseMode::NONE;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
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;
|
||||
}
|
||||
while (wheel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::SendKeyboard(
|
||||
@@ -107,13 +205,58 @@ bool CInputPipeServer::SendKeyboard(
|
||||
payload.keys[i] = keys[i];
|
||||
}
|
||||
|
||||
return SendMessage(
|
||||
LG_INPUT_PIPE_MESSAGE_KEYBOARD,
|
||||
&payload,
|
||||
sizeof(payload));
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
const bool sent = IsAvailable() &&
|
||||
SendMessageLocked(
|
||||
LG_INPUT_PIPE_MESSAGE_KEYBOARD,
|
||||
&payload,
|
||||
sizeof(payload));
|
||||
if (!sent)
|
||||
Invalidate();
|
||||
return sent;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::SendMessage(
|
||||
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)))
|
||||
return false;
|
||||
|
||||
m_mouseMode = MouseMode::NONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CInputPipeServer::SendMessageLocked(
|
||||
LGInputPipeMessageType type,
|
||||
const void * payload,
|
||||
size_t size)
|
||||
@@ -128,13 +271,40 @@ bool CInputPipeServer::SendMessage(
|
||||
message.payloadSize = static_cast<uint32_t>(size);
|
||||
memcpy(message.payload, payload, size);
|
||||
|
||||
AcquireSRWLockExclusive(&m_sendLock);
|
||||
message.sequence = ++m_sequence;
|
||||
const bool sent = m_endpoint.Send(&message, sizeof(message));
|
||||
ReleaseSRWLockExclusive(&m_sendLock);
|
||||
return sent;
|
||||
}
|
||||
|
||||
void CInputPipeServer::Invalidate()
|
||||
{
|
||||
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))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void CInputPipeServer::OnPipeConnected()
|
||||
{
|
||||
Invalidate();
|
||||
|
||||
CSRWExclusiveLock lock(&m_sendLock);
|
||||
const bool ready = ResetLocked();
|
||||
if (!ready)
|
||||
{
|
||||
DEBUG_WARN("Failed to neutralize the LGInput endpoint");
|
||||
return;
|
||||
}
|
||||
|
||||
m_state.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
void CInputPipeServer::OnPipeDisconnected()
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
bool CInputPipeServer::OnPipeMessage(
|
||||
const void * message,
|
||||
size_t size)
|
||||
|
||||
Reference in New Issue
Block a user