Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 49808f6

Browse files
Merge pull request #7400 from livecodeian/bugfix-21001_regression
[[ emscripten ]] Use a single hidden input field for all LC windows
2 parents 70380da + 11ca633 commit 49808f6

1 file changed

Lines changed: 103 additions & 54 deletions

File tree

engine/src/em-event.js

Lines changed: 103 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)