android-emulator-webrtc 1.0.18 → 2.0.1

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 (69) hide show
  1. package/README.md +93 -204
  2. package/dist/components/emulator/emulator.d.ts +64 -0
  3. package/dist/components/emulator/emulator.js +161 -173
  4. package/dist/components/emulator/net/emulator_status.d.ts +45 -0
  5. package/dist/components/emulator/net/emulator_status.js +35 -42
  6. package/dist/components/emulator/net/logcat.js +37 -54
  7. package/dist/components/emulator/net/logger.d.ts +7 -0
  8. package/dist/components/emulator/net/logger.js +20 -0
  9. package/dist/components/emulator/net/ws_jsep_protocol_driver.d.ts +213 -0
  10. package/dist/components/emulator/net/ws_jsep_protocol_driver.js +640 -0
  11. package/dist/components/emulator/views/event_handler.d.ts +37 -0
  12. package/dist/components/emulator/views/event_handler.js +274 -260
  13. package/dist/components/emulator/views/webrtc_view.d.ts +27 -0
  14. package/dist/components/emulator/views/webrtc_view.js +42 -20
  15. package/dist/index.d.ts +8 -0
  16. package/dist/index.js +0 -7
  17. package/dist/proto/emulator_controller_pb.d.ts +1 -0
  18. package/dist/proto/emulator_controller_pb.js +146 -287
  19. package/dist/src/components/emulator/emulator.d.ts +64 -0
  20. package/dist/src/components/emulator/net/emulator_status.d.ts +45 -0
  21. package/dist/src/components/emulator/net/logger.d.ts +7 -0
  22. package/dist/src/components/emulator/net/ws_jsep_protocol_driver.d.ts +213 -0
  23. package/dist/src/components/emulator/views/event_handler.d.ts +37 -0
  24. package/dist/src/components/emulator/views/webrtc_view.d.ts +27 -0
  25. package/dist/src/index.d.ts +8 -0
  26. package/dist/src/proto/emulator_controller_pb.d.ts +1 -0
  27. package/package.json +17 -17
  28. package/proto/emulator_controller.proto +746 -181
  29. package/.vscode/launch.json +0 -21
  30. package/.vscode/settings.json +0 -3
  31. package/CONTRIBUTING.md +0 -28
  32. package/Makefile +0 -123
  33. package/android-emulator-webrtc.code-workspace +0 -7
  34. package/api_descriptor.pb +0 -0
  35. package/babel.config.js +0 -16
  36. package/cloudbuild.yaml +0 -41
  37. package/cloudbuilders/.gcloudignore +0 -1
  38. package/cloudbuilders/Dockerfile +0 -20
  39. package/cloudbuilders/README.md +0 -29
  40. package/cloudbuilders/cloudbuild.yaml +0 -19
  41. package/dist/components/emulator/net/jsep_protocol_driver.js +0 -365
  42. package/dist/components/emulator/views/simple_png_view.js +0 -110
  43. package/dist/proto/emulator_controller_grpc_web_pb.js +0 -1601
  44. package/dist/proto/emulator_web_client.js +0 -176
  45. package/dist/proto/rtc_service_grpc_web_pb.js +0 -231
  46. package/dist/proto/rtc_service_pb.js +0 -338
  47. package/emulator/index.js +0 -1
  48. package/eslint_prefix.py +0 -37
  49. package/gen_md_doc.js +0 -40
  50. package/npmrc.enc +0 -0
  51. package/proto/rtc_service.proto +0 -117
  52. package/protoc-plugin/Makefile +0 -31
  53. package/protoc-plugin/grpc_generator.cc +0 -1755
  54. package/src/components/emulator/emulator.js +0 -217
  55. package/src/components/emulator/net/emulator_status.js +0 -94
  56. package/src/components/emulator/net/jsep_protocol_driver.js +0 -364
  57. package/src/components/emulator/net/logcat.js +0 -155
  58. package/src/components/emulator/views/event_handler.js +0 -268
  59. package/src/components/emulator/views/simple_png_view.js +0 -105
  60. package/src/components/emulator/views/webrtc_view.js +0 -142
  61. package/src/index.js +0 -20
  62. package/src/proto/emulator_web_client.js +0 -140
  63. package/test/cloudbuild.yaml +0 -41
  64. package/test/emulator.test.js +0 -125
  65. package/test/event_handler.test.js +0 -91
  66. package/test/fake_events.js +0 -50
  67. package/test/jsep_protocol_driver.test.js +0 -228
  68. package/test/simple_png_view.test.js +0 -145
  69. package/test/touch_event_handler.test.js +0 -118
@@ -6,35 +6,20 @@ Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
8
  exports["default"] = withMouseKeyHandler;
9
- var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
10
- var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
11
- var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
12
- var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
13
- var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
14
- var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
15
9
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
16
11
  var _propTypes = _interopRequireDefault(require("prop-types"));
17
- var _react = _interopRequireDefault(require("react"));
18
- var Proto = _interopRequireWildcard(require("../../../proto/emulator_controller_pb"));
12
+ var _react = _interopRequireWildcard(require("react"));
13
+ var _emulator_controller_pb = _interopRequireDefault(require("../../../proto/emulator_controller_pb"));
19
14
  var _emulator_status = _interopRequireDefault(require("../net/emulator_status"));
15
+ var _logger = _interopRequireDefault(require("../net/logger"));
20
16
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
21
17
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
22
- function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
23
- function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } /*
24
- * Copyright 2019 The Android Open Source Project
25
- *
26
- * Licensed under the Apache License, Version 2.0 (the "License");
27
- * you may not use this file except in compliance with the License.
28
- * You may obtain a copy of the License at
29
- *
30
- * http://www.apache.org/licenses/LICENSE-2.0
31
- *
32
- * Unless required by applicable law or agreed to in writing, software
33
- * distributed under the License is distributed on an "AS IS" BASIS,
34
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35
- * See the License for the specific language governing permissions and
36
- * limitations under the License.
37
- */
18
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
19
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
20
+ var DEFAULT_WIDTH = 1080;
21
+ var DEFAULT_HEIGHT = 2424;
22
+
38
23
  /**
39
24
  * A handler that extends a view to send key/mouse events to the emulator.
40
25
  * It wraps the inner component in a div, and will use the jsep handler
@@ -46,253 +31,282 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Re
46
31
  * You usually want to wrap a EmulatorRtcview, or EmulatorPngView in it.
47
32
  */
48
33
  function withMouseKeyHandler(WrappedComponent) {
49
- var _class;
50
- return _class = /*#__PURE__*/function (_React$Component) {
51
- (0, _inherits2["default"])(_class, _React$Component);
52
- var _super = _createSuper(_class);
53
- function _class(props) {
54
- var _this;
55
- (0, _classCallCheck2["default"])(this, _class);
56
- _this = _super.call(this, props);
57
- (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onContextMenu", function (e) {
58
- e.preventDefault();
34
+ var MouseKeyHandler = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
35
+ var statusUrl = props.statusUrl,
36
+ auth = props.auth,
37
+ jsep = props.jsep,
38
+ width = props.width,
39
+ height = props.height;
40
+ var _useState = (0, _react.useState)(DEFAULT_WIDTH),
41
+ _useState2 = (0, _slicedToArray2["default"])(_useState, 2),
42
+ deviceWidth = _useState2[0],
43
+ setDeviceWidth = _useState2[1];
44
+ var _useState3 = (0, _react.useState)(DEFAULT_HEIGHT),
45
+ _useState4 = (0, _slicedToArray2["default"])(_useState3, 2),
46
+ deviceHeight = _useState4[0],
47
+ setDeviceHeight = _useState4[1];
48
+ var _useState5 = (0, _react.useState)({
49
+ xp: 0,
50
+ yp: 0,
51
+ mouseDown: false,
52
+ mouseButton: 0
53
+ }),
54
+ _useState6 = (0, _slicedToArray2["default"])(_useState5, 2),
55
+ mouse = _useState6[0],
56
+ setMouse = _useState6[1];
57
+ var handlerRef = (0, _react.useRef)(null);
58
+ var statusRef = (0, _react.useRef)(null);
59
+ if (!statusRef.current) {
60
+ statusRef.current = new _emulator_status["default"](statusUrl, auth);
61
+ }
62
+ (0, _react.useImperativeHandle)(ref, function () {
63
+ return {
64
+ scaleCoordinates: scaleCoordinates,
65
+ setDeviceWidth: setDeviceWidth,
66
+ setDeviceHeight: setDeviceHeight,
67
+ handlerRef: handlerRef
68
+ };
69
+ });
70
+ (0, _react.useEffect)(function () {
71
+ statusRef.current.updateStatus(function (state) {
72
+ setDeviceWidth(parseInt(state.hardwareConfig["hw.lcd.width"]) || DEFAULT_WIDTH);
73
+ setDeviceHeight(parseInt(state.hardwareConfig["hw.lcd.height"]) || DEFAULT_HEIGHT);
59
74
  });
60
- (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "scaleCoordinates", function (xp, yp) {
61
- // It is totally possible that we send clicks that are offscreen..
62
- var _this$state = _this.state,
63
- deviceWidth = _this$state.deviceWidth,
64
- deviceHeight = _this$state.deviceHeight;
65
- var _this$handler$current = _this.handler.current,
66
- clientHeight = _this$handler$current.clientHeight,
67
- clientWidth = _this$handler$current.clientWidth;
68
- var scaleX = deviceWidth / clientWidth;
69
- var scaleY = deviceHeight / clientHeight;
70
- var x = Math.round(xp * scaleX);
71
- var y = Math.round(yp * scaleY);
72
- if (isNaN(x) || isNaN(y)) {
73
- console.log("Ignoring: x: " + x + ", y:" + y);
74
- return {
75
- x: -1,
76
- y: -1
77
- };
78
- }
75
+ }, [statusUrl, auth]);
76
+ var onContextMenu = function onContextMenu(e) {
77
+ e.preventDefault();
78
+ };
79
+
80
+ /**
81
+ * Translates and scales HTML coordinates (xp, yp) from the event handler's
82
+ * container element to the emulator's internal device coordinate system.
83
+ *
84
+ * This method accounts for letterboxing or pillarboxing that occurs when
85
+ * the container's aspect ratio differs from the emulator's native screen aspect ratio,
86
+ * ensuring that clicks on black borders are ignored and clicks on the active area
87
+ * are correctly mapped.
88
+ */
89
+ var scaleCoordinates = function scaleCoordinates(xp, yp) {
90
+ var _handlerRef$current = handlerRef.current,
91
+ clientHeight = _handlerRef$current.clientHeight,
92
+ clientWidth = _handlerRef$current.clientWidth;
93
+ var deviceRatio = deviceWidth / deviceHeight;
94
+ var containerRatio = clientWidth / clientHeight;
95
+ var renderedWidth = clientWidth;
96
+ var renderedHeight = clientHeight;
97
+ var offsetX = 0;
98
+ var offsetY = 0;
99
+ if (containerRatio > deviceRatio) {
100
+ // Pillarboxed (bars on left and right)
101
+ renderedWidth = clientHeight * deviceRatio;
102
+ offsetX = (clientWidth - renderedWidth) / 2;
103
+ } else {
104
+ // Letterboxed (bars on top and bottom)
105
+ renderedHeight = clientWidth / deviceRatio;
106
+ offsetY = (clientHeight - renderedHeight) / 2;
107
+ }
108
+
109
+ // Adjust coordinate relative to the actual rendered video area
110
+ var adjustedXp = xp - offsetX;
111
+ var adjustedYp = yp - offsetY;
112
+ var scaleX = deviceWidth / renderedWidth;
113
+ var scaleY = deviceHeight / renderedHeight;
114
+ var x = Math.round(adjustedXp * scaleX);
115
+ var y = Math.round(adjustedYp * scaleY);
116
+ _logger["default"].debug("scaleCoordinates: input(".concat(xp, ", ").concat(yp, "), container(").concat(clientWidth, "x").concat(clientHeight, "), ") + "device(".concat(deviceWidth, "x").concat(deviceHeight, "), offset(").concat(Math.round(offsetX), ", ").concat(Math.round(offsetY), "), ") + "adjusted(".concat(Math.round(adjustedXp), ", ").concat(Math.round(adjustedYp), "), scale(").concat(scaleX.toFixed(3), ", ").concat(scaleY.toFixed(3), "), output(").concat(x, ", ").concat(y, ")"));
117
+
118
+ // Guard against out of bounds or division by zero
119
+ if (isNaN(x) || isNaN(y) || adjustedXp < 0 || adjustedXp > renderedWidth || adjustedYp < 0 || adjustedYp > renderedHeight) {
120
+ _logger["default"].debug("Ignoring out of bounds or invalid click: x: " + x + ", y:" + y);
79
121
  return {
80
- x: x,
81
- y: y,
122
+ x: -1,
123
+ y: -1,
82
124
  scaleX: scaleX,
83
125
  scaleY: scaleY
84
126
  };
85
- });
86
- (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "setMouseCoordinates", function () {
87
- // Forward the request to the jsep engine.
88
- var _this$state$mouse = _this.state.mouse,
89
- mouseDown = _this$state$mouse.mouseDown,
90
- mouseButton = _this$state$mouse.mouseButton,
91
- xp = _this$state$mouse.xp,
92
- yp = _this$state$mouse.yp;
93
- var request = new Proto.MouseEvent();
94
- var _this$scaleCoordinate = _this.scaleCoordinates(xp, yp),
95
- x = _this$scaleCoordinate.x,
96
- y = _this$scaleCoordinate.y;
97
- request.setX(x);
98
- request.setY(y);
99
- request.setButtons(mouseDown ? mouseButton : 0);
100
- var jsep = _this.props.jsep;
101
- jsep.send("mouse", request);
102
- });
103
- (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "handleKey", function (eventType) {
104
- return function (e) {
105
- // Disable jumping to next control when pressing the space bar.
106
- if (e.keyCode === 32) {
107
- e.preventDefault();
108
- }
109
- var request = new Proto.KeyboardEvent();
110
- request.setEventtype(eventType === "KEYDOWN" ? Proto.KeyboardEvent.KeyEventType.KEYDOWN : eventType === "KEYUP" ? Proto.KeyboardEvent.KeyEventType.KEYUP : Proto.KeyboardEvent.KeyEventType.KEYPRESS);
111
- request.setKey(e.key);
112
- var jsep = _this.props.jsep;
113
- jsep.send("keyboard", request);
114
- };
115
- });
116
- // Properly handle the mouse events.
117
- (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "handleMouseDown", function (e) {
118
- var _e$nativeEvent = e.nativeEvent,
119
- offsetX = _e$nativeEvent.offsetX,
120
- offsetY = _e$nativeEvent.offsetY;
121
- _this.setState({
122
- mouse: {
123
- xp: offsetX,
124
- yp: offsetY,
125
- mouseDown: true,
126
- // In browser's MouseEvent.button property,
127
- // 0 stands for left button and 2 stands for right button.
128
- mouseButton: e.button === 0 ? 1 : e.button === 2 ? 2 : 0
129
- }
130
- }, _this.setMouseCoordinates);
131
- });
132
- (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "handleMouseUp", function (e) {
133
- var _e$nativeEvent2 = e.nativeEvent,
134
- offsetX = _e$nativeEvent2.offsetX,
135
- offsetY = _e$nativeEvent2.offsetY;
136
- _this.setState({
137
- mouse: {
138
- xp: offsetX,
139
- yp: offsetY,
140
- mouseDown: false,
141
- mouseButton: 0
142
- }
143
- }, _this.setMouseCoordinates);
144
- });
145
- (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "handleMouseMove", function (e) {
146
- // Let's not overload the endpoint with useless events.
147
- if (!_this.state.mouse.mouseDown) return;
148
- var _e$nativeEvent3 = e.nativeEvent,
149
- offsetX = _e$nativeEvent3.offsetX,
150
- offsetY = _e$nativeEvent3.offsetY;
151
- var mouse = _this.state.mouse;
152
- mouse.xp = offsetX;
153
- mouse.yp = offsetY;
154
- _this.setState({
155
- mouse: mouse
156
- }, _this.setMouseCoordinates);
157
- });
158
- /**
159
- * Scales an axis to linux input codes that the emulator understands.
160
- *
161
- * @param {*} value The value to transform.
162
- * @param {*} minIn The minimum value, the lower bound of the value param.
163
- * @param {*} maxIn The maximum value, the upper bound of the value param.
164
- */
165
- (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "scaleAxis", function (value, minIn, maxIn) {
166
- var minOut = 0x0; // EV_ABS_MIN
167
- var maxOut = 0x7fff; // EV_ABS_MAX
168
- var rangeOut = maxOut - minOut;
169
- var rangeIn = maxIn - minIn;
170
- if (rangeIn < 1) {
171
- return minOut + rangeOut / 2;
127
+ }
128
+ return {
129
+ x: x,
130
+ y: y,
131
+ scaleX: scaleX,
132
+ scaleY: scaleY
133
+ };
134
+ };
135
+ var sendMouseCoordinates = function sendMouseCoordinates(currentMouse) {
136
+ var mouseDown = currentMouse.mouseDown,
137
+ mouseButton = currentMouse.mouseButton,
138
+ xp = currentMouse.xp,
139
+ yp = currentMouse.yp;
140
+ var _scaleCoordinates = scaleCoordinates(xp, yp),
141
+ x = _scaleCoordinates.x,
142
+ y = _scaleCoordinates.y;
143
+ if (x < 0 || y < 0) {
144
+ return;
145
+ }
146
+ var request = new _emulator_controller_pb["default"].MouseEvent();
147
+ request.setX(x);
148
+ request.setY(y);
149
+ request.setButtons(mouseDown ? mouseButton : 0);
150
+ jsep.send("mouse", request);
151
+ };
152
+ var handleKey = function handleKey(eventType) {
153
+ return function (e) {
154
+ // Disable jumping to next control when pressing the space bar.
155
+ if (e.keyCode === 32) {
156
+ e.preventDefault();
172
157
  }
173
- return (value - minIn) * rangeOut / rangeIn + minOut | 0;
174
- });
175
- (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "setTouchCoordinates", function (type, touches, minForce, maxForce) {
176
- // We need to calculate the offset of the touch events.
177
- var rect = _this.handler.current.getBoundingClientRect();
178
- var scaleCoordinates = _this.scaleCoordinates;
179
- var touchesToSend = Object.keys(touches).map(function (index) {
180
- var touch = touches[index];
181
- var clientX = touch.clientX,
182
- clientY = touch.clientY,
183
- identifier = touch.identifier,
184
- force = touch.force,
185
- radiusX = touch.radiusX,
186
- radiusY = touch.radiusY;
187
- var offsetX = clientX - rect.left;
188
- var offsetY = clientY - rect.top;
189
- var _scaleCoordinates = scaleCoordinates(offsetX, offsetY),
190
- x = _scaleCoordinates.x,
191
- y = _scaleCoordinates.y,
192
- scaleX = _scaleCoordinates.scaleX,
193
- scaleY = _scaleCoordinates.scaleY;
194
- var scaledRadiusX = 2 * radiusX * scaleX;
195
- var scaledRadiusY = 2 * radiusY * scaleY;
196
- var protoTouch = new Proto.Touch();
197
- protoTouch.setX(x | 0);
198
- protoTouch.setY(y | 0);
199
- protoTouch.setIdentifier(identifier);
200
-
201
- // Normalize the force
202
- var MT_PRESSURE = _this.scaleAxis(Math.max(minForce, Math.min(maxForce, force)), 0, 1);
203
- protoTouch.setPressure(MT_PRESSURE);
204
- protoTouch.setTouchMajor(Math.max(scaledRadiusX, scaledRadiusY) | 0);
205
- protoTouch.setTouchMinor(Math.min(scaledRadiusX, scaledRadiusY) | 0);
206
- return protoTouch;
207
- });
158
+ var request = new _emulator_controller_pb["default"].KeyboardEvent();
159
+ request.setEventtype(eventType === "KEYDOWN" ? _emulator_controller_pb["default"].KeyboardEvent.KeyEventType.KEYDOWN : eventType === "KEYUP" ? _emulator_controller_pb["default"].KeyboardEvent.KeyEventType.KEYUP : _emulator_controller_pb["default"].KeyboardEvent.KeyEventType.KEYPRESS);
160
+ request.setKey(e.key);
161
+ jsep.send("keyboard", request);
162
+ };
163
+ };
208
164
 
209
- // Make the grpc call.
210
- var requestTouchEvent = new Proto.TouchEvent();
211
- requestTouchEvent.setTouchesList(touchesToSend);
212
- var jsep = _this.props.jsep;
213
- jsep.send("touch", requestTouchEvent);
214
- });
215
- (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "handleTouch", function (minForce, maxForce) {
216
- return function (e) {
217
- // Make sure they are not processed as mouse events later on.
218
- // See https://developer.mozilla.org/en-US/docs/Web/API/Touch_events
219
- if (e.cancelable) {
220
- e.preventDefault();
221
- }
222
- // Some browsers do net have a force sensor, so we have to "fake" values
223
- // for start/move/end events.
224
- _this.setTouchCoordinates(e.nativeEvent.type, e.nativeEvent.changedTouches, minForce, maxForce);
225
- };
165
+ // Properly handle the mouse events.
166
+ var handleMouseDown = function handleMouseDown(e) {
167
+ var rect = handlerRef.current ? handlerRef.current.getBoundingClientRect() : null;
168
+ var xp = rect && rect.width > 0 ? e.clientX - rect.left : e.nativeEvent.offsetX || 0;
169
+ var yp = rect && rect.height > 0 ? e.clientY - rect.top : e.nativeEvent.offsetY || 0;
170
+ var newMouse = {
171
+ xp: xp,
172
+ yp: yp,
173
+ mouseDown: true,
174
+ // In browser's MouseEvent.button property,
175
+ // 0 stands for left button and 2 stands for right button.
176
+ mouseButton: e.button === 0 ? 1 : e.button === 2 ? 2 : 0
177
+ };
178
+ setMouse(newMouse);
179
+ sendMouseCoordinates(newMouse);
180
+ };
181
+ var handleMouseUp = function handleMouseUp(e) {
182
+ var rect = handlerRef.current ? handlerRef.current.getBoundingClientRect() : null;
183
+ var xp = rect && rect.width > 0 ? e.clientX - rect.left : e.nativeEvent.offsetX || 0;
184
+ var yp = rect && rect.height > 0 ? e.clientY - rect.top : e.nativeEvent.offsetY || 0;
185
+ var newMouse = {
186
+ xp: xp,
187
+ yp: yp,
188
+ mouseDown: false,
189
+ mouseButton: 0
190
+ };
191
+ setMouse(newMouse);
192
+ sendMouseCoordinates(newMouse);
193
+ };
194
+ var handleMouseMove = function handleMouseMove(e) {
195
+ // Let's not overload the endpoint with useless events.
196
+ if (!mouse.mouseDown) return;
197
+ var rect = handlerRef.current ? handlerRef.current.getBoundingClientRect() : null;
198
+ var xp = rect && rect.width > 0 ? e.clientX - rect.left : e.nativeEvent.offsetX || 0;
199
+ var yp = rect && rect.height > 0 ? e.clientY - rect.top : e.nativeEvent.offsetY || 0;
200
+ var newMouse = _objectSpread(_objectSpread({}, mouse), {}, {
201
+ xp: xp,
202
+ yp: yp
226
203
  });
227
- _this.state = {
228
- deviceHeight: 1920,
229
- deviceWidth: 1080,
230
- mouse: {
231
- xp: 0,
232
- yp: 0,
233
- mouseDown: false,
234
- // Current state of mouse
235
- // Current button pressed.
236
- // In proto, 0 is "no button", 1 is left, and 2 is right.
237
- mouseButton: 0
204
+ setMouse(newMouse);
205
+ sendMouseCoordinates(newMouse);
206
+ };
207
+
208
+ /**
209
+ * Scales an axis to linux input codes that the emulator understands.
210
+ */
211
+ var scaleAxis = function scaleAxis(value, minIn, maxIn) {
212
+ var minOut = 0x0; // EV_ABS_MIN
213
+ var maxOut = 0x7fff; // EV_ABS_MAX
214
+ var rangeOut = maxOut - minOut;
215
+ var rangeIn = maxIn - minIn;
216
+ if (rangeIn < 1) {
217
+ return minOut + rangeOut / 2;
218
+ }
219
+ return (value - minIn) * rangeOut / rangeIn + minOut | 0;
220
+ };
221
+ var setTouchCoordinates = function setTouchCoordinates(type, touches, minForce, maxForce) {
222
+ // We need to calculate the offset of the touch events.
223
+ var rect = handlerRef.current.getBoundingClientRect();
224
+ var touchesToSend = [];
225
+ for (var i = 0; i < touches.length; i++) {
226
+ var touch = touches[i];
227
+ var clientX = touch.clientX,
228
+ clientY = touch.clientY,
229
+ identifier = touch.identifier,
230
+ force = touch.force,
231
+ radiusX = touch.radiusX,
232
+ radiusY = touch.radiusY;
233
+ var offsetX = clientX - rect.left;
234
+ var offsetY = clientY - rect.top;
235
+ var _scaleCoordinates2 = scaleCoordinates(offsetX, offsetY),
236
+ x = _scaleCoordinates2.x,
237
+ y = _scaleCoordinates2.y,
238
+ scaleX = _scaleCoordinates2.scaleX,
239
+ scaleY = _scaleCoordinates2.scaleY;
240
+ if (x < 0 || y < 0) {
241
+ continue;
238
242
  }
239
- };
240
- _this.handler = /*#__PURE__*/_react["default"].createRef();
241
- var emulator = _this.props.emulator;
242
- _this.status = new _emulator_status["default"](emulator);
243
- return _this;
244
- }
245
- (0, _createClass2["default"])(_class, [{
246
- key: "componentDidMount",
247
- value: function componentDidMount() {
248
- this.getScreenSize();
243
+ var scaledRadiusX = 2 * radiusX * scaleX;
244
+ var scaledRadiusY = 2 * radiusY * scaleY;
245
+ var protoTouch = new _emulator_controller_pb["default"].Touch();
246
+ protoTouch.setX(x | 0);
247
+ protoTouch.setY(y | 0);
248
+ protoTouch.setIdentifier(identifier);
249
+
250
+ // Normalize the force
251
+ var MT_PRESSURE = scaleAxis(Math.max(minForce, Math.min(maxForce, force)), 0, 1);
252
+ protoTouch.setPressure(MT_PRESSURE);
253
+ protoTouch.setTouchMajor(Math.max(scaledRadiusX, scaledRadiusY) | 0);
254
+ protoTouch.setTouchMinor(Math.min(scaledRadiusX, scaledRadiusY) | 0);
255
+ touchesToSend.push(protoTouch);
249
256
  }
250
- }, {
251
- key: "getScreenSize",
252
- value: function getScreenSize() {
253
- var _this2 = this;
254
- this.status.updateStatus(function (state) {
255
- _this2.setState({
256
- deviceWidth: parseInt(state.hardwareConfig["hw.lcd.width"]) || 1080,
257
- deviceHeight: parseInt(state.hardwareConfig["hw.lcd.height"]) || 1920
258
- });
259
- });
257
+ if (touchesToSend.length === 0) {
258
+ return;
260
259
  }
261
- }, {
262
- key: "render",
263
- value: function render() {
264
- return /*#__PURE__*/_react["default"].createElement("div", {
265
- /* handle interaction */
266
- onTouchStart: this.handleTouch(0.01, 1.0),
267
- onTouchMove: this.handleTouch(0.01, 1.0),
268
- onTouchEnd: this.handleTouch(0.0, 0.0),
269
- onTouchCancel: this.handleTouch(0.0, 0.0),
270
- onMouseDown: this.handleMouseDown,
271
- onMouseMove: this.handleMouseMove,
272
- onMouseUp: this.handleMouseUp,
273
- onMouseOut: this.handleMouseUp,
274
- onKeyDown: this.handleKey("KEYDOWN"),
275
- onKeyUp: this.handleKey("KEYUP"),
276
- onDragStart: this.preventDragHandler,
277
- tabIndex: "0",
278
- ref: this.handler,
279
- style: {
280
- pointerEvents: "all",
281
- outline: "none",
282
- margin: "0",
283
- padding: "0",
284
- border: "0",
285
- display: "inline-block",
286
- width: "100%"
287
- }
288
- }, /*#__PURE__*/_react["default"].createElement(WrappedComponent, this.props));
260
+
261
+ // Make the grpc call.
262
+ var requestTouchEvent = new _emulator_controller_pb["default"].TouchEvent();
263
+ requestTouchEvent.setTouchesList(touchesToSend);
264
+ jsep.send("touch", requestTouchEvent);
265
+ };
266
+ var handleTouch = function handleTouch(minForce, maxForce) {
267
+ return function (e) {
268
+ // Make sure they are not processed as mouse events later on.
269
+ if (e.cancelable) {
270
+ e.preventDefault();
271
+ }
272
+ setTouchCoordinates(e.nativeEvent.type, e.nativeEvent.changedTouches, minForce, maxForce);
273
+ };
274
+ };
275
+ return /*#__PURE__*/_react["default"].createElement("div", {
276
+ onTouchStart: handleTouch(0.01, 1.0),
277
+ onTouchMove: handleTouch(0.01, 1.0),
278
+ onTouchEnd: handleTouch(0.0, 0.0),
279
+ onTouchCancel: handleTouch(0.0, 0.0),
280
+ onMouseDown: handleMouseDown,
281
+ onMouseMove: handleMouseMove,
282
+ onMouseUp: handleMouseUp,
283
+ onMouseOut: handleMouseUp,
284
+ onKeyDown: handleKey("KEYDOWN"),
285
+ onKeyUp: handleKey("KEYUP"),
286
+ onContextMenu: onContextMenu,
287
+ tabIndex: "0",
288
+ ref: handlerRef,
289
+ style: {
290
+ pointerEvents: "all",
291
+ outline: "none",
292
+ margin: "0",
293
+ padding: "0",
294
+ border: "0",
295
+ display: "inline-block",
296
+ width: width ? "".concat(width, "px") : "100%",
297
+ height: height ? "".concat(height, "px") : "auto"
289
298
  }
290
- }]);
291
- return _class;
292
- }(_react["default"].Component), (0, _defineProperty2["default"])(_class, "propTypes", {
293
- /** The emulator object */
294
- emulator: _propTypes["default"].object.isRequired,
299
+ }, /*#__PURE__*/_react["default"].createElement(WrappedComponent, props));
300
+ });
301
+ MouseKeyHandler.propTypes = {
302
+ /** The REST endpoint to retrieve status */
303
+ statusUrl: _propTypes["default"].string,
295
304
  /** Jsep protocol driver, used to send mouse & touch events. */
296
- jsep: _propTypes["default"].object.isRequired
297
- }), _class;
305
+ jsep: _propTypes["default"].object.isRequired,
306
+ /** The authentication service to use */
307
+ auth: _propTypes["default"].object,
308
+ width: _propTypes["default"].number,
309
+ height: _propTypes["default"].number
310
+ };
311
+ return MouseKeyHandler;
298
312
  }
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+ import WsJsepProtocol from "../net/ws_jsep_protocol_driver";
3
+ export interface EmulatorWebrtcViewProps {
4
+ /** The JSEP protocol driver instance. */
5
+ jsep: WsJsepProtocol;
6
+ /** Callback for connection state changes ("connecting", "connected", "disconnected"). */
7
+ onStateChange?: (state: string) => void;
8
+ /** Callback when audio track status changes. */
9
+ onAudioStateChange?: (audio: boolean) => void;
10
+ /** Whether the audio should be muted. */
11
+ muted?: boolean;
12
+ /** Audio volume (between 0.0 and 1.0). */
13
+ volume?: number;
14
+ /** Callback invoked on signaling or playback errors. */
15
+ onError?: (error: Error) => void;
16
+ /** Component width. */
17
+ width?: number;
18
+ /** Component height. */
19
+ height?: number;
20
+ }
21
+ /**
22
+ * A React component that renders the WebRTC video stream of the emulator.
23
+ * Handles establishing the stream via the JSEP protocol driver and managing
24
+ * local playback (including handling autoplay constraints).
25
+ */
26
+ declare const EmulatorWebrtcView: React.FC<EmulatorWebrtcViewProps>;
27
+ export default EmulatorWebrtcView;