You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

remote.html 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Mediator - Remote</title>
  6. <link rel="stylesheet" href="style.css">
  7. <link rel="icon" type="image/png" href="favicon.png">
  8. <style>
  9. body {
  10. margin: 0px;
  11. }
  12. #cursor {
  13. position: absolute;
  14. left: 0px;
  15. top: 0px;
  16. }
  17. #screencast-container {
  18. max-height: calc(100% - 200px);
  19. height: 100%;
  20. text-align: center;
  21. }
  22. #screencast-container {
  23. background: black;
  24. }
  25. #screencast {
  26. max-height: calc(100vh - 200px);
  27. max-width: 100%;
  28. }
  29. </style>
  30. </head>
  31. <body>
  32. <img id="cursor" src="cursor.png" width=25>
  33. <div id="screencast-container">
  34. <img id="screencast" src="/api/remote/screencast">
  35. </div>
  36. <form id="text-form">
  37. <input name="text" type="text">
  38. </form>
  39. <script src="util.js"></script>
  40. <script>
  41. let cursorEl = document.getElementById("cursor");
  42. let screencastEl = document.getElementById("screencast");
  43. let screencastContainerEl = document.getElementById("screencast-container");
  44. let textFormEl = document.getElementById("text-form");
  45. function updateCursor(mousePos, screenSize) {
  46. let fracX = mousePos.x / screenSize.width;
  47. let fracY = mousePos.y / screenSize.height;
  48. let left = fracX * screencastEl.offsetWidth + screencastEl.offsetLeft;
  49. let top = fracY * screencastEl.offsetHeight + screencastEl.offsetTop;
  50. cursorEl.style.left = left + "px";
  51. cursorEl.style.top = top + "px";
  52. }
  53. function moveDelta(mousePos, screenSize, delta) {
  54. mousePos.x += delta.x;
  55. if (mousePos.x >= screenSize.width) {
  56. mousePos.x = screenSize.width - 1;
  57. } else if (mousePos.x < 0) {
  58. mousePos.x = 0;
  59. }
  60. mousePos.y += delta.y;
  61. if (mousePos.y >= screenSize.height) {
  62. mousePos.y = screenSize.height - 1;
  63. } else if (mousePos.y < 0) {
  64. mousePos.y = 0;
  65. }
  66. updateCursor(mousePos, screenSize);
  67. api("PUT", "remote/mouse-pos", mousePos);
  68. }
  69. function signPow(num, pow) {
  70. if (num >= 0) {
  71. return Math.pow(num, pow);
  72. } else {
  73. return -Math.pow(-num, pow);
  74. }
  75. }
  76. function roundToZero(num) {
  77. if (num >= 0) {
  78. return Math.floor(num);
  79. } else {
  80. return Math.ceil(num);
  81. }
  82. }
  83. async function main() {
  84. let screenSize = await api("GET", "remote/screen-size");
  85. let mousePos = await api("GET", "remote/mouse-pos");
  86. updateCursor(mousePos, screenSize);
  87. setInterval(async () => {
  88. mousePos = await api("GET", "remote/mouse-pos");
  89. updateCursor(mousePos, screenSize);
  90. }, 1000);
  91. textFormEl.addEventListener("submit", async evt => {
  92. evt.preventDefault();
  93. let text = evt.target.elements.text.value;
  94. evt.target.elements.text.value = "";
  95. await api("POST", "remote/keyboard-type", {text: evt.target.elements.text.value});
  96. api("POST", "remote/keyboard-keys", {key: "enter", modifiers: []});
  97. });
  98. screencastContainerEl.addEventListener("click", evt => {
  99. evt.preventDefault();
  100. api("POST", "remote/mouse-click", {button: "left", doubleClick: false});
  101. });
  102. screencastContainerEl.addEventListener("dblclick", evt => {
  103. evt.preventDefault();
  104. api("POST", "remote/mouse-click", {button: "left", doubleClick: true});
  105. });
  106. screencastEl.addEventListener("mousemove", evt => {
  107. if (evt.buttons != 0) {
  108. return;
  109. }
  110. evt.preventDefault();
  111. let fracX = evt.offsetX / evt.target.offsetWidth;
  112. let fracY = evt.offsetY / evt.target.offsetHeight;
  113. mousePos.x = Math.round(fracX * screenSize.width);
  114. mousePos.y = Math.round(fracY * screenSize.height);
  115. updateCursor(mousePos, screenSize);
  116. api("PUT", "remote/mouse-pos", mousePos);
  117. });
  118. screencastContainerEl.addEventListener("mousemove", evt => {
  119. if (evt.buttons != 1) {
  120. return;
  121. }
  122. evt.preventDefault();
  123. moveDelta(mousePos, screenSize, {x: evt.movementX, y: evt.movementY});
  124. });
  125. let numTouches = 0;
  126. let touches = {};
  127. let scrollDist = {x: 0, y: 0};
  128. screencastContainerEl.addEventListener("touchstart", evt => {
  129. evt.preventDefault();
  130. numTouches += evt.changedTouches.length;
  131. for (let touch of evt.changedTouches) {
  132. touches[touch.identifier] = {x: touch.clientX, y: touch.clientY, moveDist: 0};
  133. }
  134. });
  135. screencastContainerEl.addEventListener("touchmove", evt => {
  136. evt.preventDefault();
  137. let delta = {x: 0, y: 0}
  138. for (let touch of evt.changedTouches) {
  139. let oldTouch = touches[touch.identifier];
  140. let d = {x: touch.clientX - oldTouch.x, y: touch.clientY - oldTouch.y};
  141. oldTouch.moveDist += Math.sqrt(d.x * d.x + d.y * d.y);
  142. oldTouch.x = touch.clientX;
  143. oldTouch.y = touch.clientY;
  144. delta.x += d.x;
  145. delta.y += d.y;
  146. }
  147. if (numTouches == 1) {
  148. delta.x = Math.round(signPow(delta.x, 1.5));
  149. delta.y = Math.round(signPow(delta.y, 1.5));
  150. moveDelta(mousePos, screenSize, delta);
  151. } else if (numTouches == 2) {
  152. delta.x = delta.x / 5 / numTouches;
  153. delta.y = delta.y / 5 / numTouches;
  154. if (Math.abs(delta.x) > Math.abs(delta.y)) {
  155. scrollDist.x += delta.x;
  156. let distX = roundToZero(scrollDist.x);
  157. if (distX != 0) {
  158. api("POST", "remote/scroll", {x: distX, y: 0});
  159. scrollDist.x -= distX;
  160. }
  161. } else {
  162. scrollDist.y += delta.y;
  163. let distY = roundToZero(scrollDist.y);
  164. if (distY != 0) {
  165. api("POST", "remote/scroll", {x: 0, y: distY});
  166. scrollDist.y -= distY;
  167. }
  168. }
  169. }
  170. });
  171. screencastContainerEl.addEventListener("touchend", evt => {
  172. evt.preventDefault();
  173. numTouches -= evt.changedTouches.length;
  174. for (let touch of evt.changedTouches) {
  175. numTouches -= 1;
  176. let oldTouch = touches[touch.identifier];
  177. touches[touch.identifier] = null;
  178. if (oldTouch.moveDist < 10) {
  179. api("POST", "remote/mouse-click", {button: "left", doubleClick: false});
  180. break;
  181. }
  182. }
  183. });
  184. }
  185. main();
  186. </script>
  187. </body>
  188. </html>