@@ -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 ) => {
@@ -57,47 +57,53 @@ export default function PasteModal() {
5757 setDisableVideoFocusTrap ( false ) ;
5858 if ( rpcDataChannel ?. readyState !== "open" || ! TextAreaRef . current ) return ;
5959 if ( ! keyboardLayout ) return ;
60- if ( ! chars [ keyboardLayout ] ) return ;
60+ const keyboard : KeyboardLayout = selectedKeyboard ( keyboardLayout ) ;
61+ if ( ! keyboard ) return ;
6162
6263 const text = TextAreaRef . current . value ;
6364
6465 try {
6566 for ( const char of text ) {
66- const { key, shift, altRight, deadKey, accentKey } = chars [ keyboardLayout ] [ char ]
67+ const keyprops = keyboard . chars [ char ] ;
68+ if ( ! keyprops ) continue ;
69+
70+ const { key, shift, altRight, deadKey, accentKey } = keyprops ;
6771 if ( ! key ) continue ;
6872
69- const keyz = [ keys [ key ] ] ;
70- const modz = [ modifierCode ( shift , altRight ) ] ;
71-
72- if ( deadKey ) {
73- keyz . push ( keys [ "Space" ] ) ;
74- modz . push ( noModifier ) ;
75- }
76- if ( accentKey ) {
77- keyz . unshift ( keys [ accentKey . key ] )
78- modz . unshift ( modifierCode ( accentKey . shift , accentKey . altRight ) )
79- }
80-
81- for ( const [ index , kei ] of keyz . entries ( ) ) {
82- await new Promise < void > ( ( resolve , reject ) => {
83- send (
84- "keyboardReport" ,
85- hidKeyboardPayload ( [ kei ] , modz [ index ] ) ,
86- params => {
87- if ( "error" in params ) return reject ( params . error ) ;
88- send ( "keyboardReport" , hidKeyboardPayload ( [ ] , 0 ) , params => {
89- if ( "error" in params ) return reject ( params . error ) ;
90- resolve ( ) ;
91- } ) ;
92- } ,
93- ) ;
94- } ) ;
95- }
73+ // if this is an accented character, we need to send that accent FIRST
74+ if ( accentKey ) {
75+ await sendKeystroke ( { modifier : modifierCode ( accentKey . shift , accentKey . altRight ) , keys : [ keys [ accentKey . key ] ] } )
76+ }
77+
78+ // now send the actual key
79+ await sendKeystroke ( { modifier : modifierCode ( shift , altRight ) , keys : [ keys [ key ] ] } ) ;
80+
81+ // if what was requested was a dead key, we need to send an unmodified space to emit
82+ // just the accent character
83+ if ( deadKey ) {
84+ await sendKeystroke ( { modifier : noModifier , keys : [ keys [ "Space" ] ] } ) ;
85+ }
86+
87+ // now send a message with no keys down to "release" the keys
88+ await sendKeystroke ( { modifier : 0 , keys : [ ] } ) ;
9689 }
9790 } catch ( error ) {
98- console . error ( error ) ;
91+ console . error ( "Failed to paste text:" , error ) ;
9992 notifications . error ( "Failed to paste text" ) ;
10093 }
94+
95+ async function sendKeystroke ( stroke : KeyStroke ) {
96+ await new Promise < void > ( ( resolve , reject ) => {
97+ send (
98+ "keyboardReport" ,
99+ hidKeyboardPayload ( stroke . modifier , stroke . keys ) ,
100+ params => {
101+ if ( "error" in params ) return reject ( params . error ) ;
102+ resolve ( ) ;
103+ }
104+ ) ;
105+ } ) ;
106+ }
101107 } , [ rpcDataChannel ?. readyState , send , setDisableVideoFocusTrap , setPasteMode , keyboardLayout ] ) ;
102108
103109 useEffect ( ( ) => {
@@ -148,7 +154,7 @@ export default function PasteModal() {
148154 // @ts -expect-error TS doesn't recognize Intl.Segmenter in some environments
149155 [ ...new Intl . Segmenter ( ) . segment ( value ) ]
150156 . map ( x => x . segment )
151- . filter ( char => ! chars [ keyboardLayout ] [ char ] ) ,
157+ . filter ( char => ! selectedKeyboard ( keyboardLayout ) . chars [ char ] ) ,
152158 ) ,
153159 ] ;
154160
@@ -167,11 +173,11 @@ export default function PasteModal() {
167173 ) }
168174 </ div >
169175 </ div >
170- < div className = "space-y-4" >
176+ < div className = "space-y-4" >
171177 < p className = "text-xs text-slate-600 dark:text-slate-400" >
172- Sending text using keyboard layout: { layouts [ keyboardLayout ] }
178+ Sending text using keyboard layout: { selectedKeyboard ( keyboardLayout ) . name }
173179 </ p >
174- </ div >
180+ </ div >
175181 </ div >
176182 </ div >
177183 </ div >
0 commit comments