@@ -8,35 +8,24 @@ import { GridCard } from "@components/Card";
88import { TextAreaWithLabel } from "@components/TextArea" ;
99import { SettingsPageHeader } from "@components/SettingsPageheader" ;
1010import { 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" ;
1413import useKeyboardLayout from "@/hooks/useKeyboardLayout" ;
1514import notifications from "@/notifications" ;
1615
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-
2716export default function PasteModal ( ) {
2817 const TextAreaRef = useRef < HTMLTextAreaElement > ( null ) ;
2918 const { setPasteModeEnabled } = useHidStore ( ) ;
3019 const { setDisableVideoFocusTrap } = useUiStore ( ) ;
3120
3221 const { send } = useJsonRpc ( ) ;
33- const { rpcDataChannel } = useRTCStore ( ) ;
22+ const { executeMacro } = useKeyboard ( ) ;
3423
3524 const [ invalidChars , setInvalidChars ] = useState < string [ ] > ( [ ] ) ;
3625 const close = useClose ( ) ;
3726
3827 const { setKeyboardLayout } = useSettingsStore ( ) ;
39- const { selectedKeyboard } = useKeyboardLayout ( ) ;
28+ const { selectedKeyboard } = useKeyboardLayout ( ) ;
4029
4130 useEffect ( ( ) => {
4231 send ( "getKeyboardLayout" , { } , ( resp : JsonRpcResponse ) => {
@@ -52,15 +41,20 @@ export default function PasteModal() {
5241 } , [ setDisableVideoFocusTrap , setPasteModeEnabled ] ) ;
5342
5443 const onConfirmPaste = useCallback ( async ( ) => {
55- setPasteModeEnabled ( false ) ;
56- setDisableVideoFocusTrap ( false ) ;
44+ // setPasteModeEnabled(false);
45+ // setDisableVideoFocusTrap(false);
5746
58- if ( rpcDataChannel ?. readyState !== "open" || ! TextAreaRef . current ) return ;
59- if ( ! selectedKeyboard ) return ;
47+ if ( ! TextAreaRef . current || ! selectedKeyboard ) return ;
6048
6149 const text = TextAreaRef . current . value ;
6250
6351 try {
52+ const macroSteps : {
53+ keys : string [ ] | null ;
54+ modifiers : string [ ] | null ;
55+ delay : number ;
56+ } [ ] = [ ] ;
57+
6458 for ( const char of text ) {
6559 const keyprops = selectedKeyboard . chars [ char ] ;
6660 if ( ! keyprops ) continue ;
@@ -70,39 +64,41 @@ export default function PasteModal() {
7064
7165 // if this is an accented character, we need to send that accent FIRST
7266 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+ } ) ;
7476 }
7577
7678 // 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+ } ) ;
7888
7989 // if what was requested was a dead key, we need to send an unmodified space to emit
8090 // 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+ }
8493
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 ) ;
8796 }
8897 } catch ( error ) {
8998 console . error ( "Failed to paste text:" , error ) ;
9099 notifications . error ( "Failed to paste text" ) ;
91100 }
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 ] ) ;
106102
107103 useEffect ( ( ) => {
108104 if ( TextAreaRef . current ) {
@@ -122,14 +118,18 @@ export default function PasteModal() {
122118 />
123119
124120 < div
125- className = "animate-fadeIn opacity-0 space-y-2"
121+ className = "animate-fadeIn space-y-2 opacity-0 "
126122 style = { {
127123 animationDuration : "0.7s" ,
128124 animationDelay : "0.1s" ,
129125 } }
130126 >
131127 < 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+ >
133133 < TextAreaWithLabel
134134 ref = { TextAreaRef }
135135 label = "Paste from host"
@@ -173,15 +173,16 @@ export default function PasteModal() {
173173 </ div >
174174 < div className = "space-y-4" >
175175 < 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 }
177178 </ p >
178179 </ div >
179180 </ div >
180181 </ div >
181182 </ div >
182183 </ div >
183184 < 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 "
185186 style = { {
186187 animationDuration : "0.7s" ,
187188 animationDelay : "0.2s" ,
0 commit comments