[feat] expose system controls and verify remote unlock completion

This commit is contained in:
dijunkun
2026-11-06 20:46:11 +08:00
parent 6bfcd5cf3d
commit dd4baf2fc4
16 changed files with 222 additions and 15 deletions
@@ -1,5 +1,6 @@
#include "runtime/gui_runtime.h"
#include <stream_names.h>
#include "screen_lock.h"
namespace crossdesk {
void GuiRuntime::HandleAutomation(const std::string& remote_id,
@@ -21,7 +22,11 @@ void GuiRuntime::HandleAutomation(const std::string& remote_id,
try {
const auto method = request.value("method", std::string{});
if (method == "capabilities") {
reply(true, {{"input_ack", true}, {"clipboard", true}, {"files", true}});
json capabilities{{"input_ack", true}, {"clipboard", true}, {"files", true}};
#if defined(_WIN32) || defined(__APPLE__) || (defined(__linux__) && !defined(__OHOS__))
capabilities["system"] = true;
#endif
reply(true, std::move(capabilities));
} else if (method == "input") {
RemoteAction action{};
if (!request.contains("arguments") ||
@@ -37,6 +42,46 @@ void GuiRuntime::HandleAutomation(const std::string& remote_id,
if (result == RemoteInputDispatcher::Result::rejected ||
result == RemoteInputDispatcher::Result::overflow)
reply(false, "INPUT_REJECTED");
} else if (method == "system") {
const auto operation = request.at("arguments").at("operation").get<std::string>();
if (operation != "status" && operation != "lock" && operation != "send_sas") {
reply(false, "INVALID_ARGUMENT");
return;
}
std::lock_guard lock(automation_mutex_);
if (automation_closing_ || automation_tasks_.size() >= 32) { reply(false, "BUSY"); return; }
const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(2);
automation_tasks_.push_back([this, source, remote_id, operation, reply, deadline] {
if (std::chrono::steady_clock::now() > deadline) { reply(false, "REQUEST_EXPIRED"); return; }
if (ControllerEvents(remote_id) != source || !IsAuthorizedController(remote_id)) return;
#if defined(_WIN32) || defined(__APPLE__) || (defined(__linux__) && !defined(__OHOS__))
if (operation == "status") {
const auto state = QueryScreenLock();
json result{{"lock_state", state == ScreenLockState::locked ? "locked"
: state == ScreenLockState::unlocked ? "unlocked" : "unknown"}};
#ifdef _WIN32
result["interactive_stage"] = WindowsInputStage();
result["service_available"] = local_service_available_.load();
result["send_sas_available"] = local_service_available_.load();
#else
result["send_sas_available"] = false;
#endif
reply(true, std::move(result));
} else if (operation == "lock") {
reply(true, {{"accepted", LockScreen()}});
} else {
#ifdef _WIN32
if (!local_service_available_.load()) { reply(false, "SERVICE_UNAVAILABLE"); return; }
pending_windows_service_sas_.store(true);
reply(true, {{"accepted", true}, {"state", "queued"}});
#else
reply(false, "UNSUPPORTED_OPERATION");
#endif
}
#else
reply(false, "UNSUPPORTED_OPERATION");
#endif
});
} else {
reply(false, "UNSUPPORTED_OPERATION");
}
@@ -44,4 +89,15 @@ void GuiRuntime::HandleAutomation(const std::string& remote_id,
reply(false, "INVALID_ARGUMENT");
}
}
void GuiRuntime::ProcessAutomationRequests() {
std::function<void()> task;
{
std::lock_guard lock(automation_mutex_);
if (automation_tasks_.empty() || automation_closing_) return;
task = std::move(automation_tasks_.front());
automation_tasks_.pop_front();
}
try { task(); } catch (...) {}
}
} // namespace crossdesk
@@ -65,6 +65,11 @@ GuiRuntime::GuiRuntime()
}) {}
GuiRuntime::~GuiRuntime() {
{
std::lock_guard lock(automation_mutex_);
automation_closing_ = true;
automation_tasks_.clear();
}
remote_input_.Stop();
#if _WIN32
windows_rdp_handoff_allowed_->store(false, std::memory_order_relaxed);
@@ -104,6 +104,7 @@ class GuiRuntime : protected gui_detail::GuiState {
void HandleServerControllerDisconnected(const std::string& remote_id,
const char* reason);
void HandleWindowsServiceIntegration();
void ProcessAutomationRequests();
void HandlePrivacy();
void HandleScreenLock();
bool IsAuthorizedController(const std::string& remote_id);
@@ -153,6 +154,9 @@ class GuiRuntime : protected gui_detail::GuiState {
void SendRemoteInput(const RemoteAction& action);
InputOutcome ApplyRemoteInput(const std::string& remote_id, const RemoteAction& action);
void HandleAutomation(const std::string& remote_id, const nlohmann::json& request);
std::mutex automation_mutex_;
std::deque<std::function<void()>> automation_tasks_;
bool automation_closing_ = false;
InputOutcome InjectRemoteMouse(const RemoteAction& action, int display);
std::string gallery_group_control_id_;