@stim-cli/server 1.20.2 → 1.22.0
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/README.md +785 -276
- package/dist/{protocol-CjUChTWJ.mjs → protocol-ZY9j2h32.mjs} +1038 -79
- package/dist/protocol.mjs +1 -1
- package/dist/protocol.schema.json +2760 -122
- package/dist/stim-frames/ProcessStream.swift +2 -1
- package/dist/stim-frames/SimulatorHID.swift +33 -7
- package/dist/stim-frames/SimulatorPosture.swift +0 -6
- package/dist/{stim-server-FWcuNpW7.mjs → stim-server-BKcEacbU.mjs} +4894 -2942
- package/dist/stim-server.mjs +1 -1
- package/dist/stim-service-runner.d.mts +13 -0
- package/dist/stim-service-runner.mjs +96 -0
- package/package.json +8 -3
- package/dist/stats-read.d.mts +0 -1
- package/dist/stats-read.mjs +0 -46
|
@@ -64,6 +64,7 @@ public enum ProcessStream {
|
|
|
64
64
|
arguments: [String],
|
|
65
65
|
cwd: String,
|
|
66
66
|
environment: [String: String]? = nil,
|
|
67
|
+
standardInput: FileHandle? = nil,
|
|
67
68
|
onLine: @escaping @Sendable (OutputLine) -> Void,
|
|
68
69
|
onExit: @escaping @Sendable (Int32) -> Void
|
|
69
70
|
) throws -> Process {
|
|
@@ -72,7 +73,7 @@ public enum ProcessStream {
|
|
|
72
73
|
process.arguments = arguments
|
|
73
74
|
process.currentDirectoryURL = URL(fileURLWithPath: cwd)
|
|
74
75
|
if let environment { process.environment = environment }
|
|
75
|
-
process.standardInput = FileHandle.nullDevice
|
|
76
|
+
process.standardInput = standardInput ?? FileHandle.nullDevice
|
|
76
77
|
let out = Pipe()
|
|
77
78
|
let err = Pipe()
|
|
78
79
|
process.standardOutput = out
|
|
@@ -65,6 +65,29 @@ enum TouchPhase {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
struct SimulatorTouchSequence {
|
|
69
|
+
private var originEdge: UInt32 = 0
|
|
70
|
+
|
|
71
|
+
mutating func edge(for phase: TouchPhase, at point: CGPoint, isMultiTouch: Bool = false) -> UInt32 {
|
|
72
|
+
if phase == .down {
|
|
73
|
+
originEdge = isMultiTouch ? 0 : Self.edge(at: point)
|
|
74
|
+
}
|
|
75
|
+
let edge = originEdge
|
|
76
|
+
if phase == .up { originEdge = 0 }
|
|
77
|
+
return edge
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Indigo's native screen-edge identifiers follow Siniulator's ScreenGeometry.edge:
|
|
81
|
+
// https://github.com/kmagiera/Siniulator/blob/e181521a32595c2e537e1ee6c359aae254dbfed3/Sources/Siniulator/ScreenView.swift#L32-L38
|
|
82
|
+
private static func edge(at point: CGPoint) -> UInt32 {
|
|
83
|
+
if point.y >= 0.97 { return 3 }
|
|
84
|
+
if point.y <= 0.03 { return 1 }
|
|
85
|
+
if point.x <= 0.03 { return 2 }
|
|
86
|
+
if point.x >= 0.97 { return 4 }
|
|
87
|
+
return 0
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
68
91
|
/// Input for one booted simulator. It uses the simulator's CoreDevice HID
|
|
69
92
|
/// service when the runtime has one, and SimulatorKit's legacy HID client
|
|
70
93
|
/// otherwise. `isConnected` turns false once the CoreDevice connection closes,
|
|
@@ -74,6 +97,7 @@ enum TouchPhase {
|
|
|
74
97
|
/// Construction performs synchronous CoreSimulator XPC lookups and must run off the main thread.
|
|
75
98
|
final class SimulatorHID {
|
|
76
99
|
private let transport: Transport
|
|
100
|
+
private var touchSequence = SimulatorTouchSequence()
|
|
77
101
|
private let legacyUntil = Date().addingTimeInterval(10)
|
|
78
102
|
|
|
79
103
|
private enum Transport {
|
|
@@ -104,9 +128,10 @@ final class SimulatorHID {
|
|
|
104
128
|
|
|
105
129
|
/// `point` is a fraction of the screen in its native orientation, origin top-left.
|
|
106
130
|
func touch(_ phase: TouchPhase, at point: CGPoint, second: CGPoint? = nil, screenID: UInt32 = 1) {
|
|
131
|
+
let edge = touchSequence.edge(for: phase, at: point, isMultiTouch: second != nil)
|
|
107
132
|
switch transport {
|
|
108
|
-
case .coreDevice(let coreDevice): coreDevice.touch(phase, at: point, second: second, screenID: screenID)
|
|
109
|
-
case .legacy(let legacy): legacy.touch(phase, at: point, second: second, screenID: screenID)
|
|
133
|
+
case .coreDevice(let coreDevice): coreDevice.touch(phase, at: point, second: second, screenID: screenID, edge: edge)
|
|
134
|
+
case .legacy(let legacy): legacy.touch(phase, at: point, second: second, screenID: screenID, edge: edge)
|
|
110
135
|
}
|
|
111
136
|
}
|
|
112
137
|
|
|
@@ -211,12 +236,13 @@ final class CoreDeviceHID {
|
|
|
211
236
|
}
|
|
212
237
|
|
|
213
238
|
// dtuhidd's DigitizerTarget is 0 for the main screen and the screen ID for any other display.
|
|
214
|
-
func touch(_ phase: TouchPhase, at point: CGPoint, second: CGPoint?, screenID: UInt32) {
|
|
239
|
+
func touch(_ phase: TouchPhase, at point: CGPoint, second: CGPoint?, screenID: UInt32, edge: UInt32) {
|
|
215
240
|
let contact = xpc_dictionary_create(nil, nil, 0)
|
|
216
241
|
xpc_dictionary_set_double(contact, "x", point.x)
|
|
217
242
|
xpc_dictionary_set_double(contact, "y", point.y)
|
|
218
243
|
let payload = dictionary([
|
|
219
|
-
"eventType": phase == .down ? 0 : phase == .move ? 1 : 2, "edge":
|
|
244
|
+
"eventType": phase == .down ? 0 : phase == .move ? 1 : 2, "edge": UInt64(edge),
|
|
245
|
+
"target": UInt64(screenID == 1 ? 0 : screenID),
|
|
220
246
|
])
|
|
221
247
|
xpc_dictionary_set_value(payload, "pointOne", contact)
|
|
222
248
|
if let second {
|
|
@@ -313,17 +339,17 @@ private final class LegacyHID {
|
|
|
313
339
|
// The simulator's SimulatorHID addresses a display's digitizer by its screen
|
|
314
340
|
// ID with bit 30 set, and backboardd aborts on a target it has no service
|
|
315
341
|
// for. The main display keeps its legacy target.
|
|
316
|
-
func touch(_ phase: TouchPhase, at point: CGPoint, second: CGPoint?, screenID: UInt32) {
|
|
342
|
+
func touch(_ phase: TouchPhase, at point: CGPoint, second: CGPoint?, screenID: UInt32, edge: UInt32) {
|
|
317
343
|
let target = screenID == 1 ? Self.mainScreenTarget : 0x4000_0000 | screenID
|
|
318
344
|
var point = point
|
|
319
345
|
// The builder returns nil for a drag that arrives within 16 ms of the previous message.
|
|
320
346
|
let message: UnsafeMutableRawPointer?
|
|
321
347
|
if var other = second {
|
|
322
348
|
message = SimulatorKit.mouseMessage?(
|
|
323
|
-
&point, &other, target, UInt(phase.eventType.rawValue), CGSize(width: 1, height: 1),
|
|
349
|
+
&point, &other, target, UInt(phase.eventType.rawValue), CGSize(width: 1, height: 1), edge)
|
|
324
350
|
} else {
|
|
325
351
|
message = SimulatorKit.mouseMessage?(
|
|
326
|
-
&point, nil, target, UInt(phase.eventType.rawValue), CGSize(width: 1, height: 1),
|
|
352
|
+
&point, nil, target, UInt(phase.eventType.rawValue), CGSize(width: 1, height: 1), edge)
|
|
327
353
|
}
|
|
328
354
|
guard let message else { return }
|
|
329
355
|
deliver(message)
|
|
@@ -190,12 +190,6 @@ public enum SimulatorPosture {
|
|
|
190
190
|
/// call it off the main thread.
|
|
191
191
|
public static func isAvailable(udid: String) -> Bool { connection(udid: udid) != nil }
|
|
192
192
|
|
|
193
|
-
/// The posture Stim Desktop last moved this simulator to, if any.
|
|
194
|
-
public static func lastPosture(udid: String) -> DuoPosture? {
|
|
195
|
-
guard let angle = lastAngle(udid: udid) else { return nil }
|
|
196
|
-
return DuoPosture.allCases.first { $0.hingeAngle == angle }
|
|
197
|
-
}
|
|
198
|
-
|
|
199
193
|
/// The hinge angle Stim Desktop last moved this simulator to, in degrees.
|
|
200
194
|
public static func lastAngle(udid: String) -> Double? {
|
|
201
195
|
lock.lock()
|