11use crate :: Irqs ;
22use crate :: config:: CONFIG ;
3- use crate :: keyboard:: { Key , KeyReport , KeyState } ;
3+ use crate :: keyboard:: { Key , KeyReport , KeyState , Modifiers } ;
44use crate :: net:: alloc:: string:: ToString ;
55use crate :: process:: { LineEditor , Process , assign_proc, assign_proc_if} ;
66use crate :: rng:: WezTermRng ;
@@ -22,6 +22,7 @@ use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
2222use embassy_sync:: channel:: Channel ;
2323use embassy_sync:: lazy_lock:: LazyLock ;
2424use embassy_sync:: mutex:: Mutex ;
25+ use embassy_time:: { Duration , with_timeout} ;
2526use embedded_io_async:: { Read , Write as _} ;
2627use rand_core:: RngCore ;
2728use static_cell:: StaticCell ;
@@ -141,8 +142,11 @@ pub async fn setup_wifi(
141142 STACK . get ( ) . lock ( ) . await . replace ( stack) ;
142143}
143144
145+ const TIMEOUT_DURATION : Duration = Duration :: from_secs ( 10 ) ;
146+
144147async fn ssh_channel_task ( mut channel : ChanInOut < ' _ , ' _ > , key_rx : Arc < Channel < CS , KeyReport , 4 > > ) {
145148 log:: info!( "ssh_channel_task waiting for output" ) ;
149+
146150 loop {
147151 let mut buf = [ 0u8 ; 1024 ] ;
148152
@@ -166,24 +170,73 @@ async fn ssh_channel_task(mut channel: ChanInOut<'_, '_>, key_rx: Arc<Channel<CS
166170 Either :: Second ( key_report) => {
167171 // Encode a key with xterm style keyboard encoding.
168172 // FIXME: woefully incomplete!
173+
174+ if key_report. modifiers == Modifiers :: CTRL {
175+ if let Key :: Char ( c) = key_report. key {
176+ if let Some ( mapped) = ctrl_mapping ( c) {
177+ log:: info!(
178+ "doing mapped ctrl {} -> {}" ,
179+ c. escape_debug( ) ,
180+ mapped. escape_debug( )
181+ ) ;
182+ let mut buf = [ 0u8 ; 4 ] ;
183+ log:: info!(
184+ "{:?}" ,
185+ with_timeout(
186+ TIMEOUT_DURATION ,
187+ channel. write_all( mapped. encode_utf8( & mut buf) . as_bytes( ) ) ,
188+ )
189+ . await
190+ ) ;
191+ continue ;
192+ }
193+ }
194+ }
195+
196+ if key_report. modifiers == Modifiers :: ALT {
197+ // Alt sends escape first
198+ log:: info!( "ALT -> send escape first" ) ;
199+ log:: info!(
200+ "{:?}" ,
201+ with_timeout( TIMEOUT_DURATION , channel. write_all( b"\x1b " ) ) . await
202+ ) ;
203+ }
204+
169205 if let Key :: Char ( c) = key_report. key {
170206 let mut buf = [ 0u8 ; 4 ] ;
171- channel
172- . write_all ( c. encode_utf8 ( & mut buf) . as_bytes ( ) )
207+ log:: info!( "just sending {} as-is" , c. escape_debug( ) ) ;
208+ log:: info!(
209+ "{:?}" ,
210+ with_timeout(
211+ TIMEOUT_DURATION ,
212+ channel. write_all( c. encode_utf8( & mut buf) . as_bytes( ) ) ,
213+ )
173214 . await
174- . ok ( ) ;
215+ ) ;
175216 } else {
176217 let text = match key_report. key {
177218 Key :: Enter => "\n " ,
178219 Key :: BackSpace => "\u{7f} " ,
179220 Key :: Tab => "\t " ,
180221 Key :: Escape => "\u{1b} " ,
222+ Key :: Up => "\u{1b} [A" ,
223+ Key :: Down => "\u{1b} [B" ,
224+ Key :: Right => "\u{1b} [C" ,
225+ Key :: Left => "\u{1b} [D" ,
226+ Key :: Home => "\u{1b} [H" ,
227+ Key :: End => "\u{1b} [F" ,
228+ Key :: PageUp => "\u{1b} [5~" ,
229+ Key :: PageDown => "\u{1b} [6~" ,
181230 Key :: None | Key :: Char ( _) => continue ,
182231 _ => {
183232 continue ;
184233 }
185234 } ;
186- channel. write_all ( text. as_bytes ( ) ) . await . ok ( ) ;
235+ log:: info!( "{key_report:?} -> {}" , text. escape_debug( ) ) ;
236+ log:: info!(
237+ "{:?}" ,
238+ with_timeout( TIMEOUT_DURATION , channel. write_all( text. as_bytes( ) ) ) . await
239+ ) ;
187240 }
188241 }
189242 }
@@ -216,7 +269,6 @@ async fn ssh_session_task(host: String, command: Option<String>) {
216269 . await
217270 {
218271 Ok ( ( ) ) => {
219- use embassy_futures:: join:: * ;
220272 use embassy_futures:: select:: * ;
221273
222274 let key_channel = Arc :: new ( Channel :: new ( ) ) ;
@@ -374,7 +426,7 @@ async fn ssh_session_task(host: String, command: Option<String>) {
374426 Ok :: < ( ) , sunset:: Error > ( ( ) )
375427 } ;
376428
377- let res = select ( runner, join ( ssh_ticker, spawn_session_future) ) . await ;
429+ let res = select ( runner, select ( ssh_ticker, spawn_session_future) ) . await ;
378430 log:: info!( "ssh result is {res:?}" ) ;
379431 assign_proc ( prior_proc) . await ;
380432 }
@@ -416,6 +468,9 @@ async fn prompt_for_input(prompt: &str, kind: PromptKind) -> Option<String> {
416468
417469 #[ async_trait:: async_trait( ?Send ) ]
418470 impl Process for PromptProc {
471+ fn name ( & self ) -> & str {
472+ "prompt"
473+ }
419474 async fn render ( & self ) {
420475 let mut screen = SCREEN . get ( ) . lock ( ) . await ;
421476 match self . kind {
@@ -496,6 +551,9 @@ struct SshProcess {
496551
497552#[ async_trait:: async_trait( ?Send ) ]
498553impl Process for SshProcess {
554+ fn name ( & self ) -> & str {
555+ "ssh"
556+ }
499557 async fn render ( & self ) { }
500558 fn un_prompt ( & self , _screen : & mut Screen ) { }
501559 async fn key_input ( & self , key : KeyReport ) {
@@ -534,3 +592,51 @@ async fn wifi_scanner(mut control: Control<'static>) {
534592 }
535593}
536594*/
595+
596+ /// Taken from wezterm-input-types
597+ /// Map c to its Ctrl equivalent.
598+ /// In theory, this mapping is simply translating alpha characters
599+ /// to upper case and then masking them by 0x1f, but xterm inherits
600+ /// some built-in translation from legacy X11 so that are some
601+ /// aliased mappings and a couple that might be technically tied
602+ /// to US keyboard layout (particularly the punctuation characters
603+ /// produced in combination with SHIFT) that may not be 100%
604+ /// the right thing to do here for users with non-US layouts.
605+ fn ctrl_mapping ( c : char ) -> Option < char > {
606+ Some ( match c {
607+ '@' | '`' | ' ' | '2' => '\x00' ,
608+ 'A' | 'a' => '\x01' ,
609+ 'B' | 'b' => '\x02' ,
610+ 'C' | 'c' => '\x03' ,
611+ 'D' | 'd' => '\x04' ,
612+ 'E' | 'e' => '\x05' ,
613+ 'F' | 'f' => '\x06' ,
614+ 'G' | 'g' => '\x07' ,
615+ 'H' | 'h' => '\x08' ,
616+ 'I' | 'i' => '\x09' ,
617+ 'J' | 'j' => '\x0a' ,
618+ 'K' | 'k' => '\x0b' ,
619+ 'L' | 'l' => '\x0c' ,
620+ 'M' | 'm' => '\x0d' ,
621+ 'N' | 'n' => '\x0e' ,
622+ 'O' | 'o' => '\x0f' ,
623+ 'P' | 'p' => '\x10' ,
624+ 'Q' | 'q' => '\x11' ,
625+ 'R' | 'r' => '\x12' ,
626+ 'S' | 's' => '\x13' ,
627+ 'T' | 't' => '\x14' ,
628+ 'U' | 'u' => '\x15' ,
629+ 'V' | 'v' => '\x16' ,
630+ 'W' | 'w' => '\x17' ,
631+ 'X' | 'x' => '\x18' ,
632+ 'Y' | 'y' => '\x19' ,
633+ 'Z' | 'z' => '\x1a' ,
634+ '[' | '3' | '{' => '\x1b' ,
635+ '\\' | '4' | '|' => '\x1c' ,
636+ ']' | '5' | '}' => '\x1d' ,
637+ '^' | '6' | '~' => '\x1e' ,
638+ '_' | '7' | '/' => '\x1f' ,
639+ '8' | '?' => '\x7f' , // `Delete`
640+ _ => return None ,
641+ } )
642+ }
0 commit comments