@limrun/ui 0.1.0

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.
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # Limrun React Components
2
+
3
+ `@limbar/ui` contains the React components needed to embed Limrun instances in your web applications.
4
+
5
+ See [examples](../../examples/) to see how it can be used.
6
+
7
+ ### Releasing
8
+
9
+ This package is not part of generated SDK, hence you need to publish it manually in GitHub Actions.
@@ -0,0 +1,31 @@
1
+ import { default as React } from 'react';
2
+ declare global {
3
+ interface Window {
4
+ debugRemoteControl?: boolean;
5
+ }
6
+ }
7
+ interface RemoteControlProps {
8
+ url: string;
9
+ token: string;
10
+ className?: string;
11
+ sessionId?: string;
12
+ openUrl?: string;
13
+ }
14
+ interface ScreenshotData {
15
+ dataUri: string;
16
+ }
17
+ export interface ImperativeKeyboardEvent {
18
+ type: 'keydown' | 'keyup';
19
+ code: string;
20
+ shiftKey?: boolean;
21
+ altKey?: boolean;
22
+ ctrlKey?: boolean;
23
+ metaKey?: boolean;
24
+ }
25
+ export interface RemoteControlHandle {
26
+ openUrl: (url: string) => void;
27
+ sendKeyEvent: (event: ImperativeKeyboardEvent) => void;
28
+ screenshot: () => Promise<ScreenshotData>;
29
+ }
30
+ export declare const RemoteControl: React.ForwardRefExoticComponent<RemoteControlProps & React.RefAttributes<RemoteControlHandle>>;
31
+ export {};
@@ -0,0 +1,232 @@
1
+ export declare const CONTROL_MSG_TYPE: {
2
+ readonly INJECT_KEYCODE: 0;
3
+ readonly INJECT_TEXT: 1;
4
+ readonly INJECT_TOUCH_EVENT: 2;
5
+ readonly INJECT_SCROLL_EVENT: 3;
6
+ readonly BACK_OR_SCREEN_ON: 4;
7
+ readonly EXPAND_NOTIFICATION_PANEL: 5;
8
+ readonly EXPAND_SETTINGS_PANEL: 6;
9
+ readonly COLLAPSE_PANELS: 7;
10
+ readonly GET_CLIPBOARD: 8;
11
+ readonly SET_CLIPBOARD: 9;
12
+ readonly SET_DISPLAY_POWER: 10;
13
+ readonly ROTATE_DEVICE: 11;
14
+ };
15
+ export declare const AMOTION_EVENT: {
16
+ readonly ACTION_DOWN: 0;
17
+ readonly ACTION_UP: 1;
18
+ readonly ACTION_MOVE: 2;
19
+ readonly ACTION_CANCEL: 3;
20
+ readonly ACTION_POINTER_DOWN: 5;
21
+ readonly ACTION_POINTER_UP: 6;
22
+ readonly BUTTON_PRIMARY: 1;
23
+ readonly BUTTON_SECONDARY: 2;
24
+ readonly BUTTON_TERTIARY: 4;
25
+ };
26
+ export declare const ANDROID_KEYS: {
27
+ readonly ACTION_DOWN: 0;
28
+ readonly ACTION_UP: 1;
29
+ readonly META_NONE: 0;
30
+ readonly META_SHIFT_ON: 1;
31
+ readonly META_ALT_ON: 2;
32
+ readonly META_CTRL_ON: 4096;
33
+ readonly META_META_ON: 65536;
34
+ readonly KEYCODE_UNKNOWN: 0;
35
+ readonly KEYCODE_SOFT_LEFT: 1;
36
+ readonly KEYCODE_SOFT_RIGHT: 2;
37
+ readonly KEYCODE_HOME: 3;
38
+ readonly KEYCODE_BACK: 4;
39
+ readonly KEYCODE_CALL: 5;
40
+ readonly KEYCODE_ENDCALL: 6;
41
+ readonly KEYCODE_0: 7;
42
+ readonly KEYCODE_1: 8;
43
+ readonly KEYCODE_2: 9;
44
+ readonly KEYCODE_3: 10;
45
+ readonly KEYCODE_4: 11;
46
+ readonly KEYCODE_5: 12;
47
+ readonly KEYCODE_6: 13;
48
+ readonly KEYCODE_7: 14;
49
+ readonly KEYCODE_8: 15;
50
+ readonly KEYCODE_9: 16;
51
+ readonly KEYCODE_STAR: 17;
52
+ readonly KEYCODE_POUND: 18;
53
+ readonly DPAD_UP: 19;
54
+ readonly DPAD_DOWN: 20;
55
+ readonly DPAD_LEFT: 21;
56
+ readonly DPAD_RIGHT: 22;
57
+ readonly KEYCODE_DPAD_CENTER: 23;
58
+ readonly KEYCODE_VOLUME_UP: 24;
59
+ readonly KEYCODE_VOLUME_DOWN: 25;
60
+ readonly KEYCODE_POWER: 26;
61
+ readonly KEYCODE_CAMERA: 27;
62
+ readonly KEYCODE_CLEAR: 28;
63
+ readonly KEYCODE_A: 29;
64
+ readonly KEYCODE_B: 30;
65
+ readonly KEYCODE_C: 31;
66
+ readonly KEYCODE_D: 32;
67
+ readonly KEYCODE_E: 33;
68
+ readonly KEYCODE_F: 34;
69
+ readonly KEYCODE_G: 35;
70
+ readonly KEYCODE_H: 36;
71
+ readonly KEYCODE_I: 37;
72
+ readonly KEYCODE_J: 38;
73
+ readonly KEYCODE_K: 39;
74
+ readonly KEYCODE_L: 40;
75
+ readonly KEYCODE_M: 41;
76
+ readonly KEYCODE_N: 42;
77
+ readonly KEYCODE_O: 43;
78
+ readonly KEYCODE_P: 44;
79
+ readonly KEYCODE_Q: 45;
80
+ readonly KEYCODE_R: 46;
81
+ readonly KEYCODE_S: 47;
82
+ readonly KEYCODE_T: 48;
83
+ readonly KEYCODE_U: 49;
84
+ readonly KEYCODE_V: 50;
85
+ readonly KEYCODE_W: 51;
86
+ readonly KEYCODE_X: 52;
87
+ readonly KEYCODE_Y: 53;
88
+ readonly KEYCODE_Z: 54;
89
+ readonly KEYCODE_COMMA: 55;
90
+ readonly KEYCODE_PERIOD: 56;
91
+ readonly KEYCODE_ALT_LEFT: 57;
92
+ readonly KEYCODE_ALT_RIGHT: 58;
93
+ readonly KEYCODE_SHIFT_LEFT: 59;
94
+ readonly KEYCODE_SHIFT_RIGHT: 60;
95
+ readonly KEYCODE_TAB: 61;
96
+ readonly KEYCODE_SPACE: 62;
97
+ readonly KEYCODE_SYM: 63;
98
+ readonly KEYCODE_EXPLORER: 64;
99
+ readonly KEYCODE_ENVELOPE: 65;
100
+ readonly ENTER: 66;
101
+ readonly DEL: 67;
102
+ readonly KEYCODE_GRAVE: 68;
103
+ readonly KEYCODE_MINUS: 69;
104
+ readonly KEYCODE_EQUALS: 70;
105
+ readonly KEYCODE_LEFT_BRACKET: 71;
106
+ readonly KEYCODE_RIGHT_BRACKET: 72;
107
+ readonly KEYCODE_BACKSLASH: 73;
108
+ readonly KEYCODE_SEMICOLON: 74;
109
+ readonly KEYCODE_APOSTROPHE: 75;
110
+ readonly KEYCODE_SLASH: 76;
111
+ readonly KEYCODE_AT: 77;
112
+ readonly KEYCODE_NUM: 78;
113
+ readonly KEYCODE_HEADSETHOOK: 79;
114
+ readonly KEYCODE_FOCUS: 80;
115
+ readonly KEYCODE_PLUS: 81;
116
+ readonly MENU: 82;
117
+ readonly KEYCODE_NOTIFICATION: 83;
118
+ readonly KEYCODE_SEARCH: 84;
119
+ readonly KEYCODE_MEDIA_PLAY_PAUSE: 85;
120
+ readonly KEYCODE_MEDIA_STOP: 86;
121
+ readonly KEYCODE_MEDIA_NEXT: 87;
122
+ readonly KEYCODE_MEDIA_PREVIOUS: 88;
123
+ readonly KEYCODE_MEDIA_REWIND: 89;
124
+ readonly KEYCODE_MEDIA_FAST_FORWARD: 90;
125
+ readonly KEYCODE_MUTE: 91;
126
+ readonly KEYCODE_PAGE_UP: 92;
127
+ readonly KEYCODE_PAGE_DOWN: 93;
128
+ readonly KEYCODE_PICTSYMBOLS: 94;
129
+ readonly KEYCODE_SWITCH_CHARSET: 95;
130
+ readonly KEYCODE_BUTTON_A: 96;
131
+ readonly KEYCODE_BUTTON_B: 97;
132
+ readonly KEYCODE_BUTTON_C: 98;
133
+ readonly KEYCODE_BUTTON_X: 99;
134
+ readonly KEYCODE_BUTTON_Y: 100;
135
+ readonly KEYCODE_BUTTON_Z: 101;
136
+ readonly KEYCODE_BUTTON_L1: 102;
137
+ readonly KEYCODE_BUTTON_R1: 103;
138
+ readonly KEYCODE_BUTTON_L2: 104;
139
+ readonly KEYCODE_BUTTON_R2: 105;
140
+ readonly KEYCODE_BUTTON_THUMBL: 106;
141
+ readonly KEYCODE_BUTTON_THUMBR: 107;
142
+ readonly KEYCODE_BUTTON_START: 108;
143
+ readonly KEYCODE_BUTTON_SELECT: 109;
144
+ readonly KEYCODE_BUTTON_MODE: 110;
145
+ readonly KEYCODE_ESCAPE: 111;
146
+ readonly FORWARD_DEL: 112;
147
+ readonly KEYCODE_CTRL_LEFT: 113;
148
+ readonly KEYCODE_CTRL_RIGHT: 114;
149
+ readonly KEYCODE_CAPS_LOCK: 115;
150
+ readonly KEYCODE_SCROLL_LOCK: 116;
151
+ readonly KEYCODE_META_LEFT: 117;
152
+ readonly KEYCODE_META_RIGHT: 118;
153
+ readonly KEYCODE_FUNCTION: 119;
154
+ readonly KEYCODE_SYSRQ: 120;
155
+ readonly KEYCODE_BREAK: 121;
156
+ readonly KEYCODE_MOVE_HOME: 122;
157
+ readonly KEYCODE_MOVE_END: 123;
158
+ readonly KEYCODE_INSERT: 124;
159
+ readonly KEYCODE_FORWARD: 125;
160
+ readonly KEYCODE_MEDIA_PLAY: 126;
161
+ readonly KEYCODE_MEDIA_PAUSE: 127;
162
+ readonly KEYCODE_MEDIA_CLOSE: 128;
163
+ readonly KEYCODE_MEDIA_EJECT: 129;
164
+ readonly KEYCODE_MEDIA_RECORD: 130;
165
+ readonly KEYCODE_F1: 131;
166
+ readonly KEYCODE_F2: 132;
167
+ readonly KEYCODE_F3: 133;
168
+ readonly KEYCODE_F4: 134;
169
+ readonly KEYCODE_F5: 135;
170
+ readonly KEYCODE_F6: 136;
171
+ readonly KEYCODE_F7: 137;
172
+ readonly KEYCODE_F8: 138;
173
+ readonly KEYCODE_F9: 139;
174
+ readonly KEYCODE_F10: 140;
175
+ readonly KEYCODE_F11: 141;
176
+ readonly KEYCODE_F12: 142;
177
+ readonly KEYCODE_NUM_LOCK: 143;
178
+ readonly KEYCODE_NUMPAD_0: 144;
179
+ readonly KEYCODE_NUMPAD_1: 145;
180
+ readonly KEYCODE_NUMPAD_2: 146;
181
+ readonly KEYCODE_NUMPAD_3: 147;
182
+ readonly KEYCODE_NUMPAD_4: 148;
183
+ readonly KEYCODE_NUMPAD_5: 149;
184
+ readonly KEYCODE_NUMPAD_6: 150;
185
+ readonly KEYCODE_NUMPAD_7: 151;
186
+ readonly KEYCODE_NUMPAD_8: 152;
187
+ readonly KEYCODE_NUMPAD_9: 153;
188
+ readonly KEYCODE_NUMPAD_DIVIDE: 154;
189
+ readonly KEYCODE_NUMPAD_MULTIPLY: 155;
190
+ readonly KEYCODE_NUMPAD_SUBTRACT: 156;
191
+ readonly KEYCODE_NUMPAD_ADD: 157;
192
+ readonly KEYCODE_NUMPAD_DOT: 158;
193
+ readonly KEYCODE_NUMPAD_COMMA: 159;
194
+ readonly KEYCODE_NUMPAD_ENTER: 160;
195
+ readonly KEYCODE_NUMPAD_EQUALS: 161;
196
+ readonly KEYCODE_NUMPAD_LEFT_PAREN: 162;
197
+ readonly KEYCODE_NUMPAD_RIGHT_PAREN: 163;
198
+ readonly KEYCODE_VOLUME_MUTE: 164;
199
+ readonly KEYCODE_INFO: 165;
200
+ readonly KEYCODE_CHANNEL_UP: 166;
201
+ readonly KEYCODE_CHANNEL_DOWN: 167;
202
+ readonly KEYCODE_ZOOM_IN: 168;
203
+ readonly KEYCODE_ZOOM_OUT: 169;
204
+ readonly KEYCODE_TV: 170;
205
+ readonly KEYCODE_WINDOW: 171;
206
+ readonly KEYCODE_GUIDE: 172;
207
+ readonly KEYCODE_DVR: 173;
208
+ readonly KEYCODE_BOOKMARK: 174;
209
+ readonly KEYCODE_CAPTIONS: 175;
210
+ readonly KEYCODE_SETTINGS: 176;
211
+ readonly KEYCODE_TV_POWER: 177;
212
+ readonly KEYCODE_TV_INPUT: 178;
213
+ readonly KEYCODE_STB_POWER: 179;
214
+ readonly KEYCODE_STB_INPUT: 180;
215
+ readonly KEYCODE_AVR_POWER: 181;
216
+ readonly KEYCODE_AVR_INPUT: 182;
217
+ readonly KEYCODE_PROG_RED: 183;
218
+ readonly KEYCODE_PROG_GREEN: 184;
219
+ readonly KEYCODE_PROG_YELLOW: 185;
220
+ readonly KEYCODE_PROG_BLUE: 186;
221
+ readonly KEYCODE_APP_SWITCH: 187;
222
+ readonly KEYCODE_LANGUAGE_SWITCH: 204;
223
+ readonly KEYCODE_ASSIST: 219;
224
+ readonly KEYCODE_BRIGHTNESS_DOWN: 220;
225
+ readonly KEYCODE_BRIGHTNESS_UP: 221;
226
+ readonly KEYCODE_SLEEP: 223;
227
+ readonly KEYCODE_WAKEUP: 224;
228
+ readonly KEYCODE_SOFT_SLEEP: 276;
229
+ };
230
+ export declare const codeMap: {
231
+ [code: string]: number;
232
+ };
@@ -0,0 +1,3 @@
1
+ export declare function createTouchControlMessage(action: number, pointerId: number, videoWidth: number, videoHeight: number, x: number, y: number, pressure?: number, actionButton?: number, buttons?: number): ArrayBuffer;
2
+ export declare function createSetClipboardMessage(text: string, paste?: boolean): ArrayBuffer;
3
+ export declare function createInjectKeycodeMessage(action: number, keycode: number, repeat?: number, metaState?: number): ArrayBuffer;
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require('./index.css');const w=require("react/jsx-runtime"),y=require("react");function ne(E){var a,D,i="";if(typeof E=="string"||typeof E=="number")i+=E;else if(typeof E=="object")if(Array.isArray(E)){var l=E.length;for(a=0;a<l;a++)E[a]&&(D=ne(E[a]))&&(i&&(i+=" "),i+=D)}else for(D in E)E[D]&&(i&&(i+=" "),i+=D);return i}function _e(){for(var E,a,D=0,i="",l=arguments.length;D<l;D++)(E=arguments[D])&&(a=ne(E))&&(i&&(i+=" "),i+=a);return i}const j={INJECT_KEYCODE:0,INJECT_TOUCH_EVENT:2,SET_CLIPBOARD:9},b={ACTION_DOWN:0,ACTION_UP:1,ACTION_MOVE:2,ACTION_CANCEL:3,BUTTON_PRIMARY:1},e={ACTION_DOWN:0,ACTION_UP:1,META_NONE:0,META_SHIFT_ON:1,META_ALT_ON:2,META_CTRL_ON:4096,META_META_ON:65536,KEYCODE_0:7,KEYCODE_1:8,KEYCODE_2:9,KEYCODE_3:10,KEYCODE_4:11,KEYCODE_5:12,KEYCODE_6:13,KEYCODE_7:14,KEYCODE_8:15,KEYCODE_9:16,DPAD_UP:19,DPAD_DOWN:20,DPAD_LEFT:21,DPAD_RIGHT:22,KEYCODE_A:29,KEYCODE_B:30,KEYCODE_C:31,KEYCODE_D:32,KEYCODE_E:33,KEYCODE_F:34,KEYCODE_G:35,KEYCODE_H:36,KEYCODE_I:37,KEYCODE_J:38,KEYCODE_K:39,KEYCODE_L:40,KEYCODE_M:41,KEYCODE_N:42,KEYCODE_O:43,KEYCODE_P:44,KEYCODE_Q:45,KEYCODE_R:46,KEYCODE_S:47,KEYCODE_T:48,KEYCODE_U:49,KEYCODE_V:50,KEYCODE_W:51,KEYCODE_X:52,KEYCODE_Y:53,KEYCODE_Z:54,KEYCODE_COMMA:55,KEYCODE_PERIOD:56,KEYCODE_ALT_LEFT:57,KEYCODE_ALT_RIGHT:58,KEYCODE_SHIFT_LEFT:59,KEYCODE_SHIFT_RIGHT:60,KEYCODE_TAB:61,KEYCODE_SPACE:62,ENTER:66,DEL:67,KEYCODE_GRAVE:68,KEYCODE_MINUS:69,KEYCODE_EQUALS:70,KEYCODE_LEFT_BRACKET:71,KEYCODE_RIGHT_BRACKET:72,KEYCODE_BACKSLASH:73,KEYCODE_SEMICOLON:74,KEYCODE_APOSTROPHE:75,KEYCODE_SLASH:76,MENU:82,KEYCODE_PAGE_UP:92,KEYCODE_PAGE_DOWN:93,KEYCODE_ESCAPE:111,FORWARD_DEL:112,KEYCODE_CTRL_LEFT:113,KEYCODE_CTRL_RIGHT:114,KEYCODE_META_LEFT:117,KEYCODE_META_RIGHT:118,KEYCODE_MOVE_HOME:122,KEYCODE_MOVE_END:123,KEYCODE_INSERT:124,KEYCODE_F1:131,KEYCODE_F2:132,KEYCODE_F3:133,KEYCODE_F4:134,KEYCODE_F5:135,KEYCODE_F6:136,KEYCODE_F7:137,KEYCODE_F8:138,KEYCODE_F9:139,KEYCODE_F10:140,KEYCODE_F11:141,KEYCODE_F12:142,KEYCODE_NUMPAD_0:144,KEYCODE_NUMPAD_1:145,KEYCODE_NUMPAD_2:146,KEYCODE_NUMPAD_3:147,KEYCODE_NUMPAD_4:148,KEYCODE_NUMPAD_5:149,KEYCODE_NUMPAD_6:150,KEYCODE_NUMPAD_7:151,KEYCODE_NUMPAD_8:152,KEYCODE_NUMPAD_9:153,KEYCODE_NUMPAD_DIVIDE:154,KEYCODE_NUMPAD_MULTIPLY:155,KEYCODE_NUMPAD_SUBTRACT:156,KEYCODE_NUMPAD_ADD:157,KEYCODE_NUMPAD_DOT:158,KEYCODE_NUMPAD_COMMA:159,KEYCODE_NUMPAD_ENTER:160,KEYCODE_NUMPAD_EQUALS:161},re={KeyA:e.KEYCODE_A,KeyB:e.KEYCODE_B,KeyC:e.KEYCODE_C,KeyD:e.KEYCODE_D,KeyE:e.KEYCODE_E,KeyF:e.KEYCODE_F,KeyG:e.KEYCODE_G,KeyH:e.KEYCODE_H,KeyI:e.KEYCODE_I,KeyJ:e.KEYCODE_J,KeyK:e.KEYCODE_K,KeyL:e.KEYCODE_L,KeyM:e.KEYCODE_M,KeyN:e.KEYCODE_N,KeyO:e.KEYCODE_O,KeyP:e.KEYCODE_P,KeyQ:e.KEYCODE_Q,KeyR:e.KEYCODE_R,KeyS:e.KEYCODE_S,KeyT:e.KEYCODE_T,KeyU:e.KEYCODE_U,KeyV:e.KEYCODE_V,KeyW:e.KEYCODE_W,KeyX:e.KEYCODE_X,KeyY:e.KEYCODE_Y,KeyZ:e.KEYCODE_Z,Digit0:e.KEYCODE_0,Digit1:e.KEYCODE_1,Digit2:e.KEYCODE_2,Digit3:e.KEYCODE_3,Digit4:e.KEYCODE_4,Digit5:e.KEYCODE_5,Digit6:e.KEYCODE_6,Digit7:e.KEYCODE_7,Digit8:e.KEYCODE_8,Digit9:e.KEYCODE_9,Backquote:e.KEYCODE_GRAVE,Minus:e.KEYCODE_MINUS,Equal:e.KEYCODE_EQUALS,BracketLeft:e.KEYCODE_LEFT_BRACKET,BracketRight:e.KEYCODE_RIGHT_BRACKET,Backslash:e.KEYCODE_BACKSLASH,Semicolon:e.KEYCODE_SEMICOLON,Quote:e.KEYCODE_APOSTROPHE,Comma:e.KEYCODE_COMMA,Period:e.KEYCODE_PERIOD,Slash:e.KEYCODE_SLASH,Space:e.KEYCODE_SPACE,Tab:e.KEYCODE_TAB,Escape:e.KEYCODE_ESCAPE,ArrowUp:e.DPAD_UP,ArrowDown:e.DPAD_DOWN,ArrowLeft:e.DPAD_LEFT,ArrowRight:e.DPAD_RIGHT,Enter:e.ENTER,Backspace:e.DEL,Delete:e.FORWARD_DEL,Home:e.KEYCODE_MOVE_HOME,End:e.KEYCODE_MOVE_END,PageUp:e.KEYCODE_PAGE_UP,PageDown:e.KEYCODE_PAGE_DOWN,Insert:e.KEYCODE_INSERT,F1:e.KEYCODE_F1,F2:e.KEYCODE_F2,F3:e.KEYCODE_F3,F4:e.KEYCODE_F4,F5:e.KEYCODE_F5,F6:e.KEYCODE_F6,F7:e.KEYCODE_F7,F8:e.KEYCODE_F8,F9:e.KEYCODE_F9,F10:e.KEYCODE_F10,F11:e.KEYCODE_F11,F12:e.KEYCODE_F12,ShiftLeft:e.KEYCODE_SHIFT_LEFT,ShiftRight:e.KEYCODE_SHIFT_RIGHT,ControlLeft:e.KEYCODE_CTRL_LEFT,ControlRight:e.KEYCODE_CTRL_RIGHT,AltLeft:e.KEYCODE_ALT_LEFT,AltRight:e.KEYCODE_ALT_RIGHT,MetaLeft:e.KEYCODE_META_LEFT,MetaRight:e.KEYCODE_META_RIGHT,ContextMenu:e.MENU,Numpad0:e.KEYCODE_NUMPAD_0,Numpad1:e.KEYCODE_NUMPAD_1,Numpad2:e.KEYCODE_NUMPAD_2,Numpad3:e.KEYCODE_NUMPAD_3,Numpad4:e.KEYCODE_NUMPAD_4,Numpad5:e.KEYCODE_NUMPAD_5,Numpad6:e.KEYCODE_NUMPAD_6,Numpad7:e.KEYCODE_NUMPAD_7,Numpad8:e.KEYCODE_NUMPAD_8,Numpad9:e.KEYCODE_NUMPAD_9,NumpadDivide:e.KEYCODE_NUMPAD_DIVIDE,NumpadMultiply:e.KEYCODE_NUMPAD_MULTIPLY,NumpadSubtract:e.KEYCODE_NUMPAD_SUBTRACT,NumpadAdd:e.KEYCODE_NUMPAD_ADD,NumpadDecimal:e.KEYCODE_NUMPAD_DOT,NumpadComma:e.KEYCODE_NUMPAD_COMMA,NumpadEnter:e.KEYCODE_NUMPAD_ENTER,NumpadEqual:e.KEYCODE_NUMPAD_EQUALS};function De(E,a,D,i,l,Y,o=1,c=0,s=0){const u=new ArrayBuffer(32),N=new DataView(u);let d=0;return N.setUint8(d,j.INJECT_TOUCH_EVENT),d+=1,N.setUint8(d,E),d+=1,N.setBigInt64(d,BigInt(a)),d+=8,N.setInt32(d,Math.round(l),!0),d+=4,N.setInt32(d,Math.round(Y),!0),d+=4,N.setUint16(d,D,!0),d+=2,N.setUint16(d,i,!0),d+=2,N.setInt16(d,Math.round(o*65535),!0),d+=2,N.setInt32(d,c,!0),d+=4,N.setInt32(d,s,!0),u}function Ce(E,a=!0){const i=new TextEncoder().encode(E),l=new ArrayBuffer(14+i.length),Y=new DataView(l);let o=0;return Y.setUint8(o,j.SET_CLIPBOARD),o+=1,Y.setBigInt64(o,BigInt(0),!1),o+=8,Y.setUint8(o,a?1:0),o+=1,Y.setUint32(o,i.length,!1),o+=4,new Uint8Array(l,o).set(i),l}function W(E,a,D=0,i=0){const l=new ArrayBuffer(14),Y=new DataView(l);let o=0;return Y.setUint8(o,j.INJECT_KEYCODE),o+=1,Y.setUint8(o,E),o+=1,Y.setInt32(o,a,!0),o+=4,Y.setInt32(o,D,!0),o+=4,Y.setInt32(o,i,!0),l}const T=(...E)=>{window.debugRemoteControl&&console.log(...E)},f=(...E)=>{window.debugRemoteControl&&console.warn(...E)};function Oe(E){const a=E.code,D=re[a];if(!D)return f(`Unknown event.code: ${a}, key: ${E.key}`),null;let i=e.META_NONE;const l=a>="KeyA"&&a<="KeyZ",Y=E.getModifierState("CapsLock"),o=E.shiftKey;let c=o;return l&&(c=o!==Y),c&&(i|=e.META_SHIFT_ON),E.ctrlKey&&(i|=e.META_CTRL_ON),E.altKey&&(i|=e.META_ALT_ON),E.metaKey&&(i|=e.META_META_ON),{keycode:D,metaState:i}}const Ke=y.forwardRef(({className:E,url:a,token:D,sessionId:i,openUrl:l},Y)=>{const o=y.useRef(null),c=y.useRef(null),s=y.useRef(null),u=y.useRef(null),[N,d]=y.useState(!1),I=y.useRef(void 0),S=y.useRef(new Map),P=y.useRef(new Map),p=y.useRef(new Map),m=y.useMemo(()=>i||Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15),[i]),C=r=>{T(r)},U=r=>{!u.current||u.current.readyState!=="open"||u.current.send(r)},M=r=>{if(r.preventDefault(),r.stopPropagation(),!u.current||u.current.readyState!=="open"||!o.current)return;const O=o.current,t=O.getBoundingClientRect(),n=O.videoWidth,_=O.videoHeight;if(!n||!_)return;const g=(A,K,k,h)=>{const F=t.width,v=t.height,$=n/_,se=F/v;let H=F,B=v;$>se?B=F/$:H=v*$;const ae=(F-H)/2,de=(v-B)/2,V=K-t.left-ae,G=k-t.top-de,x=V>=0&&V<=H&&G>=0&&G<=B;let J=0,q=0;x&&(J=Math.max(0,Math.min(n,V/H*n)),q=Math.max(0,Math.min(_,G/B*_)));let L=null,R=null,ue=1;const ee=b.BUTTON_PRIMARY;switch(h){case"down":x?(L=b.ACTION_DOWN,R={x:J,y:q},p.current.set(A,R),A===-1&&o.current?.focus()):p.current.delete(A);break;case"move":p.current.has(A)&&x&&(L=b.ACTION_MOVE,R={x:J,y:q},p.current.set(A,R));break;case"up":case"cancel":p.current.has(A)&&(L=h==="cancel"?b.ACTION_CANCEL:b.ACTION_UP,R=p.current.get(A),p.current.delete(A));break}if(L!==null&&R!==null){const te=De(L,A,n,_,R.x,R.y,ue,ee,ee);te&&U(te)}else(h==="up"||h==="cancel")&&p.current.delete(A)};if("touches"in r){const A=r.changedTouches;let K;switch(r.type){case"touchstart":K="down";break;case"touchmove":K="move";break;case"touchend":K="up";break;case"touchcancel":K="cancel";break;default:return}for(let k=0;k<A.length;k++){const h=A[k];g(h.identifier,h.clientX,h.clientY,K)}}else{let K=null;switch(r.type){case"mousedown":r.button===0&&(K="down");break;case"mousemove":p.current.has(-1)&&(K="move");break;case"mouseup":r.button===0&&(K="up");break;case"mouseleave":p.current.has(-1)&&(K="up");break}K&&g(-1,r.clientX,r.clientY,K)}},Q=r=>{if(r.preventDefault(),r.stopPropagation(),T("Keyboard event:",{type:r.type,key:r.key,keyCode:r.keyCode,code:r.code,target:r.target.tagName,focused:document.activeElement===o.current}),document.activeElement!==o.current){f("Video element not focused, skipping keyboard event");return}if(!u.current||u.current.readyState!=="open"){f("Data channel not ready for keyboard event:",u.current?.readyState);return}if(r.type==="keydown"){if(r.key.toLowerCase()==="v"&&(r.metaKey||r.ctrlKey)){T("Paste shortcut detected"),navigator.clipboard.readText().then(t=>{if(t){T("Pasting text via SET_CLIPBOARD:",t.substring(0,20)+(t.length>20?"...":""));const n=Ce(t,!0);U(n)}}).catch(t=>{console.error("Failed to read clipboard contents: ",t)});return}if(r.key.toLowerCase()==="m"&&(r.metaKey||r.ctrlKey)){T("Menu shortcut detected");const t=W(e.ACTION_DOWN,e.MENU,0,e.META_NONE);U(t);const n=W(e.ACTION_UP,e.MENU,0,e.META_NONE);U(n);return}}const O=Oe(r);if(O){const{keycode:t,metaState:n}=O,_=r.type==="keydown"?e.ACTION_DOWN:e.ACTION_UP;T(`Sending Keycode: key=${r.key}, code=${t}, action=${_}, meta=${n}`);const g=W(_,t,0,n);U(g)}else T(`Ignoring unhandled key event: type=${r.type}, key=${r.key}`)},oe=()=>{c.current&&c.current.readyState===WebSocket.OPEN&&c.current.send(JSON.stringify({type:"keepAlive",sessionId:m}))},X=()=>{I.current&&window.clearInterval(I.current),I.current=window.setInterval(oe,1e4)},Z=()=>{I.current&&(window.clearInterval(I.current),I.current=void 0)},z=()=>{document.hidden?Z():X()},ce=async()=>{try{c.current=new WebSocket(`${a}?token=${D}`),c.current.onerror=t=>{C("WebSocket error: "+t)},c.current.onclose=()=>{C("WebSocket closed")},await new Promise((t,n)=>{c.current&&(c.current.onopen=t,setTimeout(()=>n(new Error("WebSocket connection timeout")),5e3))});const O=await new Promise((t,n)=>{const _=setTimeout(()=>n(new Error("RTCConfiguration timeout")),5e3),g=A=>{try{const K=JSON.parse(A.data);K.type==="rtcConfiguration"&&(clearTimeout(_),c.current?.removeEventListener("message",g),t(K.rtcConfiguration))}catch(K){console.error("Error handling RTC configuration:",K),n(K)}};c.current?.addEventListener("message",g),c.current?.send(JSON.stringify({type:"requestRtcConfiguration",sessionId:m}))});if(s.current=new RTCPeerConnection(O),s.current.addTransceiver("audio",{direction:"recvonly"}),s.current.addTransceiver("video",{direction:"recvonly"}),u.current=s.current.createDataChannel("control",{ordered:!0,negotiated:!0,id:1}),u.current.onopen=()=>{if(C("Control channel opened"),c.current&&(c.current.send(JSON.stringify({type:"requestFrame",sessionId:m})),l))try{const t=decodeURIComponent(l);C("Opening URL"),c.current.send(JSON.stringify({type:"openUrl",url:t,sessionId:m}))}catch(t){console.error({error:t},"Error decoding URL, falling back to the original URL"),c.current.send(JSON.stringify({type:"openUrl",url:l,sessionId:m}))}},u.current.onclose=()=>{C("Control channel closed")},u.current.onerror=t=>{console.error("Control channel error:",t),C("Control channel error: "+t)},s.current.onconnectionstatechange=()=>{C("Connection state: "+s.current?.connectionState),d(s.current?.connectionState==="connected")},s.current.oniceconnectionstatechange=()=>{C("ICE state: "+s.current?.iceConnectionState)},s.current.ontrack=t=>{C("Received remote track: "+t.track.kind),t.track.kind==="video"&&o.current&&(T(`[${new Date().toISOString()}] Video track received:`,t.track),o.current.srcObject=t.streams[0])},s.current.onicecandidate=t=>{if(t.candidate&&c.current){const n={type:"candidate",candidate:t.candidate.candidate,sdpMid:t.candidate.sdpMid,sdpMLineIndex:t.candidate.sdpMLineIndex,sessionId:m};c.current.send(JSON.stringify(n)),C("Sent ICE candidate")}else C("ICE candidate gathering completed")},c.current.onmessage=async t=>{let n;try{n=JSON.parse(t.data)}catch(_){f("Error parsing message:",_);return}switch(C("Received: "+n.type),n.type){case"answer":if(!s.current){C("No peer connection, skipping answer");break}await s.current.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:n.sdp})),C("Set remote description");break;case"candidate":if(!s.current){C("No peer connection, skipping candidate");break}await s.current.addIceCandidate(new RTCIceCandidate({candidate:n.candidate,sdpMid:n.sdpMid,sdpMLineIndex:n.sdpMLineIndex})),C("Added ICE candidate");break;case"screenshot":if(typeof n.id!="string"||typeof n.dataUri!="string"){f("Received invalid screenshot success message:",n);break}const _=S.current.get(n.id);if(!_){f(`Received screenshot data for unknown or handled id: ${n.id}`);break}T(`Received screenshot data for id ${n.id}`),_({dataUri:n.dataUri}),S.current.delete(n.id),P.current.delete(n.id);break;case"screenshotError":if(typeof n.id!="string"||typeof n.message!="string"){f("Received invalid screenshot error message:",n);break}const g=P.current.get(n.id);if(!g){f(`Received screenshot error for unknown or handled id: ${n.id}`);break}f(`Received screenshot error for id ${n.id}: ${n.message}`),g(new Error(n.message)),S.current.delete(n.id),P.current.delete(n.id);break;default:f(`Received unhandled message type: ${n.type}`,n);break}},s.current){const t=await s.current.createOffer({offerToReceiveVideo:!0,offerToReceiveAudio:!1});await s.current.setLocalDescription(t),c.current&&c.current.send(JSON.stringify({type:"offer",sdp:t.sdp,sessionId:m})),C("Sent offer")}}catch(r){C("Error: "+r)}},Ee=()=>{c.current&&(c.current.close(),c.current=null),s.current&&(s.current.close(),s.current=null),o.current&&(o.current.srcObject=null),u.current&&(u.current.close(),u.current=null),d(!1),C("Stopped")};y.useEffect(()=>(ce(),document.hidden||X(),document.addEventListener("visibilitychange",z),()=>{Z(),Ee(),document.removeEventListener("visibilitychange",z)}),[a,D,i]);const ie=()=>{o.current&&o.current.focus()};return y.useImperativeHandle(Y,()=>({openUrl:r=>{if(!c.current||c.current.readyState!==WebSocket.OPEN){f("WebSocket not open, cannot send open_url command via ref.");return}try{const O=decodeURIComponent(r);C("Opening URL"),c.current.send(JSON.stringify({type:"openUrl",url:O,sessionId:m}))}catch(O){f("Error decoding or sending URL via ref:",{error:O,url:r}),c.current.send(JSON.stringify({type:"openUrl",url:r,sessionId:m}))}},sendKeyEvent:r=>{if(!u.current||u.current.readyState!=="open"){f("Data channel not ready for imperative key command:",u.current?.readyState);return}const O=re[r.code];if(!O){f(`Unknown event.code for imperative command: ${r.code}`);return}let t=e.META_NONE;r.shiftKey&&(t|=e.META_SHIFT_ON),r.altKey&&(t|=e.META_ALT_ON),r.ctrlKey&&(t|=e.META_CTRL_ON),r.metaKey&&(t|=e.META_META_ON);const n=r.type==="keydown"?e.ACTION_DOWN:e.ACTION_UP;T(`Sending Imperative Key Command: code=${r.code}, keycode=${O}, action=${n}, meta=${t}`);const _=W(n,O,0,t);_&&U(_)},screenshot:()=>new Promise((r,O)=>{if(!c.current||c.current.readyState!==WebSocket.OPEN)return f("WebSocket not open, cannot send screenshot command."),O(new Error("WebSocket is not connected or connection is not open."));const t=`ui-ss-${Date.now()}-${Math.random().toString(36).substring(2,9)}`,n={type:"screenshot",id:t};S.current.set(t,r),P.current.set(t,O),T("Sending screenshot request:",n);try{c.current.send(JSON.stringify(n))}catch(_){f("Failed to send screenshot request immediately:",_),S.current.delete(t),P.current.delete(t),O(_);return}setTimeout(()=>{S.current.has(t)&&(f(`Screenshot request timed out for id ${t}`),P.current.get(t)?.(new Error("Screenshot request timed out")),S.current.delete(t),P.current.delete(t))},3e4)})})),w.jsxs("div",{className:_e("rc-container",E),style:{touchAction:"none"},onMouseDown:M,onMouseMove:M,onMouseUp:M,onMouseLeave:M,onTouchStart:M,onTouchMove:M,onTouchEnd:M,onTouchCancel:M,children:[w.jsx("video",{ref:o,className:"rc-video",autoPlay:!0,playsInline:!0,muted:!0,tabIndex:0,style:{outline:"none",pointerEvents:"none"},onKeyDown:Q,onKeyUp:Q,onClick:ie,onFocus:()=>{o.current&&(o.current.style.outline="none")},onBlur:()=>{o.current&&(o.current.style.outline="none")}}),!N&&w.jsxs("div",{className:"rc-placeholder-wrapper",children:[w.jsx("div",{className:"rc-spinner"}),w.jsx("p",{className:"rc-placeholder-content",children:"Connecting..."})]})]})});exports.RemoteControl=Ke;
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ .rc-container{position:relative;display:flex;height:100%;align-items:center;justify-content:center;isolation:isolate;contain:layout style;background-color:#0000000d;touch-action:none;--rc-spinner-color: #3b82f6;--rc-text-muted: #6b7280}.rc-video{height:100%;width:100%;max-height:100%;max-width:100%;object-fit:contain;outline:none;pointer-events:none;cursor:none}.rc-placeholder-wrapper{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}.rc-placeholder-content{color:var(--rc-text-muted);font-size:.875rem;line-height:1.25rem;margin:0;font-family:inherit}.rc-spinner{width:32px;height:32px;border:2px solid transparent;border-top-color:var(--rc-spinner-color);border-radius:50%;margin:0 auto 8px;animation:rc-spin 1s linear infinite}@keyframes rc-spin{to{transform:rotate(360deg)}}
@@ -0,0 +1 @@
1
+ export { RemoteControl } from './components/remote-control';