@@ -4,12 +4,13 @@ use std::rc::Rc;
44use std:: sync:: { Arc , Mutex } ;
55
66use dpi:: { LogicalPosition , PhysicalPosition , PhysicalSize } ;
7+ use js_sys:: { Array , Function , Reflect } ;
78use smol_str:: SmolStr ;
8- use wasm_bindgen:: JsCast ;
99use wasm_bindgen:: closure:: Closure ;
10+ use wasm_bindgen:: { JsCast , JsValue } ;
1011use web_sys:: {
11- CssStyleDeclaration , Document , Event , FocusEvent , HtmlCanvasElement , KeyboardEvent , Navigator ,
12- PointerEvent , WheelEvent ,
12+ CompositionEvent , CssStyleDeclaration , Document , Event , EventTarget , FocusEvent ,
13+ HtmlCanvasElement , KeyboardEvent , Navigator , PointerEvent , WheelEvent ,
1314} ;
1415use winit_core:: error:: RequestError ;
1516use winit_core:: event:: {
@@ -57,6 +58,9 @@ struct Handlers {
5758 on_intersect : Option < IntersectionObserverHandle > ,
5859 on_touch_end : Option < EventListenerHandle < dyn FnMut ( Event ) > > ,
5960 on_context_menu : Option < EventListenerHandle < dyn FnMut ( PointerEvent ) > > ,
61+ on_composition_start : Option < EventListenerHandle < dyn FnMut ( CompositionEvent ) > > ,
62+ on_composition_end : Option < EventListenerHandle < dyn FnMut ( CompositionEvent ) > > ,
63+ on_text_update : Option < EventListenerHandle < dyn FnMut ( Event ) > > ,
6064}
6165
6266pub struct Common {
@@ -67,6 +71,7 @@ pub struct Common {
6771 /// the DPI factor is maintained. Note: this is read-only because we use a pointer to this
6872 /// for [`WindowHandle`][rwh_06::WindowHandle].
6973 raw : Rc < HtmlCanvasElement > ,
74+ raw_edit_context : Option < Rc < JsValue > > ,
7075 style : Style ,
7176 old_size : Rc < Cell < PhysicalSize < u32 > > > ,
7277 current_size : Rc < Cell < PhysicalSize < u32 > > > ,
@@ -102,6 +107,15 @@ impl Canvas {
102107 . unchecked_into ( ) ,
103108 } ;
104109
110+ let edit_context = if let Ok ( edit_context_ctor) =
111+ Reflect :: get ( & window, & JsValue :: from_str ( "EditContext" ) )
112+ {
113+ let edit_context_ctor = JsCast :: unchecked_ref :: < js_sys:: Function > ( & edit_context_ctor) ;
114+ Reflect :: construct ( & edit_context_ctor, & Array :: new ( ) ) . ok ( )
115+ } else {
116+ None
117+ } ;
118+
105119 if web_attributes. append && !document. contains ( Some ( & canvas) ) {
106120 document
107121 . body ( )
@@ -130,6 +144,7 @@ impl Canvas {
130144 document : document. clone ( ) ,
131145 navigator,
132146 raw : Rc :: new ( canvas. clone ( ) ) ,
147+ raw_edit_context : edit_context. map ( Rc :: new) ,
133148 style,
134149 old_size : Rc :: default ( ) ,
135150 current_size : Rc :: default ( ) ,
@@ -185,6 +200,9 @@ impl Canvas {
185200 on_intersect : None ,
186201 on_touch_end : None ,
187202 on_context_menu : None ,
203+ on_composition_start : None ,
204+ on_composition_end : None ,
205+ on_text_update : None ,
188206 } ) ,
189207 } )
190208 }
@@ -464,6 +482,89 @@ impl Canvas {
464482 } ) ) ;
465483 }
466484
485+ pub ( crate ) fn on_composition_start < F > ( & self , mut handler : F )
486+ where
487+ F : ' static + FnMut ( Option < String > , Option < ( usize , usize ) > ) ,
488+ {
489+ let prevent_default = Rc :: clone ( & self . prevent_default ) ;
490+ self . handlers . borrow_mut ( ) . on_composition_start =
491+ self . common . add_ime_event ( "compositionstart" , move |event : CompositionEvent | {
492+ if prevent_default. get ( ) {
493+ event. prevent_default ( ) ;
494+ }
495+ handler ( event. data ( ) , None ) ;
496+ } ) ;
497+ }
498+
499+ pub ( crate ) fn on_composition_end < F > ( & self , mut handler : F )
500+ where
501+ F : ' static + FnMut ( Option < String > ) ,
502+ {
503+ let prevent_default = Rc :: clone ( & self . prevent_default ) ;
504+ self . handlers . borrow_mut ( ) . on_composition_end =
505+ self . common . add_ime_event ( "compositionend" , move |event : CompositionEvent | {
506+ if prevent_default. get ( ) {
507+ event. prevent_default ( ) ;
508+ }
509+ handler ( event. data ( ) ) ;
510+ } ) ;
511+ }
512+
513+ pub ( crate ) fn on_text_update < F > ( & self , mut handler : F )
514+ where
515+ F : ' static + FnMut ( Option < String > , Option < ( usize , usize ) > ) ,
516+ {
517+ let prevent_default = Rc :: clone ( & self . prevent_default ) ;
518+ self . handlers . borrow_mut ( ) . on_text_update =
519+ self . common . add_ime_event ( "textupdate" , move |event : Event | {
520+ if prevent_default. get ( ) {
521+ event. prevent_default ( ) ;
522+ }
523+ let edit_context = JsValue :: from ( event. target ( ) ) ;
524+ let text_update_event = JsValue :: from ( event) ;
525+ if let ( Ok ( text) , Ok ( update_range_end) ) = (
526+ Reflect :: get ( & text_update_event, & JsValue :: from_str ( "text" ) ) ,
527+ Reflect :: get ( & text_update_event, & JsValue :: from_str ( "updateRangeEnd" ) ) ,
528+ ) {
529+ handler ( text. as_string ( ) , None ) ;
530+
531+ // Clear the text update to avoid repeated updates.
532+ let Ok ( func) = Reflect :: get ( & edit_context, & JsValue :: from_str ( "updateText" ) )
533+ else {
534+ return ;
535+ } ;
536+ let func = JsCast :: unchecked_ref :: < Function > ( & func) ;
537+ let _ = func. call3 (
538+ & edit_context,
539+ & JsValue :: from_f64 ( 0.0 ) ,
540+ & JsValue :: from_f64 ( update_range_end. as_f64 ( ) . unwrap_or ( 0.0 ) ) ,
541+ & JsValue :: from_str ( "" ) ,
542+ ) ;
543+ }
544+ } ) ;
545+ }
546+
547+ pub ( crate ) fn is_support_edit_context ( & self ) -> bool {
548+ self . common . raw_edit_context . is_some ( )
549+ }
550+
551+ pub ( crate ) fn enable_edit_context ( & self ) {
552+ if let Some ( raw_edit_context) = & self . common . raw_edit_context {
553+ let canvas_js = JsValue :: from ( self . raw ( ) ) ;
554+ Reflect :: set ( & canvas_js, & JsValue :: from_str ( "editContext" ) , raw_edit_context)
555+ . expect ( "Failed to set editContext on canvas" ) ;
556+ }
557+ }
558+
559+ pub ( crate ) fn disable_edit_context ( & self ) {
560+ if self . common . raw_edit_context . is_none ( ) {
561+ return ;
562+ }
563+ let canvas_js = JsValue :: from ( self . raw ( ) ) ;
564+ Reflect :: set ( & canvas_js, & JsValue :: from_str ( "editContext" ) , & JsValue :: NULL )
565+ . expect ( "Failed to unset editContext on canvas" ) ;
566+ }
567+
467568 pub ( crate ) fn request_fullscreen ( & self , fullscreen : Fullscreen ) {
468569 fullscreen:: request_fullscreen (
469570 self . main_thread ,
@@ -559,6 +660,25 @@ impl Common {
559660 EventListenerHandle :: new ( self . raw . deref ( ) . clone ( ) , event_name, Closure :: new ( handler) )
560661 }
561662
663+ pub fn add_ime_event < E , F > (
664+ & self ,
665+ event_name : & ' static str ,
666+ handler : F ,
667+ ) -> Option < EventListenerHandle < dyn FnMut ( E ) > >
668+ where
669+ E : ' static + AsRef < web_sys:: Event > + wasm_bindgen:: convert:: FromWasmAbi ,
670+ F : ' static + FnMut ( E ) ,
671+ {
672+ if let Some ( edit_context) =
673+ self . raw_edit_context . as_ref ( ) . map ( |edit_context| edit_context. deref ( ) . clone ( ) )
674+ {
675+ let edit_context = JsCast :: unchecked_into :: < EventTarget > ( edit_context) ;
676+ Some ( EventListenerHandle :: new ( edit_context, event_name, Closure :: new ( handler) ) )
677+ } else {
678+ None
679+ }
680+ }
681+
562682 pub fn raw ( & self ) -> & HtmlCanvasElement {
563683 & self . raw
564684 }
0 commit comments