@@ -30,66 +30,59 @@ mergeInto(LibraryManager.library, {
3030 // text element used to capture input events
3131 _inputelement : null ,
3232
33+ // current target of keyboard / input events
34+ _inputtarget : null ,
35+
3336 // This function is used to call a function for each event
3437 // type to handler mapping defined for LiveCode on Emscripten.
3538 //
36- // The <func> must take three arguments: the event type, the
37- // handler function used to handle that event type, and a
38- // boolean indicating whether the event handler should be
39- // attached to the hidden input control.
39+ // The <func> must take two arguments: the event type, and the
40+ // handler function used to handle that event type.
4041 _eventForEach : function ( func ) {
4142
4243 // Master mapping from event types to handler functions.
4344 var mapping = [
44- [ 'focus' , LiveCodeEvents . _handleFocusEvent , false ] ,
45- [ 'blur' , LiveCodeEvents . _handleFocusEvent , false ] ,
45+ [ 'focus' , LiveCodeEvents . _handleFocusEvent ] ,
46+ [ 'blur' , LiveCodeEvents . _handleFocusEvent ] ,
4647
47- [ 'mousemove' , LiveCodeEvents . _handleMouseEvent , false ] ,
48- [ 'mousedown' , LiveCodeEvents . _handleMouseEvent , false ] ,
49- [ 'mouseup' , LiveCodeEvents . _handleMouseEvent , false ] ,
50- [ 'mouseenter' , LiveCodeEvents . _handleMouseEvent , false ] ,
51- [ 'mouseleave' , LiveCodeEvents . _handleMouseEvent , false ] ,
48+ [ 'mousemove' , LiveCodeEvents . _handleMouseEvent ] ,
49+ [ 'mousedown' , LiveCodeEvents . _handleMouseEvent ] ,
50+ [ 'mouseup' , LiveCodeEvents . _handleMouseEvent ] ,
51+ [ 'mouseenter' , LiveCodeEvents . _handleMouseEvent ] ,
52+ [ 'mouseleave' , LiveCodeEvents . _handleMouseEvent ] ,
5253
53- [ 'keyup ' , LiveCodeEvents . _handleKeyboardEvent , true ] ,
54- [ 'keydown' , LiveCodeEvents . _handleKeyboardEvent , true ] ,
54+ [ 'contextmenu ' , LiveCodeEvents . _handleContextMenu ] ,
55+ ] ;
5556
56- [ 'input' , LiveCodeEvents . _handleInput , true ] ,
57- [ 'beforeinput' , LiveCodeEvents . _handleInput , true ] ,
57+ var mapLength = mapping . length ;
58+ for ( var i = 0 ; i < mapLength ; i ++ ) {
59+ func ( mapping [ i ] [ 0 ] , mapping [ i ] [ 1 ] , mapping [ i ] [ 2 ] ) ;
60+ }
61+ } ,
5862
59- [ 'compositionstart' , LiveCodeEvents . _handleComposition , true ] ,
60- [ 'compositionupdate' , LiveCodeEvents . _handleComposition , true ] ,
61- [ 'compositionend' , LiveCodeEvents . _handleComposition , true ] ,
62-
63- [ 'contextmenu' , LiveCodeEvents . _handleContextMenu , false ] ,
63+ _inputEventForEach : function ( pFunc ) {
64+ var mapping = [
65+ [ 'keyup' , LiveCodeEvents . _handleKeyboardEvent ] ,
66+ [ 'keydown' , LiveCodeEvents . _handleKeyboardEvent ] ,
67+
68+ [ 'input' , LiveCodeEvents . _handleInput ] ,
69+ [ 'beforeinput' , LiveCodeEvents . _handleInput ] ,
70+
71+ [ 'compositionstart' , LiveCodeEvents . _handleComposition ] ,
72+ [ 'compositionupdate' , LiveCodeEvents . _handleComposition ] ,
73+ [ 'compositionend' , LiveCodeEvents . _handleComposition ] ,
6474 ] ;
6575
6676 var mapLength = mapping . length ;
6777 for ( var i = 0 ; i < mapLength ; i ++ ) {
68- func ( mapping [ i ] [ 0 ] , mapping [ i ] [ 1 ] , mapping [ i ] [ 2 ] ) ;
78+ pFunc ( mapping [ i ] [ 0 ] , mapping [ i ] [ 1 ] ) ;
6979 }
7080 } ,
7181
7282 addEventListeners : function ( pElement )
7383 {
74- // Create the hidden input element
75- var tInput = document . createElement ( 'input' ) ;
76- tInput . type = 'text' ;
77- tInput . style . position = 'absolute' ;
78- tInput . style . zIndex = 0 ;
79- tInput . style . opacity = 0 ;
80-
81- LiveCodeEvents . _inputelement = tInput ;
82- document . body . appendChild ( tInput ) ;
83-
84- LiveCodeEvents . _eventForEach ( function ( type , handler , addToInputField ) {
85- if ( addToInputField )
86- {
87- tInput . addEventListener ( type , function ( e ) {
88- handler ( e , pElement ) ;
89- } ) ;
90- }
91- else
92- pElement . addEventListener ( type , handler , true ) ;
84+ LiveCodeEvents . _eventForEach ( function ( type , handler ) {
85+ pElement . addEventListener ( type , handler , true ) ;
9386 } ) ;
9487
9588 // Make sure the canvas is treated as focusable...
@@ -106,9 +99,6 @@ mergeInto(LibraryManager.library, {
10699 LiveCodeEvents . _eventForEach ( function ( type , handler ) {
107100 pElement . removeEventListener ( type , handler , true ) ;
108101 } ) ;
109-
110- document . body . removeChild ( LiveCodeEvents . _inputelement ) ;
111- LiveCodeEvents . _inputelements = null ;
112102 } ,
113103
114104 initialize : function ( ) {
@@ -121,6 +111,20 @@ mergeInto(LibraryManager.library, {
121111 document . addEventListener ( "mouseup" , LiveCodeEvents . _handleDocumentMouseEvent ) ;
122112 document . addEventListener ( "mousemove" , LiveCodeEvents . _handleDocumentMouseEvent ) ;
123113
114+ // Create the hidden input element
115+ var tInput = document . createElement ( 'input' ) ;
116+ tInput . type = 'text' ;
117+ tInput . style . position = 'absolute' ;
118+ tInput . style . zIndex = 0 ;
119+ tInput . style . opacity = 0 ;
120+
121+ LiveCodeEvents . _inputelement = tInput ;
122+ document . body . appendChild ( tInput ) ;
123+
124+ LiveCodeEvents . _inputEventForEach ( function ( type , handler ) {
125+ tInput . addEventListener ( type , handler ) ;
126+ } ) ;
127+
124128 LiveCodeEvents . _initialised = true ;
125129 } ,
126130
@@ -129,6 +133,9 @@ mergeInto(LibraryManager.library, {
129133 return ;
130134 }
131135
136+ document . body . removeChild ( LiveCodeEvents . _inputelement ) ;
137+ LiveCodeEvents . _inputelements = null ;
138+
132139 LiveCodeEvents . _initialised = false ; ;
133140 } ,
134141
@@ -167,24 +174,64 @@ mergeInto(LibraryManager.library, {
167174 [ stack , owner ] ) ;
168175 } ,
169176
177+ // When a LC canvas acquires focus, mark it as the current key focus target, then pass focus to the hidden input field
178+ _setInputFocus : function ( pTarget ) {
179+ if ( pTarget != LiveCodeEvents . _inputtarget )
180+ {
181+ if ( LiveCodeEvents . _inputtarget != null )
182+ {
183+ var tOldTarget = LiveCodeEvents . _inputtarget ;
184+ LiveCodeEvents . _inputtarget = null ;
185+ LiveCodeEvents . _postKeyFocus ( LiveCodeEvents . _getStackForCanvas ( tOldTarget ) , false ) ;
186+ tOldTarget . blur ( ) ;
187+ }
188+
189+ if ( pTarget != null )
190+ {
191+ LiveCodeEvents . _inputtarget = pTarget ;
192+ LiveCodeEvents . _postKeyFocus ( LiveCodeEvents . _getStackForCanvas ( pTarget ) , true ) ;
193+ }
194+ }
195+
196+ if ( LiveCodeEvents . _inputelement != null )
197+ LiveCodeEvents . _inputelement . focus ( { "preventScroll" : true } ) ;
198+ } ,
199+
170200 _handleFocusEvent : function ( e ) {
171201 LiveCodeAsync . delay ( function ( ) {
172202 var stack = LiveCodeEvents . _getStackForCanvas ( e . target ) ;
203+
204+ // clear the current focus target when the hidden input field loses focus to a non-LC element.
205+ if ( e . target == LiveCodeEvents . _inputelement &&
206+ ( e . type == 'blur' || e . type == 'focusout' ) &&
207+ LiveCodeEvents . _getStackForCanvas ( e . relatedTarget ) == null )
208+ {
209+ _setInputFocus ( null ) ;
210+ return ;
211+ }
212+
173213 // ignore events for non-lc elements
174214 if ( ! stack )
175215 return ;
176216
177217 switch ( e . type ) {
178218 case 'focus' :
179219 case 'focusin' :
180- LiveCodeEvents . _postKeyFocus ( stack , true ) ;
181-
182- // direct key events to input element
183- LiveCodeEvents . _inputelement . focus ( ) ;
220+ LiveCodeEvents . _setInputFocus ( e . target ) ;
184221 break ;
185222 case 'blur' :
186223 case 'focusout' :
187- LiveCodeEvents . _postKeyFocus ( stack , false ) ;
224+ // ignore passing focus to hidden input field
225+ if ( e . relatedTarget == LiveCodeEvents . _inputelement )
226+ return ;
227+
228+ // if losing focus to another LC stack don't remove focus here, as focus will
229+ // be reassigned in the 'focusin' event sent to that stack canvas
230+ var tFocusStack = LiveCodeEvents . _getStackForCanvas ( e . relatedTarget ) ;
231+ if ( tFocusStack != null )
232+ return ;
233+
234+ LiveCodeEvents . _setInputFocus ( null ) ;
188235 break ;
189236 default :
190237 console . debug ( 'Unexpected focus event type: ' + e . type ) ;
@@ -531,14 +578,14 @@ mergeInto(LibraryManager.library, {
531578 [ stack , modifiers , char_code , key_code , key_state ] ) ;
532579 } ,
533580
534- _handleKeyboardEvent : function ( e , pCanvas ) {
581+ _handleKeyboardEvent : function ( e ) {
535582 LiveCodeAsync . delay ( function ( ) {
536583
537584 const kKeyStateDown = 0 ;
538585 const kKeyStateUp = 1 ;
539586 const kKeyStatePressed = 2 ;
540587
541- var stack = LiveCodeEvents . _getStackForCanvas ( pCanvas ) ;
588+ var stack = LiveCodeEvents . _getStackForCanvas ( LiveCodeEvents . _inputtarget ) ;
542589 /* TODO - reenable alt key detection
543590 * As there is no direct way to tell the difference between an alt+<key>
544591 * combination that produces a different character, and holding alt down
@@ -603,7 +650,7 @@ mergeInto(LibraryManager.library, {
603650 [ stack , enabled , offset , chars , length ] ) ;
604651 } ,
605652
606- _handleInput : function ( inputEvent , pCanvas ) {
653+ _handleInput : function ( inputEvent ) {
607654 console . debug ( 'Input event: ' + inputEvent . type + ' ' + inputEvent . data ) ;
608655 } ,
609656
@@ -612,15 +659,16 @@ mergeInto(LibraryManager.library, {
612659 return [ buffer , string . length ] ;
613660 } ,
614661
615- _handleComposition : function ( compositionEvent , pCanvas ) {
662+ _handleComposition : function ( compositionEvent ) {
616663 LiveCodeAsync . delay ( function ( ) {
617664 // Stack that we're targeting
618- var stack = LiveCodeEvents . _getStackForCanvas ( pCanvas ) ;
665+ var stack = LiveCodeEvents . _getStackForCanvas ( LiveCodeEvents . _inputtarget ) ;
619666
620667 // ignore events for non-lc elements
621668 if ( ! stack )
622669 return ;
623670
671+ console . log ( 'composition event: ' + compositionEvent . type + " '" + compositionEvent . data + "'" ) ;
624672 var encodedString ;
625673 var chars , length ;
626674 switch ( compositionEvent . type ) {
@@ -759,7 +807,8 @@ mergeInto(LibraryManager.library, {
759807 case 'mousedown' :
760808 // In the case of mouse down, specifically request
761809 // keyboard focus
762- e . target . focus ( ) ;
810+ LiveCodeEvents . _setInputFocus ( target ) ;
811+
763812 LiveCodeEvents . _postMousePosition ( stack , e . timeStamp , mods , pos [ 0 ] , pos [ 1 ] ) ;
764813 var state = LiveCodeEvents . _encodeMouseState ( e . type ) ;
765814 LiveCodeEvents . _postMousePress ( stack , e . timeStamp , mods ,
0 commit comments