@@ -188,6 +188,11 @@ use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::{
188188 zwp_virtual_keyboard_v1:: ZwpVirtualKeyboardV1 ,
189189} ;
190190
191+ use wayland_protocols:: wp:: text_input:: zv3:: client:: {
192+ zwp_text_input_manager_v3:: ZwpTextInputManagerV3 ,
193+ zwp_text_input_v3:: { self , ContentHint , ContentPurpose , ZwpTextInputV3 } ,
194+ } ;
195+
191196pub use calloop;
192197
193198use calloop:: {
@@ -571,6 +576,18 @@ impl<T> WindowStateUnit<T> {
571576 }
572577}
573578
579+ #[ derive( Debug , PartialEq , Eq , Clone , Copy , Hash ) ]
580+ pub enum ImePurpose {
581+ /// No special hints for the IME (default).
582+ Normal ,
583+ /// The IME is used for password input.
584+ Password ,
585+ /// The IME is used to input into a terminal.
586+ ///
587+ /// For example, that could alter OSK on Wayland to show extra buttons.
588+ Terminal ,
589+ }
590+
574591/// main state, store the main information
575592#[ derive( Debug ) ]
576593pub struct WindowState < T > {
@@ -627,6 +644,12 @@ pub struct WindowState<T> {
627644 start_mode : StartMode ,
628645 init_finished : bool ,
629646 events_transparent : bool ,
647+
648+ text_input_manager : Option < ZwpTextInputManagerV3 > ,
649+ text_input : Option < ZwpTextInputV3 > ,
650+ text_inputs : Vec < ZwpTextInputV3 > ,
651+ ime_purpose : ImePurpose ,
652+ ime_allowed : bool ,
630653}
631654
632655impl < T > WindowState < T > {
@@ -776,6 +799,44 @@ impl<T> WindowState<T> {
776799 pub fn is_with_target ( & self ) -> bool {
777800 self . start_mode . is_with_target ( )
778801 }
802+ pub fn ime_allowed ( & self ) -> bool {
803+ self . ime_allowed
804+ }
805+ pub fn set_ime_allowed ( & mut self , ime_allowed : bool ) {
806+ self . ime_allowed = ime_allowed
807+ }
808+
809+ #[ inline]
810+ pub fn text_input_entered ( & mut self , text_input : & ZwpTextInputV3 ) {
811+ if !self . text_inputs . iter ( ) . any ( |t| t == text_input) {
812+ self . text_inputs . push ( text_input. clone ( ) ) ;
813+ }
814+ }
815+ #[ inline]
816+ pub fn text_input_left ( & mut self , text_input : & ZwpTextInputV3 ) {
817+ if let Some ( position) = self . text_inputs . iter ( ) . position ( |t| t == text_input) {
818+ self . text_inputs . remove ( position) ;
819+ }
820+ }
821+
822+ fn ime_purpose ( & self ) -> ImePurpose {
823+ self . ime_purpose
824+ }
825+ }
826+
827+ pub trait ZwpTextInputV3Ext {
828+ fn set_content_type_by_purpose ( & self , purpose : ImePurpose ) ;
829+ }
830+
831+ impl ZwpTextInputV3Ext for ZwpTextInputV3 {
832+ fn set_content_type_by_purpose ( & self , purpose : ImePurpose ) {
833+ let ( hint, purpose) = match purpose {
834+ ImePurpose :: Normal => ( ContentHint :: None , ContentPurpose :: Normal ) ,
835+ ImePurpose :: Password => ( ContentHint :: SensitiveData , ContentPurpose :: Password ) ,
836+ ImePurpose :: Terminal => ( ContentHint :: None , ContentPurpose :: Terminal ) ,
837+ } ;
838+ self . set_content_type ( hint, purpose) ;
839+ }
779840}
780841
781842impl WindowWrapper {
@@ -1007,6 +1068,12 @@ impl<T> Default for WindowState<T> {
10071068 start_mode : StartMode :: Active ,
10081069 init_finished : false ,
10091070 events_transparent : false ,
1071+
1072+ text_input_manager : None ,
1073+ text_input : None ,
1074+ text_inputs : Vec :: new ( ) ,
1075+ ime_purpose : ImePurpose :: Normal ,
1076+ ime_allowed : false ,
10101077 }
10111078 }
10121079}
@@ -1771,6 +1838,55 @@ impl<T> Dispatch<wp_fractional_scale_v1::WpFractionalScaleV1, ()> for WindowStat
17711838 }
17721839}
17731840
1841+ impl < T > Dispatch < zwp_text_input_v3:: ZwpTextInputV3 , ( ) > for WindowState < T > {
1842+ fn event (
1843+ state : & mut Self ,
1844+ text_input : & zwp_text_input_v3:: ZwpTextInputV3 ,
1845+ event : <zwp_text_input_v3:: ZwpTextInputV3 as Proxy >:: Event ,
1846+ data : & ( ) ,
1847+ conn : & Connection ,
1848+ qhandle : & QueueHandle < Self > ,
1849+ ) {
1850+ use zwp_text_input_v3:: Event ;
1851+ match event {
1852+ Event :: Enter { surface } => {
1853+ let Some ( id) = state. get_id_from_surface ( & surface) else {
1854+ return ;
1855+ } ;
1856+ if state. ime_allowed ( ) {
1857+ text_input. enable ( ) ;
1858+ text_input. set_content_type_by_purpose ( state. ime_purpose ( ) ) ;
1859+ text_input. commit ( ) ;
1860+ state
1861+ . message
1862+ . push ( ( Some ( id) , DispatchMessageInner :: Ime ( events:: Ime :: Enabled ) ) ) ;
1863+ }
1864+ state. text_input_entered ( text_input) ;
1865+ }
1866+ Event :: Leave { surface } => {
1867+ text_input. disable ( ) ;
1868+ text_input. commit ( ) ;
1869+ let Some ( id) = state. get_id_from_surface ( & surface) else {
1870+ return ;
1871+ } ;
1872+ state. text_input_left ( text_input) ;
1873+ state
1874+ . message
1875+ . push ( ( Some ( id) , DispatchMessageInner :: Ime ( events:: Ime :: Disabled ) ) ) ;
1876+ }
1877+ Event :: CommitString { text } => { }
1878+ Event :: DeleteSurroundingText { .. } => { }
1879+ Event :: Done { serial } => { }
1880+ Event :: PreeditString {
1881+ text,
1882+ cursor_begin,
1883+ cursor_end,
1884+ } => { }
1885+ _ => { }
1886+ }
1887+ }
1888+ }
1889+
17741890delegate_noop ! ( @<T > WindowState <T >: ignore WlCompositor ) ; // WlCompositor is need to create a surface
17751891delegate_noop ! ( @<T > WindowState <T >: ignore WlSurface ) ; // surface is the base needed to show buffer
17761892delegate_noop ! ( @<T > WindowState <T >: ignore WlOutput ) ; // output is need to place layer_shell, although here
@@ -1796,6 +1912,8 @@ delegate_noop!(@<T> WindowState<T>: ignore WpFractionalScaleManagerV1);
17961912delegate_noop ! ( @<T > WindowState <T >: ignore XdgPositioner ) ;
17971913delegate_noop ! ( @<T > WindowState <T >: ignore XdgWmBase ) ;
17981914
1915+ delegate_noop ! ( @<T > WindowState <T >: ignore ZwpTextInputManagerV3 ) ;
1916+
17991917impl < T : ' static > WindowState < T > {
18001918 /// build a new WindowState
18011919 pub fn build ( mut self ) -> Result < Self , LayerEventError > {
@@ -1839,6 +1957,12 @@ impl<T: 'static> WindowState<T> {
18391957 let fractional_scale_manager = globals
18401958 . bind :: < WpFractionalScaleManagerV1 , _ , _ > ( & qh, 1 ..=1 , ( ) )
18411959 . ok ( ) ;
1960+ let text_input_manager = globals
1961+ . bind :: < ZwpTextInputManagerV3 , _ , _ > ( & qh, 1 ..=1 , ( ) )
1962+ . ok ( ) ;
1963+ let text_input = text_input_manager
1964+ . as_ref ( )
1965+ . map ( |manager| manager. get_text_input ( self . get_seat ( ) , & qh, ( ) ) ) ;
18421966
18431967 event_queue. blocking_dispatch ( & mut self ) ?; // then make a dispatch
18441968
@@ -2022,6 +2146,9 @@ impl<T: 'static> WindowState<T> {
20222146 self . xdg_output_manager = Some ( xdg_output_manager) ;
20232147 self . connection = Some ( connection) ;
20242148
2149+ self . text_input = text_input;
2150+ self . text_input_manager = text_input_manager;
2151+
20252152 Ok ( self )
20262153 }
20272154 /// main event loop, every time dispatch, it will store the messages, and do callback. it will
0 commit comments