@houwert/conductor 0.27.2 → 0.29.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.
@@ -1,12 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VALID_KEYS = exports.HELP = void 0;
3
+ exports.ANDROID_KEYCODE = exports.VALID_KEYS = exports.HELP = void 0;
4
+ exports.dispatchKey = dispatchKey;
4
5
  exports.pressKey = pressKey;
5
6
  exports.HELP = ` press-key <key> Press a key (Enter, Backspace, Home, ...)
6
7
  --long-press Hold the button ~1.5s (tvOS remote buttons)
7
- --duration <seconds> Hold for a custom duration (tvOS remote buttons)`;
8
+ --duration <seconds> Hold for a custom duration (tvOS remote buttons)
9
+ --measure Time the app's response to the press
10
+ --repeat <n> With --measure, take n samples and report a distribution
11
+ --sequence <k1,k2,...> With --repeat, cycle these keys so focus oscillates
12
+ --timeout <ms> With --measure, give up on a sample after n ms (default 3000)
13
+ --poll-interval <ms> With --measure, delay between focus polls (default 0)
14
+ --settle <ms> With --measure on Android, render time to allow (default 700)`;
8
15
  const runner_js_1 = require("../runner.js");
9
16
  const output_js_1 = require("../output.js");
17
+ const input_latency_js_1 = require("./input-latency.js");
10
18
  const ios_js_1 = require("../drivers/ios.js");
11
19
  const android_js_1 = require("../drivers/android.js");
12
20
  const web_js_1 = require("../drivers/web.js");
@@ -87,7 +95,7 @@ const VEGA_REMOTE_BUTTONS = {
87
95
  VolumeDown: 'volumeDown',
88
96
  };
89
97
  // Android keyevent codes
90
- const ANDROID_KEYCODE = {
98
+ exports.ANDROID_KEYCODE = {
91
99
  Home: 3,
92
100
  Back: 4,
93
101
  Enter: 66,
@@ -124,6 +132,72 @@ const ANDROID_KEYCODE = {
124
132
  'TV Input HDMI 2': 244,
125
133
  'TV Input HDMI 3': 245,
126
134
  };
135
+ /**
136
+ * Send `key` on an already-connected driver. Split out of `pressKey` so
137
+ * `--measure` can reuse one driver across repeats instead of paying driver
138
+ * setup on every sample.
139
+ */
140
+ async function dispatchKey(driver, matched, holdSeconds) {
141
+ if (driver instanceof ios_js_1.IOSDriver) {
142
+ if (driver.platform === 'tvos') {
143
+ const tvosButton = TVOS_REMOTE_BUTTONS[matched];
144
+ const iosButton = IOS_BUTTON_MAP[matched];
145
+ if (tvosButton) {
146
+ await driver.pressButton(tvosButton, holdSeconds);
147
+ }
148
+ else if (iosButton) {
149
+ await driver.pressButton(iosButton, holdSeconds);
150
+ }
151
+ // Keys not mapped on tvOS are silently ignored
152
+ }
153
+ else {
154
+ const iosKey = IOS_KEY_MAP[matched];
155
+ const iosButton = IOS_BUTTON_MAP[matched];
156
+ if (iosKey) {
157
+ await driver.pressKey(iosKey);
158
+ }
159
+ else if (iosButton) {
160
+ await driver.pressButton(iosButton);
161
+ }
162
+ // Keys not mapped on iOS (e.g. Back, VolumeUp) are silently ignored
163
+ }
164
+ }
165
+ else if (driver instanceof web_js_1.WebDriver) {
166
+ const WEB_KEY_MAP = {
167
+ Enter: 'Enter',
168
+ Tab: 'Tab',
169
+ Backspace: 'Backspace',
170
+ Delete: 'Delete',
171
+ Escape: 'Escape',
172
+ Home: 'Home',
173
+ End: 'End',
174
+ // Canvas webtv apps (Lightning/WPE) navigate focus via the D-pad, which they listen
175
+ // for as arrow keys (and Enter for select). Maps the TV remote onto web keyboard.
176
+ 'Remote Dpad Up': 'ArrowUp',
177
+ 'Remote Dpad Down': 'ArrowDown',
178
+ 'Remote Dpad Left': 'ArrowLeft',
179
+ 'Remote Dpad Right': 'ArrowRight',
180
+ 'Remote Dpad Center': 'Enter',
181
+ };
182
+ const webKey = WEB_KEY_MAP[matched];
183
+ if (webKey) {
184
+ await driver.pressKey(webKey);
185
+ }
186
+ }
187
+ else if (driver instanceof vega_js_1.VegaDriver) {
188
+ const vegaButton = VEGA_REMOTE_BUTTONS[matched];
189
+ if (vegaButton) {
190
+ await driver.pressButton(vegaButton);
191
+ }
192
+ // Keys not mapped on vega are silently ignored
193
+ }
194
+ else if (driver instanceof android_js_1.AndroidDriver) {
195
+ const code = exports.ANDROID_KEYCODE[matched];
196
+ if (code !== undefined) {
197
+ await driver.pressKeyEvent(code);
198
+ }
199
+ }
200
+ }
127
201
  async function pressKey(key, opts = {}, sessionName = 'default', flags = {}) {
128
202
  // A held press is requested via --long-press (default 1.5s) or an explicit --duration.
129
203
  const holdSeconds = flags.duration ?? (flags.longPress ? 1.5 : undefined);
@@ -136,67 +210,39 @@ async function pressKey(key, opts = {}, sessionName = 'default', flags = {}) {
136
210
  (0, output_js_1.printError)(`Unknown key "${key}". Valid keys: ${exports.VALID_KEYS.join(', ')}`, opts);
137
211
  return 1;
138
212
  }
139
- const result = await (0, runner_js_1.runDirect)(async (driver) => {
140
- if (driver instanceof ios_js_1.IOSDriver) {
141
- if (driver.platform === 'tvos') {
142
- const tvosButton = TVOS_REMOTE_BUTTONS[matched];
143
- const iosButton = IOS_BUTTON_MAP[matched];
144
- if (tvosButton) {
145
- await driver.pressButton(tvosButton, holdSeconds);
146
- }
147
- else if (iosButton) {
148
- await driver.pressButton(iosButton, holdSeconds);
149
- }
150
- // Keys not mapped on tvOS are silently ignored
151
- }
152
- else {
153
- const iosKey = IOS_KEY_MAP[matched];
154
- const iosButton = IOS_BUTTON_MAP[matched];
155
- if (iosKey) {
156
- await driver.pressKey(iosKey);
157
- }
158
- else if (iosButton) {
159
- await driver.pressButton(iosButton);
160
- }
161
- // Keys not mapped on iOS (e.g. Back, VolumeUp) are silently ignored
213
+ if (flags.measure) {
214
+ const sequence = [matched];
215
+ for (const raw of flags.sequence ?? []) {
216
+ const k = exports.VALID_KEYS.find((v) => v.toLowerCase() === raw.trim().toLowerCase());
217
+ if (!k) {
218
+ (0, output_js_1.printError)(`Unknown key "${raw}" in --sequence. Valid keys: ${exports.VALID_KEYS.join(', ')}`, opts);
219
+ return 1;
162
220
  }
221
+ sequence.push(k);
163
222
  }
164
- else if (driver instanceof web_js_1.WebDriver) {
165
- const WEB_KEY_MAP = {
166
- Enter: 'Enter',
167
- Tab: 'Tab',
168
- Backspace: 'Backspace',
169
- Delete: 'Delete',
170
- Escape: 'Escape',
171
- Home: 'Home',
172
- End: 'End',
173
- // Canvas webtv apps (Lightning/WPE) navigate focus via the D-pad, which they listen
174
- // for as arrow keys (and Enter for select). Maps the TV remote onto web keyboard.
175
- 'Remote Dpad Up': 'ArrowUp',
176
- 'Remote Dpad Down': 'ArrowDown',
177
- 'Remote Dpad Left': 'ArrowLeft',
178
- 'Remote Dpad Right': 'ArrowRight',
179
- 'Remote Dpad Center': 'Enter',
180
- };
181
- const webKey = WEB_KEY_MAP[matched];
182
- if (webKey) {
183
- await driver.pressKey(webKey);
184
- }
223
+ const measureOpts = {
224
+ repeat: flags.repeat ?? 1,
225
+ timeoutMs: flags.timeoutMs ?? 3000,
226
+ pollIntervalMs: flags.pollIntervalMs ?? 0,
227
+ settleMs: flags.settleMs ?? 700,
228
+ appId: flags.appId,
229
+ holdSeconds,
230
+ };
231
+ try {
232
+ const report = await (0, input_latency_js_1.measureKeyLatency)(sessionName, sequence, measureOpts);
233
+ if (opts.json)
234
+ (0, output_js_1.printData)({ status: 'ok', ...report }, opts);
235
+ else
236
+ (0, input_latency_js_1.printLatencyReport)(report);
237
+ // Nothing measurable at all is a failure; boundary refusals are not.
238
+ return report.outcomes.moved === 0 && !report.pressToFrame ? 1 : 0;
185
239
  }
186
- else if (driver instanceof vega_js_1.VegaDriver) {
187
- const vegaButton = VEGA_REMOTE_BUTTONS[matched];
188
- if (vegaButton) {
189
- await driver.pressButton(vegaButton);
190
- }
191
- // Keys not mapped on vega are silently ignored
240
+ catch (err) {
241
+ (0, output_js_1.printError)(`press-key ${matched} --measure — ${err instanceof Error ? err.message : String(err)}`, opts);
242
+ return 1;
192
243
  }
193
- else if (driver instanceof android_js_1.AndroidDriver) {
194
- const code = ANDROID_KEYCODE[matched];
195
- if (code !== undefined) {
196
- await driver.pressKeyEvent(code);
197
- }
198
- }
199
- }, sessionName);
244
+ }
245
+ const result = await (0, runner_js_1.runDirect)((driver) => dispatchKey(driver, matched, holdSeconds), sessionName);
200
246
  if (result.success) {
201
247
  (0, output_js_1.printSuccess)(`press-key ${matched} — done`, opts);
202
248
  return 0;