@yume-chan/scrcpy 0.0.17 → 0.0.18

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 (214) hide show
  1. package/CHANGELOG.json +21 -3
  2. package/CHANGELOG.md +13 -4
  3. package/LICENSE +1 -1
  4. package/README.md +41 -24
  5. package/bin/scrcpy-server +0 -0
  6. package/bin/version.d.ts +1 -1
  7. package/bin/version.js +1 -1
  8. package/esm/adb/client.d.ts +15 -14
  9. package/esm/adb/client.d.ts.map +1 -1
  10. package/esm/adb/client.js +66 -41
  11. package/esm/adb/client.js.map +1 -1
  12. package/esm/adb/connection.d.ts +16 -7
  13. package/esm/adb/connection.d.ts.map +1 -1
  14. package/esm/adb/connection.js +21 -13
  15. package/esm/adb/connection.js.map +1 -1
  16. package/esm/adb/options/1_16.d.ts +4 -4
  17. package/esm/adb/options/1_16.d.ts.map +1 -1
  18. package/esm/adb/options/1_16.js +2 -2
  19. package/esm/adb/options/1_16.js.map +1 -1
  20. package/esm/adb/options/1_22.d.ts +4 -4
  21. package/esm/adb/options/1_22.d.ts.map +1 -1
  22. package/esm/adb/options/1_22.js +2 -2
  23. package/esm/adb/options/1_22.js.map +1 -1
  24. package/esm/adb/options/types.d.ts +10 -9
  25. package/esm/adb/options/types.d.ts.map +1 -1
  26. package/esm/adb/options/types.js +11 -4
  27. package/esm/adb/options/types.js.map +1 -1
  28. package/esm/control/back-or-screen-on.d.ts +3 -0
  29. package/esm/control/back-or-screen-on.d.ts.map +1 -0
  30. package/esm/control/back-or-screen-on.js +2 -0
  31. package/esm/control/back-or-screen-on.js.map +1 -0
  32. package/esm/control/hover-helper.d.ts +18 -0
  33. package/esm/control/hover-helper.d.ts.map +1 -0
  34. package/esm/control/hover-helper.js +44 -0
  35. package/esm/control/hover-helper.js.map +1 -0
  36. package/esm/control/index.d.ts +11 -7
  37. package/esm/control/index.d.ts.map +1 -1
  38. package/esm/control/index.js +11 -7
  39. package/esm/control/index.js.map +1 -1
  40. package/esm/control/inject-keycode.d.ts +12 -4
  41. package/esm/control/inject-keycode.d.ts.map +1 -1
  42. package/esm/control/inject-keycode.js +15 -7
  43. package/esm/control/inject-keycode.js.map +1 -1
  44. package/esm/control/inject-scroll.d.ts +3 -0
  45. package/esm/control/inject-scroll.d.ts.map +1 -0
  46. package/esm/control/inject-scroll.js +2 -0
  47. package/esm/control/inject-scroll.js.map +1 -0
  48. package/esm/control/inject-text.d.ts +2 -2
  49. package/esm/control/inject-text.d.ts.map +1 -1
  50. package/esm/control/inject-touch.d.ts +12 -4
  51. package/esm/control/inject-touch.d.ts.map +1 -1
  52. package/esm/control/inject-touch.js +44 -11
  53. package/esm/control/inject-touch.js.map +1 -1
  54. package/esm/control/rotate-device.d.ts +2 -2
  55. package/esm/control/rotate-device.d.ts.map +1 -1
  56. package/esm/control/serializer.d.ts +22 -11
  57. package/esm/control/serializer.d.ts.map +1 -1
  58. package/esm/control/serializer.js +32 -26
  59. package/esm/control/serializer.js.map +1 -1
  60. package/esm/control/set-clipboard.d.ts +3 -0
  61. package/esm/control/set-clipboard.d.ts.map +1 -0
  62. package/esm/control/set-clipboard.js +2 -0
  63. package/esm/control/set-clipboard.js.map +1 -0
  64. package/esm/control/set-screen-power-mode.d.ts +2 -2
  65. package/esm/control/set-screen-power-mode.d.ts.map +1 -1
  66. package/esm/device-message/ack-clipboard.d.ts +9 -0
  67. package/esm/device-message/ack-clipboard.d.ts.map +1 -0
  68. package/esm/device-message/ack-clipboard.js +6 -0
  69. package/esm/device-message/ack-clipboard.js.map +1 -0
  70. package/esm/device-message/clipboard.d.ts +3 -3
  71. package/esm/device-message/clipboard.d.ts.map +1 -1
  72. package/esm/device-message/clipboard.js +4 -4
  73. package/esm/device-message/clipboard.js.map +1 -1
  74. package/esm/device-message/index.d.ts +4 -3
  75. package/esm/device-message/index.d.ts.map +1 -1
  76. package/esm/device-message/index.js +4 -3
  77. package/esm/device-message/index.js.map +1 -1
  78. package/esm/device-message/stream.d.ts +4 -3
  79. package/esm/device-message/stream.d.ts.map +1 -1
  80. package/esm/device-message/stream.js +8 -4
  81. package/esm/device-message/stream.js.map +1 -1
  82. package/esm/options/1_16/codec-options.d.ts +3 -2
  83. package/esm/options/1_16/codec-options.d.ts.map +1 -1
  84. package/esm/options/1_16/codec-options.js +6 -7
  85. package/esm/options/1_16/codec-options.js.map +1 -1
  86. package/esm/options/1_16/h264-configuration.d.ts +49 -0
  87. package/esm/options/1_16/h264-configuration.d.ts.map +1 -0
  88. package/esm/options/1_16/h264-configuration.js +414 -0
  89. package/esm/options/1_16/h264-configuration.js.map +1 -0
  90. package/esm/options/1_16/index.d.ts +4 -3
  91. package/esm/options/1_16/index.d.ts.map +1 -1
  92. package/esm/options/1_16/index.js +4 -3
  93. package/esm/options/1_16/index.js.map +1 -1
  94. package/esm/options/1_16/options.d.ts +17 -20
  95. package/esm/options/1_16/options.d.ts.map +1 -1
  96. package/esm/options/1_16/options.js +51 -49
  97. package/esm/options/1_16/options.js.map +1 -1
  98. package/esm/options/1_16/scroll.d.ts +27 -0
  99. package/esm/options/1_16/scroll.d.ts.map +1 -0
  100. package/esm/options/1_16/scroll.js +56 -0
  101. package/esm/options/1_16/scroll.js.map +1 -0
  102. package/esm/options/1_16/sps.d.ts +1 -1
  103. package/esm/options/1_16/sps.d.ts.map +1 -1
  104. package/esm/options/1_16/sps.js +25 -17
  105. package/esm/options/1_16/sps.js.map +1 -1
  106. package/esm/options/1_18.d.ts +6 -6
  107. package/esm/options/1_18.d.ts.map +1 -1
  108. package/esm/options/1_18.js +5 -5
  109. package/esm/options/1_18.js.map +1 -1
  110. package/esm/options/1_21.d.ts +12 -1
  111. package/esm/options/1_21.d.ts.map +1 -1
  112. package/esm/options/1_21.js +14 -3
  113. package/esm/options/1_21.js.map +1 -1
  114. package/esm/options/1_22/index.d.ts +3 -0
  115. package/esm/options/1_22/index.d.ts.map +1 -0
  116. package/esm/options/1_22/index.js +3 -0
  117. package/esm/options/1_22/index.js.map +1 -0
  118. package/esm/options/{1_22.d.ts → 1_22/options.d.ts} +4 -15
  119. package/esm/options/1_22/options.d.ts.map +1 -0
  120. package/esm/options/{1_22.js → 1_22/options.js} +5 -9
  121. package/esm/options/1_22/options.js.map +1 -0
  122. package/esm/options/1_22/scroll.d.ts +17 -0
  123. package/esm/options/1_22/scroll.d.ts.map +1 -0
  124. package/esm/options/1_22/scroll.js +15 -0
  125. package/esm/options/1_22/scroll.js.map +1 -0
  126. package/esm/options/1_23.d.ts +3 -3
  127. package/esm/options/1_23.d.ts.map +1 -1
  128. package/esm/options/1_23.js +7 -6
  129. package/esm/options/1_23.js.map +1 -1
  130. package/esm/options/1_25/index.d.ts +3 -0
  131. package/esm/options/1_25/index.d.ts.map +1 -0
  132. package/esm/options/1_25/index.js +3 -0
  133. package/esm/options/1_25/index.js.map +1 -0
  134. package/esm/options/1_25/options.d.ts +6 -0
  135. package/esm/options/1_25/options.d.ts.map +1 -0
  136. package/esm/options/1_25/options.js +8 -0
  137. package/esm/options/1_25/options.js.map +1 -0
  138. package/esm/options/1_25/scroll.d.ts +19 -0
  139. package/esm/options/1_25/scroll.d.ts.map +1 -0
  140. package/esm/options/1_25/scroll.js +33 -0
  141. package/esm/options/1_25/scroll.js.map +1 -0
  142. package/esm/options/index.d.ts +5 -4
  143. package/esm/options/index.d.ts.map +1 -1
  144. package/esm/options/index.js +5 -4
  145. package/esm/options/index.js.map +1 -1
  146. package/esm/options/types.d.ts +14 -12
  147. package/esm/options/types.d.ts.map +1 -1
  148. package/esm/options/types.js +6 -4
  149. package/esm/options/types.js.map +1 -1
  150. package/package.json +19 -12
  151. package/scripts/fetch-server.cjs +19 -9
  152. package/src/adb/client.ts +142 -89
  153. package/src/adb/connection.ts +77 -30
  154. package/src/adb/options/1_16.ts +13 -6
  155. package/src/adb/options/1_22.ts +12 -6
  156. package/src/adb/options/types.ts +34 -14
  157. package/src/control/back-or-screen-on.ts +4 -0
  158. package/src/control/hover-helper.ts +56 -0
  159. package/src/control/index.ts +11 -7
  160. package/src/control/inject-keycode.ts +23 -10
  161. package/src/control/inject-scroll.ts +4 -0
  162. package/src/control/inject-touch.ts +58 -14
  163. package/src/control/serializer.ts +106 -41
  164. package/src/control/set-clipboard.ts +4 -0
  165. package/src/device-message/ack-clipboard.ts +10 -0
  166. package/src/device-message/clipboard.ts +8 -8
  167. package/src/device-message/index.ts +4 -3
  168. package/src/device-message/stream.ts +17 -7
  169. package/src/options/1_16/codec-options.ts +17 -10
  170. package/src/options/1_16/h264-configuration.ts +485 -0
  171. package/src/options/1_16/index.ts +4 -3
  172. package/src/options/1_16/options.ts +175 -130
  173. package/src/options/1_16/scroll.ts +76 -0
  174. package/src/options/1_18.ts +22 -12
  175. package/src/options/1_21.ts +31 -13
  176. package/src/options/1_22/index.ts +2 -0
  177. package/src/options/{1_22.ts → 1_22/options.ts} +8 -17
  178. package/src/options/1_22/scroll.ts +26 -0
  179. package/src/options/1_23.ts +32 -20
  180. package/src/options/1_25/index.ts +2 -0
  181. package/src/options/1_25/options.ts +12 -0
  182. package/src/options/1_25/scroll.ts +52 -0
  183. package/src/options/index.ts +5 -4
  184. package/src/options/types.ts +34 -17
  185. package/tsconfig.build.json +1 -1
  186. package/tsconfig.build.tsbuildinfo +1 -1
  187. package/esm/decoder/index.d.ts +0 -28
  188. package/esm/decoder/index.d.ts.map +0 -1
  189. package/esm/decoder/index.js +0 -2
  190. package/esm/decoder/index.js.map +0 -1
  191. package/esm/decoder/tinyh264/index.d.ts +0 -20
  192. package/esm/decoder/tinyh264/index.d.ts.map +0 -1
  193. package/esm/decoder/tinyh264/index.js +0 -86
  194. package/esm/decoder/tinyh264/index.js.map +0 -1
  195. package/esm/decoder/tinyh264/worker.d.ts +0 -2
  196. package/esm/decoder/tinyh264/worker.d.ts.map +0 -1
  197. package/esm/decoder/tinyh264/worker.js +0 -3
  198. package/esm/decoder/tinyh264/worker.js.map +0 -1
  199. package/esm/decoder/tinyh264/wrapper.d.ts +0 -21
  200. package/esm/decoder/tinyh264/wrapper.d.ts.map +0 -1
  201. package/esm/decoder/tinyh264/wrapper.js +0 -74
  202. package/esm/decoder/tinyh264/wrapper.js.map +0 -1
  203. package/esm/decoder/types.d.ts +0 -2
  204. package/esm/decoder/types.d.ts.map +0 -1
  205. package/esm/decoder/types.js +0 -2
  206. package/esm/decoder/types.js.map +0 -1
  207. package/esm/decoder/web-codecs/index.d.ts +0 -22
  208. package/esm/decoder/web-codecs/index.d.ts.map +0 -1
  209. package/esm/decoder/web-codecs/index.js +0 -81
  210. package/esm/decoder/web-codecs/index.js.map +0 -1
  211. package/esm/options/1_22.d.ts.map +0 -1
  212. package/esm/options/1_22.js.map +0 -1
  213. package/src/options/1_16/sps.ts +0 -300
  214. package/tsconfig.test.tsbuildinfo +0 -1
@@ -1,19 +1,38 @@
1
- import { StructDeserializeStream, TransformStream } from '@yume-chan/stream-extra';
2
- import Struct from '@yume-chan/struct';
3
-
4
- import { AndroidKeyEventAction, ScrcpyControlMessageType } from '../../control/index.js';
5
- import type { ScrcpyBackOrScreenOnControlMessage1_18 } from '../1_18.js';
6
- import type { ScrcpyInjectScrollControlMessage1_22 } from '../1_22.js';
7
- import { toScrcpyOptionValue, type ScrcpyOptions, type ScrcpyVideoStreamPacket } from '../types.js';
8
- import { CodecOptions } from './codec-options.js';
9
- import { parse_sequence_parameter_set } from './sps.js';
1
+ import {
2
+ StructDeserializeStream,
3
+ TransformStream,
4
+ } from "@yume-chan/stream-extra";
5
+ import Struct from "@yume-chan/struct";
6
+
7
+ import {
8
+ AndroidKeyEventAction,
9
+ ScrcpyControlMessageType,
10
+ type ScrcpyBackOrScreenOnControlMessage,
11
+ type ScrcpySetClipboardControlMessage,
12
+ } from "../../control/index.js";
13
+ import {
14
+ toScrcpyOptionValue,
15
+ type ScrcpyOptions,
16
+ type ScrcpyVideoStreamPacket,
17
+ } from "../types.js";
18
+
19
+ import { CodecOptions } from "./codec-options.js";
20
+ import {
21
+ parseH264Configuration,
22
+ parseSequenceParameterSet,
23
+ removeH264Emulation,
24
+ } from "./h264-configuration.js";
25
+ import {
26
+ ScrcpyScrollController1_16,
27
+ type ScrcpyScrollController,
28
+ } from "./scroll.js";
10
29
 
11
30
  export enum ScrcpyLogLevel {
12
- Verbose = 'verbose',
13
- Debug = 'debug',
14
- Info = 'info',
15
- Warn = 'warn',
16
- Error = 'error',
31
+ Verbose = "verbose",
32
+ Debug = "debug",
33
+ Info = "info",
34
+ Warn = "warn",
35
+ Error = "error",
17
36
  }
18
37
 
19
38
  export enum ScrcpyVideoOrientation {
@@ -83,40 +102,44 @@ export interface ScrcpyOptionsInit1_16 {
83
102
  encoderName: string;
84
103
  }
85
104
 
86
- export const VideoPacket =
87
- new Struct()
88
- .uint64('pts')
89
- .uint32('size')
90
- .uint8Array('data', { lengthField: 'size' });
105
+ export const VideoPacket = new Struct()
106
+ .uint64("pts")
107
+ .uint32("size")
108
+ .uint8Array("data", { lengthField: "size" });
91
109
 
92
110
  export const NO_PTS = BigInt(1) << BigInt(63);
93
111
 
94
- export const ScrcpyBackOrScreenOnControlMessage1_16 =
95
- new Struct()
96
- .uint8('type', ScrcpyControlMessageType.BackOrScreenOn as const);
97
-
98
- export const ScrcpyInjectScrollControlMessage1_16 =
99
- new Struct()
100
- .uint8('type', ScrcpyControlMessageType.InjectScroll as const)
101
- .uint32('pointerX')
102
- .uint32('pointerY')
103
- .uint16('screenWidth')
104
- .uint16('screenHeight')
105
- .int32('scrollX')
106
- .int32('scrollY');
107
-
108
- export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsInit1_16>
109
- implements ScrcpyOptions<T> {
112
+ export const ScrcpyBackOrScreenOnControlMessage1_16 = new Struct().uint8(
113
+ "type",
114
+ ScrcpyControlMessageType.BackOrScreenOn as const
115
+ );
116
+
117
+ export const ScrcpySetClipboardControlMessage1_15 = new Struct()
118
+ .uint8("type", ScrcpyControlMessageType.SetClipboard as const)
119
+ .uint32("length")
120
+ .string("content", { lengthField: "length" });
121
+
122
+ export type ScrcpySetClipboardControlMessage1_15 =
123
+ typeof ScrcpySetClipboardControlMessage1_15["TInit"];
124
+
125
+ export class ScrcpyOptions1_16<
126
+ T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsInit1_16
127
+ > implements ScrcpyOptions<T>
128
+ {
110
129
  public value: Partial<T>;
111
130
 
112
131
  public constructor(value: Partial<ScrcpyOptionsInit1_16>) {
113
- if (new.target === ScrcpyOptions1_16 &&
114
- value.logLevel === ScrcpyLogLevel.Verbose) {
132
+ if (
133
+ new.target === ScrcpyOptions1_16 &&
134
+ value.logLevel === ScrcpyLogLevel.Verbose
135
+ ) {
115
136
  value.logLevel = ScrcpyLogLevel.Debug;
116
137
  }
117
138
 
118
- if (new.target === ScrcpyOptions1_16 &&
119
- value.lockVideoOrientation === ScrcpyVideoOrientation.Initial) {
139
+ if (
140
+ new.target === ScrcpyOptions1_16 &&
141
+ value.lockVideoOrientation === ScrcpyVideoOrientation.Initial
142
+ ) {
120
143
  value.lockVideoOrientation = ScrcpyVideoOrientation.Unlocked;
121
144
  }
122
145
 
@@ -125,20 +148,20 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
125
148
 
126
149
  protected getArgumentOrder(): (keyof T)[] {
127
150
  return [
128
- 'logLevel',
129
- 'maxSize',
130
- 'bitRate',
131
- 'maxFps',
132
- 'lockVideoOrientation',
133
- 'tunnelForward',
134
- 'crop',
135
- 'sendFrameMeta',
136
- 'control',
137
- 'displayId',
138
- 'showTouches',
139
- 'stayAwake',
140
- 'codecOptions',
141
- 'encoderName',
151
+ "logLevel",
152
+ "maxSize",
153
+ "bitRate",
154
+ "maxFps",
155
+ "lockVideoOrientation",
156
+ "tunnelForward",
157
+ "crop",
158
+ "sendFrameMeta",
159
+ "control",
160
+ "displayId",
161
+ "showTouches",
162
+ "stayAwake",
163
+ "codecOptions",
164
+ "encoderName",
142
165
  ];
143
166
  }
144
167
 
@@ -150,37 +173,38 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
150
173
  maxFps: 0,
151
174
  lockVideoOrientation: ScrcpyVideoOrientation.Unlocked,
152
175
  tunnelForward: false,
153
- crop: '-',
176
+ crop: "-",
154
177
  sendFrameMeta: true,
155
178
  control: true,
156
179
  displayId: 0,
157
180
  showTouches: false,
158
181
  stayAwake: false,
159
182
  codecOptions: new CodecOptions({}),
160
- encoderName: '-',
183
+ encoderName: "-",
161
184
  } as T;
162
185
  }
163
186
 
164
187
  public formatServerArguments(): string[] {
165
188
  const defaults = this.getDefaultValue();
166
- return this.getArgumentOrder()
167
- .map(
168
- key =>
169
- toScrcpyOptionValue(this.value[key] || defaults[key], '-')
170
- );
189
+ return this.getArgumentOrder().map((key) =>
190
+ toScrcpyOptionValue(this.value[key] || defaults[key], "-")
191
+ );
171
192
  }
172
193
 
173
194
  public getOutputEncoderNameRegex(): RegExp {
174
195
  return /\s+scrcpy --encoder-name '(.*?)'/;
175
196
  }
176
197
 
177
- public createVideoStreamTransformer(): TransformStream<Uint8Array, ScrcpyVideoStreamPacket> {
198
+ public createVideoStreamTransformer(): TransformStream<
199
+ Uint8Array,
200
+ ScrcpyVideoStreamPacket
201
+ > {
178
202
  // Optimized path for video frames only
179
203
  if (this.value.sendFrameMeta === false) {
180
204
  return new TransformStream({
181
205
  transform(chunk, controller) {
182
206
  controller.enqueue({
183
- type: 'frame',
207
+ type: "frame",
184
208
  data: chunk,
185
209
  });
186
210
  },
@@ -189,74 +213,91 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
189
213
 
190
214
  let header: Uint8Array | undefined;
191
215
 
192
- let deserializeStream = new StructDeserializeStream(VideoPacket);
216
+ const deserializeStream = new StructDeserializeStream(VideoPacket);
193
217
  return {
194
218
  writable: deserializeStream.writable,
195
- readable: deserializeStream.readable.pipeThrough(new TransformStream({
196
- transform(packet, controller) {
197
- if (packet.pts === NO_PTS) {
198
- const sequenceParameterSet = parse_sequence_parameter_set(packet.data.slice().buffer);
199
-
200
- const {
201
- profile_idc: profileIndex,
202
- constraint_set: constraintSet,
203
- level_idc: levelIndex,
204
- pic_width_in_mbs_minus1,
205
- pic_height_in_map_units_minus1,
206
- frame_mbs_only_flag,
207
- frame_crop_left_offset,
208
- frame_crop_right_offset,
209
- frame_crop_top_offset,
210
- frame_crop_bottom_offset,
211
- } = sequenceParameterSet;
212
-
213
- const encodedWidth = (pic_width_in_mbs_minus1 + 1) * 16;
214
- const encodedHeight = (pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag) * 16;
215
- const cropLeft = frame_crop_left_offset * 2;
216
- const cropRight = frame_crop_right_offset * 2;
217
- const cropTop = frame_crop_top_offset * 2;
218
- const cropBottom = frame_crop_bottom_offset * 2;
219
-
220
- const croppedWidth = encodedWidth - cropLeft - cropRight;
221
- const croppedHeight = encodedHeight - cropTop - cropBottom;
222
-
223
- header = packet.data;
219
+ readable: deserializeStream.readable.pipeThrough(
220
+ new TransformStream({
221
+ transform(packet, controller) {
222
+ if (packet.pts === NO_PTS) {
223
+ const {
224
+ sequenceParameterSet,
225
+ pictureParameterSet,
226
+ } = parseH264Configuration(packet.data);
227
+
228
+ const {
229
+ profile_idc: profileIndex,
230
+ constraint_set: constraintSet,
231
+ level_idc: levelIndex,
232
+ pic_width_in_mbs_minus1,
233
+ pic_height_in_map_units_minus1,
234
+ frame_mbs_only_flag,
235
+ frame_crop_left_offset,
236
+ frame_crop_right_offset,
237
+ frame_crop_top_offset,
238
+ frame_crop_bottom_offset,
239
+ } = parseSequenceParameterSet(
240
+ removeH264Emulation(sequenceParameterSet)
241
+ );
242
+
243
+ const encodedWidth =
244
+ (pic_width_in_mbs_minus1 + 1) * 16;
245
+ const encodedHeight =
246
+ (pic_height_in_map_units_minus1 + 1) *
247
+ (2 - frame_mbs_only_flag) *
248
+ 16;
249
+ const cropLeft = frame_crop_left_offset * 2;
250
+ const cropRight = frame_crop_right_offset * 2;
251
+ const cropTop = frame_crop_top_offset * 2;
252
+ const cropBottom = frame_crop_bottom_offset * 2;
253
+
254
+ const croppedWidth =
255
+ encodedWidth - cropLeft - cropRight;
256
+ const croppedHeight =
257
+ encodedHeight - cropTop - cropBottom;
258
+
259
+ header = packet.data;
260
+ controller.enqueue({
261
+ type: "configuration",
262
+ pictureParameterSet,
263
+ sequenceParameterSet,
264
+ data: {
265
+ profileIndex,
266
+ constraintSet,
267
+ levelIndex,
268
+ encodedWidth,
269
+ encodedHeight,
270
+ cropLeft,
271
+ cropRight,
272
+ cropTop,
273
+ cropBottom,
274
+ croppedWidth,
275
+ croppedHeight,
276
+ },
277
+ });
278
+ return;
279
+ }
280
+
281
+ let frameData: Uint8Array;
282
+ if (header) {
283
+ frameData = new Uint8Array(
284
+ header.byteLength + packet.data.byteLength
285
+ );
286
+ frameData.set(header);
287
+ frameData.set(packet.data, header.byteLength);
288
+ header = undefined;
289
+ } else {
290
+ frameData = packet.data;
291
+ }
292
+
224
293
  controller.enqueue({
225
- type: 'configuration',
226
- data: {
227
- profileIndex,
228
- constraintSet,
229
- levelIndex,
230
- encodedWidth,
231
- encodedHeight,
232
- cropLeft,
233
- cropRight,
234
- cropTop,
235
- cropBottom,
236
- croppedWidth,
237
- croppedHeight,
238
- }
294
+ type: "frame",
295
+ pts: packet.pts,
296
+ data: frameData,
239
297
  });
240
- return;
241
- }
242
-
243
- let frameData: Uint8Array;
244
- if (header) {
245
- frameData = new Uint8Array(header.byteLength + packet.data.byteLength);
246
- frameData.set(header);
247
- frameData.set(packet.data, header.byteLength);
248
- header = undefined;
249
- } else {
250
- frameData = packet.data;
251
- }
252
-
253
- controller.enqueue({
254
- type: 'frame',
255
- pts: packet.pts,
256
- data: frameData,
257
- });
258
- }
259
- }))
298
+ },
299
+ })
300
+ ),
260
301
  };
261
302
  }
262
303
 
@@ -277,7 +318,7 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
277
318
  }
278
319
 
279
320
  public serializeBackOrScreenOnControlMessage(
280
- message: ScrcpyBackOrScreenOnControlMessage1_18,
321
+ message: ScrcpyBackOrScreenOnControlMessage
281
322
  ) {
282
323
  if (message.action === AndroidKeyEventAction.Down) {
283
324
  return ScrcpyBackOrScreenOnControlMessage1_16.serialize(message);
@@ -286,9 +327,13 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
286
327
  return undefined;
287
328
  }
288
329
 
289
- public serializeInjectScrollControlMessage(
290
- message: ScrcpyInjectScrollControlMessage1_22,
330
+ public serializeSetClipboardControlMessage(
331
+ message: ScrcpySetClipboardControlMessage
291
332
  ): Uint8Array {
292
- return ScrcpyInjectScrollControlMessage1_16.serialize(message);
333
+ return ScrcpySetClipboardControlMessage1_15.serialize(message);
334
+ }
335
+
336
+ public getScrollController(): ScrcpyScrollController {
337
+ return new ScrcpyScrollController1_16();
293
338
  }
294
339
  }
@@ -0,0 +1,76 @@
1
+ import Struct from "@yume-chan/struct";
2
+
3
+ import {
4
+ ScrcpyControlMessageType,
5
+ type ScrcpyInjectScrollControlMessage,
6
+ } from "../../control/index.js";
7
+
8
+ export interface ScrcpyScrollController {
9
+ serializeScrollMessage(
10
+ message: ScrcpyInjectScrollControlMessage
11
+ ): Uint8Array | undefined;
12
+ }
13
+
14
+ export const ScrcpyInjectScrollControlMessage1_16 = new Struct()
15
+ .uint8("type", ScrcpyControlMessageType.InjectScroll as const)
16
+ .uint32("pointerX")
17
+ .uint32("pointerY")
18
+ .uint16("screenWidth")
19
+ .uint16("screenHeight")
20
+ .int32("scrollX")
21
+ .int32("scrollY");
22
+
23
+ /**
24
+ * Old version of Scrcpy server only supports integer values for scroll.
25
+ *
26
+ * Accumulate scroll values and send scroll message when accumulated value
27
+ * reaches 1 or -1.
28
+ */
29
+ export class ScrcpyScrollController1_16 implements ScrcpyScrollController {
30
+ private accumulatedX = 0;
31
+ private accumulatedY = 0;
32
+
33
+ protected processMessage(
34
+ message: ScrcpyInjectScrollControlMessage
35
+ ): ScrcpyInjectScrollControlMessage | undefined {
36
+ this.accumulatedX += message.scrollX;
37
+ this.accumulatedY += message.scrollY;
38
+
39
+ let scrollX = 0;
40
+ let scrollY = 0;
41
+ if (this.accumulatedX >= 1) {
42
+ scrollX = 1;
43
+ this.accumulatedX = 0;
44
+ } else if (this.accumulatedX <= -1) {
45
+ scrollX = -1;
46
+ this.accumulatedX = 0;
47
+ }
48
+
49
+ if (this.accumulatedY >= 1) {
50
+ scrollY = 1;
51
+ this.accumulatedY = 0;
52
+ } else if (this.accumulatedY <= -1) {
53
+ scrollY = -1;
54
+ this.accumulatedY = 0;
55
+ }
56
+
57
+ if (scrollX === 0 && scrollY === 0) {
58
+ return undefined;
59
+ }
60
+
61
+ message.scrollX = scrollX;
62
+ message.scrollY = scrollY;
63
+ return message;
64
+ }
65
+
66
+ public serializeScrollMessage(
67
+ message: ScrcpyInjectScrollControlMessage
68
+ ): Uint8Array | undefined {
69
+ const processed = this.processMessage(message);
70
+ if (!processed) {
71
+ return undefined;
72
+ }
73
+
74
+ return ScrcpyInjectScrollControlMessage1_16.serialize(processed);
75
+ }
76
+ }
@@ -1,27 +1,37 @@
1
- import Struct, { placeholder } from '@yume-chan/struct';
1
+ import Struct, { placeholder } from "@yume-chan/struct";
2
2
 
3
- import { AndroidKeyEventAction, ScrcpyControlMessageType } from '../control/index.js';
4
- import { ScrcpyBackOrScreenOnControlMessage1_16, ScrcpyOptions1_16, type ScrcpyOptionsInit1_16 } from './1_16/options.js';
3
+ import {
4
+ ScrcpyControlMessageType,
5
+ type AndroidKeyEventAction,
6
+ type ScrcpyBackOrScreenOnControlMessage,
7
+ } from "../control/index.js";
8
+
9
+ import {
10
+ ScrcpyBackOrScreenOnControlMessage1_16,
11
+ ScrcpyOptions1_16,
12
+ type ScrcpyOptionsInit1_16,
13
+ } from "./1_16/options.js";
5
14
 
6
15
  export interface ScrcpyOptionsInit1_18 extends ScrcpyOptionsInit1_16 {
7
16
  powerOffOnClose: boolean;
8
17
  }
9
18
 
10
- export const ScrcpyBackOrScreenOnControlMessage1_18 =
11
- new Struct()
12
- .fields(ScrcpyBackOrScreenOnControlMessage1_16)
13
- .uint8('action', placeholder<AndroidKeyEventAction>());
19
+ export const ScrcpyBackOrScreenOnControlMessage1_18 = new Struct()
20
+ .fields(ScrcpyBackOrScreenOnControlMessage1_16)
21
+ .uint8("action", placeholder<AndroidKeyEventAction>());
14
22
 
15
- export type ScrcpyBackOrScreenOnControlMessage1_18 = typeof ScrcpyBackOrScreenOnControlMessage1_18['TInit'];
23
+ export type ScrcpyBackOrScreenOnControlMessage1_18 =
24
+ typeof ScrcpyBackOrScreenOnControlMessage1_18["TInit"];
16
25
 
17
- export class ScrcpyOptions1_18<T extends ScrcpyOptionsInit1_18 = ScrcpyOptionsInit1_18>
18
- extends ScrcpyOptions1_16<T> {
26
+ export class ScrcpyOptions1_18<
27
+ T extends ScrcpyOptionsInit1_18 = ScrcpyOptionsInit1_18
28
+ > extends ScrcpyOptions1_16<T> {
19
29
  constructor(value: Partial<ScrcpyOptionsInit1_18>) {
20
30
  super(value);
21
31
  }
22
32
 
23
33
  protected override getArgumentOrder(): (keyof T)[] {
24
- return super.getArgumentOrder().concat(['powerOffOnClose']);
34
+ return super.getArgumentOrder().concat(["powerOffOnClose"]);
25
35
  }
26
36
 
27
37
  public override getDefaultValue(): T {
@@ -56,7 +66,7 @@ export class ScrcpyOptions1_18<T extends ScrcpyOptionsInit1_18 = ScrcpyOptionsIn
56
66
  }
57
67
 
58
68
  public override serializeBackOrScreenOnControlMessage(
59
- message: ScrcpyBackOrScreenOnControlMessage1_18,
69
+ message: ScrcpyBackOrScreenOnControlMessage
60
70
  ) {
61
71
  return ScrcpyBackOrScreenOnControlMessage1_18.serialize(message);
62
72
  }
@@ -1,18 +1,36 @@
1
1
  // cspell: ignore autosync
2
2
 
3
- import { ScrcpyOptions1_18, type ScrcpyOptionsInit1_18 } from './1_18.js';
4
- import { toScrcpyOptionValue } from './types.js';
3
+ import Struct from "@yume-chan/struct";
4
+
5
+ import {
6
+ ScrcpyControlMessageType,
7
+ type ScrcpySetClipboardControlMessage,
8
+ } from "../control/index.js";
9
+
10
+ import { ScrcpyOptions1_18, type ScrcpyOptionsInit1_18 } from "./1_18.js";
11
+ import { toScrcpyOptionValue } from "./types.js";
5
12
 
6
13
  export interface ScrcpyOptionsInit1_21 extends ScrcpyOptionsInit1_18 {
7
14
  clipboardAutosync?: boolean;
8
15
  }
9
16
 
10
17
  function toSnakeCase(input: string): string {
11
- return input.replace(/([A-Z])/g, '_$1').toLowerCase();
18
+ return input.replace(/([A-Z])/g, "_$1").toLowerCase();
12
19
  }
13
20
 
14
- export class ScrcpyOptions1_21<T extends ScrcpyOptionsInit1_21 = ScrcpyOptionsInit1_21>
15
- extends ScrcpyOptions1_18<T> {
21
+ export const ScrcpySetClipboardControlMessage1_21 = new Struct()
22
+ .uint8("type", ScrcpyControlMessageType.SetClipboard as const)
23
+ .uint64("sequence")
24
+ .int8("paste")
25
+ .uint32("length")
26
+ .string("content", { lengthField: "length" });
27
+
28
+ export type ScrcpySetClipboardControlMessage1_21 =
29
+ typeof ScrcpySetClipboardControlMessage1_21["TInit"];
30
+
31
+ export class ScrcpyOptions1_21<
32
+ T extends ScrcpyOptionsInit1_21 = ScrcpyOptionsInit1_21
33
+ > extends ScrcpyOptions1_18<T> {
16
34
  public constructor(init: Partial<ScrcpyOptionsInit1_21>) {
17
35
  super(init);
18
36
  }
@@ -32,13 +50,13 @@ export class ScrcpyOptions1_21<T extends ScrcpyOptionsInit1_21 = ScrcpyOptionsIn
32
50
  ([key, value]) =>
33
51
  [key, toScrcpyOptionValue(value, undefined)] as const
34
52
  )
35
- .filter(
36
- (pair): pair is [string, string] =>
37
- pair[1] !== undefined
38
- )
39
- .map(
40
- ([key, value]) =>
41
- `${toSnakeCase(key)}=${value}`
42
- );
53
+ .filter((pair): pair is [string, string] => pair[1] !== undefined)
54
+ .map(([key, value]) => `${toSnakeCase(key)}=${value}`);
55
+ }
56
+
57
+ public override serializeSetClipboardControlMessage(
58
+ message: ScrcpySetClipboardControlMessage
59
+ ): Uint8Array {
60
+ return ScrcpySetClipboardControlMessage1_21.serialize(message);
43
61
  }
44
62
  }
@@ -0,0 +1,2 @@
1
+ export * from "./options.js";
2
+ export * from "./scroll.js";
@@ -1,7 +1,7 @@
1
- import Struct from '@yume-chan/struct';
1
+ import { type ScrcpyScrollController } from "../1_16/index.js";
2
+ import { ScrcpyOptions1_21, type ScrcpyOptionsInit1_21 } from "../1_21.js";
2
3
 
3
- import { ScrcpyInjectScrollControlMessage1_16 } from './1_16/options.js';
4
- import { ScrcpyOptions1_21, type ScrcpyOptionsInit1_21 } from './1_21.js';
4
+ import { ScrcpyScrollController1_22 } from "./scroll.js";
5
5
 
6
6
  export interface ScrcpyOptionsInit1_22 extends ScrcpyOptionsInit1_21 {
7
7
  downsizeOnError: boolean;
@@ -28,16 +28,9 @@ export interface ScrcpyOptionsInit1_22 extends ScrcpyOptionsInit1_21 {
28
28
  rawVideoStream: boolean;
29
29
  }
30
30
 
31
- export const ScrcpyInjectScrollControlMessage1_22 =
32
- new Struct()
33
- .fields(ScrcpyInjectScrollControlMessage1_16)
34
- .int32('buttons');
35
-
36
- export type ScrcpyInjectScrollControlMessage1_22 =
37
- typeof ScrcpyInjectScrollControlMessage1_22['TInit'];
38
-
39
- export class ScrcpyOptions1_22<T extends ScrcpyOptionsInit1_22 = ScrcpyOptionsInit1_22>
40
- extends ScrcpyOptions1_21<T> {
31
+ export class ScrcpyOptions1_22<
32
+ T extends ScrcpyOptionsInit1_22 = ScrcpyOptionsInit1_22
33
+ > extends ScrcpyOptions1_21<T> {
41
34
  public constructor(init: Partial<ScrcpyOptionsInit1_22>) {
42
35
  if (init.rawVideoStream) {
43
36
  // Set implied options for client-side processing
@@ -59,9 +52,7 @@ export class ScrcpyOptions1_22<T extends ScrcpyOptionsInit1_22 = ScrcpyOptionsIn
59
52
  };
60
53
  }
61
54
 
62
- public override serializeInjectScrollControlMessage(
63
- message: ScrcpyInjectScrollControlMessage1_22,
64
- ): Uint8Array {
65
- return ScrcpyInjectScrollControlMessage1_22.serialize(message);
55
+ public override getScrollController(): ScrcpyScrollController {
56
+ return new ScrcpyScrollController1_22();
66
57
  }
67
58
  }
@@ -0,0 +1,26 @@
1
+ import Struct from "@yume-chan/struct";
2
+
3
+ import {
4
+ ScrcpyInjectScrollControlMessage1_16,
5
+ ScrcpyScrollController1_16,
6
+ } from "../1_16/index.js";
7
+
8
+ export const ScrcpyInjectScrollControlMessage1_22 = new Struct()
9
+ .fields(ScrcpyInjectScrollControlMessage1_16)
10
+ .int32("buttons");
11
+
12
+ export type ScrcpyInjectScrollControlMessage1_22 =
13
+ typeof ScrcpyInjectScrollControlMessage1_22["TInit"];
14
+
15
+ export class ScrcpyScrollController1_22 extends ScrcpyScrollController1_16 {
16
+ public override serializeScrollMessage(
17
+ message: ScrcpyInjectScrollControlMessage1_22
18
+ ): Uint8Array | undefined {
19
+ const processed = this.processMessage(message);
20
+ if (!processed) {
21
+ return undefined;
22
+ }
23
+
24
+ return ScrcpyInjectScrollControlMessage1_22.serialize(processed);
25
+ }
26
+ }