@yume-chan/scrcpy 0.0.23 → 0.0.24

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.
Files changed (173) hide show
  1. package/CHANGELOG.json +21 -0
  2. package/CHANGELOG.md +11 -1
  3. package/LICENSE +1 -1
  4. package/esm/codec/av1.d.ts +364 -0
  5. package/esm/codec/av1.d.ts.map +1 -1
  6. package/esm/codec/av1.js +591 -0
  7. package/esm/codec/av1.js.map +1 -1
  8. package/esm/codec/nalu.d.ts +0 -9
  9. package/esm/codec/nalu.d.ts.map +1 -1
  10. package/esm/codec/nalu.js +56 -129
  11. package/esm/codec/nalu.js.map +1 -1
  12. package/esm/control/{basic.d.ts → empty.d.ts} +2 -2
  13. package/esm/control/empty.d.ts.map +1 -0
  14. package/esm/control/empty.js +3 -0
  15. package/esm/control/empty.js.map +1 -0
  16. package/esm/control/index.d.ts +1 -1
  17. package/esm/control/index.js +1 -1
  18. package/esm/control/rotate-device.js +2 -2
  19. package/esm/control/serializer.d.ts +2 -0
  20. package/esm/control/serializer.d.ts.map +1 -1
  21. package/esm/control/serializer.js +10 -4
  22. package/esm/control/serializer.js.map +1 -1
  23. package/esm/control/type.js +1 -1
  24. package/esm/control/type.js.map +1 -1
  25. package/esm/control/writer.d.ts +4 -1
  26. package/esm/control/writer.d.ts.map +1 -1
  27. package/esm/control/writer.js +12 -2
  28. package/esm/control/writer.js.map +1 -1
  29. package/esm/index.d.ts +0 -1
  30. package/esm/index.d.ts.map +1 -1
  31. package/esm/index.js +0 -1
  32. package/esm/index.js.map +1 -1
  33. package/esm/options/1_16/float.d.ts +6 -0
  34. package/esm/options/1_16/float.d.ts.map +1 -0
  35. package/esm/options/1_16/{float-to-uint16.js → float.js} +7 -6
  36. package/esm/options/1_16/float.js.map +1 -0
  37. package/esm/options/1_16/index.d.ts +1 -1
  38. package/esm/options/1_16/index.d.ts.map +1 -1
  39. package/esm/options/1_16/index.js +1 -1
  40. package/esm/options/1_16/index.js.map +1 -1
  41. package/esm/options/1_16/message.d.ts +4 -0
  42. package/esm/options/1_16/message.d.ts.map +1 -1
  43. package/esm/options/1_16/message.js +7 -4
  44. package/esm/options/1_16/message.js.map +1 -1
  45. package/esm/options/1_16/options.d.ts +13 -4
  46. package/esm/options/1_16/options.d.ts.map +1 -1
  47. package/esm/options/1_16/options.js +43 -15
  48. package/esm/options/1_16/options.js.map +1 -1
  49. package/esm/options/1_17.d.ts +2 -3
  50. package/esm/options/1_17.d.ts.map +1 -1
  51. package/esm/options/1_17.js +3 -6
  52. package/esm/options/1_17.js.map +1 -1
  53. package/esm/options/1_18.d.ts +2 -3
  54. package/esm/options/1_18.d.ts.map +1 -1
  55. package/esm/options/1_18.js +4 -24
  56. package/esm/options/1_18.js.map +1 -1
  57. package/esm/options/1_21.d.ts +9 -4
  58. package/esm/options/1_21.d.ts.map +1 -1
  59. package/esm/options/1_21.js +30 -7
  60. package/esm/options/1_21.js.map +1 -1
  61. package/esm/options/1_22/options.d.ts +2 -3
  62. package/esm/options/1_22/options.d.ts.map +1 -1
  63. package/esm/options/1_22/options.js +4 -7
  64. package/esm/options/1_22/options.js.map +1 -1
  65. package/esm/options/1_23.d.ts +2 -3
  66. package/esm/options/1_23.d.ts.map +1 -1
  67. package/esm/options/1_23.js +4 -7
  68. package/esm/options/1_23.js.map +1 -1
  69. package/esm/options/1_24.d.ts +2 -3
  70. package/esm/options/1_24.d.ts.map +1 -1
  71. package/esm/options/1_24.js +3 -6
  72. package/esm/options/1_24.js.map +1 -1
  73. package/esm/options/1_25/options.d.ts +2 -3
  74. package/esm/options/1_25/options.d.ts.map +1 -1
  75. package/esm/options/1_25/options.js +3 -6
  76. package/esm/options/1_25/options.js.map +1 -1
  77. package/esm/options/1_25/scroll.d.ts +3 -2
  78. package/esm/options/1_25/scroll.d.ts.map +1 -1
  79. package/esm/options/1_25/scroll.js +8 -7
  80. package/esm/options/1_25/scroll.js.map +1 -1
  81. package/esm/options/2_0.d.ts +10 -8
  82. package/esm/options/2_0.d.ts.map +1 -1
  83. package/esm/options/2_0.js +68 -74
  84. package/esm/options/2_0.js.map +1 -1
  85. package/esm/options/2_1.d.ts +4 -5
  86. package/esm/options/2_1.d.ts.map +1 -1
  87. package/esm/options/2_1.js +3 -6
  88. package/esm/options/2_1.js.map +1 -1
  89. package/esm/options/2_2.d.ts +4 -5
  90. package/esm/options/2_2.d.ts.map +1 -1
  91. package/esm/options/2_2.js +3 -6
  92. package/esm/options/2_2.js.map +1 -1
  93. package/esm/options/2_3.d.ts +59 -0
  94. package/esm/options/2_3.d.ts.map +1 -0
  95. package/esm/options/2_3.js +47 -0
  96. package/esm/options/2_3.js.map +1 -0
  97. package/esm/options/codec.d.ts +1 -0
  98. package/esm/options/codec.d.ts.map +1 -1
  99. package/esm/options/codec.js +1 -0
  100. package/esm/options/codec.js.map +1 -1
  101. package/esm/options/index.d.ts +1 -0
  102. package/esm/options/index.d.ts.map +1 -1
  103. package/esm/options/index.js +1 -0
  104. package/esm/options/index.js.map +1 -1
  105. package/esm/options/latest.d.ts +4 -4
  106. package/esm/options/latest.js +2 -2
  107. package/esm/options/types.d.ts +30 -32
  108. package/esm/options/types.d.ts.map +1 -1
  109. package/esm/options/types.js +77 -26
  110. package/esm/options/types.js.map +1 -1
  111. package/package.json +11 -11
  112. package/src/codec/av1.ts +670 -0
  113. package/src/codec/nalu.ts +67 -154
  114. package/src/control/empty.ts +3 -0
  115. package/src/control/index.ts +1 -1
  116. package/src/control/rotate-device.ts +2 -2
  117. package/src/control/serializer.ts +12 -4
  118. package/src/control/type.ts +1 -1
  119. package/src/control/writer.ts +16 -6
  120. package/src/index.ts +0 -1
  121. package/src/options/1_16/{float-to-uint16.ts → float.ts} +8 -6
  122. package/src/options/1_16/index.ts +1 -1
  123. package/src/options/1_16/message.ts +8 -4
  124. package/src/options/1_16/options.ts +68 -28
  125. package/src/options/1_17.ts +3 -9
  126. package/src/options/1_18.ts +3 -36
  127. package/src/options/1_21.ts +40 -11
  128. package/src/options/1_22/options.ts +4 -10
  129. package/src/options/1_23.ts +4 -10
  130. package/src/options/1_24.ts +3 -9
  131. package/src/options/1_25/options.ts +3 -9
  132. package/src/options/1_25/scroll.ts +10 -11
  133. package/src/options/2_0.ts +87 -92
  134. package/src/options/2_1.ts +3 -9
  135. package/src/options/2_2.ts +3 -9
  136. package/src/options/2_3.ts +70 -0
  137. package/src/options/codec.ts +6 -0
  138. package/src/options/index.ts +1 -0
  139. package/src/options/latest.ts +4 -4
  140. package/src/options/types.ts +89 -98
  141. package/tsconfig.build.tsbuildinfo +1 -1
  142. package/esm/control/basic.d.ts.map +0 -1
  143. package/esm/control/basic.js +0 -3
  144. package/esm/control/basic.js.map +0 -1
  145. package/esm/device-message/ack-clipboard.d.ts +0 -9
  146. package/esm/device-message/ack-clipboard.d.ts.map +0 -1
  147. package/esm/device-message/ack-clipboard.js +0 -6
  148. package/esm/device-message/ack-clipboard.js.map +0 -1
  149. package/esm/device-message/clipboard.d.ts +0 -10
  150. package/esm/device-message/clipboard.d.ts.map +0 -1
  151. package/esm/device-message/clipboard.js +0 -7
  152. package/esm/device-message/clipboard.js.map +0 -1
  153. package/esm/device-message/index.d.ts +0 -5
  154. package/esm/device-message/index.d.ts.map +0 -1
  155. package/esm/device-message/index.js +0 -5
  156. package/esm/device-message/index.js.map +0 -1
  157. package/esm/device-message/stream.d.ts +0 -8
  158. package/esm/device-message/stream.d.ts.map +0 -1
  159. package/esm/device-message/stream.js +0 -35
  160. package/esm/device-message/stream.js.map +0 -1
  161. package/esm/device-message/type.d.ts +0 -5
  162. package/esm/device-message/type.d.ts.map +0 -1
  163. package/esm/device-message/type.js +0 -7
  164. package/esm/device-message/type.js.map +0 -1
  165. package/esm/options/1_16/float-to-uint16.d.ts +0 -5
  166. package/esm/options/1_16/float-to-uint16.d.ts.map +0 -1
  167. package/esm/options/1_16/float-to-uint16.js.map +0 -1
  168. package/src/control/basic.ts +0 -3
  169. package/src/device-message/ack-clipboard.ts +0 -10
  170. package/src/device-message/clipboard.ts +0 -11
  171. package/src/device-message/index.ts +0 -4
  172. package/src/device-message/stream.ts +0 -49
  173. package/src/device-message/type.ts +0 -5
package/src/codec/nalu.ts CHANGED
@@ -91,153 +91,17 @@ export function* annexBSplitNalu(buffer: Uint8Array): Generator<Uint8Array> {
91
91
  yield buffer.subarray(start, buffer.length);
92
92
  }
93
93
 
94
- /**
95
- * Remove emulation prevention bytes from a H.264/H.265 NAL Unit.
96
- *
97
- * The input is not modified.
98
- * If the input doesn't contain any emulation prevention bytes,
99
- * the input is returned as-is.
100
- * Otherwise, a new `Uint8Array` is created and returned.
101
- */
102
- export function naluRemoveEmulation(buffer: Uint8Array) {
103
- // output will be created when first emulation prevention byte is found
104
- let output: Uint8Array | undefined;
105
- let outputOffset = 0;
106
-
107
- let zeroCount = 0;
108
- let inEmulation = false;
109
-
110
- let i = 0;
111
- scan: for (; i < buffer.length; i += 1) {
112
- const byte = buffer[i]!;
113
-
114
- if (byte === 0x00) {
115
- zeroCount += 1;
116
- continue;
117
- }
118
-
119
- // Current byte is not zero
120
- const prevZeroCount = zeroCount;
121
- zeroCount = 0;
122
-
123
- if (prevZeroCount < 2) {
124
- // zero or one `0x00`s are acceptable
125
- continue;
126
- }
127
-
128
- if (byte === 0x01) {
129
- // Unexpected start code
130
- throw new Error("Invalid data");
131
- }
132
-
133
- if (prevZeroCount > 2) {
134
- // Too much `0x00`s
135
- throw new Error("Invalid data");
136
- }
137
-
138
- switch (byte) {
139
- case 0x02:
140
- // Didn't find why, but 7.4.1 NAL unit semantics forbids `0x000002` appearing in NAL units
141
- throw new Error("Invalid data");
142
- case 0x03:
143
- // `0x000003` is the "emulation_prevention_three_byte"
144
- // `0x00000300`, `0x00000301`, `0x00000302` and `0x00000303` represent
145
- // `0x000000`, `0x000001`, `0x000002` and `0x000003` respectively
146
- inEmulation = true;
147
-
148
- // Create output and copy the data before the emulation prevention byte
149
- // Output size is unknown, so we use the input size as an upper bound
150
- output = new Uint8Array(buffer.length - 1);
151
- output.set(buffer.subarray(0, i));
152
- outputOffset = i;
153
- i += 1;
154
- break scan;
155
- default:
156
- // `0x000004` or larger are as-is
157
- break;
158
- }
159
- }
160
-
161
- if (!output) {
162
- return buffer;
163
- }
164
-
165
- // Continue at the byte after the emulation prevention byte
166
- for (; i < buffer.length; i += 1) {
167
- const byte = buffer[i]!;
168
-
169
- output[outputOffset] = byte;
170
- outputOffset += 1;
171
-
172
- if (inEmulation) {
173
- if (byte > 0x03) {
174
- // `0x00000304` or larger are invalid
175
- throw new Error("Invalid data");
176
- }
177
-
178
- // `00000300000300` results in `0000000000` (both `0x03` are removed)
179
- // which means the `0x00` after `0x03` also counts
180
- if (byte === 0x00) {
181
- zeroCount += 1;
182
- }
183
-
184
- inEmulation = false;
185
- continue;
186
- }
187
-
188
- if (byte === 0x00) {
189
- zeroCount += 1;
190
- continue;
191
- }
192
-
193
- const prevZeroCount = zeroCount;
194
- zeroCount = 0;
195
-
196
- if (prevZeroCount < 2) {
197
- // zero or one `0x00`s are acceptable
198
- continue;
199
- }
200
-
201
- if (byte === 0x01) {
202
- // Unexpected start code
203
- throw new Error("Invalid data");
204
- }
205
-
206
- if (prevZeroCount > 2) {
207
- // Too much `0x00`s
208
- throw new Error("Invalid data");
209
- }
210
-
211
- switch (byte) {
212
- case 0x02:
213
- // Didn't find why, but 7.4.1 NAL unit semantics forbids `0x000002` appearing in NAL units
214
- throw new Error("Invalid data");
215
- case 0x03:
216
- // `0x000003` is the "emulation_prevention_three_byte"
217
- // `0x00000300`, `0x00000301`, `0x00000302` and `0x00000303` represent
218
- // `0x000000`, `0x000001`, `0x000002` and `0x000003` respectively
219
- inEmulation = true;
220
-
221
- // Remove the emulation prevention byte
222
- outputOffset -= 1;
223
- break;
224
- default:
225
- // `0x000004` or larger are as-is
226
- break;
227
- }
228
- }
229
-
230
- return output.subarray(0, outputOffset);
231
- }
232
-
233
94
  export class NaluSodbBitReader {
234
95
  readonly #nalu: Uint8Array;
96
+ // logical length is `#byteLength * 8 + (7 - #stopBitIndex)`
235
97
  readonly #byteLength: number;
236
98
  readonly #stopBitIndex: number;
237
99
 
238
100
  #zeroCount = 0;
239
- #bytePosition = -1;
240
- #bitPosition = -1;
101
+
102
+ // logical position is `#bytePosition * 8 + (7 - #bitPosition)`
103
+ #bytePosition = 0;
104
+ #bitPosition = 7;
241
105
  #byte = 0;
242
106
 
243
107
  get byteLength() {
@@ -258,14 +122,15 @@ export class NaluSodbBitReader {
258
122
 
259
123
  get ended() {
260
124
  return (
261
- this.#bytePosition === this.#byteLength &&
262
- this.#bitPosition === this.#stopBitIndex
125
+ this.#bytePosition >= this.#byteLength &&
126
+ this.#bitPosition <= this.#stopBitIndex
263
127
  );
264
128
  }
265
129
 
266
130
  constructor(nalu: Uint8Array) {
267
131
  this.#nalu = nalu;
268
132
 
133
+ // Search for the last bit being `1`, also known as the stop bit
269
134
  for (let i = nalu.length - 1; i >= 0; i -= 1) {
270
135
  if (this.#nalu[i] === 0) {
271
136
  continue;
@@ -276,7 +141,7 @@ export class NaluSodbBitReader {
276
141
  if (((byte >> j) & 1) === 1) {
277
142
  this.#byteLength = i;
278
143
  this.#stopBitIndex = j;
279
- this.#readByte();
144
+ this.#loadByte();
280
145
  return;
281
146
  }
282
147
  }
@@ -285,15 +150,22 @@ export class NaluSodbBitReader {
285
150
  throw new Error("Stop bit not found");
286
151
  }
287
152
 
288
- #readByte() {
153
+ #loadByte() {
289
154
  this.#byte = this.#nalu[this.#bytePosition]!;
155
+
156
+ // If the current sequence is `0x000003`, skip to the next byte.
157
+ // `annexBSplitNalu` had validated the input, so skip the check here
290
158
  if (this.#zeroCount === 2 && this.#byte === 3) {
291
159
  this.#zeroCount = 0;
292
160
  this.#bytePosition += 1;
293
- this.#readByte();
161
+ // Call `#loadByte` again, because if the next byte is `0x00`,
162
+ // it need to be counted in `#zeroCount` as well.
163
+ this.#loadByte();
294
164
  return;
295
165
  }
296
166
 
167
+ // `0x00000301` becomes `0x000001`, so only the `0x03` byte needs to be skipped
168
+ // All `0x00` bytes are returned as-is
297
169
  if (this.#byte === 0) {
298
170
  this.#zeroCount += 1;
299
171
  } else {
@@ -302,18 +174,19 @@ export class NaluSodbBitReader {
302
174
  }
303
175
 
304
176
  next() {
305
- if (this.#bitPosition === -1) {
306
- this.#bitPosition = 7;
307
- this.#bytePosition += 1;
308
- this.#readByte();
309
- }
310
-
311
177
  if (this.ended) {
312
178
  throw new Error("Bit index out of bounds");
313
179
  }
314
180
 
315
181
  const value = (this.#byte >> this.#bitPosition) & 1;
182
+
316
183
  this.#bitPosition -= 1;
184
+ if (this.#bitPosition < 0) {
185
+ this.#bytePosition += 1;
186
+ this.#bitPosition = 7;
187
+ this.#loadByte();
188
+ }
189
+
317
190
  return value;
318
191
  }
319
192
 
@@ -329,10 +202,50 @@ export class NaluSodbBitReader {
329
202
  return result;
330
203
  }
331
204
 
205
+ /**
206
+ * Throws an error if the current position is invalid for `skip`.
207
+ *
208
+ * Usually it will throw if `ended` is `true`,
209
+ * except when the bit position is at the stop bit,
210
+ * in which case `ended` will be `true`, but it won't throw.
211
+ * `skip` can skip all remaining bits, and stop at the end position.
212
+ * The next `next` call will throw since there is no more bits to read.
213
+ */
214
+ #checkSkipPosition() {
215
+ if (
216
+ this.#bytePosition >= this.#byteLength &&
217
+ this.#bitPosition < this.#stopBitIndex
218
+ ) {
219
+ throw new Error("Bit index out of bounds");
220
+ }
221
+ }
222
+
332
223
  skip(length: number) {
333
- for (let i = 0; i < length; i += 1) {
334
- this.next();
224
+ if (length <= this.#bitPosition + 1) {
225
+ this.#bitPosition -= length;
226
+ this.#checkSkipPosition();
227
+ return;
228
+ }
229
+
230
+ // Because of emulation prevention bytes,
231
+ // we don't know how many bits are left in the NAL,
232
+ // nor how many bits should be skipped.
233
+ // So we need to check each byte.
234
+
235
+ length -= this.#bitPosition + 1;
236
+ this.#bytePosition += 1;
237
+ this.#bitPosition = 7;
238
+ this.#loadByte();
239
+ this.#checkSkipPosition();
240
+
241
+ for (; length >= 8; length -= 8) {
242
+ this.#bytePosition += 1;
243
+ this.#loadByte();
244
+ this.#checkSkipPosition();
335
245
  }
246
+
247
+ this.#bitPosition = 7 - length;
248
+ this.#checkSkipPosition();
336
249
  }
337
250
 
338
251
  decodeExponentialGolombNumber(): number {
@@ -0,0 +1,3 @@
1
+ import { Struct } from "@yume-chan/struct";
2
+
3
+ export const EmptyControlMessage = new Struct().uint8("type");
@@ -1,5 +1,5 @@
1
1
  export * from "./back-or-screen-on.js";
2
- export * from "./basic.js";
2
+ export * from "./empty.js";
3
3
  export * from "./hover-helper.js";
4
4
  export * from "./inject-keycode.js";
5
5
  export * from "./inject-scroll.js";
@@ -1,6 +1,6 @@
1
- import { BasicControlMessage } from "./basic.js";
1
+ import { EmptyControlMessage } from "./empty.js";
2
2
 
3
- export const ScrcpyRotateDeviceControlMessage = BasicControlMessage;
3
+ export const ScrcpyRotateDeviceControlMessage = EmptyControlMessage;
4
4
 
5
5
  export type ScrcpyRotateDeviceControlMessage =
6
6
  (typeof ScrcpyRotateDeviceControlMessage)["TInit"];
@@ -3,13 +3,14 @@ import type {
3
3
  ScrcpyScrollController,
4
4
  } from "../options/index.js";
5
5
 
6
- import { BasicControlMessage } from "./basic.js";
6
+ import { EmptyControlMessage } from "./empty.js";
7
7
  import type { AndroidKeyEventAction } from "./inject-keycode.js";
8
8
  import { ScrcpyInjectKeyCodeControlMessage } from "./inject-keycode.js";
9
9
  import type { ScrcpyInjectScrollControlMessage } from "./inject-scroll.js";
10
10
  import { ScrcpyInjectTextControlMessage } from "./inject-text.js";
11
11
  import type { ScrcpyInjectTouchControlMessage } from "./inject-touch.js";
12
12
  import { ScrcpyRotateDeviceControlMessage } from "./rotate-device.js";
13
+ import type { ScrcpySetClipboardControlMessage } from "./set-clipboard.js";
13
14
  import type { AndroidScreenPowerMode } from "./set-screen-power-mode.js";
14
15
  import { ScrcpySetScreenPowerModeControlMessage } from "./set-screen-power-mode.js";
15
16
  import {
@@ -85,7 +86,7 @@ export class ScrcpyControlMessageSerializer {
85
86
  }
86
87
 
87
88
  expandNotificationPanel() {
88
- return BasicControlMessage.serialize({
89
+ return EmptyControlMessage.serialize({
89
90
  type: this.#typeValues.get(
90
91
  ScrcpyControlMessageType.ExpandNotificationPanel,
91
92
  ),
@@ -93,7 +94,7 @@ export class ScrcpyControlMessageSerializer {
93
94
  }
94
95
 
95
96
  expandSettingPanel() {
96
- return BasicControlMessage.serialize({
97
+ return EmptyControlMessage.serialize({
97
98
  type: this.#typeValues.get(
98
99
  ScrcpyControlMessageType.ExpandSettingPanel,
99
100
  ),
@@ -101,7 +102,7 @@ export class ScrcpyControlMessageSerializer {
101
102
  }
102
103
 
103
104
  collapseNotificationPanel() {
104
- return BasicControlMessage.serialize({
105
+ return EmptyControlMessage.serialize({
105
106
  type: this.#typeValues.get(
106
107
  ScrcpyControlMessageType.CollapseNotificationPanel,
107
108
  ),
@@ -113,4 +114,11 @@ export class ScrcpyControlMessageSerializer {
113
114
  type: this.#typeValues.get(ScrcpyControlMessageType.RotateDevice),
114
115
  });
115
116
  }
117
+
118
+ setClipboard(message: Omit<ScrcpySetClipboardControlMessage, "type">) {
119
+ return this.#options.serializeSetClipboardControlMessage({
120
+ ...message,
121
+ type: this.#typeValues.get(ScrcpyControlMessageType.SetClipboard),
122
+ });
123
+ }
116
124
  }
@@ -34,7 +34,7 @@ export class ScrcpyControlMessageTypeValue {
34
34
  get(type: ScrcpyControlMessageType): number {
35
35
  const value = this.#types.indexOf(type);
36
36
  if (value === -1) {
37
- throw new Error("Not supported");
37
+ throw new TypeError("Invalid or unsupported control message type");
38
38
  }
39
39
  return value;
40
40
  }
@@ -1,8 +1,5 @@
1
- import type {
2
- Consumable,
3
- WritableStreamDefaultWriter,
4
- } from "@yume-chan/stream-extra";
5
- import { ConsumableWritableStream } from "@yume-chan/stream-extra";
1
+ import type { WritableStreamDefaultWriter } from "@yume-chan/stream-extra";
2
+ import { Consumable } from "@yume-chan/stream-extra";
6
3
 
7
4
  import type { ScrcpyOptions } from "../options/index.js";
8
5
 
@@ -13,6 +10,7 @@ import type {
13
10
  import type { ScrcpyInjectScrollControlMessage } from "./inject-scroll.js";
14
11
  import type { ScrcpyInjectTouchControlMessage } from "./inject-touch.js";
15
12
  import { ScrcpyControlMessageSerializer } from "./serializer.js";
13
+ import type { ScrcpySetClipboardControlMessage } from "./set-clipboard.js";
16
14
  import type { AndroidScreenPowerMode } from "./set-screen-power-mode.js";
17
15
 
18
16
  export class ScrcpyControlMessageWriter {
@@ -28,7 +26,7 @@ export class ScrcpyControlMessageWriter {
28
26
  }
29
27
 
30
28
  async write(message: Uint8Array) {
31
- await ConsumableWritableStream.write(this.#writer, message);
29
+ await Consumable.WritableStream.write(this.#writer, message);
32
30
  }
33
31
 
34
32
  async injectKeyCode(
@@ -87,6 +85,18 @@ export class ScrcpyControlMessageWriter {
87
85
  await this.write(this.#serializer.rotateDevice());
88
86
  }
89
87
 
88
+ async setClipboard(
89
+ message: Omit<ScrcpySetClipboardControlMessage, "type">,
90
+ ) {
91
+ const result = this.#serializer.setClipboard(message);
92
+ if (result instanceof Uint8Array) {
93
+ await this.write(result);
94
+ } else {
95
+ await this.write(result[0]);
96
+ await result[1];
97
+ }
98
+ }
99
+
90
100
  releaseLock() {
91
101
  this.#writer.releaseLock();
92
102
  }
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export * from "./codec/index.js";
2
2
  export * from "./control/index.js";
3
- export * from "./device-message/index.js";
4
3
  export * from "./options/index.js";
@@ -1,4 +1,6 @@
1
- import { NumberFieldDefinition, NumberFieldType } from "@yume-chan/struct";
1
+ import { getUint16 } from "@yume-chan/no-data-view";
2
+ import type { NumberFieldVariant } from "@yume-chan/struct";
3
+ import { NumberFieldDefinition } from "@yume-chan/struct";
2
4
 
3
5
  export function clamp(value: number, min: number, max: number): number {
4
6
  if (value < min) {
@@ -12,11 +14,11 @@ export function clamp(value: number, min: number, max: number): number {
12
14
  return value;
13
15
  }
14
16
 
15
- export const ScrcpyFloatToUint16NumberType: NumberFieldType = {
17
+ export const ScrcpyUnsignedFloatNumberVariant: NumberFieldVariant = {
16
18
  size: 2,
17
19
  signed: false,
18
20
  deserialize(array, littleEndian) {
19
- const value = NumberFieldType.Uint16.deserialize(array, littleEndian);
21
+ const value = getUint16(array, 0, littleEndian);
20
22
  // https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/server/src/main/java/com/genymobile/scrcpy/Binary.java#L22
21
23
  return value === 0xffff ? 1 : value / 0x10000;
22
24
  },
@@ -24,10 +26,10 @@ export const ScrcpyFloatToUint16NumberType: NumberFieldType = {
24
26
  // https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/app/src/util/binary.h#L51
25
27
  value = clamp(value, -1, 1);
26
28
  value = value === 1 ? 0xffff : value * 0x10000;
27
- NumberFieldType.Uint16.serialize(dataView, offset, value, littleEndian);
29
+ dataView.setUint16(offset, value, littleEndian);
28
30
  },
29
31
  };
30
32
 
31
- export const ScrcpyFloatToUint16FieldDefinition = new NumberFieldDefinition(
32
- ScrcpyFloatToUint16NumberType,
33
+ export const ScrcpyUnsignedFloatFieldDefinition = new NumberFieldDefinition(
34
+ ScrcpyUnsignedFloatNumberVariant,
33
35
  );
@@ -1,5 +1,5 @@
1
1
  export * from "./codec-options.js";
2
- export * from "./float-to-uint16.js";
2
+ export * from "./float.js";
3
3
  export * from "./init.js";
4
4
  export * from "./message.js";
5
5
  export * from "./options.js";
@@ -2,11 +2,11 @@ import Struct, { placeholder } from "@yume-chan/struct";
2
2
 
3
3
  import type { AndroidMotionEventAction } from "../../control/index.js";
4
4
  import {
5
- BasicControlMessage,
5
+ EmptyControlMessage,
6
6
  ScrcpyControlMessageType,
7
7
  } from "../../control/index.js";
8
8
 
9
- import { ScrcpyFloatToUint16FieldDefinition } from "./float-to-uint16.js";
9
+ import { ScrcpyUnsignedFloatFieldDefinition } from "./float.js";
10
10
 
11
11
  export const SCRCPY_CONTROL_MESSAGE_TYPES_1_16: readonly ScrcpyControlMessageType[] =
12
12
  [
@@ -38,13 +38,13 @@ export const ScrcpyInjectTouchControlMessage1_16 = new Struct()
38
38
  .uint32("pointerY")
39
39
  .uint16("screenWidth")
40
40
  .uint16("screenHeight")
41
- .field("pressure", ScrcpyFloatToUint16FieldDefinition)
41
+ .field("pressure", ScrcpyUnsignedFloatFieldDefinition)
42
42
  .uint32("buttons");
43
43
 
44
44
  export type ScrcpyInjectTouchControlMessage1_16 =
45
45
  (typeof ScrcpyInjectTouchControlMessage1_16)["TInit"];
46
46
 
47
- export const ScrcpyBackOrScreenOnControlMessage1_16 = BasicControlMessage;
47
+ export const ScrcpyBackOrScreenOnControlMessage1_16 = EmptyControlMessage;
48
48
 
49
49
  export const ScrcpySetClipboardControlMessage1_15 = new Struct()
50
50
  .uint8("type")
@@ -53,3 +53,7 @@ export const ScrcpySetClipboardControlMessage1_15 = new Struct()
53
53
 
54
54
  export type ScrcpySetClipboardControlMessage1_15 =
55
55
  (typeof ScrcpySetClipboardControlMessage1_15)["TInit"];
56
+
57
+ export const ScrcpyClipboardDeviceMessage = new Struct()
58
+ .uint32("length")
59
+ .string("content", { lengthField: "length" });