@midscene/computer 1.9.1-beta-20260605031620.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/darwin/rdp-helper +0 -0
- package/bin/linux/rdp-helper +0 -0
- package/dist/es/cli.mjs +3 -4
- package/dist/es/index.mjs +3 -4
- package/dist/es/mcp-server.mjs +3 -4
- package/dist/lib/cli.js +3 -4
- package/dist/lib/index.js +3 -4
- package/dist/lib/mcp-server.js +3 -4
- package/native/rdp/include/rdp_helper_session.hpp +0 -23
- package/native/rdp/src/json.cpp +19 -28
- package/native/rdp/src/main.cpp +11 -25
- package/native/rdp/src/session.cpp +0 -108
- package/package.json +3 -3
package/bin/darwin/rdp-helper
CHANGED
|
Binary file
|
package/bin/linux/rdp-helper
CHANGED
|
Binary file
|
package/dist/es/cli.mjs
CHANGED
|
@@ -520,7 +520,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
520
520
|
}
|
|
521
521
|
async healthCheck() {
|
|
522
522
|
console.log('[HealthCheck] Starting health check...');
|
|
523
|
-
console.log("[HealthCheck] @midscene/computer v1.9.1
|
|
523
|
+
console.log("[HealthCheck] @midscene/computer v1.9.1");
|
|
524
524
|
console.log('[HealthCheck] Taking screenshot...');
|
|
525
525
|
const screenshotTimeout = 15000;
|
|
526
526
|
let timeoutId;
|
|
@@ -1239,8 +1239,7 @@ class RDPDevice {
|
|
|
1239
1239
|
port: this.options.port,
|
|
1240
1240
|
username: this.options.username
|
|
1241
1241
|
});
|
|
1242
|
-
|
|
1243
|
-
this.connectionInfo = await this.backend.connect(config);
|
|
1242
|
+
this.connectionInfo = await this.backend.connect(this.options);
|
|
1244
1243
|
this.cursorPosition = [
|
|
1245
1244
|
Math.round(this.connectionInfo.size.width / 2),
|
|
1246
1245
|
Math.round(this.connectionInfo.size.height / 2)
|
|
@@ -1698,7 +1697,7 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
|
|
|
1698
1697
|
const tools = new ComputerMidsceneTools();
|
|
1699
1698
|
runToolsCLI(tools, 'midscene-computer', {
|
|
1700
1699
|
stripPrefix: 'computer_',
|
|
1701
|
-
version: "1.9.1
|
|
1700
|
+
version: "1.9.1",
|
|
1702
1701
|
extraCommands: createReportCliCommands()
|
|
1703
1702
|
}).catch((e)=>{
|
|
1704
1703
|
process.exit(reportCLIError(e));
|
package/dist/es/index.mjs
CHANGED
|
@@ -520,7 +520,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
520
520
|
}
|
|
521
521
|
async healthCheck() {
|
|
522
522
|
console.log('[HealthCheck] Starting health check...');
|
|
523
|
-
console.log("[HealthCheck] @midscene/computer v1.9.1
|
|
523
|
+
console.log("[HealthCheck] @midscene/computer v1.9.1");
|
|
524
524
|
console.log('[HealthCheck] Taking screenshot...');
|
|
525
525
|
const screenshotTimeout = 15000;
|
|
526
526
|
let timeoutId;
|
|
@@ -1282,8 +1282,7 @@ class RDPDevice {
|
|
|
1282
1282
|
port: this.options.port,
|
|
1283
1283
|
username: this.options.username
|
|
1284
1284
|
});
|
|
1285
|
-
|
|
1286
|
-
this.connectionInfo = await this.backend.connect(config);
|
|
1285
|
+
this.connectionInfo = await this.backend.connect(this.options);
|
|
1287
1286
|
this.cursorPosition = [
|
|
1288
1287
|
Math.round(this.connectionInfo.size.width / 2),
|
|
1289
1288
|
Math.round(this.connectionInfo.size.height / 2)
|
|
@@ -1739,7 +1738,7 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
|
|
|
1739
1738
|
}
|
|
1740
1739
|
}
|
|
1741
1740
|
function version() {
|
|
1742
|
-
const currentVersion = "1.9.1
|
|
1741
|
+
const currentVersion = "1.9.1";
|
|
1743
1742
|
console.log(`@midscene/computer v${currentVersion}`);
|
|
1744
1743
|
return currentVersion;
|
|
1745
1744
|
}
|
package/dist/es/mcp-server.mjs
CHANGED
|
@@ -520,7 +520,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
520
520
|
}
|
|
521
521
|
async healthCheck() {
|
|
522
522
|
console.log('[HealthCheck] Starting health check...');
|
|
523
|
-
console.log("[HealthCheck] @midscene/computer v1.9.1
|
|
523
|
+
console.log("[HealthCheck] @midscene/computer v1.9.1");
|
|
524
524
|
console.log('[HealthCheck] Taking screenshot...');
|
|
525
525
|
const screenshotTimeout = 15000;
|
|
526
526
|
let timeoutId;
|
|
@@ -1239,8 +1239,7 @@ class RDPDevice {
|
|
|
1239
1239
|
port: this.options.port,
|
|
1240
1240
|
username: this.options.username
|
|
1241
1241
|
});
|
|
1242
|
-
|
|
1243
|
-
this.connectionInfo = await this.backend.connect(config);
|
|
1242
|
+
this.connectionInfo = await this.backend.connect(this.options);
|
|
1244
1243
|
this.cursorPosition = [
|
|
1245
1244
|
Math.round(this.connectionInfo.size.width / 2),
|
|
1246
1245
|
Math.round(this.connectionInfo.size.height / 2)
|
|
@@ -1702,7 +1701,7 @@ class ComputerMCPServer extends BaseMCPServer {
|
|
|
1702
1701
|
constructor(toolsManager){
|
|
1703
1702
|
super({
|
|
1704
1703
|
name: '@midscene/computer-mcp',
|
|
1705
|
-
version: "1.9.1
|
|
1704
|
+
version: "1.9.1",
|
|
1706
1705
|
description: 'Control the computer desktop using natural language commands'
|
|
1707
1706
|
}, toolsManager);
|
|
1708
1707
|
}
|
package/dist/lib/cli.js
CHANGED
|
@@ -546,7 +546,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
546
546
|
}
|
|
547
547
|
async healthCheck() {
|
|
548
548
|
console.log('[HealthCheck] Starting health check...');
|
|
549
|
-
console.log("[HealthCheck] @midscene/computer v1.9.1
|
|
549
|
+
console.log("[HealthCheck] @midscene/computer v1.9.1");
|
|
550
550
|
console.log('[HealthCheck] Taking screenshot...');
|
|
551
551
|
const screenshotTimeout = 15000;
|
|
552
552
|
let timeoutId;
|
|
@@ -1266,8 +1266,7 @@ class RDPDevice {
|
|
|
1266
1266
|
port: this.options.port,
|
|
1267
1267
|
username: this.options.username
|
|
1268
1268
|
});
|
|
1269
|
-
|
|
1270
|
-
this.connectionInfo = await this.backend.connect(config);
|
|
1269
|
+
this.connectionInfo = await this.backend.connect(this.options);
|
|
1271
1270
|
this.cursorPosition = [
|
|
1272
1271
|
Math.round(this.connectionInfo.size.width / 2),
|
|
1273
1272
|
Math.round(this.connectionInfo.size.height / 2)
|
|
@@ -1725,7 +1724,7 @@ class ComputerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools
|
|
|
1725
1724
|
const tools = new ComputerMidsceneTools();
|
|
1726
1725
|
(0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-computer', {
|
|
1727
1726
|
stripPrefix: 'computer_',
|
|
1728
|
-
version: "1.9.1
|
|
1727
|
+
version: "1.9.1",
|
|
1729
1728
|
extraCommands: (0, core_namespaceObject.createReportCliCommands)()
|
|
1730
1729
|
}).catch((e)=>{
|
|
1731
1730
|
process.exit((0, cli_namespaceObject.reportCLIError)(e));
|
package/dist/lib/index.js
CHANGED
|
@@ -573,7 +573,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
573
573
|
}
|
|
574
574
|
async healthCheck() {
|
|
575
575
|
console.log('[HealthCheck] Starting health check...');
|
|
576
|
-
console.log("[HealthCheck] @midscene/computer v1.9.1
|
|
576
|
+
console.log("[HealthCheck] @midscene/computer v1.9.1");
|
|
577
577
|
console.log('[HealthCheck] Taking screenshot...');
|
|
578
578
|
const screenshotTimeout = 15000;
|
|
579
579
|
let timeoutId;
|
|
@@ -1337,8 +1337,7 @@ class RDPDevice {
|
|
|
1337
1337
|
port: this.options.port,
|
|
1338
1338
|
username: this.options.username
|
|
1339
1339
|
});
|
|
1340
|
-
|
|
1341
|
-
this.connectionInfo = await this.backend.connect(config);
|
|
1340
|
+
this.connectionInfo = await this.backend.connect(this.options);
|
|
1342
1341
|
this.cursorPosition = [
|
|
1343
1342
|
Math.round(this.connectionInfo.size.width / 2),
|
|
1344
1343
|
Math.round(this.connectionInfo.size.height / 2)
|
|
@@ -1797,7 +1796,7 @@ class ComputerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools
|
|
|
1797
1796
|
}
|
|
1798
1797
|
const env_namespaceObject = require("@midscene/shared/env");
|
|
1799
1798
|
function version() {
|
|
1800
|
-
const currentVersion = "1.9.1
|
|
1799
|
+
const currentVersion = "1.9.1";
|
|
1801
1800
|
console.log(`@midscene/computer v${currentVersion}`);
|
|
1802
1801
|
return currentVersion;
|
|
1803
1802
|
}
|
package/dist/lib/mcp-server.js
CHANGED
|
@@ -560,7 +560,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
560
560
|
}
|
|
561
561
|
async healthCheck() {
|
|
562
562
|
console.log('[HealthCheck] Starting health check...');
|
|
563
|
-
console.log("[HealthCheck] @midscene/computer v1.9.1
|
|
563
|
+
console.log("[HealthCheck] @midscene/computer v1.9.1");
|
|
564
564
|
console.log('[HealthCheck] Taking screenshot...');
|
|
565
565
|
const screenshotTimeout = 15000;
|
|
566
566
|
let timeoutId;
|
|
@@ -1280,8 +1280,7 @@ class RDPDevice {
|
|
|
1280
1280
|
port: this.options.port,
|
|
1281
1281
|
username: this.options.username
|
|
1282
1282
|
});
|
|
1283
|
-
|
|
1284
|
-
this.connectionInfo = await this.backend.connect(config);
|
|
1283
|
+
this.connectionInfo = await this.backend.connect(this.options);
|
|
1285
1284
|
this.cursorPosition = [
|
|
1286
1285
|
Math.round(this.connectionInfo.size.width / 2),
|
|
1287
1286
|
Math.round(this.connectionInfo.size.height / 2)
|
|
@@ -1745,7 +1744,7 @@ class ComputerMCPServer extends mcp_namespaceObject.BaseMCPServer {
|
|
|
1745
1744
|
constructor(toolsManager){
|
|
1746
1745
|
super({
|
|
1747
1746
|
name: '@midscene/computer-mcp',
|
|
1748
|
-
version: "1.9.1
|
|
1747
|
+
version: "1.9.1",
|
|
1749
1748
|
description: 'Control the computer desktop using natural language commands'
|
|
1750
1749
|
}, toolsManager);
|
|
1751
1750
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
#include <atomic>
|
|
4
|
-
#include <condition_variable>
|
|
5
3
|
#include <cstdint>
|
|
6
4
|
#include <mutex>
|
|
7
5
|
#include <optional>
|
|
@@ -70,16 +68,6 @@ class FreeRdpSessionTransport final : public SessionTransport {
|
|
|
70
68
|
bool IsConnected() const override;
|
|
71
69
|
std::optional<ErrorPayload> LastError() const override;
|
|
72
70
|
void MarkGdiInitialized();
|
|
73
|
-
// Chain a frame-paint hook onto the GDI update pipeline so the session can
|
|
74
|
-
// tell when the first real desktop frame has arrived. Must be called after
|
|
75
|
-
// gdi_init() has installed its own EndPaint handler.
|
|
76
|
-
void HookEndPaint(rdpUpdate* update);
|
|
77
|
-
// Invoked from the event loop after each EndPaint; records that at least one
|
|
78
|
-
// real paint has reached the local framebuffer and wakes Connect().
|
|
79
|
-
void MarkFramePainted();
|
|
80
|
-
BOOL CallOriginalEndPaint(rdpContext* context);
|
|
81
|
-
// Mark the session as no longer active and wake any first-frame waiter.
|
|
82
|
-
void SignalSessionInactive();
|
|
83
71
|
|
|
84
72
|
FreeRdpSessionTransport(const FreeRdpSessionTransport&) = delete;
|
|
85
73
|
FreeRdpSessionTransport& operator=(const FreeRdpSessionTransport&) = delete;
|
|
@@ -93,17 +81,6 @@ class FreeRdpSessionTransport final : public SessionTransport {
|
|
|
93
81
|
bool running_ = false;
|
|
94
82
|
bool connected_ = false;
|
|
95
83
|
bool gdi_initialized_ = false;
|
|
96
|
-
// Number of desktop paints that have reached the local framebuffer. A fresh
|
|
97
|
-
// RDP session exposes a zero-filled (all black) buffer until the first paint
|
|
98
|
-
// is processed, so screenshots taken before this is > 0 would be blank.
|
|
99
|
-
std::atomic<uint64_t> frames_painted_{0};
|
|
100
|
-
// Tracks whether the session is still alive while Connect() waits for the
|
|
101
|
-
// first frame, so a drop during that window wakes the wait immediately
|
|
102
|
-
// instead of stalling until the timeout.
|
|
103
|
-
std::atomic<bool> session_active_{false};
|
|
104
|
-
std::condition_variable frame_cv_;
|
|
105
|
-
std::mutex frame_mutex_;
|
|
106
|
-
pEndPaint original_end_paint_ = nullptr;
|
|
107
84
|
uint16_t mouse_x_ = 0;
|
|
108
85
|
uint16_t mouse_y_ = 0;
|
|
109
86
|
std::string session_id_;
|
package/native/rdp/src/json.cpp
CHANGED
|
@@ -434,38 +434,29 @@ std::string ExtractRequestId(std::string_view line) {
|
|
|
434
434
|
}
|
|
435
435
|
|
|
436
436
|
std::optional<ParsedRequest> ParseRequestLine(std::string_view line) {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
try {
|
|
443
|
-
JsonParser parser(line);
|
|
444
|
-
JsonValue root = parser.Parse();
|
|
445
|
-
if (!root.IsObject()) {
|
|
446
|
-
return std::nullopt;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
const JsonObject& request_object = root.AsObject();
|
|
450
|
-
const auto request_id = GetStringField(request_object, "id");
|
|
451
|
-
const JsonObject* payload = GetObjectField(request_object, "payload");
|
|
452
|
-
if (!request_id.has_value() || !payload) {
|
|
453
|
-
return std::nullopt;
|
|
454
|
-
}
|
|
437
|
+
JsonParser parser(line);
|
|
438
|
+
JsonValue root = parser.Parse();
|
|
439
|
+
if (!root.IsObject()) {
|
|
440
|
+
return std::nullopt;
|
|
441
|
+
}
|
|
455
442
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
443
|
+
const JsonObject& request_object = root.AsObject();
|
|
444
|
+
const auto request_id = GetStringField(request_object, "id");
|
|
445
|
+
const JsonObject* payload = GetObjectField(request_object, "payload");
|
|
446
|
+
if (!request_id.has_value() || !payload) {
|
|
447
|
+
return std::nullopt;
|
|
448
|
+
}
|
|
460
449
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
ParseRequestType(*type_name).value_or(RequestType::kUnknown),
|
|
464
|
-
*payload,
|
|
465
|
-
};
|
|
466
|
-
} catch (const std::exception&) {
|
|
450
|
+
const auto type_name = GetStringField(*payload, "type");
|
|
451
|
+
if (!type_name.has_value()) {
|
|
467
452
|
return std::nullopt;
|
|
468
453
|
}
|
|
454
|
+
|
|
455
|
+
return ParsedRequest{
|
|
456
|
+
*request_id,
|
|
457
|
+
ParseRequestType(*type_name).value_or(RequestType::kUnknown),
|
|
458
|
+
*payload,
|
|
459
|
+
};
|
|
469
460
|
}
|
|
470
461
|
|
|
471
462
|
std::optional<std::string> GetStringField(const JsonObject& object,
|
package/native/rdp/src/main.cpp
CHANGED
|
@@ -285,32 +285,18 @@ int main() {
|
|
|
285
285
|
midscene::rdp::FreeRdpSessionTransport transport;
|
|
286
286
|
std::string line;
|
|
287
287
|
while (std::getline(std::cin, line)) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
const std::string request_id = midscene::rdp::ExtractRequestId(line);
|
|
297
|
-
std::cout << midscene::rdp::MakeErrorResponse(
|
|
298
|
-
request_id, "invalid_request",
|
|
299
|
-
"Failed to parse helper request JSON")
|
|
300
|
-
<< '\n';
|
|
301
|
-
std::cout.flush();
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
std::cout << midscene::rdp::HandleRequest(*request, transport) << '\n';
|
|
306
|
-
std::cout.flush();
|
|
307
|
-
} catch (const std::exception& error) {
|
|
308
|
-
const std::string request_id = midscene::rdp::ExtractRequestId(line);
|
|
309
|
-
std::cout << midscene::rdp::MakeErrorResponse(request_id, "internal_error",
|
|
310
|
-
error.what())
|
|
311
|
-
<< '\n';
|
|
312
|
-
std::cout.flush();
|
|
288
|
+
const auto request = midscene::rdp::ParseRequestLine(line);
|
|
289
|
+
const std::string request_id =
|
|
290
|
+
request.has_value() ? request->id : midscene::rdp::ExtractRequestId(line);
|
|
291
|
+
|
|
292
|
+
if (!request.has_value()) {
|
|
293
|
+
std::fprintf(stderr, "Failed to parse helper request JSON\n");
|
|
294
|
+
std::fflush(stderr);
|
|
295
|
+
continue;
|
|
313
296
|
}
|
|
297
|
+
|
|
298
|
+
std::cout << midscene::rdp::HandleRequest(*request, transport) << '\n';
|
|
299
|
+
std::cout.flush();
|
|
314
300
|
}
|
|
315
301
|
|
|
316
302
|
transport.Disconnect();
|
|
@@ -29,26 +29,6 @@ struct MidsceneRdpContext {
|
|
|
29
29
|
FreeRdpSessionTransport* owner = nullptr;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
// Maximum time Connect() waits for the first desktop frame before giving up.
|
|
33
|
-
// Normal sessions paint within a few hundred milliseconds; a session that
|
|
34
|
-
// never paints within this window is treated as blank/locked and fails fast
|
|
35
|
-
// instead of feeding an all-black screenshot to the caller.
|
|
36
|
-
constexpr int kFirstFrameTimeoutMs = 10'000;
|
|
37
|
-
|
|
38
|
-
// EndPaint hook chained in front of FreeRDP's GDI handler. FreeRDP invokes
|
|
39
|
-
// this from the event loop after every paint PDU; we defer to the original
|
|
40
|
-
// GDI EndPaint (which actually blits into the primary buffer) and then mark
|
|
41
|
-
// that a real frame has landed.
|
|
42
|
-
BOOL MidsceneEndPaint(rdpContext* context) {
|
|
43
|
-
auto* typed_context = reinterpret_cast<MidsceneRdpContext*>(context);
|
|
44
|
-
BOOL ok = TRUE;
|
|
45
|
-
if (typed_context->owner) {
|
|
46
|
-
ok = typed_context->owner->CallOriginalEndPaint(context);
|
|
47
|
-
typed_context->owner->MarkFramePainted();
|
|
48
|
-
}
|
|
49
|
-
return ok;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
32
|
std::string ToLower(std::string_view value) {
|
|
53
33
|
std::string lowered(value);
|
|
54
34
|
std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char ch) {
|
|
@@ -168,9 +148,6 @@ BOOL PostConnect(freerdp* instance) {
|
|
|
168
148
|
reinterpret_cast<MidsceneRdpContext*>(instance->context);
|
|
169
149
|
if (typed_context->owner) {
|
|
170
150
|
typed_context->owner->MarkGdiInitialized();
|
|
171
|
-
// gdi_init() just installed its EndPaint handler; chain ours on top so we
|
|
172
|
-
// can observe when the first real frame is painted.
|
|
173
|
-
typed_context->owner->HookEndPaint(instance->context->update);
|
|
174
151
|
}
|
|
175
152
|
|
|
176
153
|
rdpInput* input = instance->context ? instance->context->input : nullptr;
|
|
@@ -468,8 +445,6 @@ ConnectionInfo FreeRdpSessionTransport::Connect(const ConnectionConfig& config)
|
|
|
468
445
|
instance_ = instance;
|
|
469
446
|
mouse_x_ = 0;
|
|
470
447
|
mouse_y_ = 0;
|
|
471
|
-
frames_painted_.store(0, std::memory_order_relaxed);
|
|
472
|
-
original_end_paint_ = nullptr;
|
|
473
448
|
ClearSessionErrorLocked();
|
|
474
449
|
}
|
|
475
450
|
|
|
@@ -504,47 +479,7 @@ ConnectionInfo FreeRdpSessionTransport::Connect(const ConnectionConfig& config)
|
|
|
504
479
|
}
|
|
505
480
|
}
|
|
506
481
|
|
|
507
|
-
session_active_.store(true, std::memory_order_relaxed);
|
|
508
482
|
event_thread_ = std::thread(&FreeRdpSessionTransport::EventLoop, this);
|
|
509
|
-
|
|
510
|
-
// Block until the remote desktop paints its first frame. Without this the
|
|
511
|
-
// primary buffer is still zero-filled (all black) and an immediate
|
|
512
|
-
// screenshot would hand the caller a blank image, which the agent reads as
|
|
513
|
-
// "nothing on screen" and aborts. This race is the root cause of the
|
|
514
|
-
// intermittent blank-screenshot failures.
|
|
515
|
-
bool painted = false;
|
|
516
|
-
{
|
|
517
|
-
std::unique_lock<std::mutex> frame_lock(frame_mutex_);
|
|
518
|
-
painted = frame_cv_.wait_for(
|
|
519
|
-
frame_lock, std::chrono::milliseconds(kFirstFrameTimeoutMs),
|
|
520
|
-
[this] {
|
|
521
|
-
return frames_painted_.load(std::memory_order_relaxed) > 0 ||
|
|
522
|
-
!session_active_.load(std::memory_order_relaxed);
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
// A wait that ended without a frame because the session dropped should
|
|
527
|
-
// surface as a failure, not a false "painted" success.
|
|
528
|
-
if (frames_painted_.load(std::memory_order_relaxed) == 0) {
|
|
529
|
-
painted = false;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
if (!painted) {
|
|
533
|
-
std::string reason;
|
|
534
|
-
{
|
|
535
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
536
|
-
reason = connected_ ? std::string() : LastFreeRdpErrorLocked();
|
|
537
|
-
}
|
|
538
|
-
StopInstance(false);
|
|
539
|
-
std::string message =
|
|
540
|
-
"Connected to the RDP server but received no desktop frame within "
|
|
541
|
-
"timeout; the remote desktop may be blank or locked";
|
|
542
|
-
if (!reason.empty()) {
|
|
543
|
-
message += " (" + reason + ")";
|
|
544
|
-
}
|
|
545
|
-
throw std::runtime_error(message);
|
|
546
|
-
}
|
|
547
|
-
|
|
548
483
|
return info;
|
|
549
484
|
}
|
|
550
485
|
|
|
@@ -558,11 +493,6 @@ RawFrame FreeRdpSessionTransport::CaptureFrame() {
|
|
|
558
493
|
throw std::runtime_error("No remote framebuffer is available");
|
|
559
494
|
}
|
|
560
495
|
|
|
561
|
-
if (frames_painted_.load(std::memory_order_relaxed) == 0) {
|
|
562
|
-
throw std::runtime_error(
|
|
563
|
-
"Remote framebuffer has not received its first paint yet");
|
|
564
|
-
}
|
|
565
|
-
|
|
566
496
|
rdpGdi* gdi = instance_->context->gdi;
|
|
567
497
|
if (!gdi->primary_buffer || gdi->width <= 0 || gdi->height <= 0 || gdi->stride == 0) {
|
|
568
498
|
throw std::runtime_error("Remote framebuffer is empty");
|
|
@@ -818,8 +748,6 @@ void FreeRdpSessionTransport::ResetStateLocked() {
|
|
|
818
748
|
running_ = false;
|
|
819
749
|
connected_ = false;
|
|
820
750
|
gdi_initialized_ = false;
|
|
821
|
-
frames_painted_.store(0, std::memory_order_relaxed);
|
|
822
|
-
original_end_paint_ = nullptr;
|
|
823
751
|
mouse_x_ = 0;
|
|
824
752
|
mouse_y_ = 0;
|
|
825
753
|
session_id_.clear();
|
|
@@ -829,37 +757,6 @@ void FreeRdpSessionTransport::MarkGdiInitialized() {
|
|
|
829
757
|
gdi_initialized_ = true;
|
|
830
758
|
}
|
|
831
759
|
|
|
832
|
-
void FreeRdpSessionTransport::HookEndPaint(rdpUpdate* update) {
|
|
833
|
-
if (!update) {
|
|
834
|
-
return;
|
|
835
|
-
}
|
|
836
|
-
original_end_paint_ = update->EndPaint;
|
|
837
|
-
update->EndPaint = &MidsceneEndPaint;
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
BOOL FreeRdpSessionTransport::CallOriginalEndPaint(rdpContext* context) {
|
|
841
|
-
if (original_end_paint_) {
|
|
842
|
-
return original_end_paint_(context);
|
|
843
|
-
}
|
|
844
|
-
return TRUE;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
void FreeRdpSessionTransport::MarkFramePainted() {
|
|
848
|
-
{
|
|
849
|
-
std::lock_guard<std::mutex> lock(frame_mutex_);
|
|
850
|
-
frames_painted_.fetch_add(1, std::memory_order_relaxed);
|
|
851
|
-
}
|
|
852
|
-
frame_cv_.notify_all();
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
void FreeRdpSessionTransport::SignalSessionInactive() {
|
|
856
|
-
{
|
|
857
|
-
std::lock_guard<std::mutex> lock(frame_mutex_);
|
|
858
|
-
session_active_.store(false, std::memory_order_relaxed);
|
|
859
|
-
}
|
|
860
|
-
frame_cv_.notify_all();
|
|
861
|
-
}
|
|
862
|
-
|
|
863
760
|
void FreeRdpSessionTransport::ClearSessionErrorLocked() {
|
|
864
761
|
last_error_.reset();
|
|
865
762
|
}
|
|
@@ -925,8 +822,6 @@ void FreeRdpSessionTransport::StopInstance(bool preserve_session_error) {
|
|
|
925
822
|
}
|
|
926
823
|
}
|
|
927
824
|
|
|
928
|
-
SignalSessionInactive();
|
|
929
|
-
|
|
930
825
|
if (should_disconnect) {
|
|
931
826
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
932
827
|
freerdp_disconnect(instance_);
|
|
@@ -977,7 +872,6 @@ void FreeRdpSessionTransport::EventLoop() {
|
|
|
977
872
|
std::fprintf(stderr,
|
|
978
873
|
"RDP session event loop failed: freerdp_get_event_handles returned no handles\n");
|
|
979
874
|
std::fflush(stderr);
|
|
980
|
-
SignalSessionInactive();
|
|
981
875
|
return;
|
|
982
876
|
}
|
|
983
877
|
|
|
@@ -993,7 +887,6 @@ void FreeRdpSessionTransport::EventLoop() {
|
|
|
993
887
|
std::fprintf(stderr,
|
|
994
888
|
"RDP session event loop failed: WaitForMultipleObjects failed\n");
|
|
995
889
|
std::fflush(stderr);
|
|
996
|
-
SignalSessionInactive();
|
|
997
890
|
return;
|
|
998
891
|
}
|
|
999
892
|
|
|
@@ -1023,7 +916,6 @@ void FreeRdpSessionTransport::EventLoop() {
|
|
|
1023
916
|
std::fprintf(stderr, "RDP session event loop failed: %s\n",
|
|
1024
917
|
failure_reason.c_str());
|
|
1025
918
|
std::fflush(stderr);
|
|
1026
|
-
SignalSessionInactive();
|
|
1027
919
|
return;
|
|
1028
920
|
}
|
|
1029
921
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/computer",
|
|
3
|
-
"version": "1.9.1
|
|
3
|
+
"version": "1.9.1",
|
|
4
4
|
"description": "Midscene.js Computer Desktop Automation",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"@computer-use/libnut": "^4.2.0",
|
|
39
39
|
"clipboardy": "^4.0.0",
|
|
40
40
|
"screenshot-desktop": "^1.15.3",
|
|
41
|
-
"@midscene/core": "1.9.1
|
|
42
|
-
"@midscene/shared": "1.9.1
|
|
41
|
+
"@midscene/core": "1.9.1",
|
|
42
|
+
"@midscene/shared": "1.9.1"
|
|
43
43
|
},
|
|
44
44
|
"optionalDependencies": {
|
|
45
45
|
"node-mac-permissions": "2.5.0"
|