Apply per-session input policy updates via control stream
Some checks failed
ci-bundle.yml / Apply per-session input policy updates via control stream (push) Failing after 0s
ci-copr.yml / Apply per-session input policy updates via control stream (push) Failing after 0s
ci-homebrew.yml / Apply per-session input policy updates via control stream (push) Failing after 0s

This commit is contained in:
Joey Yakimowich-Payne 2026-02-12 00:13:42 -07:00
commit 5d0a6106e6
3 changed files with 115 additions and 29 deletions

View file

@ -184,7 +184,10 @@ namespace input {
mouse_left_button_timeout {},
touch_port {{0, 0, 0, 0}, 0, 0, 1.0f, 1.0f, 0, 0},
accumulated_vscroll_delta {},
accumulated_hscroll_delta {} {
accumulated_hscroll_delta {},
allow_keyboard {true},
allow_mouse {true},
allow_gamepad {true} {
}
// Keep track of alt+ctrl+shift key combo
@ -209,8 +212,24 @@ namespace input {
std::atomic<uint64_t> *activity_keyboard_ms = nullptr;
std::atomic<uint64_t> *activity_mouse_ms = nullptr;
std::atomic<uint64_t> *activity_gamepad_ms = nullptr;
std::atomic<bool> allow_keyboard;
std::atomic<bool> allow_mouse;
std::atomic<bool> allow_gamepad;
};
static inline bool keyboard_allowed(const std::shared_ptr<input_t> &input) {
return config::input.keyboard && input->allow_keyboard.load(std::memory_order_relaxed);
}
static inline bool mouse_allowed(const std::shared_ptr<input_t> &input) {
return config::input.mouse && input->allow_mouse.load(std::memory_order_relaxed);
}
static inline bool gamepad_allowed(const std::shared_ptr<input_t> &input) {
return config::input.controller && input->allow_gamepad.load(std::memory_order_relaxed);
}
/**
* @brief Apply shortcut based on VKEY
* @param keyCode The VKEY code
@ -458,7 +477,7 @@ namespace input {
}
void passthrough(std::shared_ptr<input_t> &input, PNV_REL_MOUSE_MOVE_PACKET packet) {
if (!config::input.mouse) {
if (!mouse_allowed(input)) {
return;
}
@ -557,7 +576,7 @@ namespace input {
}
void passthrough(std::shared_ptr<input_t> &input, PNV_ABS_MOUSE_MOVE_PACKET packet) {
if (!config::input.mouse) {
if (!mouse_allowed(input)) {
return;
}
@ -609,7 +628,7 @@ namespace input {
}
void passthrough(std::shared_ptr<input_t> &input, PNV_MOUSE_BUTTON_PACKET packet) {
if (!config::input.mouse) {
if (!mouse_allowed(input)) {
return;
}
@ -775,7 +794,7 @@ namespace input {
}
void passthrough(std::shared_ptr<input_t> &input, PNV_KEYBOARD_PACKET packet) {
if (!config::input.keyboard) {
if (!keyboard_allowed(input)) {
return;
}
@ -837,7 +856,7 @@ namespace input {
* @param packet The scroll packet.
*/
void passthrough(std::shared_ptr<input_t> &input, PNV_SCROLL_PACKET packet) {
if (!config::input.mouse) {
if (!mouse_allowed(input)) {
return;
}
@ -862,7 +881,7 @@ namespace input {
* @param packet The scroll packet.
*/
void passthrough(std::shared_ptr<input_t> &input, PSS_HSCROLL_PACKET packet) {
if (!config::input.mouse) {
if (!mouse_allowed(input)) {
return;
}
@ -881,8 +900,8 @@ namespace input {
}
}
void passthrough(PNV_UNICODE_PACKET packet) {
if (!config::input.keyboard) {
void passthrough(std::shared_ptr<input_t> &input, PNV_UNICODE_PACKET packet) {
if (!keyboard_allowed(input)) {
return;
}
@ -896,7 +915,7 @@ namespace input {
* @param packet The controller arrival packet.
*/
void passthrough(std::shared_ptr<input_t> &input, PSS_CONTROLLER_ARRIVAL_PACKET packet) {
if (!config::input.controller) {
if (!gamepad_allowed(input)) {
return;
}
@ -938,7 +957,7 @@ namespace input {
* @param packet The touch packet.
*/
void passthrough(std::shared_ptr<input_t> &input, PSS_TOUCH_PACKET packet) {
if (!config::input.mouse) {
if (!mouse_allowed(input)) {
return;
}
@ -996,7 +1015,7 @@ namespace input {
* @param packet The pen packet.
*/
void passthrough(std::shared_ptr<input_t> &input, PSS_PEN_PACKET packet) {
if (!config::input.mouse) {
if (!mouse_allowed(input)) {
return;
}
@ -1056,7 +1075,7 @@ namespace input {
* @param packet The controller touch packet.
*/
void passthrough(std::shared_ptr<input_t> &input, PSS_CONTROLLER_TOUCH_PACKET packet) {
if (!config::input.controller) {
if (!gamepad_allowed(input)) {
return;
}
@ -1091,7 +1110,7 @@ namespace input {
* @param packet The controller motion packet.
*/
void passthrough(std::shared_ptr<input_t> &input, PSS_CONTROLLER_MOTION_PACKET packet) {
if (!config::input.controller) {
if (!gamepad_allowed(input)) {
return;
}
@ -1125,7 +1144,7 @@ namespace input {
* @param packet The controller battery packet.
*/
void passthrough(std::shared_ptr<input_t> &input, PSS_CONTROLLER_BATTERY_PACKET packet) {
if (!config::input.controller) {
if (!gamepad_allowed(input)) {
return;
}
@ -1152,7 +1171,7 @@ namespace input {
}
void passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET packet) {
if (!config::input.controller) {
if (!gamepad_allowed(input)) {
return;
}
@ -1620,7 +1639,7 @@ namespace input {
passthrough(input, (PNV_KEYBOARD_PACKET) payload);
break;
case UTF8_TEXT_EVENT_MAGIC:
passthrough((PNV_UNICODE_PACKET) payload);
passthrough(input, (PNV_UNICODE_PACKET) payload);
break;
case MULTI_CONTROLLER_MAGIC_GEN5:
passthrough(input, (PNV_MULTI_CONTROLLER_PACKET) payload);
@ -1735,4 +1754,14 @@ namespace input {
input->activity_mouse_ms = mouse_ms;
input->activity_gamepad_ms = gamepad_ms;
}
void set_policy(
std::shared_ptr<input_t> &input,
bool allow_keyboard,
bool allow_mouse,
bool allow_gamepad) {
input->allow_keyboard.store(allow_keyboard, std::memory_order_relaxed);
input->allow_mouse.store(allow_mouse, std::memory_order_relaxed);
input->allow_gamepad.store(allow_gamepad, std::memory_order_relaxed);
}
} // namespace input

View file

@ -30,6 +30,12 @@ namespace input {
std::atomic<uint64_t> *mouse_ms,
std::atomic<uint64_t> *gamepad_ms);
void set_policy(
std::shared_ptr<input_t> &input,
bool allow_keyboard,
bool allow_mouse,
bool allow_gamepad);
struct touch_port_t: public platf::touch_port_t {
int env_width, env_height;

View file

@ -51,6 +51,7 @@ extern "C" {
#define IDX_SET_MOTION_EVENT 13
#define IDX_SET_RGB_LED 14
#define IDX_SET_ADAPTIVE_TRIGGERS 15
#define IDX_SET_INPUT_POLICY 16
static const short packetTypes[] = {
0x0305, // Start A
@ -69,6 +70,7 @@ static const short packetTypes[] = {
0x5501, // Set motion event (Sunshine protocol extension)
0x5502, // Set RGB LED (Sunshine protocol extension)
0x5503, // Set Adaptive triggers (Sunshine protocol extension)
0x5504,
};
namespace asio = boost::asio;
@ -205,6 +207,13 @@ namespace stream {
std::uint8_t right[DS_EFFECT_PAYLOAD_SIZE];
};
struct control_set_input_policy_t {
std::uint8_t allow_keyboard;
std::uint8_t allow_mouse;
std::uint8_t allow_gamepad;
std::uint8_t reason;
};
struct control_hdr_mode_t {
control_header_v2 header;
@ -346,10 +355,10 @@ namespace stream {
* @brief Per-session input policy (which remote input types are allowed).
*/
struct session_input_policy_t {
bool allow_gamepad = true;
bool allow_keyboard = false;
bool allow_mouse = false;
bool is_owner_session = false;
std::atomic<bool> allow_gamepad {true};
std::atomic<bool> allow_keyboard {false};
std::atomic<bool> allow_mouse {false};
std::atomic<bool> is_owner_session {false};
};
/**
@ -448,6 +457,24 @@ namespace stream {
std::atomic<session::state_e> state;
};
static void apply_session_input_policy(session_t *session, bool allow_keyboard, bool allow_mouse, bool allow_gamepad, uint8_t reason) {
auto effective_keyboard = config::input.keyboard && allow_keyboard;
auto effective_mouse = config::input.mouse && allow_mouse;
auto effective_gamepad = config::input.controller && allow_gamepad;
session->input_policy.allow_keyboard.store(effective_keyboard, std::memory_order_relaxed);
session->input_policy.allow_mouse.store(effective_mouse, std::memory_order_relaxed);
session->input_policy.allow_gamepad.store(effective_gamepad, std::memory_order_relaxed);
if (session->input) {
input::set_policy(session->input, effective_keyboard, effective_mouse, effective_gamepad);
}
BOOST_LOG(debug)
<< "Session input policy updated [reason="sv << (int) reason << "] kb="sv << effective_keyboard
<< " mouse="sv << effective_mouse << " gamepad="sv << effective_gamepad;
}
/**
* First part of cipher must be struct of type control_encrypted_t
*
@ -1095,6 +1122,23 @@ namespace stream {
}
});
server->map(packetTypes[IDX_SET_INPUT_POLICY], [](session_t *session, const std::string_view &payload) {
BOOST_LOG(debug) << "type [IDX_SET_INPUT_POLICY]"sv;
if (payload.size() < sizeof(control_set_input_policy_t)) {
BOOST_LOG(warning) << "Dropping runt input policy payload"sv;
return;
}
auto *policy = (const control_set_input_policy_t *) payload.data();
apply_session_input_policy(
session,
policy->allow_keyboard != 0,
policy->allow_mouse != 0,
policy->allow_gamepad != 0,
policy->reason);
});
// This thread handles latency-sensitive control messages
platf::set_thread_name("stream::controlBroadcast");
platf::adjust_thread_priority(platf::thread_priority_e::critical);
@ -1964,12 +2008,12 @@ namespace stream {
entry["session_id"] = session->launch_session_id;
entry["client_uuid"] = session->client_unique_id;
entry["client_name"] = session->client_name;
entry["is_owner_session"] = session->input_policy.is_owner_session;
entry["is_owner_session"] = session->input_policy.is_owner_session.load(std::memory_order_relaxed);
entry["policy"] = {
{"allow_keyboard", session->input_policy.allow_keyboard},
{"allow_mouse", session->input_policy.allow_mouse},
{"allow_gamepad", session->input_policy.allow_gamepad},
{"allow_keyboard", session->input_policy.allow_keyboard.load(std::memory_order_relaxed)},
{"allow_mouse", session->input_policy.allow_mouse.load(std::memory_order_relaxed)},
{"allow_gamepad", session->input_policy.allow_gamepad.load(std::memory_order_relaxed)},
};
auto kb_ago = last_kb > 0 ? now - last_kb : UINT64_MAX;
@ -2065,6 +2109,13 @@ namespace stream {
&session.input_activity.last_mouse_ms,
&session.input_activity.last_gamepad_ms);
apply_session_input_policy(
&session,
session.input_policy.allow_keyboard.load(std::memory_order_relaxed),
session.input_policy.allow_mouse.load(std::memory_order_relaxed),
session.input_policy.allow_gamepad.load(std::memory_order_relaxed),
0);
session.broadcast_ref = broadcast.ref();
if (!session.broadcast_ref) {
return -1;
@ -2117,10 +2168,10 @@ namespace stream {
auto &owner_uuids = config::input.owner_client_uuids;
bool is_owner = std::find(owner_uuids.begin(), owner_uuids.end(), launch_session.unique_id) != owner_uuids.end();
session->input_policy.is_owner_session = is_owner;
session->input_policy.allow_gamepad = true;
session->input_policy.allow_keyboard = is_owner;
session->input_policy.allow_mouse = is_owner;
session->input_policy.is_owner_session.store(is_owner, std::memory_order_relaxed);
session->input_policy.allow_gamepad.store(true, std::memory_order_relaxed);
session->input_policy.allow_keyboard.store(is_owner, std::memory_order_relaxed);
session->input_policy.allow_mouse.store(is_owner, std::memory_order_relaxed);
if (is_owner) {
BOOST_LOG(info) << "Owner session detected for client: "sv << launch_session.unique_id;