diff --git a/src/input.cpp b/src/input.cpp index 8a77ab58..908fec79 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -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 *activity_keyboard_ms = nullptr; std::atomic *activity_mouse_ms = nullptr; std::atomic *activity_gamepad_ms = nullptr; + + std::atomic allow_keyboard; + std::atomic allow_mouse; + std::atomic allow_gamepad; }; + static inline bool keyboard_allowed(const std::shared_ptr &input) { + return config::input.keyboard && input->allow_keyboard.load(std::memory_order_relaxed); + } + + static inline bool mouse_allowed(const std::shared_ptr &input) { + return config::input.mouse && input->allow_mouse.load(std::memory_order_relaxed); + } + + static inline bool gamepad_allowed(const std::shared_ptr &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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, + 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 diff --git a/src/input.h b/src/input.h index 82a52e6e..9426db71 100644 --- a/src/input.h +++ b/src/input.h @@ -30,6 +30,12 @@ namespace input { std::atomic *mouse_ms, std::atomic *gamepad_ms); + void set_policy( + std::shared_ptr &input, + bool allow_keyboard, + bool allow_mouse, + bool allow_gamepad); + struct touch_port_t: public platf::touch_port_t { int env_width, env_height; diff --git a/src/stream.cpp b/src/stream.cpp index 3be157a2..3379878c 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -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 allow_gamepad {true}; + std::atomic allow_keyboard {false}; + std::atomic allow_mouse {false}; + std::atomic is_owner_session {false}; }; /** @@ -448,6 +457,24 @@ namespace stream { std::atomic 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;