@@ -134,6 +134,15 @@ enum InputModeChoice {
134134 Family ( & ' static [ protocol:: Persona ] ) ,
135135}
136136
137+ impl InputModeChoice {
138+ fn bluetooth_persona ( self ) -> Option < protocol:: Persona > {
139+ match self {
140+ Self :: Persona ( persona) if persona. is_bluetooth ( ) => Some ( persona) ,
141+ _ => None ,
142+ }
143+ }
144+ }
145+
137146async fn scan_pico_inventory ( ) -> Result < PicoInventory > {
138147 let mut inventory = PicoInventory :: default ( ) ;
139148 match cmd_run:: discover_picos ( Duration :: from_secs ( HOME_SCAN_SECONDS ) ) . await {
@@ -473,7 +482,7 @@ fn missing_saved_card(pico: config::PicoIdentity) -> PicoCard {
473482impl PicoAction {
474483 fn label ( & self ) -> String {
475484 match self {
476- Self :: StartStreaming { .. } => "Start streaming with Controller 1 " . to_string ( ) ,
485+ Self :: StartStreaming { .. } => "Start streaming" . to_string ( ) ,
477486 Self :: ChooseRouting { .. } => "Choose controller and stream" . to_string ( ) ,
478487 Self :: CheckUsbAdapter { .. } => "Check console USB adapter" . to_string ( ) ,
479488 Self :: SwitchToUsbDebug { .. } => "Switch to USB debug mode" . to_string ( ) ,
@@ -804,13 +813,22 @@ fn print_xinput_sources() {
804813async fn route_one ( picos : Vec < cmd_run:: PicoTarget > ) -> Result < ( ) > {
805814 let pico_items: Vec < String > = picos. iter ( ) . map ( |p| p. detail_label ( ) ) . collect ( ) ;
806815 let pico_index = select ( "Which Pico should receive the controller?" , & pico_items, 0 ) . await ?;
816+ let pico = picos[ pico_index] . clone ( ) ;
817+ let mode = choose_input_mode ( ) . await ?;
818+ if mode. bluetooth_persona ( ) . is_some ( ) {
819+ let routes = vec ! [ cmd_run:: StreamRoute {
820+ source_slot: 0 ,
821+ pico,
822+ } ] ;
823+ let routes = prepare_routes_for_input_mode ( routes, mode) . await ?;
824+ let routes = choose_bluetooth_source_slots ( routes) . await ?;
825+ return start_stream ( routes, true ) . await ;
826+ }
827+
807828 let source_slot =
808829 choose_source_slot ( "Which Windows controller should feed that Pico?" , None ) . await ?;
809- let routes = vec ! [ cmd_run:: StreamRoute {
810- source_slot,
811- pico: picos[ pico_index] . clone( ) ,
812- } ] ;
813- stream ( routes, true ) . await
830+ let routes = vec ! [ cmd_run:: StreamRoute { source_slot, pico } ] ;
831+ stream_with_mode ( routes, mode, true ) . await
814832}
815833
816834async fn choose_source_slot ( prompt : & str , default_slot : Option < u32 > ) -> Result < u32 > {
@@ -829,7 +847,24 @@ fn slot_item(slot: u32) -> String {
829847
830848async fn stream ( routes : Vec < cmd_run:: StreamRoute > , save : bool ) -> Result < ( ) > {
831849 let mode = choose_input_mode ( ) . await ?;
850+ stream_with_mode ( routes, mode, save) . await
851+ }
852+
853+ async fn stream_with_mode (
854+ routes : Vec < cmd_run:: StreamRoute > ,
855+ mode : InputModeChoice ,
856+ save : bool ,
857+ ) -> Result < ( ) > {
832858 let routes = prepare_routes_for_input_mode ( routes, mode) . await ?;
859+ let routes = if mode. bluetooth_persona ( ) . is_some ( ) {
860+ choose_bluetooth_source_slots ( routes) . await ?
861+ } else {
862+ routes
863+ } ;
864+ start_stream ( routes, save) . await
865+ }
866+
867+ async fn start_stream ( routes : Vec < cmd_run:: StreamRoute > , save : bool ) -> Result < ( ) > {
833868 println ! ( ) ;
834869 println ! ( "Ready to stream:" ) ;
835870 for route in & routes {
@@ -849,6 +884,35 @@ async fn stream(routes: Vec<cmd_run::StreamRoute>, save: bool) -> Result<()> {
849884 . await
850885}
851886
887+ async fn choose_bluetooth_source_slots (
888+ mut routes : Vec < cmd_run:: StreamRoute > ,
889+ ) -> Result < Vec < cmd_run:: StreamRoute > > {
890+ let targets: Vec < _ > = routes. iter ( ) . map ( |route| route. pico . clone ( ) ) . collect ( ) ;
891+ cmd_persona:: wait_for_bluetooth_xinput_release ( & targets, false ) . await ?;
892+
893+ print_xinput_sources ( ) ;
894+ if routes. len ( ) == 1 {
895+ routes[ 0 ] . source_slot = choose_source_slot (
896+ "Which Windows controller should feed that Bluetooth Pico?" ,
897+ Some ( routes[ 0 ] . source_slot ) ,
898+ )
899+ . await ?;
900+ return Ok ( routes) ;
901+ }
902+
903+ for route in & mut routes {
904+ route. source_slot = choose_source_slot (
905+ & format ! (
906+ "Which Windows controller should feed {}?" ,
907+ route. pico. short_label( )
908+ ) ,
909+ Some ( route. source_slot ) ,
910+ )
911+ . await ?;
912+ }
913+ Ok ( routes)
914+ }
915+
852916async fn choose_input_mode ( ) -> Result < InputModeChoice > {
853917 let choices = vec ! [
854918 menu_item(
0 commit comments