@@ -10,11 +10,11 @@ import { SettingsPageHeader } from "@components/SettingsPageheader";
1010import { useJsonRpc } from "@/hooks/useJsonRpc" ;
1111import { useHidStore , useRTCStore , useUiStore , useSettingsStore } from "@/hooks/stores" ;
1212import { keys , modifiers } from "@/keyboardMappings" ;
13- import { layouts , chars } from "@/keyboardLayouts" ;
13+ import { KeyStroke , KeyboardLayout , selectedKeyboard } from "@/keyboardLayouts" ;
1414import notifications from "@/notifications" ;
1515
16- const hidKeyboardPayload = ( keys : number [ ] , modifier : number ) => {
17- return { keys , modifier } ;
16+ const hidKeyboardPayload = ( modifier : number , keys : number [ ] ) => {
17+ return { modifier , keys } ;
1818} ;
1919
2020const modifierCode = ( shift ?: boolean , altRight ?: boolean ) => {
@@ -62,49 +62,56 @@ export default function PasteModal() {
6262 const onConfirmPaste = useCallback ( async ( ) => {
6363 setPasteMode ( false ) ;
6464 setDisableVideoFocusTrap ( false ) ;
65+
6566 if ( rpcDataChannel ?. readyState !== "open" || ! TextAreaRef . current ) return ;
66- if ( ! safeKeyboardLayout ) return ;
67- if ( ! chars [ safeKeyboardLayout ] ) return ;
67+ const keyboard : KeyboardLayout = selectedKeyboard ( safeKeyboardLayout ) ;
68+ if ( ! keyboard ) return ;
69+
6870 const text = TextAreaRef . current . value ;
6971
7072 try {
7173 for ( const char of text ) {
72- const { key , shift , altRight , deadKey , accentKey } = chars [ safeKeyboardLayout ] [ char ]
73- if ( ! key ) continue ;
74+ const keyprops = keyboard . chars [ char ] ;
75+ if ( ! keyprops ) continue ;
7476
75- const keyz = [ keys [ key ] ] ;
76- const modz = [ modifierCode ( shift , altRight ) ] ;
77+ const { key , shift , altRight , deadKey , accentKey } = keyprops ;
78+ if ( ! key ) continue ;
7779
78- if ( deadKey ) {
79- keyz . push ( keys [ "Space" ] ) ;
80- modz . push ( noModifier ) ;
81- }
80+ // if this is an accented character, we need to send that accent FIRST
8281 if ( accentKey ) {
83- keyz . unshift ( keys [ accentKey . key ] )
84- modz . unshift ( modifierCode ( accentKey . shift , accentKey . altRight ) )
82+ await sendKeystroke ( { modifier : modifierCode ( accentKey . shift , accentKey . altRight ) , keys : [ keys [ accentKey . key ] ] } )
8583 }
8684
87- for ( const [ index , kei ] of keyz . entries ( ) ) {
88- await new Promise < void > ( ( resolve , reject ) => {
89- send (
90- "keyboardReport" ,
91- hidKeyboardPayload ( [ kei ] , modz [ index ] ) ,
92- params => {
93- if ( "error" in params ) return reject ( params . error ) ;
94- send ( "keyboardReport" , hidKeyboardPayload ( [ ] , 0 ) , params => {
95- if ( "error" in params ) return reject ( params . error ) ;
96- resolve ( ) ;
97- } ) ;
98- } ,
99- ) ;
100- } ) ;
85+ // now send the actual key
86+ await sendKeystroke ( { modifier : modifierCode ( shift , altRight ) , keys : [ keys [ key ] ] } ) ;
87+
88+ // if what was requested was a dead key, we need to send an unmodified space to emit
89+ // just the accent character
90+ if ( deadKey ) {
91+ await sendKeystroke ( { modifier : noModifier , keys : [ keys [ "Space" ] ] } ) ;
10192 }
93+
94+ // now send a message with no keys down to "release" the keys
95+ await sendKeystroke ( { modifier : 0 , keys : [ ] } ) ;
10296 }
10397 } catch ( error ) {
104- console . error ( error ) ;
98+ console . error ( "Failed to paste text:" , error ) ;
10599 notifications . error ( "Failed to paste text" ) ;
106100 }
107- } , [ rpcDataChannel ?. readyState , send , setDisableVideoFocusTrap , setPasteMode , safeKeyboardLayout ] ) ;
101+
102+ async function sendKeystroke ( stroke : KeyStroke ) {
103+ await new Promise < void > ( ( resolve , reject ) => {
104+ send (
105+ "keyboardReport" ,
106+ hidKeyboardPayload ( stroke . modifier , stroke . keys ) ,
107+ params => {
108+ if ( "error" in params ) return reject ( params . error ) ;
109+ resolve ( ) ;
110+ }
111+ ) ;
112+ } ) ;
113+ }
114+ } , [ rpcDataChannel ?. readyState , safeKeyboardLayout , send , setDisableVideoFocusTrap , setPasteMode ] ) ;
108115
109116 useEffect ( ( ) => {
110117 if ( TextAreaRef . current ) {
@@ -154,7 +161,7 @@ export default function PasteModal() {
154161 // @ts -expect-error TS doesn't recognize Intl.Segmenter in some environments
155162 [ ...new Intl . Segmenter ( ) . segment ( value ) ]
156163 . map ( x => x . segment )
157- . filter ( char => ! chars [ safeKeyboardLayout ] [ char ] ) ,
164+ . filter ( char => ! selectedKeyboard ( safeKeyboardLayout ) . chars [ char ] ) ,
158165 ) ,
159166 ] ;
160167
@@ -175,7 +182,7 @@ export default function PasteModal() {
175182 </ div >
176183 < div className = "space-y-4" >
177184 < p className = "text-xs text-slate-600 dark:text-slate-400" >
178- Sending text using keyboard layout: { layouts [ safeKeyboardLayout ] }
185+ Sending text using keyboard layout: { selectedKeyboard ( safeKeyboardLayout ) . name }
179186 </ p >
180187 </ div >
181188 </ div >
0 commit comments