@yume-chan/scrcpy 0.0.20 → 0.0.22

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 (147) hide show
  1. package/CHANGELOG.json +33 -0
  2. package/CHANGELOG.md +18 -1
  3. package/README.md +8 -122
  4. package/esm/codec/av1.js +2 -2
  5. package/esm/codec/av1.js.map +1 -1
  6. package/esm/codec/h264.js +2 -2
  7. package/esm/codec/h264.js.map +1 -1
  8. package/esm/codec/h265.d.ts +72 -4
  9. package/esm/codec/h265.d.ts.map +1 -1
  10. package/esm/codec/h265.js +18 -19
  11. package/esm/codec/h265.js.map +1 -1
  12. package/esm/codec/nalu.d.ts +1 -8
  13. package/esm/codec/nalu.d.ts.map +1 -1
  14. package/esm/codec/nalu.js +53 -40
  15. package/esm/codec/nalu.js.map +1 -1
  16. package/esm/control/hover-helper.d.ts +1 -1
  17. package/esm/control/hover-helper.d.ts.map +1 -1
  18. package/esm/control/hover-helper.js +8 -9
  19. package/esm/control/hover-helper.js.map +1 -1
  20. package/esm/control/inject-keycode.d.ts +13 -13
  21. package/esm/control/inject-keycode.d.ts.map +1 -1
  22. package/esm/control/inject-keycode.js +3 -3
  23. package/esm/control/inject-keycode.js.map +1 -1
  24. package/esm/control/inject-touch.d.ts.map +1 -1
  25. package/esm/control/inject-touch.js +3 -4
  26. package/esm/control/inject-touch.js.map +1 -1
  27. package/esm/control/serializer.d.ts +4 -3
  28. package/esm/control/serializer.d.ts.map +1 -1
  29. package/esm/control/serializer.js +30 -14
  30. package/esm/control/serializer.js.map +1 -1
  31. package/esm/control/set-screen-power-mode.js +1 -1
  32. package/esm/control/set-screen-power-mode.js.map +1 -1
  33. package/esm/control/type.d.ts +1 -1
  34. package/esm/control/type.d.ts.map +1 -1
  35. package/esm/control/type.js +4 -4
  36. package/esm/control/type.js.map +1 -1
  37. package/esm/control/writer.d.ts +5 -3
  38. package/esm/control/writer.d.ts.map +1 -1
  39. package/esm/control/writer.js +23 -14
  40. package/esm/control/writer.js.map +1 -1
  41. package/esm/device-message/stream.js.map +1 -1
  42. package/esm/device-message/type.js +1 -1
  43. package/esm/device-message/type.js.map +1 -1
  44. package/esm/options/1_16/codec-options.d.ts +2 -2
  45. package/esm/options/1_16/codec-options.d.ts.map +1 -1
  46. package/esm/options/1_16/codec-options.js +15 -5
  47. package/esm/options/1_16/codec-options.js.map +1 -1
  48. package/esm/options/1_16/float-to-uint16.js.map +1 -1
  49. package/esm/options/1_16/init.js +2 -2
  50. package/esm/options/1_16/init.js.map +1 -1
  51. package/esm/options/1_16/options.d.ts +1 -1
  52. package/esm/options/1_16/options.d.ts.map +1 -1
  53. package/esm/options/1_16/options.js +2 -3
  54. package/esm/options/1_16/options.js.map +1 -1
  55. package/esm/options/1_16/scroll.d.ts +1 -2
  56. package/esm/options/1_16/scroll.d.ts.map +1 -1
  57. package/esm/options/1_16/scroll.js +12 -12
  58. package/esm/options/1_16/scroll.js.map +1 -1
  59. package/esm/options/1_17.d.ts +1 -1
  60. package/esm/options/1_17.d.ts.map +1 -1
  61. package/esm/options/1_17.js +1 -2
  62. package/esm/options/1_17.js.map +1 -1
  63. package/esm/options/1_18.d.ts +1 -1
  64. package/esm/options/1_18.d.ts.map +1 -1
  65. package/esm/options/1_18.js +3 -4
  66. package/esm/options/1_18.js.map +1 -1
  67. package/esm/options/1_21.d.ts +1 -1
  68. package/esm/options/1_21.d.ts.map +1 -1
  69. package/esm/options/1_21.js +1 -2
  70. package/esm/options/1_21.js.map +1 -1
  71. package/esm/options/1_22/options.d.ts +1 -1
  72. package/esm/options/1_22/options.d.ts.map +1 -1
  73. package/esm/options/1_22/options.js +1 -2
  74. package/esm/options/1_22/options.js.map +1 -1
  75. package/esm/options/1_22/scroll.d.ts.map +1 -1
  76. package/esm/options/1_22/scroll.js.map +1 -1
  77. package/esm/options/1_23.d.ts +1 -1
  78. package/esm/options/1_23.d.ts.map +1 -1
  79. package/esm/options/1_23.js +1 -2
  80. package/esm/options/1_23.js.map +1 -1
  81. package/esm/options/1_24.d.ts +1 -1
  82. package/esm/options/1_24.d.ts.map +1 -1
  83. package/esm/options/1_24.js +1 -2
  84. package/esm/options/1_24.js.map +1 -1
  85. package/esm/options/1_25/options.d.ts.map +1 -1
  86. package/esm/options/1_25/options.js.map +1 -1
  87. package/esm/options/2_0.d.ts +1 -1
  88. package/esm/options/2_0.d.ts.map +1 -1
  89. package/esm/options/2_0.js +2 -4
  90. package/esm/options/2_0.js.map +1 -1
  91. package/esm/options/2_1.d.ts +48 -0
  92. package/esm/options/2_1.d.ts.map +1 -0
  93. package/esm/options/2_1.js +23 -0
  94. package/esm/options/2_1.js.map +1 -0
  95. package/esm/options/2_2.d.ts +67 -0
  96. package/esm/options/2_2.d.ts.map +1 -0
  97. package/esm/options/2_2.js +44 -0
  98. package/esm/options/2_2.js.map +1 -0
  99. package/esm/options/codec.d.ts.map +1 -1
  100. package/esm/options/codec.js +3 -4
  101. package/esm/options/codec.js.map +1 -1
  102. package/esm/options/index.d.ts +2 -0
  103. package/esm/options/index.d.ts.map +1 -1
  104. package/esm/options/index.js +2 -0
  105. package/esm/options/index.js.map +1 -1
  106. package/esm/options/latest.d.ts +4 -5
  107. package/esm/options/latest.d.ts.map +1 -1
  108. package/esm/options/latest.js +2 -3
  109. package/esm/options/latest.js.map +1 -1
  110. package/esm/options/types.d.ts +1 -0
  111. package/esm/options/types.d.ts.map +1 -1
  112. package/esm/options/types.js +15 -0
  113. package/esm/options/types.js.map +1 -1
  114. package/package.json +10 -22
  115. package/src/codec/h265.ts +40 -31
  116. package/src/codec/nalu.ts +73 -55
  117. package/src/control/hover-helper.ts +10 -11
  118. package/src/control/inject-touch.ts +0 -1
  119. package/src/control/serializer.ts +56 -35
  120. package/src/control/type.ts +7 -7
  121. package/src/control/writer.ts +40 -30
  122. package/src/device-message/stream.ts +2 -2
  123. package/src/options/1_16/codec-options.ts +22 -7
  124. package/src/options/1_16/float-to-uint16.ts +1 -1
  125. package/src/options/1_16/options.ts +32 -36
  126. package/src/options/1_16/scroll.ts +16 -16
  127. package/src/options/1_17.ts +11 -11
  128. package/src/options/1_18.ts +12 -12
  129. package/src/options/1_21.ts +9 -9
  130. package/src/options/1_22/options.ts +7 -7
  131. package/src/options/1_22/scroll.ts +2 -2
  132. package/src/options/1_23.ts +6 -6
  133. package/src/options/1_24.ts +4 -4
  134. package/src/options/1_25/options.ts +4 -4
  135. package/src/options/1_25/scroll.ts +2 -2
  136. package/src/options/2_0.ts +25 -25
  137. package/src/options/2_1.ts +35 -0
  138. package/src/options/2_2.ts +68 -0
  139. package/src/options/codec.ts +13 -13
  140. package/src/options/index.ts +2 -0
  141. package/src/options/latest.ts +4 -6
  142. package/src/options/types.ts +47 -28
  143. package/tsconfig.build.tsbuildinfo +1 -1
  144. package/bin/scrcpy-server +0 -0
  145. package/bin/version.d.ts +0 -1
  146. package/bin/version.js +0 -1
  147. package/scripts/fetch-server.cjs +0 -38
@@ -15,34 +15,33 @@ import { ScrcpyControlMessageType } from "./type.js";
15
15
  * so Scrcpy server can remove the previously hovering pointer.
16
16
  */
17
17
  export class ScrcpyHoverHelper {
18
- // AFAIK, only mouse and pen can have hover state
19
- // and you can't have two mouses or pens.
20
- // So remember the last hovering pointer is enough.
21
- private lastHoverMessage: ScrcpyInjectTouchControlMessage | undefined;
18
+ // There can be only one hovering pointer (either mouse or pen,
19
+ // touch can have multiple pointers but no hovering state).
20
+ #lastHoverMessage: ScrcpyInjectTouchControlMessage | undefined;
22
21
 
23
- public process(
24
- message: Omit<ScrcpyInjectTouchControlMessage, "type">
22
+ process(
23
+ message: Omit<ScrcpyInjectTouchControlMessage, "type">,
25
24
  ): ScrcpyInjectTouchControlMessage[] {
26
25
  const result: ScrcpyInjectTouchControlMessage[] = [];
27
26
 
28
27
  // A different pointer appeared,
29
28
  // Cancel previously hovering pointer so Scrcpy server can free up the pointer ID.
30
29
  if (
31
- this.lastHoverMessage &&
32
- this.lastHoverMessage.pointerId !== message.pointerId
30
+ this.#lastHoverMessage &&
31
+ this.#lastHoverMessage.pointerId !== message.pointerId
33
32
  ) {
34
33
  // TODO: Inject MotionEvent.ACTION_HOVER_EXIT
35
34
  // From testing, it seems no App cares about this event.
36
35
  result.push({
37
- ...this.lastHoverMessage,
36
+ ...this.#lastHoverMessage,
38
37
  action: AndroidMotionEventAction.Up,
39
38
  });
40
- this.lastHoverMessage = undefined;
39
+ this.#lastHoverMessage = undefined;
41
40
  }
42
41
 
43
42
  if (message.action === AndroidMotionEventAction.HoverMove) {
44
43
  // TODO: Inject MotionEvent.ACTION_HOVER_ENTER
45
- this.lastHoverMessage = message as ScrcpyInjectTouchControlMessage;
44
+ this.#lastHoverMessage = message as ScrcpyInjectTouchControlMessage;
46
45
  }
47
46
 
48
47
  (message as ScrcpyInjectTouchControlMessage).type =
@@ -27,7 +27,6 @@ export enum AndroidMotionEventButton {
27
27
  StylusSecondary = 0x40,
28
28
  }
29
29
 
30
- // eslint-disable-next-line @typescript-eslint/no-namespace
31
30
  export namespace ScrcpyPointerId {
32
31
  export const Mouse = -1n;
33
32
  export const Finger = -2n;
@@ -3,6 +3,7 @@ import type {
3
3
  ScrcpyScrollController,
4
4
  } from "../options/index.js";
5
5
 
6
+ import { BasicControlMessage } from "./basic.js";
6
7
  import type { AndroidKeyEventAction } from "./inject-keycode.js";
7
8
  import { ScrcpyInjectKeyCodeControlMessage } from "./inject-keycode.js";
8
9
  import type { ScrcpyInjectScrollControlMessage } from "./inject-scroll.js";
@@ -17,79 +18,99 @@ import {
17
18
  } from "./type.js";
18
19
 
19
20
  export class ScrcpyControlMessageSerializer {
20
- private _options: ScrcpyOptions<object>;
21
- private _typeValues: ScrcpyControlMessageTypeValue;
22
- private _scrollController: ScrcpyScrollController;
21
+ #options: ScrcpyOptions<object>;
22
+ #typeValues: ScrcpyControlMessageTypeValue;
23
+ #scrollController: ScrcpyScrollController;
23
24
 
24
- public constructor(options: ScrcpyOptions<object>) {
25
- this._options = options;
26
- this._typeValues = new ScrcpyControlMessageTypeValue(options);
27
- this._scrollController = options.createScrollController();
25
+ constructor(options: ScrcpyOptions<object>) {
26
+ this.#options = options;
27
+ this.#typeValues = new ScrcpyControlMessageTypeValue(options);
28
+ this.#scrollController = options.createScrollController();
28
29
  }
29
30
 
30
- public injectKeyCode(
31
- message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">
32
- ) {
31
+ injectKeyCode(message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">) {
33
32
  return ScrcpyInjectKeyCodeControlMessage.serialize(
34
- this._typeValues.fillMessageType(
33
+ this.#typeValues.fillMessageType(
35
34
  message,
36
- ScrcpyControlMessageType.InjectKeyCode
37
- )
35
+ ScrcpyControlMessageType.InjectKeyCode,
36
+ ),
38
37
  );
39
38
  }
40
39
 
41
- public injectText(text: string) {
40
+ injectText(text: string) {
42
41
  return ScrcpyInjectTextControlMessage.serialize({
43
42
  text,
44
- type: this._typeValues.get(ScrcpyControlMessageType.InjectText),
43
+ type: this.#typeValues.get(ScrcpyControlMessageType.InjectText),
45
44
  });
46
45
  }
47
46
 
48
47
  /**
49
48
  * `pressure` is a float value between 0 and 1.
50
49
  */
51
- public injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, "type">) {
52
- return this._options.serializeInjectTouchControlMessage(
53
- this._typeValues.fillMessageType(
50
+ injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, "type">) {
51
+ return this.#options.serializeInjectTouchControlMessage(
52
+ this.#typeValues.fillMessageType(
54
53
  message,
55
- ScrcpyControlMessageType.InjectTouch
56
- )
54
+ ScrcpyControlMessageType.InjectTouch,
55
+ ),
57
56
  );
58
57
  }
59
58
 
60
59
  /**
61
60
  * `scrollX` and `scrollY` are float values between 0 and 1.
62
61
  */
63
- public injectScroll(
64
- message: Omit<ScrcpyInjectScrollControlMessage, "type">
65
- ) {
66
- return this._scrollController.serializeScrollMessage(
67
- this._typeValues.fillMessageType(
62
+ injectScroll(message: Omit<ScrcpyInjectScrollControlMessage, "type">) {
63
+ return this.#scrollController.serializeScrollMessage(
64
+ this.#typeValues.fillMessageType(
68
65
  message,
69
- ScrcpyControlMessageType.InjectScroll
70
- )
66
+ ScrcpyControlMessageType.InjectScroll,
67
+ ),
71
68
  );
72
69
  }
73
70
 
74
- public backOrScreenOn(action: AndroidKeyEventAction) {
75
- return this._options.serializeBackOrScreenOnControlMessage({
71
+ backOrScreenOn(action: AndroidKeyEventAction) {
72
+ return this.#options.serializeBackOrScreenOnControlMessage({
76
73
  action,
77
- type: this._typeValues.get(ScrcpyControlMessageType.BackOrScreenOn),
74
+ type: this.#typeValues.get(ScrcpyControlMessageType.BackOrScreenOn),
78
75
  });
79
76
  }
80
77
 
81
- public setScreenPowerMode(mode: AndroidScreenPowerMode) {
78
+ setScreenPowerMode(mode: AndroidScreenPowerMode) {
82
79
  return ScrcpySetScreenPowerModeControlMessage.serialize({
83
80
  mode,
84
- type: this._typeValues.get(
85
- ScrcpyControlMessageType.SetScreenPowerMode
81
+ type: this.#typeValues.get(
82
+ ScrcpyControlMessageType.SetScreenPowerMode,
83
+ ),
84
+ });
85
+ }
86
+
87
+ expandNotificationPanel() {
88
+ return BasicControlMessage.serialize({
89
+ type: this.#typeValues.get(
90
+ ScrcpyControlMessageType.ExpandNotificationPanel,
91
+ ),
92
+ });
93
+ }
94
+
95
+ expandSettingPanel() {
96
+ return BasicControlMessage.serialize({
97
+ type: this.#typeValues.get(
98
+ ScrcpyControlMessageType.ExpandSettingPanel,
99
+ ),
100
+ });
101
+ }
102
+
103
+ collapseNotificationPanel() {
104
+ return BasicControlMessage.serialize({
105
+ type: this.#typeValues.get(
106
+ ScrcpyControlMessageType.CollapseNotificationPanel,
86
107
  ),
87
108
  });
88
109
  }
89
110
 
90
- public rotateDevice() {
111
+ rotateDevice() {
91
112
  return ScrcpyRotateDeviceControlMessage.serialize({
92
- type: this._typeValues.get(ScrcpyControlMessageType.RotateDevice),
113
+ type: this.#typeValues.get(ScrcpyControlMessageType.RotateDevice),
93
114
  });
94
115
  }
95
116
  }
@@ -25,23 +25,23 @@ export enum ScrcpyControlMessageType {
25
25
  * This class provides a way to get the actual value for a given type.
26
26
  */
27
27
  export class ScrcpyControlMessageTypeValue {
28
- private types: readonly ScrcpyControlMessageType[];
28
+ #types: readonly ScrcpyControlMessageType[];
29
29
 
30
- public constructor(options: ScrcpyOptions<object>) {
31
- this.types = options.controlMessageTypes;
30
+ constructor(options: ScrcpyOptions<object>) {
31
+ this.#types = options.controlMessageTypes;
32
32
  }
33
33
 
34
- public get(type: ScrcpyControlMessageType): number {
35
- const value = this.types.indexOf(type);
34
+ get(type: ScrcpyControlMessageType): number {
35
+ const value = this.#types.indexOf(type);
36
36
  if (value === -1) {
37
37
  throw new Error("Not supported");
38
38
  }
39
39
  return value;
40
40
  }
41
41
 
42
- public fillMessageType<T extends { type: ScrcpyControlMessageType }>(
42
+ fillMessageType<T extends { type: ScrcpyControlMessageType }>(
43
43
  message: Omit<T, "type">,
44
- type: T["type"]
44
+ type: T["type"],
45
45
  ): T {
46
46
  (message as T).type = this.get(type);
47
47
  return message as T;
@@ -16,72 +16,82 @@ import { ScrcpyControlMessageSerializer } from "./serializer.js";
16
16
  import type { AndroidScreenPowerMode } from "./set-screen-power-mode.js";
17
17
 
18
18
  export class ScrcpyControlMessageWriter {
19
- private _writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>;
20
- private _serializer: ScrcpyControlMessageSerializer;
19
+ #writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>;
20
+ #serializer: ScrcpyControlMessageSerializer;
21
21
 
22
- public constructor(
22
+ constructor(
23
23
  writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>,
24
- options: ScrcpyOptions<object>
24
+ options: ScrcpyOptions<object>,
25
25
  ) {
26
- this._writer = writer;
27
- this._serializer = new ScrcpyControlMessageSerializer(options);
26
+ this.#writer = writer;
27
+ this.#serializer = new ScrcpyControlMessageSerializer(options);
28
28
  }
29
29
 
30
- private async write(message: Uint8Array) {
31
- await ConsumableWritableStream.write(this._writer, message);
30
+ async write(message: Uint8Array) {
31
+ await ConsumableWritableStream.write(this.#writer, message);
32
32
  }
33
33
 
34
- public async injectKeyCode(
35
- message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">
34
+ async injectKeyCode(
35
+ message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">,
36
36
  ) {
37
- await this.write(this._serializer.injectKeyCode(message));
37
+ await this.write(this.#serializer.injectKeyCode(message));
38
38
  }
39
39
 
40
- public async injectText(text: string) {
41
- await this.write(this._serializer.injectText(text));
40
+ async injectText(text: string) {
41
+ await this.write(this.#serializer.injectText(text));
42
42
  }
43
43
 
44
44
  /**
45
45
  * `pressure` is a float value between 0 and 1.
46
46
  */
47
- public async injectTouch(
48
- message: Omit<ScrcpyInjectTouchControlMessage, "type">
49
- ) {
50
- await this.write(this._serializer.injectTouch(message));
47
+ async injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, "type">) {
48
+ await this.write(this.#serializer.injectTouch(message));
51
49
  }
52
50
 
53
51
  /**
54
52
  * `scrollX` and `scrollY` are float values between 0 and 1.
55
53
  */
56
- public async injectScroll(
57
- message: Omit<ScrcpyInjectScrollControlMessage, "type">
54
+ async injectScroll(
55
+ message: Omit<ScrcpyInjectScrollControlMessage, "type">,
58
56
  ) {
59
- const data = this._serializer.injectScroll(message);
57
+ const data = this.#serializer.injectScroll(message);
60
58
  if (data) {
61
59
  await this.write(data);
62
60
  }
63
61
  }
64
62
 
65
- public async backOrScreenOn(action: AndroidKeyEventAction) {
66
- const data = this._serializer.backOrScreenOn(action);
63
+ async backOrScreenOn(action: AndroidKeyEventAction) {
64
+ const data = this.#serializer.backOrScreenOn(action);
67
65
  if (data) {
68
66
  await this.write(data);
69
67
  }
70
68
  }
71
69
 
72
- public async setScreenPowerMode(mode: AndroidScreenPowerMode) {
73
- await this.write(this._serializer.setScreenPowerMode(mode));
70
+ async setScreenPowerMode(mode: AndroidScreenPowerMode) {
71
+ await this.write(this.#serializer.setScreenPowerMode(mode));
72
+ }
73
+
74
+ async expandNotificationPanel() {
75
+ await this.write(this.#serializer.expandNotificationPanel());
76
+ }
77
+
78
+ async expandSettingPanel() {
79
+ await this.write(this.#serializer.expandSettingPanel());
80
+ }
81
+
82
+ async collapseNotificationPanel() {
83
+ await this.write(this.#serializer.collapseNotificationPanel());
74
84
  }
75
85
 
76
- public async rotateDevice() {
77
- await this.write(this._serializer.rotateDevice());
86
+ async rotateDevice() {
87
+ await this.write(this.#serializer.rotateDevice());
78
88
  }
79
89
 
80
- public releaseLock() {
81
- this._writer.releaseLock();
90
+ releaseLock() {
91
+ this.#writer.releaseLock();
82
92
  }
83
93
 
84
- public async close() {
85
- await this._writer.close();
94
+ async close() {
95
+ await this.#writer.close();
86
96
  }
87
97
  }
@@ -21,11 +21,11 @@ export class ScrcpyDeviceMessageDeserializeStream extends BufferedTransformStrea
21
21
  switch (type[0]) {
22
22
  case ScrcpyDeviceMessageType.Clipboard:
23
23
  return await ScrcpyClipboardDeviceMessage.deserialize(
24
- stream
24
+ stream,
25
25
  );
26
26
  case ScrcpyDeviceMessageType.AckClipboard:
27
27
  return await ScrcpyAckClipboardDeviceMessage.deserialize(
28
- stream
28
+ stream,
29
29
  );
30
30
  default:
31
31
  throw new Error("Unsupported control message type");
@@ -27,15 +27,23 @@ const CODEC_OPTION_TYPES: Partial<
27
27
  };
28
28
 
29
29
  export class CodecOptions implements ScrcpyOptionValue {
30
- public value: Partial<CodecOptionsInit>;
30
+ options: Partial<CodecOptionsInit>;
31
31
 
32
- public constructor(value: Partial<CodecOptionsInit> = {}) {
33
- this.value = value;
32
+ constructor(options: Partial<CodecOptionsInit> = {}) {
33
+ for (const [key, value] of Object.entries(options)) {
34
+ if (typeof value !== "number") {
35
+ throw new Error(
36
+ `Invalid option value for ${key}: ${String(value)}`,
37
+ );
38
+ }
39
+ }
40
+
41
+ this.options = options;
34
42
  }
35
43
 
36
- public toOptionValue(): string | undefined {
37
- const entries = Object.entries(this.value).filter(
38
- ([, value]) => value !== undefined
44
+ toOptionValue(): string | undefined {
45
+ const entries = Object.entries(this.options).filter(
46
+ ([, value]) => value !== undefined,
39
47
  );
40
48
 
41
49
  if (entries.length === 0) {
@@ -44,8 +52,15 @@ export class CodecOptions implements ScrcpyOptionValue {
44
52
 
45
53
  return entries
46
54
  .map(([key, value]) => {
55
+ let result = toDashCase(key);
56
+
47
57
  const type = CODEC_OPTION_TYPES[key as keyof CodecOptionsInit];
48
- return `${toDashCase(key)}${type ? `:${type}` : ""}=${value}`;
58
+ if (type) {
59
+ result += `:${type}`;
60
+ }
61
+
62
+ result += `=${value}`;
63
+ return result;
49
64
  })
50
65
  .join(",");
51
66
  }
@@ -29,5 +29,5 @@ export const ScrcpyFloatToUint16NumberType: NumberFieldType = {
29
29
  };
30
30
 
31
31
  export const ScrcpyFloatToUint16FieldDefinition = new NumberFieldDefinition(
32
- ScrcpyFloatToUint16NumberType
32
+ ScrcpyFloatToUint16NumberType,
33
33
  );
@@ -38,14 +38,14 @@ import type { ScrcpyScrollController } from "./scroll.js";
38
38
  import { ScrcpyScrollController1_16 } from "./scroll.js";
39
39
 
40
40
  export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
41
- public static readonly DEFAULTS = {
41
+ static readonly DEFAULTS = {
42
42
  logLevel: ScrcpyLogLevel1_16.Debug,
43
43
  maxSize: 0,
44
44
  bitRate: 8_000_000,
45
45
  maxFps: 0,
46
46
  lockVideoOrientation: ScrcpyVideoOrientation1_16.Unlocked,
47
47
  tunnelForward: false,
48
- crop: undefined,
48
+ crop: "",
49
49
  sendFrameMeta: true,
50
50
  control: true,
51
51
  displayId: 0,
@@ -54,7 +54,7 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
54
54
  codecOptions: new CodecOptions(),
55
55
  } as const satisfies Required<ScrcpyOptionsInit1_16>;
56
56
 
57
- public static readonly SERIALIZE_ORDER = [
57
+ static readonly SERIALIZE_ORDER = [
58
58
  "logLevel",
59
59
  "maxSize",
60
60
  "bitRate",
@@ -70,68 +70,64 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
70
70
  "codecOptions",
71
71
  ] as const satisfies readonly (keyof ScrcpyOptionsInit1_16)[];
72
72
 
73
- public static serialize<T>(options: T, order: readonly (keyof T)[]) {
73
+ static serialize<T>(options: T, order: readonly (keyof T)[]) {
74
74
  return order.map((key) => toScrcpyOptionValue(options[key], "-"));
75
75
  }
76
76
 
77
- public static async parseCString(
77
+ static async parseCString(
78
78
  stream: AsyncExactReadable,
79
- maxLength: number
79
+ maxLength: number,
80
80
  ): Promise<string> {
81
81
  let result = decodeUtf8(await stream.readExactly(maxLength));
82
82
  result = result.substring(0, result.indexOf("\0"));
83
83
  return result;
84
84
  }
85
85
 
86
- public static async parseUint16BE(
87
- stream: AsyncExactReadable
88
- ): Promise<number> {
86
+ static async parseUint16BE(stream: AsyncExactReadable): Promise<number> {
89
87
  const buffer = await stream.readExactly(NumberFieldType.Uint16.size);
90
88
  return NumberFieldType.Uint16.deserialize(buffer, false);
91
89
  }
92
90
 
93
- public static async parseUint32BE(
94
- stream: AsyncExactReadable
95
- ): Promise<number> {
91
+ static async parseUint32BE(stream: AsyncExactReadable): Promise<number> {
96
92
  const buffer = await stream.readExactly(NumberFieldType.Uint32.size);
97
93
  return NumberFieldType.Uint32.deserialize(buffer, false);
98
94
  }
99
95
 
100
- public value: Required<ScrcpyOptionsInit1_16>;
96
+ value: Required<ScrcpyOptionsInit1_16>;
101
97
 
102
- public readonly defaults: Required<ScrcpyOptionsInit1_16> =
98
+ readonly defaults: Required<ScrcpyOptionsInit1_16> =
103
99
  ScrcpyOptions1_16.DEFAULTS;
104
100
 
105
- public readonly controlMessageTypes: readonly ScrcpyControlMessageType[] =
101
+ readonly controlMessageTypes: readonly ScrcpyControlMessageType[] =
106
102
  SCRCPY_CONTROL_MESSAGE_TYPES_1_16;
107
103
 
108
- public constructor(init: ScrcpyOptionsInit1_16) {
104
+ constructor(init: ScrcpyOptionsInit1_16) {
109
105
  this.value = { ...ScrcpyOptions1_16.DEFAULTS, ...init };
110
106
  }
111
107
 
112
- public serialize(): string[] {
108
+ serialize(): string[] {
113
109
  return ScrcpyOptions1_16.serialize(
114
110
  this.value,
115
- ScrcpyOptions1_16.SERIALIZE_ORDER
111
+ ScrcpyOptions1_16.SERIALIZE_ORDER,
116
112
  );
117
113
  }
118
114
 
119
- public setListEncoders(): void {
115
+ setListEncoders(): void {
120
116
  throw new Error("Not supported");
121
117
  }
122
118
 
123
- public setListDisplays(): void {
119
+ setListDisplays(): void {
124
120
  // Set to an invalid value
125
121
  // Server will print valid values before crashing
126
122
  // (server will crash before opening sockets)
127
123
  this.value.displayId = -1;
128
124
  }
129
125
 
130
- public parseEncoder(): ScrcpyEncoder | undefined {
126
+ parseEncoder(): ScrcpyEncoder | undefined {
131
127
  throw new Error("Not supported");
132
128
  }
133
129
 
134
- public parseDisplay(line: string): ScrcpyDisplay | undefined {
130
+ parseDisplay(line: string): ScrcpyDisplay | undefined {
135
131
  const displayIdRegex = /\s+scrcpy --display (\d+)/;
136
132
  const match = line.match(displayIdRegex);
137
133
  if (match) {
@@ -142,8 +138,8 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
142
138
  return undefined;
143
139
  }
144
140
 
145
- public parseVideoStreamMetadata(
146
- stream: ReadableStream<Uint8Array>
141
+ parseVideoStreamMetadata(
142
+ stream: ReadableStream<Uint8Array>,
147
143
  ): ValueOrPromise<ScrcpyVideoStream> {
148
144
  return (async () => {
149
145
  const buffered = new BufferedReadableStream(stream);
@@ -152,7 +148,7 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
152
148
  };
153
149
  metadata.deviceName = await ScrcpyOptions1_16.parseCString(
154
150
  buffered,
155
- 64
151
+ 64,
156
152
  );
157
153
  metadata.width = await ScrcpyOptions1_16.parseUint16BE(buffered);
158
154
  metadata.height = await ScrcpyOptions1_16.parseUint16BE(buffered);
@@ -160,11 +156,11 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
160
156
  })();
161
157
  }
162
158
 
163
- public parseAudioStreamMetadata(): never {
159
+ parseAudioStreamMetadata(): never {
164
160
  throw new Error("Not supported");
165
161
  }
166
162
 
167
- public createMediaStreamTransformer(): TransformStream<
163
+ createMediaStreamTransformer(): TransformStream<
168
164
  Uint8Array,
169
165
  ScrcpyMediaStreamPacket
170
166
  > {
@@ -181,7 +177,7 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
181
177
  }
182
178
 
183
179
  const deserializeStream = new StructDeserializeStream(
184
- ScrcpyMediaStreamRawPacket
180
+ ScrcpyMediaStreamRawPacket,
185
181
  );
186
182
  return {
187
183
  writable: deserializeStream.writable,
@@ -202,19 +198,19 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
202
198
  data: packet.data,
203
199
  });
204
200
  },
205
- })
201
+ }),
206
202
  ),
207
203
  };
208
204
  }
209
205
 
210
- public serializeInjectTouchControlMessage(
211
- message: ScrcpyInjectTouchControlMessage
206
+ serializeInjectTouchControlMessage(
207
+ message: ScrcpyInjectTouchControlMessage,
212
208
  ): Uint8Array {
213
209
  return ScrcpyInjectTouchControlMessage1_16.serialize(message);
214
210
  }
215
211
 
216
- public serializeBackOrScreenOnControlMessage(
217
- message: ScrcpyBackOrScreenOnControlMessage
212
+ serializeBackOrScreenOnControlMessage(
213
+ message: ScrcpyBackOrScreenOnControlMessage,
218
214
  ) {
219
215
  if (message.action === AndroidKeyEventAction.Down) {
220
216
  return ScrcpyBackOrScreenOnControlMessage1_16.serialize(message);
@@ -223,13 +219,13 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
223
219
  return undefined;
224
220
  }
225
221
 
226
- public serializeSetClipboardControlMessage(
227
- message: ScrcpySetClipboardControlMessage
222
+ serializeSetClipboardControlMessage(
223
+ message: ScrcpySetClipboardControlMessage,
228
224
  ): Uint8Array {
229
225
  return ScrcpySetClipboardControlMessage1_15.serialize(message);
230
226
  }
231
227
 
232
- public createScrollController(): ScrcpyScrollController {
228
+ createScrollController(): ScrcpyScrollController {
233
229
  return new ScrcpyScrollController1_16();
234
230
  }
235
231
  }
@@ -4,7 +4,7 @@ import type { ScrcpyInjectScrollControlMessage } from "../../control/index.js";
4
4
 
5
5
  export interface ScrcpyScrollController {
6
6
  serializeScrollMessage(
7
- message: ScrcpyInjectScrollControlMessage
7
+ message: ScrcpyInjectScrollControlMessage,
8
8
  ): Uint8Array | undefined;
9
9
  }
10
10
 
@@ -24,31 +24,31 @@ export const ScrcpyInjectScrollControlMessage1_16 = new Struct()
24
24
  * reaches 1 or -1.
25
25
  */
26
26
  export class ScrcpyScrollController1_16 implements ScrcpyScrollController {
27
- private accumulatedX = 0;
28
- private accumulatedY = 0;
27
+ #accumulatedX = 0;
28
+ #accumulatedY = 0;
29
29
 
30
30
  protected processMessage(
31
- message: ScrcpyInjectScrollControlMessage
31
+ message: ScrcpyInjectScrollControlMessage,
32
32
  ): ScrcpyInjectScrollControlMessage | undefined {
33
- this.accumulatedX += message.scrollX;
34
- this.accumulatedY += message.scrollY;
33
+ this.#accumulatedX += message.scrollX;
34
+ this.#accumulatedY += message.scrollY;
35
35
 
36
36
  let scrollX = 0;
37
37
  let scrollY = 0;
38
- if (this.accumulatedX >= 1) {
38
+ if (this.#accumulatedX >= 1) {
39
39
  scrollX = 1;
40
- this.accumulatedX = 0;
41
- } else if (this.accumulatedX <= -1) {
40
+ this.#accumulatedX = 0;
41
+ } else if (this.#accumulatedX <= -1) {
42
42
  scrollX = -1;
43
- this.accumulatedX = 0;
43
+ this.#accumulatedX = 0;
44
44
  }
45
45
 
46
- if (this.accumulatedY >= 1) {
46
+ if (this.#accumulatedY >= 1) {
47
47
  scrollY = 1;
48
- this.accumulatedY = 0;
49
- } else if (this.accumulatedY <= -1) {
48
+ this.#accumulatedY = 0;
49
+ } else if (this.#accumulatedY <= -1) {
50
50
  scrollY = -1;
51
- this.accumulatedY = 0;
51
+ this.#accumulatedY = 0;
52
52
  }
53
53
 
54
54
  if (scrollX === 0 && scrollY === 0) {
@@ -60,8 +60,8 @@ export class ScrcpyScrollController1_16 implements ScrcpyScrollController {
60
60
  return message;
61
61
  }
62
62
 
63
- public serializeScrollMessage(
64
- message: ScrcpyInjectScrollControlMessage
63
+ serializeScrollMessage(
64
+ message: ScrcpyInjectScrollControlMessage,
65
65
  ): Uint8Array | undefined {
66
66
  const processed = this.processMessage(message);
67
67
  if (!processed) {