@velor/remote-mouse 6.4.8

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 (316) hide show
  1. package/.artifacts/screenshots/remote-mobile-config.png +0 -0
  2. package/.artifacts/screenshots/remote-mobile-home.png +0 -0
  3. package/.artifacts/screenshots/remote-mobile-preferences.png +0 -0
  4. package/.artifacts/screenshots/remote-mobile-server-info.png +0 -0
  5. package/.artifacts/screenshots/remote-mobile-vlc.png +0 -0
  6. package/.env.example +93 -0
  7. package/README.md +370 -0
  8. package/bin/remote-mouse.js +19 -0
  9. package/client/core/dom.js +148 -0
  10. package/client/core/init-socket-io.js +117 -0
  11. package/client/core/socket-emit.js +6 -0
  12. package/client/core/window-events.js +23 -0
  13. package/client/i18n/apply-page-translations.js +18 -0
  14. package/client/i18n/constants.js +3 -0
  15. package/client/i18n/core.js +40 -0
  16. package/client/i18n/locale-registry.js +77 -0
  17. package/client/i18n/locales/de.js +227 -0
  18. package/client/i18n/locales/en.js +389 -0
  19. package/client/i18n/locales/es.js +228 -0
  20. package/client/i18n/locales/fr.js +389 -0
  21. package/client/i18n/locales/it.js +227 -0
  22. package/client/i18n/locales/ja.js +227 -0
  23. package/client/i18n/locales/pt.js +227 -0
  24. package/client/i18n/locales/ru.js +240 -0
  25. package/client/i18n/locales/zh.js +227 -0
  26. package/client/preferences/constants.js +15 -0
  27. package/client/preferences/effects.js +24 -0
  28. package/client/preferences/load.js +19 -0
  29. package/client/preferences/render.js +26 -0
  30. package/client/preferences/rows.js +78 -0
  31. package/client/preferences/state.js +29 -0
  32. package/client/preview/create-preview-frame-receiver.js +13 -0
  33. package/client/preview/draw.js +77 -0
  34. package/client/preview/parse-preview-frame.js +39 -0
  35. package/client/preview/preview-stream.js +152 -0
  36. package/client/services/app-state/appStateKeys.js +30 -0
  37. package/client/services/app-state/createAppStateService.js +216 -0
  38. package/client/services/app-state/createPersistStoreService.js +122 -0
  39. package/client/services/app-state/createStateStoreService.js +64 -0
  40. package/client/services/app-state/localStorageBinding.js +26 -0
  41. package/client/services/app-state/normalizers.js +74 -0
  42. package/client/services/app-state/resolveEffectiveStateValue.js +58 -0
  43. package/client/services/app-state/stateDefinitions.js +107 -0
  44. package/client/services/backend/createBackendService.js +55 -0
  45. package/client/services/config/ConfigView.js +45 -0
  46. package/client/services/config/createClientConfigService.js +122 -0
  47. package/client/services/config/defaultClientConfig.js +22 -0
  48. package/client/services/createServicesContainer.js +48 -0
  49. package/client/services/createServicesRegistry.js +26 -0
  50. package/client/services/i18n/createI18nService.js +86 -0
  51. package/client/services/notifications/createNotificationService.js +56 -0
  52. package/client/services/pubsub/createPubSubService.js +20 -0
  53. package/client/services/remotes/createRemotesService.js +20 -0
  54. package/client/services/transport/createSocketIoTransportService.js +50 -0
  55. package/client/touch/bindTouchPassthrough.js +94 -0
  56. package/client/touch/createTouchList.js +18 -0
  57. package/client/touch/dispatchSyntheticTouch.js +20 -0
  58. package/client/touch/gesture-zone.js +28 -0
  59. package/client/touch/throttle.js +46 -0
  60. package/client/touch/touch-handlers.js +193 -0
  61. package/client/touch/touchpad.js +231 -0
  62. package/client/ui/config/page.js +840 -0
  63. package/client/ui/main/applyRemoteVisibilityState.js +60 -0
  64. package/client/ui/main/bind-client-notifications.js +3 -0
  65. package/client/ui/main/bindings/bindAccordion.js +121 -0
  66. package/client/ui/main/bindings/bindActionButtons.js +13 -0
  67. package/client/ui/main/bindings/bindAdminDrawer.js +137 -0
  68. package/client/ui/main/bindings/bindAdminRemoteButtons.js +77 -0
  69. package/client/ui/main/bindings/bindAdminVersion.js +27 -0
  70. package/client/ui/main/bindings/bindBrowserRemoteButtons.js +119 -0
  71. package/client/ui/main/bindings/bindRemoteAccordion.js +23 -0
  72. package/client/ui/main/bindings/bindSamsungRemoteButtons.js +320 -0
  73. package/client/ui/main/bindings/bindSystemRemoteButtons.js +41 -0
  74. package/client/ui/main/bindings/bindVlcRemoteButtons.js +64 -0
  75. package/client/ui/main/canvas-ui.js +33 -0
  76. package/client/ui/main/connection-overlay.js +57 -0
  77. package/client/ui/main/init-ui.js +54 -0
  78. package/client/ui/main/keyboard-panel.js +271 -0
  79. package/client/ui/main/mouse-buttons.js +94 -0
  80. package/client/ui/main/page.js +21 -0
  81. package/client/ui/notifications/show-toast.js +48 -0
  82. package/client/ui/preferences/bindPreferenceSwitchers.js +49 -0
  83. package/client/ui/preferences/page.js +61 -0
  84. package/client/ui/preferences/switchers.js +200 -0
  85. package/index.js +9 -0
  86. package/package.json +41 -0
  87. package/public/admin-config.css +447 -0
  88. package/public/admin-config.html +63 -0
  89. package/public/apple-touch-icon.png +0 -0
  90. package/public/brave-icon.svg +13 -0
  91. package/public/favicon.svg +30 -0
  92. package/public/icon-192.png +0 -0
  93. package/public/icon-512.png +0 -0
  94. package/public/index.html +246 -0
  95. package/public/manifest.webmanifest +45 -0
  96. package/public/preferences.html +55 -0
  97. package/public/server-info.html +574 -0
  98. package/public/styles.css +1042 -0
  99. package/public/sw.js +103 -0
  100. package/scripts/codex-commit.sh +112 -0
  101. package/scripts/generate-mobile-screenshots.mjs +244 -0
  102. package/scripts/install-linux.sh +633 -0
  103. package/scripts/install-windows.ps1 +369 -0
  104. package/server/application/createApplicationLifecycle.js +15 -0
  105. package/server/application/logger.js +216 -0
  106. package/server/application/shutdown.js +81 -0
  107. package/server/application/start.js +95 -0
  108. package/server/application/state.js +19 -0
  109. package/server/connection/api/admin-actions.router.js +65 -0
  110. package/server/connection/api/admin-configs.router.js +165 -0
  111. package/server/connection/api/admin-remotes.router.js +61 -0
  112. package/server/connection/api/admin-subs.router.js +49 -0
  113. package/server/connection/api/client.router.js +15 -0
  114. package/server/connection/api/configs.js +96 -0
  115. package/server/connection/api/qr-page.handler.js +17 -0
  116. package/server/connection/api/remotes.router.js +30 -0
  117. package/server/connection/api/server-info.router.js +149 -0
  118. package/server/connection/api/session.middleware.js +93 -0
  119. package/server/connection/api/unauthorized-response.js +73 -0
  120. package/server/connection/socket/createConnectionRegistrar.js +23 -0
  121. package/server/connection/socket/createSocketSessionAuthMiddleware.js +49 -0
  122. package/server/connection/socket/socket-action-responder.js +12 -0
  123. package/server/connection/socket/socket.timestamp-middleware.js +51 -0
  124. package/server/index.js +12 -0
  125. package/server/init/bootstrapApi.js +87 -0
  126. package/server/init/bootstrapSocket.js +79 -0
  127. package/server/init/createAdminApiRouter.js +22 -0
  128. package/server/init/createAdminUiRouter.js +21 -0
  129. package/server/init/createSocketActionRegistrars.js +52 -0
  130. package/server/init/observers/startConfigObserver.js +51 -0
  131. package/server/init/observers/startDisplaySizeObserver.js +55 -0
  132. package/server/init/observers/startNotificationObserver.js +49 -0
  133. package/server/init/observers/startQrOverlayHoverObserver.js +89 -0
  134. package/server/init/observers/startQrOverlayRefreshObserver.js +53 -0
  135. package/server/os/darwin/app.js +45 -0
  136. package/server/os/darwin/applescript.js +51 -0
  137. package/server/os/darwin/cliSocket.js +53 -0
  138. package/server/os/darwin/url.js +9 -0
  139. package/server/os/darwin/window.js +10 -0
  140. package/server/os/linux/app.js +120 -0
  141. package/server/os/linux/cliSocket.js +53 -0
  142. package/server/os/linux/process.js +69 -0
  143. package/server/os/linux/screen.js +58 -0
  144. package/server/os/linux/systemd.js +139 -0
  145. package/server/os/linux/url.js +17 -0
  146. package/server/os/linux/windows.js +144 -0
  147. package/server/os/win32/app.js +66 -0
  148. package/server/os/win32/cliSocket.js +15 -0
  149. package/server/os/win32/powershell.js +70 -0
  150. package/server/os/win32/process.js +20 -0
  151. package/server/os/win32/service.js +95 -0
  152. package/server/os/win32/url.js +9 -0
  153. package/server/os/win32/window.js +10 -0
  154. package/server/remotes/admin/createAdminEventGuardMiddleware.js +29 -0
  155. package/server/remotes/admin/createForceUpdateCheckAction.js +39 -0
  156. package/server/remotes/admin/createInstallUpdateAction.js +64 -0
  157. package/server/remotes/admin/createOpenQrBrowserAction.js +63 -0
  158. package/server/remotes/admin/createOpenServerInfoBrowserAction.js +58 -0
  159. package/server/remotes/admin/createRestartServiceAction.js +20 -0
  160. package/server/remotes/admin/createRotateEntryTokenAction.js +43 -0
  161. package/server/remotes/admin/createToggleQrOverlayAction.js +38 -0
  162. package/server/remotes/admin/index.js +32 -0
  163. package/server/remotes/admin/notifyIfRestarted.js +102 -0
  164. package/server/remotes/admin/registrar.js +94 -0
  165. package/server/remotes/browser/actions/createFocusOrLaunchBrowserAction.js +22 -0
  166. package/server/remotes/browser/actions/openUrlOnHost.js +3 -0
  167. package/server/remotes/browser/browserCatalog.js +70 -0
  168. package/server/remotes/browser/index.js +15 -0
  169. package/server/remotes/browser/listBrowsersOnHost.js +23 -0
  170. package/server/remotes/browser/registrar.js +29 -0
  171. package/server/remotes/browser/spec.js +18 -0
  172. package/server/remotes/browser/state.js +5 -0
  173. package/server/remotes/input/registrar.js +39 -0
  174. package/server/remotes/preview/bgraToRgbaBuffer.js +20 -0
  175. package/server/remotes/preview/captureAroundCursor.js +19 -0
  176. package/server/remotes/preview/createPreviewStreamer.js +85 -0
  177. package/server/remotes/preview/registrar.js +34 -0
  178. package/server/remotes/samsung/createSamsungCommandService.js +203 -0
  179. package/server/remotes/samsung/createSamsungRemote.js +26 -0
  180. package/server/remotes/samsung/createSamsungRemoteGetter.js +46 -0
  181. package/server/remotes/samsung/createSamsungTvGetter.js +102 -0
  182. package/server/remotes/samsung/device-config.js +122 -0
  183. package/server/remotes/samsung/registrar.js +59 -0
  184. package/server/remotes/samsung/utils.js +56 -0
  185. package/server/remotes/vlc/index.js +39 -0
  186. package/server/remotes/vlc/registrar.js +94 -0
  187. package/server/remotes/vlc/spec.js +15 -0
  188. package/server/remotes/vlc/state.js +5 -0
  189. package/server/remotes/window/index.js +6 -0
  190. package/server/remotes/window/registrar.js +28 -0
  191. package/server/services/application/createApplicationDaemonService.js +144 -0
  192. package/server/services/application/getDaemonServiceAdapter.js +56 -0
  193. package/server/services/application/utils.js +29 -0
  194. package/server/services/config/bootstrapConfig.js +38 -0
  195. package/server/services/config/configPaths.js +42 -0
  196. package/server/services/config/configSchema.js +297 -0
  197. package/server/services/config/configService.js +89 -0
  198. package/server/services/config/defaultConfig.js +137 -0
  199. package/server/services/config/envConfig.js +49 -0
  200. package/server/services/config/index.js +9 -0
  201. package/server/services/config/logConfig.js +54 -0
  202. package/server/services/config/system-config.js +44 -0
  203. package/server/services/createServicesContainer.js +94 -0
  204. package/server/services/createServicesRegistry.js +48 -0
  205. package/server/services/input/createInputController.js +17 -0
  206. package/server/services/input/createKeyboardController.js +146 -0
  207. package/server/services/input/createMouseController.js +182 -0
  208. package/server/services/notifier/createClientNotifier.js +23 -0
  209. package/server/services/notifier/createHostNotifier.js +41 -0
  210. package/server/services/notifier/createNotifier.js +13 -0
  211. package/server/services/notifier/createNotifierComposite.js +122 -0
  212. package/server/services/notifier/handleOpenQrBrowserEvent.js +40 -0
  213. package/server/services/notifier/handleOpenServerInfoBrowserEvent.js +40 -0
  214. package/server/services/notifier/handleRestartServiceEvent.js +37 -0
  215. package/server/services/notifier/handleRotateEntryTokenEvent.js +42 -0
  216. package/server/services/notifier/handleSessionEvent.js +24 -0
  217. package/server/services/notifier/handleToggleQrOverlayEvent.js +21 -0
  218. package/server/services/notifier/host-notifier/createLinuxHostNotifier.js +23 -0
  219. package/server/services/notifier/host-notifier/createNodeNotifierHostNotifier.js +24 -0
  220. package/server/services/notifier/host-notifier/index.js +11 -0
  221. package/server/services/notifier/mapper/handleForceUpdateCheckEvent.js +24 -0
  222. package/server/services/notifier/mapper/handleInstallUpdateEvent.js +53 -0
  223. package/server/services/notifier/mapper/handleSocketEvent.js +40 -0
  224. package/server/services/notifier/mapper/handleUpdateManagerEvent.js +24 -0
  225. package/server/services/notifier/mapper/notify.js +7 -0
  226. package/server/services/os/index.js +23 -0
  227. package/server/services/os/platforms/createFallbackAdapter.js +31 -0
  228. package/server/services/os/platforms/darwin/app.js +6 -0
  229. package/server/services/os/platforms/darwin/index.js +21 -0
  230. package/server/services/os/platforms/darwin/scripts.js +4 -0
  231. package/server/services/os/platforms/darwin/url.js +1 -0
  232. package/server/services/os/platforms/darwin/window.js +4 -0
  233. package/server/services/os/platforms/linux/app.js +6 -0
  234. package/server/services/os/platforms/linux/index.js +33 -0
  235. package/server/services/os/platforms/linux/url.js +1 -0
  236. package/server/services/os/platforms/linux/windows.js +11 -0
  237. package/server/services/os/platforms/win32/app.js +6 -0
  238. package/server/services/os/platforms/win32/index.js +21 -0
  239. package/server/services/os/platforms/win32/overlay.js +6 -0
  240. package/server/services/os/platforms/win32/powershell.js +4 -0
  241. package/server/services/os/platforms/win32/url.js +1 -0
  242. package/server/services/os/platforms/win32/window.js +4 -0
  243. package/server/services/os/shared.js +2 -0
  244. package/server/services/overlay/createNoopOverlay.js +13 -0
  245. package/server/services/overlay/createQrOverlay.js +27 -0
  246. package/server/services/overlay/createQrOverlayWin32.js +158 -0
  247. package/server/services/overlay/createQrOverlayYad.js +178 -0
  248. package/server/services/overlay/renderQrPage.js +82 -0
  249. package/server/services/persistence/createConfigDao.js +106 -0
  250. package/server/services/persistence/createDatabaseProvider.js +23 -0
  251. package/server/services/persistence/createEntryTokenDao.js +140 -0
  252. package/server/services/persistence/createRestartLogDao.js +210 -0
  253. package/server/services/persistence/index.js +19 -0
  254. package/server/services/pubsub/createEventStore.js +54 -0
  255. package/server/services/pubsub/createPubSub.js +89 -0
  256. package/server/services/pubsub/createServiceEvents.js +29 -0
  257. package/server/services/pubsub/serviceEventConstants.js +39 -0
  258. package/server/services/remotes/createRemotes.js +25 -0
  259. package/server/services/server/createHttpsServer.js +12 -0
  260. package/server/services/server/createServer.js +66 -0
  261. package/server/services/sse/createSseService.js +96 -0
  262. package/server/services/sse/utils.js +7 -0
  263. package/server/services/system/createSystemService.js +170 -0
  264. package/server/services/system/getNetworkInfo.js +18 -0
  265. package/server/services/system/getScreenInfo.js +32 -0
  266. package/server/services/system/listNetworkInterfaces.js +27 -0
  267. package/server/services/task-manager/createTaskManager.js +68 -0
  268. package/server/services/task-runner/createTaskRunner.js +114 -0
  269. package/server/services/token-manager/createTokenManager.js +244 -0
  270. package/server/services/token-manager/token-format.js +7 -0
  271. package/server/services/token-manager/token-store-utils.js +8 -0
  272. package/server/services/update-manager/CommandUpdateSource.js +70 -0
  273. package/server/services/update-manager/NpmUpdateSource.js +34 -0
  274. package/server/services/update-manager/buildNpmGlobalUpdateCommand.js +15 -0
  275. package/server/services/update-manager/chooseUpdateCheckSource.js +20 -0
  276. package/server/services/update-manager/chooseUpdateInstallSource.js +5 -0
  277. package/server/services/update-manager/createUpdateManager.js +109 -0
  278. package/server/services/update-manager/resolveInstallUpdateCommand.js +42 -0
  279. package/server/term/cli/executeLocalServiceCommand.js +42 -0
  280. package/server/term/cli/getCliSocketPath.js +5 -0
  281. package/server/term/cli/parseCliArgs.js +110 -0
  282. package/server/term/cli/printCliResult.js +18 -0
  283. package/server/term/cli/runCliCmd.js +50 -0
  284. package/server/term/cli/sendCliCommand.js +76 -0
  285. package/server/term/cliSocket.js +29 -0
  286. package/server/term/srv/commands/configCommand.js +84 -0
  287. package/server/term/srv/commands/helpCommand.js +6 -0
  288. package/server/term/srv/commands/infoCommand.js +7 -0
  289. package/server/term/srv/commands/openQrCommand.js +7 -0
  290. package/server/term/srv/commands/samsungDetectCommand.js +52 -0
  291. package/server/term/srv/commands/serviceCommand.js +25 -0
  292. package/server/term/srv/commands/systemConfigCommand.js +7 -0
  293. package/server/term/srv/commands/tasksCommand.js +24 -0
  294. package/server/term/srv/commands/tokensCommand.js +15 -0
  295. package/server/term/srv/executeCliCommand.js +44 -0
  296. package/server/term/srv/executeCliRequest.js +38 -0
  297. package/server/term/srv/startCliServer.js +140 -0
  298. package/server/utils/createRandomToken.js +11 -0
  299. package/server/utils/env.js +155 -0
  300. package/server/utils/git.js +13 -0
  301. package/server/utils/http.js +7 -0
  302. package/server/utils/network.js +45 -0
  303. package/server/utils/paths.js +10 -0
  304. package/server/utils/process.js +57 -0
  305. package/server/utils/robot.js +11 -0
  306. package/server/utils/semver.js +33 -0
  307. package/server/utils/truncateText.js +7 -0
  308. package/utils/createLazy.js +13 -0
  309. package/utils/functional.js +48 -0
  310. package/utils/math.js +26 -0
  311. package/utils/notificationSettings.js +61 -0
  312. package/utils/object.utils.js +79 -0
  313. package/utils/predicates.js +17 -0
  314. package/utils/remoteCommands.js +40 -0
  315. package/utils/sync.js +3 -0
  316. package/velor-remote-mouse-6.4.8.tgz +0 -0
@@ -0,0 +1,29 @@
1
+ export const LOCAL_REMOTE_DEFINITIONS = [
2
+ {id: 'keyboard', labelKey: 'preferences.remote.keyboard'},
3
+ ];
4
+
5
+ export function createPreferencesState() {
6
+ return {
7
+ availableRemotes: [],
8
+ availableBrowsers: [],
9
+ };
10
+ }
11
+
12
+ export function mergeAvailableRemotes(remotes = []) {
13
+ const byId = new Map();
14
+
15
+ for (const remote of remotes) {
16
+ if (!remote?.id) {
17
+ continue;
18
+ }
19
+ byId.set(remote.id, remote);
20
+ }
21
+
22
+ for (const remote of LOCAL_REMOTE_DEFINITIONS) {
23
+ if (!byId.has(remote.id)) {
24
+ byId.set(remote.id, remote);
25
+ }
26
+ }
27
+
28
+ return Array.from(byId.values());
29
+ }
@@ -0,0 +1,13 @@
1
+ import {parsePreviewFrame} from "./parse-preview-frame.js";
2
+ import {drawPreviewFrame} from "./draw.js";
3
+
4
+ export function createPreviewFrameReceiver({ctx, previewCanvas, previewLabel}) {
5
+ return (meta, payload) => {
6
+ const frame = parsePreviewFrame(meta, payload);
7
+ if (!frame) {
8
+ return;
9
+ }
10
+
11
+ drawPreviewFrame({ctx, previewCanvas, previewLabel, frame});
12
+ };
13
+ }
@@ -0,0 +1,77 @@
1
+ function drawCursorOverlay(ctx, width, height, cursorFrameX, cursorFrameY) {
2
+ const cx = Math.round(Number.isFinite(cursorFrameX) ? cursorFrameX : width / 2);
3
+ const cy = Math.round(Number.isFinite(cursorFrameY) ? cursorFrameY : height / 2);
4
+
5
+ ctx.save();
6
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.95)';
7
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.45)';
8
+ ctx.lineWidth = 1.5;
9
+
10
+ // Pointe de curseur simplifiee.
11
+ ctx.beginPath();
12
+ ctx.moveTo(cx - 2, cy - 11);
13
+ ctx.lineTo(cx - 2, cy + 9);
14
+ ctx.lineTo(cx + 4, cy + 4);
15
+ ctx.lineTo(cx + 7, cy + 10);
16
+ ctx.lineTo(cx + 10, cy + 8);
17
+ ctx.lineTo(cx + 6, cy + 2);
18
+ ctx.lineTo(cx + 12, cy + 2);
19
+ ctx.closePath();
20
+ ctx.fill();
21
+ ctx.stroke();
22
+ ctx.restore();
23
+ }
24
+
25
+ function readCssPx(name, fallback = 0) {
26
+ const value = Number.parseFloat(getComputedStyle(document.documentElement).getPropertyValue(name));
27
+ return Number.isFinite(value) ? value : fallback;
28
+ }
29
+
30
+ function getPreviewViewportSize(width, height) {
31
+ const outerEdgePx = 6;
32
+ const previewGapPx = readCssPx('--preview-gap-from-scroll', 8);
33
+ const scrollZoneWidthPx = readCssPx('--scroll-zone-width', 36);
34
+ const scrollZoneEdgeGapPx = readCssPx('--scroll-zone-edge-gap', 10);
35
+ const menuHeightPx = readCssPx('--menu-h', 58);
36
+ const reservedSidePx = scrollZoneWidthPx + scrollZoneEdgeGapPx + previewGapPx + 12;
37
+ const availableWidth = Math.max(48, window.innerWidth - outerEdgePx - reservedSidePx);
38
+ const availableHeight = Math.max(48, window.innerHeight - menuHeightPx - scrollZoneEdgeGapPx - 20);
39
+
40
+ return {
41
+ width: Math.min(width, availableWidth),
42
+ height: Math.min(height, availableHeight),
43
+ };
44
+ }
45
+
46
+ export function drawPreviewFrame({ctx, previewCanvas, previewLabel, frame}) {
47
+ const {width, height, rgba, x, y, cursorX, cursorY, cursorFrameX, cursorFrameY} = frame;
48
+ if (previewCanvas.width !== width || previewCanvas.height !== height) {
49
+ previewCanvas.width = width;
50
+ previewCanvas.height = height;
51
+ }
52
+
53
+ const viewportSize = getPreviewViewportSize(width, height);
54
+ const offsetX = Math.max(0, Math.round((width - viewportSize.width) / 2));
55
+ const offsetY = Math.max(0, Math.round((height - viewportSize.height) / 2));
56
+
57
+ previewCanvas.style.width = `${width}px`;
58
+ previewCanvas.style.height = `${height}px`;
59
+ previewCanvas.style.marginLeft = `${-offsetX}px`;
60
+ previewCanvas.style.marginTop = `${-offsetY}px`;
61
+
62
+ const previewRoot = previewCanvas.closest('#cursor-preview');
63
+ if (previewRoot) {
64
+ previewRoot.style.width = `${viewportSize.width}px`;
65
+ previewRoot.style.height = `${viewportSize.height}px`;
66
+ }
67
+
68
+ const imageData = new ImageData(rgba, width, height);
69
+ ctx.putImageData(imageData, 0, 0);
70
+ drawCursorOverlay(ctx, width, height, cursorFrameX, cursorFrameY);
71
+
72
+ if (previewLabel) {
73
+ const labelX = Number.isFinite(cursorX) ? cursorX : x;
74
+ const labelY = Number.isFinite(cursorY) ? cursorY : y;
75
+ previewLabel.textContent = `(${labelX}, ${labelY})`;
76
+ }
77
+ }
@@ -0,0 +1,39 @@
1
+ export function parsePreviewFrame(meta, payload) {
2
+ if (!meta || !payload) {
3
+ return null;
4
+ }
5
+
6
+ const width = Number(meta.width) || 0;
7
+ const height = Number(meta.height) || 0;
8
+ if (width <= 0 || height <= 0) {
9
+ return null;
10
+ }
11
+
12
+ const arrayBuffer = typeof payload.byteLength === 'number' && !payload.buffer
13
+ ? payload
14
+ : payload.buffer;
15
+ if (!arrayBuffer) {
16
+ return null;
17
+ }
18
+
19
+ const rgba = new Uint8ClampedArray(arrayBuffer);
20
+ if (rgba.length < width * height * 4) {
21
+ return null;
22
+ }
23
+
24
+ return {
25
+ width,
26
+ height,
27
+ rgba,
28
+ x: Number(meta.x) || 0,
29
+ y: Number(meta.y) || 0,
30
+ cursorX: Number(meta.cursorX) || 0,
31
+ cursorY: Number(meta.cursorY) || 0,
32
+ cursorFrameX: Number.isFinite(Number(meta.cursorFrameX))
33
+ ? Number(meta.cursorFrameX)
34
+ : Math.round(width / 2),
35
+ cursorFrameY: Number.isFinite(Number(meta.cursorFrameY))
36
+ ? Number(meta.cursorFrameY)
37
+ : Math.round(height / 2),
38
+ };
39
+ }
@@ -0,0 +1,152 @@
1
+ import {createPreviewFrameReceiver} from "./create-preview-frame-receiver.js";
2
+ import {emitWithTimestamp} from "../core/socket-emit.js";
3
+ import {
4
+ REMOTE_EVENT_PREVIEW_START,
5
+ REMOTE_EVENT_PREVIEW_STOP,
6
+ } from '../../utils/remoteCommands.js';
7
+ import {
8
+ APP_STATE_EFFECTIVE_PREVIEW_REMOTE_VISIBLE,
9
+ APP_STATE_KEYBOARD_PREVIEW_ACTIVE,
10
+ APP_STATE_PREVIEW_ACTIVITY_AT,
11
+ getAppStatePropertyChangedEventName,
12
+ } from '../services/app-state/createAppStateService.js';
13
+
14
+ export function bindPreviewStream(services, dom) {
15
+ const socket = services.getTransport();
16
+ const clientConfig = services.getClientConfig();
17
+ const appState = services.getAppState();
18
+ const pubsub = services.getPubSub();
19
+ const {previewCanvas, previewLabel} = dom.remotes.preview;
20
+
21
+ if (!previewCanvas) {
22
+ return;
23
+ }
24
+
25
+ const ctx = previewCanvas.getContext('2d');
26
+ const onPreviewFrame = createPreviewFrameReceiver({ ctx, previewCanvas, previewLabel });
27
+ const previewRoot = previewCanvas.closest('#cursor-preview');
28
+ let isPreviewActive = false;
29
+ let stopTimer = null;
30
+ let keyboardPreviewActive = false;
31
+
32
+ const isPreviewEnabled = () =>
33
+ appState.get(APP_STATE_EFFECTIVE_PREVIEW_REMOTE_VISIBLE);
34
+
35
+ const getInactivityDelayMs = () => {
36
+ const configuredDelay = Number(services.getConfigView().getPreviewConfig()?.hideDelayMs);
37
+ if (Number.isFinite(configuredDelay) && configuredDelay >= 200) {
38
+ return configuredDelay;
39
+ }
40
+ return 10_000;
41
+ };
42
+
43
+ const showPreview = () => {
44
+ if (!isPreviewEnabled()) {
45
+ return;
46
+ }
47
+ if (previewRoot) {
48
+ previewRoot.classList.add('is-visible');
49
+ }
50
+ };
51
+
52
+ const hidePreview = () => {
53
+ if (previewRoot) {
54
+ previewRoot.classList.remove('is-visible');
55
+ }
56
+ };
57
+
58
+ const clearStopTimer = () => {
59
+ if (stopTimer) {
60
+ clearTimeout(stopTimer);
61
+ stopTimer = null;
62
+ }
63
+ };
64
+
65
+ const stopPreview = () => {
66
+ clearStopTimer();
67
+ if (keyboardPreviewActive) {
68
+ return;
69
+ }
70
+ if (isPreviewActive) {
71
+ emitWithTimestamp(socket, REMOTE_EVENT_PREVIEW_STOP);
72
+ isPreviewActive = false;
73
+ }
74
+ hidePreview();
75
+ };
76
+
77
+ const armInactivityStop = () => {
78
+ if (keyboardPreviewActive) {
79
+ return;
80
+ }
81
+ clearStopTimer();
82
+ stopTimer = setTimeout(() => {
83
+ stopPreview();
84
+ }, getInactivityDelayMs());
85
+ };
86
+
87
+ const startPreview = () => {
88
+ if (!isPreviewEnabled()) {
89
+ stopPreview();
90
+ return;
91
+ }
92
+ if (!socket.connected) {
93
+ return;
94
+ }
95
+ if (!isPreviewActive) {
96
+ emitWithTimestamp(socket, REMOTE_EVENT_PREVIEW_START);
97
+ isPreviewActive = true;
98
+ showPreview();
99
+ }
100
+ armInactivityStop();
101
+ };
102
+
103
+ const onMouseMoveActivity = () => {
104
+ startPreview();
105
+ };
106
+
107
+ const setKeyboardPreviewActive = (active) => {
108
+ keyboardPreviewActive = active;
109
+
110
+ if (active) {
111
+ startPreview();
112
+ clearStopTimer();
113
+ return;
114
+ }
115
+
116
+ armInactivityStop();
117
+ };
118
+
119
+ pubsub.subscribe(getAppStatePropertyChangedEventName(APP_STATE_PREVIEW_ACTIVITY_AT), onMouseMoveActivity);
120
+ pubsub.subscribe(getAppStatePropertyChangedEventName(APP_STATE_KEYBOARD_PREVIEW_ACTIVE), ({value}) => {
121
+ setKeyboardPreviewActive(Boolean(value));
122
+ });
123
+
124
+ socket.on('preview:frame', onPreviewFrame);
125
+ socket.on('disconnect', stopPreview);
126
+ window.addEventListener('beforeunload', stopPreview);
127
+ clientConfig.onChange(() => {
128
+ if (!isPreviewEnabled()) {
129
+ stopPreview();
130
+ return;
131
+ }
132
+
133
+ if (isPreviewActive) {
134
+ armInactivityStop();
135
+ }
136
+ });
137
+ appState.subscribeProperty(APP_STATE_EFFECTIVE_PREVIEW_REMOTE_VISIBLE, () => {
138
+ if (!isPreviewEnabled()) {
139
+ stopPreview();
140
+ return;
141
+ }
142
+
143
+ if (keyboardPreviewActive || isPreviewActive) {
144
+ showPreview();
145
+ armInactivityStop();
146
+ }
147
+ });
148
+
149
+ hidePreview();
150
+
151
+ setKeyboardPreviewActive(Boolean(appState.get(APP_STATE_KEYBOARD_PREVIEW_ACTIVE)));
152
+ }
@@ -0,0 +1,30 @@
1
+ export const APP_STATE_PROPERTY_CHANGED_EVENT = 'app-state.property.changed';
2
+
3
+ export const APP_STATE_PREVIEW_ACTIVITY_AT = 'ui.previewActivityAt';
4
+ export const APP_STATE_KEYBOARD_PREVIEW_ACTIVE = 'ui.keyboardPreviewActive';
5
+ export const APP_STATE_REMOTE_ACCORDION_EXPANDED_PANEL = 'ui.remoteAccordionExpandedPanel';
6
+
7
+ export const APP_STATE_THEME = 'preferences.theme';
8
+ export const APP_STATE_LOCALE = 'preferences.locale';
9
+ export const APP_STATE_HANDEDNESS = 'preferences.handedness';
10
+ export const APP_STATE_REMOTE_AUTO_HIDE = 'preferences.remoteAutoHide';
11
+ export const APP_STATE_REMOTE_VISIBILITY = 'preferences.remoteVisibility';
12
+ export const APP_STATE_BROWSER_VISIBILITY = 'preferences.browserVisibility';
13
+
14
+ export const APP_STATE_EFFECTIVE_BROWSER_REMOTE_VISIBLE = 'effective.remote.browser.visible';
15
+ export const APP_STATE_EFFECTIVE_KEYBOARD_REMOTE_VISIBLE = 'effective.remote.keyboard.visible';
16
+ export const APP_STATE_EFFECTIVE_VLC_REMOTE_VISIBLE = 'effective.remote.vlc.visible';
17
+ export const APP_STATE_EFFECTIVE_SAMSUNG_REMOTE_VISIBLE = 'effective.remote.samsung.visible';
18
+ export const APP_STATE_EFFECTIVE_PREVIEW_REMOTE_VISIBLE = 'effective.remote.preview.visible';
19
+
20
+ export const EFFECTIVE_APP_STATE_KEYS = [
21
+ APP_STATE_EFFECTIVE_BROWSER_REMOTE_VISIBLE,
22
+ APP_STATE_EFFECTIVE_KEYBOARD_REMOTE_VISIBLE,
23
+ APP_STATE_EFFECTIVE_VLC_REMOTE_VISIBLE,
24
+ APP_STATE_EFFECTIVE_SAMSUNG_REMOTE_VISIBLE,
25
+ APP_STATE_EFFECTIVE_PREVIEW_REMOTE_VISIBLE,
26
+ ];
27
+
28
+ export function getAppStatePropertyChangedEventName(property) {
29
+ return `app-state.${String(property || '').trim()}.changed`;
30
+ }
@@ -0,0 +1,216 @@
1
+ import {createQueuedRecompute} from '../../../utils/functional.js';
2
+ import {
3
+ APP_STATE_HANDEDNESS,
4
+ APP_STATE_PROPERTY_CHANGED_EVENT,
5
+ APP_STATE_REMOTE_AUTO_HIDE,
6
+ APP_STATE_THEME,
7
+ EFFECTIVE_APP_STATE_KEYS,
8
+ getAppStatePropertyChangedEventName,
9
+ } from './appStateKeys.js';
10
+ import {
11
+ APP_STATE_STORE_PERSIST,
12
+ APP_STATE_STORE_STATE,
13
+ getAppStateDefinition,
14
+ } from './stateDefinitions.js';
15
+ import {resolveEffectiveStateValue} from './resolveEffectiveStateValue.js';
16
+ import {
17
+ applyHandednessToDocument,
18
+ applyRemoteAutoHideToDocument,
19
+ applyThemeToDocument,
20
+ } from '../../preferences/effects.js';
21
+
22
+ export {
23
+ APP_STATE_BROWSER_VISIBILITY,
24
+ APP_STATE_EFFECTIVE_BROWSER_REMOTE_VISIBLE,
25
+ APP_STATE_EFFECTIVE_KEYBOARD_REMOTE_VISIBLE,
26
+ APP_STATE_EFFECTIVE_PREVIEW_REMOTE_VISIBLE,
27
+ APP_STATE_EFFECTIVE_SAMSUNG_REMOTE_VISIBLE,
28
+ APP_STATE_EFFECTIVE_VLC_REMOTE_VISIBLE,
29
+ APP_STATE_HANDEDNESS,
30
+ APP_STATE_KEYBOARD_PREVIEW_ACTIVE,
31
+ APP_STATE_LOCALE,
32
+ APP_STATE_PREVIEW_ACTIVITY_AT,
33
+ APP_STATE_PROPERTY_CHANGED_EVENT,
34
+ APP_STATE_REMOTE_ACCORDION_EXPANDED_PANEL,
35
+ APP_STATE_REMOTE_AUTO_HIDE,
36
+ APP_STATE_REMOTE_VISIBILITY,
37
+ APP_STATE_THEME,
38
+ getAppStatePropertyChangedEventName,
39
+ } from './appStateKeys.js';
40
+
41
+ function cloneValue(value) {
42
+ return value && typeof value === 'object' ? structuredClone(value) : value;
43
+ }
44
+
45
+ function applyPreferenceEffect(key, value) {
46
+ if (key === APP_STATE_THEME) {
47
+ applyThemeToDocument(value);
48
+ return;
49
+ }
50
+ if (key === APP_STATE_HANDEDNESS) {
51
+ applyHandednessToDocument(value);
52
+ return;
53
+ }
54
+ if (key === APP_STATE_REMOTE_AUTO_HIDE) {
55
+ applyRemoteAutoHideToDocument(value);
56
+ }
57
+ }
58
+
59
+ export function createAppStateService(services) {
60
+ const stateStore = services.getStateStore();
61
+ const persistStore = services.getPersistStore();
62
+ const clientConfig = services.getClientConfig();
63
+ const pubsub = services.getPubSub();
64
+ const effectiveCache = new Map();
65
+ const listeners = new Set();
66
+ const propertyListeners = new Map();
67
+ let initialized = false;
68
+
69
+ function publishChange(key, value, previousValue) {
70
+ const payload = {
71
+ key,
72
+ property: key,
73
+ value: cloneValue(value),
74
+ previousValue: cloneValue(previousValue),
75
+ state: getSnapshot(),
76
+ };
77
+
78
+ for (const listener of listeners) {
79
+ listener(payload);
80
+ }
81
+
82
+ for (const listener of propertyListeners.get(key) || []) {
83
+ listener(payload);
84
+ }
85
+
86
+ pubsub.publish(APP_STATE_PROPERTY_CHANGED_EVENT, payload);
87
+ pubsub.publish(getAppStatePropertyChangedEventName(key), payload);
88
+ }
89
+
90
+ function getRaw(key) {
91
+ const definition = getAppStateDefinition(key);
92
+ if (!definition) {
93
+ return undefined;
94
+ }
95
+
96
+ if (definition.store === APP_STATE_STORE_STATE) {
97
+ return stateStore.get(key);
98
+ }
99
+ if (definition.store === APP_STATE_STORE_PERSIST) {
100
+ return persistStore.get(key);
101
+ }
102
+
103
+ return undefined;
104
+ }
105
+
106
+ function get(key) {
107
+ if (String(key).startsWith('effective.')) {
108
+ return resolveEffectiveStateValue(key, {stateStore, persistStore, clientConfig});
109
+ }
110
+
111
+ return getRaw(key);
112
+ }
113
+
114
+ function set(key, value) {
115
+ const definition = getAppStateDefinition(key);
116
+ if (!definition) {
117
+ throw new Error(`Unknown app state key: ${key}`);
118
+ }
119
+
120
+ const normalizedValue = definition.normalize(value);
121
+ if (definition.store === APP_STATE_STORE_STATE) {
122
+ return stateStore.set(key, normalizedValue);
123
+ }
124
+ if (definition.store === APP_STATE_STORE_PERSIST) {
125
+ return persistStore.set(key, normalizedValue);
126
+ }
127
+
128
+ throw new Error(`Read-only app state key: ${key}`);
129
+ }
130
+
131
+ function getSnapshot() {
132
+ const snapshot = {
133
+ ...stateStore.getSnapshot(),
134
+ ...persistStore.getSnapshot(),
135
+ };
136
+
137
+ for (const key of EFFECTIVE_APP_STATE_KEYS) {
138
+ snapshot[key] = get(key);
139
+ }
140
+
141
+ return snapshot;
142
+ }
143
+
144
+ const recomputeEffectiveState = createQueuedRecompute(() => {
145
+ for (const key of EFFECTIVE_APP_STATE_KEYS) {
146
+ const nextValue = get(key);
147
+ const previousValue = effectiveCache.get(key);
148
+ if (!Object.is(previousValue, nextValue)) {
149
+ effectiveCache.set(key, cloneValue(nextValue));
150
+ publishChange(key, nextValue, previousValue);
151
+ }
152
+ }
153
+ });
154
+
155
+ function handleStoreChange({key, value, previousValue}) {
156
+ applyPreferenceEffect(key, value);
157
+ publishChange(key, value, previousValue);
158
+ recomputeEffectiveState();
159
+ }
160
+
161
+ function init() {
162
+ if (initialized) {
163
+ return this;
164
+ }
165
+
166
+ persistStore.init();
167
+ stateStore.subscribe(handleStoreChange);
168
+ persistStore.subscribe(handleStoreChange);
169
+ clientConfig.onChange(recomputeEffectiveState);
170
+
171
+ for (const key of [APP_STATE_THEME, APP_STATE_HANDEDNESS, APP_STATE_REMOTE_AUTO_HIDE]) {
172
+ applyPreferenceEffect(key, persistStore.get(key));
173
+ }
174
+
175
+ recomputeEffectiveState();
176
+ initialized = true;
177
+ return this;
178
+ }
179
+
180
+ function subscribe(keyOrListener, maybeListener) {
181
+ if (typeof keyOrListener === 'function') {
182
+ listeners.add(keyOrListener);
183
+ return () => {
184
+ listeners.delete(keyOrListener);
185
+ };
186
+ }
187
+
188
+ return subscribeProperty(keyOrListener, maybeListener);
189
+ }
190
+
191
+ function subscribeProperty(key, listener) {
192
+ if (typeof listener !== 'function') {
193
+ return () => {};
194
+ }
195
+
196
+ const listenersForProperty = propertyListeners.get(key) || new Set();
197
+ listenersForProperty.add(listener);
198
+ propertyListeners.set(key, listenersForProperty);
199
+
200
+ return () => {
201
+ listenersForProperty.delete(listener);
202
+ if (!listenersForProperty.size) {
203
+ propertyListeners.delete(key);
204
+ }
205
+ };
206
+ }
207
+
208
+ return {
209
+ get,
210
+ getSnapshot,
211
+ init,
212
+ set,
213
+ subscribe,
214
+ subscribeProperty,
215
+ };
216
+ }
@@ -0,0 +1,122 @@
1
+ import {createStorageBinding} from './localStorageBinding.js';
2
+ import {getPersistStateDefinitions} from './stateDefinitions.js';
3
+
4
+ function cloneValue(value) {
5
+ return value && typeof value === 'object' ? structuredClone(value) : value;
6
+ }
7
+
8
+ export function createPersistStoreService() {
9
+ const definitions = new Map(getPersistStateDefinitions());
10
+ const storageKeyIndex = new Map();
11
+ const state = {};
12
+ const listeners = new Set();
13
+ let initialized = false;
14
+ let storageBound = false;
15
+
16
+ for (const [key, definition] of definitions.entries()) {
17
+ storageKeyIndex.set(definition.storageKey, {key, definition});
18
+ state[key] = cloneValue(definition.defaultValue);
19
+ }
20
+
21
+ function notify(key, value, previousValue) {
22
+ const payload = {
23
+ key,
24
+ value: cloneValue(value),
25
+ previousValue: cloneValue(previousValue),
26
+ state: getSnapshot(),
27
+ };
28
+
29
+ for (const listener of listeners) {
30
+ listener(payload);
31
+ }
32
+ }
33
+
34
+ function applyValue(key, value) {
35
+ const previousValue = state[key];
36
+ if (Object.is(previousValue, value)) {
37
+ return value;
38
+ }
39
+
40
+ state[key] = cloneValue(value);
41
+ notify(key, value, previousValue);
42
+ return value;
43
+ }
44
+
45
+ function readStorageValue(definition) {
46
+ const rawValue = createStorageBinding(definition.storageKey).read();
47
+ return definition.normalize(rawValue || definition.defaultValue);
48
+ }
49
+
50
+ function bindStorageSync() {
51
+ if (storageBound || typeof window === 'undefined') {
52
+ return;
53
+ }
54
+
55
+ window.addEventListener('storage', (event) => {
56
+ const entry = storageKeyIndex.get(event.key);
57
+ if (!entry) {
58
+ return;
59
+ }
60
+
61
+ applyValue(entry.key, entry.definition.normalize(event.newValue || entry.definition.defaultValue));
62
+ });
63
+
64
+ storageBound = true;
65
+ }
66
+
67
+ function init() {
68
+ if (initialized) {
69
+ return;
70
+ }
71
+
72
+ for (const [key, definition] of definitions.entries()) {
73
+ state[key] = readStorageValue(definition);
74
+ }
75
+ bindStorageSync();
76
+ initialized = true;
77
+ }
78
+
79
+ function get(key) {
80
+ init();
81
+ return cloneValue(state[key]);
82
+ }
83
+
84
+ function getSnapshot() {
85
+ init();
86
+ return Object.fromEntries(
87
+ Object.entries(state).map(([key, value]) => [key, cloneValue(value)]),
88
+ );
89
+ }
90
+
91
+ function set(key, value) {
92
+ init();
93
+ const definition = definitions.get(key);
94
+ if (!definition) {
95
+ throw new Error(`Unknown persisted app state key: ${key}`);
96
+ }
97
+
98
+ const normalizedValue = definition.normalize(value);
99
+ const storage = createStorageBinding(definition.storageKey);
100
+ storage.write(definition.serialize(normalizedValue));
101
+ return applyValue(key, normalizedValue);
102
+ }
103
+
104
+ function subscribe(listener) {
105
+ if (typeof listener !== 'function') {
106
+ return () => {};
107
+ }
108
+
109
+ listeners.add(listener);
110
+ return () => {
111
+ listeners.delete(listener);
112
+ };
113
+ }
114
+
115
+ return {
116
+ init,
117
+ get,
118
+ getSnapshot,
119
+ set,
120
+ subscribe,
121
+ };
122
+ }