@@ -8,35 +8,24 @@ import { GridCard } from "@components/Card";
8
8
import { TextAreaWithLabel } from "@components/TextArea" ;
9
9
import { SettingsPageHeader } from "@components/SettingsPageheader" ;
10
10
import { JsonRpcResponse , useJsonRpc } from "@/hooks/useJsonRpc" ;
11
- import { useHidStore , useRTCStore , useUiStore , useSettingsStore } from "@/hooks/stores" ;
12
- import { keys , modifiers } from "@/keyboardMappings" ;
13
- import { KeyStroke } from "@/keyboardLayouts" ;
11
+ import { useHidStore , useSettingsStore , useUiStore } from "@/hooks/stores" ;
12
+ import useKeyboard from "@/hooks/useKeyboard" ;
14
13
import useKeyboardLayout from "@/hooks/useKeyboardLayout" ;
15
14
import notifications from "@/notifications" ;
16
15
17
- const hidKeyboardPayload = ( modifier : number , keys : number [ ] ) => {
18
- return { modifier, keys } ;
19
- } ;
20
-
21
- const modifierCode = ( shift ?: boolean , altRight ?: boolean ) => {
22
- return ( shift ? modifiers . ShiftLeft : 0 )
23
- | ( altRight ? modifiers . AltRight : 0 )
24
- }
25
- const noModifier = 0
26
-
27
16
export default function PasteModal ( ) {
28
17
const TextAreaRef = useRef < HTMLTextAreaElement > ( null ) ;
29
18
const { setPasteModeEnabled } = useHidStore ( ) ;
30
19
const { setDisableVideoFocusTrap } = useUiStore ( ) ;
31
20
32
21
const { send } = useJsonRpc ( ) ;
33
- const { rpcDataChannel } = useRTCStore ( ) ;
22
+ const { executeMacro } = useKeyboard ( ) ;
34
23
35
24
const [ invalidChars , setInvalidChars ] = useState < string [ ] > ( [ ] ) ;
36
25
const close = useClose ( ) ;
37
26
38
27
const { setKeyboardLayout } = useSettingsStore ( ) ;
39
- const { selectedKeyboard } = useKeyboardLayout ( ) ;
28
+ const { selectedKeyboard } = useKeyboardLayout ( ) ;
40
29
41
30
useEffect ( ( ) => {
42
31
send ( "getKeyboardLayout" , { } , ( resp : JsonRpcResponse ) => {
@@ -52,15 +41,20 @@ export default function PasteModal() {
52
41
} , [ setDisableVideoFocusTrap , setPasteModeEnabled ] ) ;
53
42
54
43
const onConfirmPaste = useCallback ( async ( ) => {
55
- setPasteModeEnabled ( false ) ;
56
- setDisableVideoFocusTrap ( false ) ;
44
+ // setPasteModeEnabled(false);
45
+ // setDisableVideoFocusTrap(false);
57
46
58
- if ( rpcDataChannel ?. readyState !== "open" || ! TextAreaRef . current ) return ;
59
- if ( ! selectedKeyboard ) return ;
47
+ if ( ! TextAreaRef . current || ! selectedKeyboard ) return ;
60
48
61
49
const text = TextAreaRef . current . value ;
62
50
63
51
try {
52
+ const macroSteps : {
53
+ keys : string [ ] | null ;
54
+ modifiers : string [ ] | null ;
55
+ delay : number ;
56
+ } [ ] = [ ] ;
57
+
64
58
for ( const char of text ) {
65
59
const keyprops = selectedKeyboard . chars [ char ] ;
66
60
if ( ! keyprops ) continue ;
@@ -70,39 +64,41 @@ export default function PasteModal() {
70
64
71
65
// if this is an accented character, we need to send that accent FIRST
72
66
if ( accentKey ) {
73
- await sendKeystroke ( { modifier : modifierCode ( accentKey . shift , accentKey . altRight ) , keys : [ keys [ accentKey . key ] ] } )
67
+ const accentModifiers : string [ ] = [ ] ;
68
+ if ( accentKey . shift ) accentModifiers . push ( "ShiftLeft" ) ;
69
+ if ( accentKey . altRight ) accentModifiers . push ( "AltRight" ) ;
70
+
71
+ macroSteps . push ( {
72
+ keys : [ String ( accentKey . key ) ] ,
73
+ modifiers : accentModifiers . length > 0 ? accentModifiers : null ,
74
+ delay : 100 ,
75
+ } ) ;
74
76
}
75
77
76
78
// now send the actual key
77
- await sendKeystroke ( { modifier : modifierCode ( shift , altRight ) , keys : [ keys [ key ] ] } ) ;
79
+ const modifiers : string [ ] = [ ] ;
80
+ if ( shift ) modifiers . push ( "ShiftLeft" ) ;
81
+ if ( altRight ) modifiers . push ( "AltRight" ) ;
82
+
83
+ macroSteps . push ( {
84
+ keys : [ String ( key ) ] ,
85
+ modifiers : modifiers . length > 0 ? modifiers : null ,
86
+ delay : 100 ,
87
+ } ) ;
78
88
79
89
// if what was requested was a dead key, we need to send an unmodified space to emit
80
90
// just the accent character
81
- if ( deadKey ) {
82
- await sendKeystroke ( { modifier : noModifier , keys : [ keys [ "Space" ] ] } ) ;
83
- }
91
+ if ( deadKey ) macroSteps . push ( { keys : [ "Space" ] , modifiers : null , delay : 100 } ) ;
92
+ }
84
93
85
- // now send a message with no keys down to "release" the keys
86
- await sendKeystroke ( { modifier : 0 , keys : [ ] } ) ;
94
+ if ( macroSteps . length > 0 ) {
95
+ await executeMacro ( macroSteps ) ;
87
96
}
88
97
} catch ( error ) {
89
98
console . error ( "Failed to paste text:" , error ) ;
90
99
notifications . error ( "Failed to paste text" ) ;
91
100
}
92
-
93
- async function sendKeystroke ( stroke : KeyStroke ) {
94
- await new Promise < void > ( ( resolve , reject ) => {
95
- send (
96
- "keyboardReport" ,
97
- hidKeyboardPayload ( stroke . modifier , stroke . keys ) ,
98
- params => {
99
- if ( "error" in params ) return reject ( params . error ) ;
100
- resolve ( ) ;
101
- }
102
- ) ;
103
- } ) ;
104
- }
105
- } , [ selectedKeyboard , rpcDataChannel ?. readyState , send , setDisableVideoFocusTrap , setPasteModeEnabled ] ) ;
101
+ } , [ selectedKeyboard , executeMacro ] ) ;
106
102
107
103
useEffect ( ( ) => {
108
104
if ( TextAreaRef . current ) {
@@ -122,14 +118,18 @@ export default function PasteModal() {
122
118
/>
123
119
124
120
< div
125
- className = "animate-fadeIn opacity-0 space-y-2"
121
+ className = "animate-fadeIn space-y-2 opacity-0 "
126
122
style = { {
127
123
animationDuration : "0.7s" ,
128
124
animationDelay : "0.1s" ,
129
125
} }
130
126
>
131
127
< div >
132
- < div className = "w-full" onKeyUp = { e => e . stopPropagation ( ) } onKeyDown = { e => e . stopPropagation ( ) } >
128
+ < div
129
+ className = "w-full"
130
+ onKeyUp = { e => e . stopPropagation ( ) }
131
+ onKeyDown = { e => e . stopPropagation ( ) }
132
+ >
133
133
< TextAreaWithLabel
134
134
ref = { TextAreaRef }
135
135
label = "Paste from host"
@@ -173,15 +173,16 @@ export default function PasteModal() {
173
173
</ div >
174
174
< div className = "space-y-4" >
175
175
< p className = "text-xs text-slate-600 dark:text-slate-400" >
176
- Sending text using keyboard layout: { selectedKeyboard . isoCode } -{ selectedKeyboard . name }
176
+ Sending text using keyboard layout: { selectedKeyboard . isoCode } -
177
+ { selectedKeyboard . name }
177
178
</ p >
178
179
</ div >
179
180
</ div >
180
181
</ div >
181
182
</ div >
182
183
</ div >
183
184
< div
184
- className = "flex animate-fadeIn opacity-0 items-center justify-end gap-x-2"
185
+ className = "flex animate-fadeIn items-center justify-end gap-x-2 opacity-0 "
185
186
style = { {
186
187
animationDuration : "0.7s" ,
187
188
animationDelay : "0.2s" ,
0 commit comments